Closed carlhammann closed 1 year ago
my only concern is with the naming of
liftFilter
andliftLookup
That's also my concern... Why should we call a function b -> m (Maybe c)
a "lookup" and a function b -> Maybe c
a "filter", and in what sense do we "lift"? Both functions apply a possibly failing "updating" operation to a list of outputs (represented as pairs (TxOutRef, o)
for some o
), and keep only the successfully updated outputs. The difference is that, for liftLookup
, the updating operation can depend on the state of the mock chain.
Here's a more fundamental solution that just occurred to me: We could in principle go around the explicit applications of liftFilter
and liftLookup
(or whatever we want to call them) with a similar trick as we use for tweaks, defining a custom monad for retrieving and filtering of UTxOs. This would allow idioms like
utxos <-
getUtxos $
utxosAt (Pl.validatorAddress A.auctionValidator)
>>= isOutputWithValueSuchThat (`Value.geq` theNft)
>>= resolveDatum
>>= isOutputWithInlineDatumOfType @A.AuctionState
I think it'd be nice to have something like this, but let's discuss the options first.
I took another swing at this, and I'm now (relatively) satisfied. I have written a small module with a type UtxoSearch m a
and a function
runUtxoSearch :: Monad m => UtxoSearch m a -> m [(TxOutRef, a)]
The module also contains various functions like filterWith :: UtxoSearch m a -> (a -> m (Maybe b)) -> UtxoSearch m b
, so that the running example in this discussion finally becomes:
utxos <- runUtxoSearch $
utxosAtSearch (Pl.validatorAddress A.auctionValidator)
`filterWithBool` ((`Value.geq` theNft) . outputValue)
`filterWith` resolveDatum
`filterWithPure` isOutputWithInlineDatumOfType @A.AuctionState
As a additional feature, we could have an additional search module with helpers for searching with a certain reference script, as certain staking credential, etc.
As a additional feature, we could have an additional search module with helpers for searching with a certain reference script, as certain staking credential, etc.
I think that's a question that will be answered by our usage patterns. For now, I think that idioms like allUtxos `filterWith` resolveReferenceScript `filterWithBool` ((== theReferenceScript) . outputReferenceScriptL)
are enough.
Edit: Look at this comment to see where the PR ended up. I'll leave the original comment here in order to keep the conversation logical.
This PR proposes a small improvement to how we retrieve UTxOs from the blockchain. It will close #239. (I did not implement all ideas I proposed there, because some of them did not seem worth the trouble, at least not until we actually store more type information in the mock chain, see issue #235.)
I removed all of the
filteredUtxos...
and the...withDatums
functions, in favour of the two functionsliftFilter
andliftLookup
. This enables us to write something likeinstead of
which I think is much clearer.
I also added a few "lookup" functions to use with
liftLookup
, namelyresolveDatum
resolveValidator
andresolveReferenceScript
. For the last of these three, I also changed the implementation of the direct monad a bit so that it keeps track of reference scripts, (i.e.validatorFromHash
returnsJust
the full script, even for scripts that sit in the reference script field of some UTxO, independently of whether they own any outputs). This is tested here.