@@ -74,35 +74,36 @@ readParamsMethod _req = do
7474-- | Handle the @ReadUtxos@ RPC method.
7575-- Looks up specific UTxO entries by their 'TxIn' keys and returns them
7676-- along with the ledger tip.
77+ -- Returns an empty response when no keys are provided, matching other
78+ -- UTxO RPC implementations (Dolos, cardano-node-api, Dingo).
7779readUtxosMethod
7880 :: MonadRpc e m
7981 => Proto UtxoRpc. ReadUtxosRequest
8082 -> m (Proto UtxoRpc. ReadUtxosResponse )
81- readUtxosMethod req = do
82- utxoFilter <-
83- if not (null $ req ^. U5c. keys)
84- then QueryUTxOByTxIn . fromList <$> mapM txoRefToTxIn (req ^. U5c. keys)
85- else pure QueryUTxOWhole
86-
87- nodeConnInfo <- grab
88- AnyCardanoEra era <- liftIO . throwExceptT $ determineEra nodeConnInfo
89- eon <- forEraInEon @ Era era (error " Minimum Conway era required" ) pure
90-
91- let target = VolatileTip
92- (utxo, chainPoint, blockNo, systemStart, eraHistory) <- liftIO . (throwEither =<< ) $ executeLocalStateQueryExpr nodeConnInfo target $ do
93- utxo <- throwEither =<< throwEither =<< queryUtxo (convert eon) utxoFilter
94- chainPoint <- throwEither =<< queryChainPoint
95- blockNo <- throwEither =<< queryChainBlockNo
96- systemStart <- throwEither =<< querySystemStart
97- eraHistory <- throwEither =<< queryEraHistory
98- pure (utxo, chainPoint, blockNo, systemStart, eraHistory)
99-
100- timestamp <- slotToTimestamp systemStart eraHistory chainPoint
101-
102- pure $
103- defMessage
104- & U5c. ledgerTip .~ mkChainPointMsg chainPoint blockNo timestamp
105- & U5c. items .~ obtainCommonConstraints eon (utxoToUtxoRpcAnyUtxoData utxo)
83+ readUtxosMethod req
84+ | null $ req ^. U5c. keys = pure defMessage
85+ | otherwise = do
86+ utxoFilter <- QueryUTxOByTxIn . fromList <$> mapM txoRefToTxIn (req ^. U5c. keys)
87+
88+ nodeConnInfo <- grab
89+ AnyCardanoEra era <- liftIO . throwExceptT $ determineEra nodeConnInfo
90+ eon <- forEraInEon @ Era era (error " Minimum Conway era required" ) pure
91+
92+ let target = VolatileTip
93+ (utxo, chainPoint, blockNo, systemStart, eraHistory) <- liftIO . (throwEither =<< ) $ executeLocalStateQueryExpr nodeConnInfo target $ do
94+ utxo <- throwEither =<< throwEither =<< queryUtxo (convert eon) utxoFilter
95+ chainPoint <- throwEither =<< queryChainPoint
96+ blockNo <- throwEither =<< queryChainBlockNo
97+ systemStart <- throwEither =<< querySystemStart
98+ eraHistory <- throwEither =<< queryEraHistory
99+ pure (utxo, chainPoint, blockNo, systemStart, eraHistory)
100+
101+ timestamp <- slotToTimestamp systemStart eraHistory chainPoint
102+
103+ pure $
104+ defMessage
105+ & U5c. ledgerTip .~ mkChainPointMsg chainPoint blockNo timestamp
106+ & U5c. items .~ obtainCommonConstraints eon (utxoToUtxoRpcAnyUtxoData utxo)
106107 where
107108 txoRefToTxIn :: MonadRpc e m => Proto UtxoRpc. TxoRef -> m TxIn
108109 txoRefToTxIn r = do
@@ -111,8 +112,8 @@ readUtxosMethod req = do
111112
112113-- | Handle the @SearchUtxos@ RPC method.
113114-- Filters the UTxO set by a predicate and returns a paginated result.
114- -- When the predicate contains exact address matches, the query is narrowed
115- -- to those addresses; otherwise the entire UTxO set is fetched .
115+ -- The predicate must contain exact address matches so the query can be
116+ -- narrowed; broad predicates are rejected with @INVALID_ARGUMENT@ .
116117searchUtxosMethod
117118 :: MonadRpc e m
118119 => Proto UtxoRpc. SearchUtxosRequest
@@ -123,10 +124,12 @@ searchUtxosMethod req = do
123124 maxItems = req ^. U5c. maxItems
124125 startToken = req ^. U5c. maybe'startToken
125126
126- -- Determine query strategy: use address-based query if possible, otherwise fetch whole UTxO
127- let utxoFilter = case mPredicate >>= extractAddressesFromPredicate of
128- Just addrs -> QueryUTxOByAddress addrs
129- _ -> QueryUTxOWhole
127+ utxoFilter <- case mPredicate >>= extractAddressesFromPredicate of
128+ Just addrs -> pure $ QueryUTxOByAddress addrs
129+ Nothing ->
130+ throwGrpcErrorWithMessage
131+ GrpcInvalidArgument
132+ " predicate too broad: must contain exact address match to avoid fetching the entire UTxO set"
130133
131134 nodeConnInfo <- grab
132135 AnyCardanoEra era <- liftIO . throwExceptT $ determineEra nodeConnInfo
0 commit comments