Proposal to get rid of initial distributions (clickbait issue title)
Opened this issue · 0 comments
Running a trace, which consists of a sequence of transactions (each specified by a transaction skeleton), requires to choose an initial state of the mockchain to run it on. This initial distribution is often an association list that maps a set of values to each wallet of interest. Over time, the concept has been enhanced to allow setting datums, or reference scripts. Now, an initial distribution can be any list of TxSkelOut
, which is nice and convenient.
In the backstage, initial distributions are implemented as a transaction that is forced upon the mockchain, skipping validation.
I am proposing to modify this in a way that I think is
- the logical continuation of previous work on initial distributions
- most of all: a significant simplification of our user-facing API
- an additional feature that might come in handy
Problem
Annoyance of initial distributions in the API
There are many functions in cooked that exist in two variants: one takes the default init dist, the other has an additional parameter to override it. PR #450 helps in this regard.
We also have a dedicated InitialDistribution
type and module.
Conceptually awkward and inconvenient from the user/auditor side
It turns out in practice that we always need to define a custom initial distribution. Smart contracts in the wild involve custom tokens that we need from the start, we may want to tidy up the initial state to get rid of all the useless Ada utxos, we don't need the 10 known wallets, sometimes we like to set reference scripts at the beginning too.
When we design a trace, we always have a specific initial distribution in mind. Most traces would never even succeed on the default distribution.
Therefore, we specify a custom distribution (sometimes several) and we pass it as a parameter to every single unit test during audits or development. But this happens in the test tree, not near the definition of the trace although the trace is designed with this specific distribution in mind.
Proposal
I suggest that we add a new action in our mock chain monad. We would have both the classic validateTxSkel
and a new forceTxSkel
(or any better name).
forceTxSkel
would apply a transaction without validation, just like it is already done with the transaction obtained from the [TxSkelOut]
of InitialDistribution
.
E.g.
foo :: MonadBlockChain m => m ()
foo = do
forceTxSkel $
txSkelTemplate
{ txSkelOuts =
[ paysPK alice (apple 3)
paysPK bob (banana 7) `withDatum` bar
],
txSkelOpts = def { txOptEnsureMinAda = true }
(of course in practice you would define it and reuse it as a first action of other traces)
- This would not make it any more difficult to define initial distributions. Initial distributions are already almost transactions type-wise.
- We could use the
txOptEnsureMinAda
directly instead oftoInitDistWithMinAda
- We would get rid of initial distributions as parameters of many functions
- We would no longer need two variants of these functions
- We would have more self-contained traces in audits
- We would have less verbose test trees that don't need to always refer to the initial distribution
- As a transaction based on a skeleton, this would be possible to use tweaks on it
- As a transaction, we could get the list of utxos in return as we have with
validateTxSkel
which would make it easier to extract aTxOutRef
to use as an input when minting NFTs afterwards without having to use a search. - As a bonus, we would be able to force transactions at later points too. This would often be a bad idea but sometimes we run into technical difficulties when we interact with external smart contracts (versions mismatch, bugs in tx generation that lead to mismatching hashes, etc) and we are stuck at an early step although we know for certain that the transaction is conceptually valid. While we investigate how to solve it, we could force it on the chain and proceed anyway. Think of it as our
undefined
in Haskell dev.