kompact-io-landing/content/posts/cip-118.md

319 lines
17 KiB
Markdown

---
title: "CIP 118: Too much solution for not enough need"
date: 2025-07-21
---
## Abstract
CIP 118 fails to demonstrate sufficient need for the ledger changes it proposes.
The use cases CIP 118 cites can already be supported. No evidence is provided
that the specific contexts which cannot be supported are critical, nor is there
an attempt to quantify the claimed performance improvements. Accepting CIP 118
will not only add to ledger complexity, it is an open invitation for a series of
subsequent ledger changes, both tweaks and fixes of missteps, and as more of the
inexhaustible list of intents gets shoe horned in. Efforts and energies would be
much better spent making accessible and utilizing what we already have.
## Context
### Of the CIP
CIP 118 proposes ledger changes to accommodate "nested transactions". At
present, a participant of a transaction must sign the transaction body, complete
byte for byte. With CIP 118, a participant could provide witness to an "intent"
or "subtransaction". A subtransaction does not need to follow the same ledger
rules as a transaction. For example, a subtransaction does not need to be
balanced.
### Of the author
All solutions worth the time of day ought to be solving actual problems. It may
be highly subjective as to whether or not something is a problem. Some say
feature others say bug. Even if we agree that something is a problem, we may
still disagree on its relative severity. What to me is a mild annoyance, may to
you be an absolute deal breaker.
The problems I think are the ones most worth solving are generally the ones that
have caused me the most trauma. While it is not so hard to extrapolate from
personal experience and otherwise sympathize with other people's problems, it is
harder to judge their relative severity, and thus a solution's relative
importance.
While working on Cardano, designing dapps, I have no shortage of pain points to
point at. I have spent relatively little time architect-ing systems that might
be described as something along the lines of "singular, many to many". Token
swaps would be an example: a participant wishes to partake in a singular event,
potentially with any other participant(s). By the end of the transaction, a user
has no further expectation of, nor obligations to, other users. I have spent
much more time thinking about "on-going, few to few" systems such as Lightning
Networks, where engagements are p2p enduring and with only a small subset of the
overall network, or Subbit.xyz, where a consumer pays their provider repeatedly
over a long period of time.
### Of the piece
This piece came about in preparation to participating in
[this](https://www.youtube.com/watch?v=p8uJ_4ydoBU) roundtable discussion.
## Main
Making ledger changes is not something to be undertaken lightly. One should ask:
1. Is the problem addressed sufficiently important?
2. Does the proposal adequately address the problem(s) claimed?
3. What are other consequences of the proposal?
4. What are the alternatives?
The following is mainly concerned with question one, with three and four
considered in passing. We do not dwell on question two.
### Use cases can already be accommodated
It is immediate that any unsafe behavior found in the ledger is a problem
sufficiently important that the ledger ought to be changed. For example, a way
to submit transactions that can result in a DDOS style attack. The case for a
set of ledger changes that only add or augment features and functionality is
much less immediate, and should be demonstrated with receipts.
The use cases cited by the proposal can be feasibly accommodated with the
current ledger rules. The proposed use cases are outlined in a
[CPS](https://github.com/cardano-foundation/CIPs/pull/779), referenced in
CIP 118. They are: atomic swaps including limit orders, market orders, and babel
fees; dapp fee sponsorship; and access to yet to be determined data. Some
implementations, albeit nascent, are or will soon be available (Aquarium,
Bullet).
CIP 118 is not sufficiently explicit which characteristics of the use cases the
authors deem necessary to support. For example, if it includes that a user must
be able to spend a UTXO at a payment key address with only a partial witness,
then a ledger change is of course necessary. If this requirement is relaxed by,
say, we can assume it is a validator address, or there can be some multi step
communication between parties, then such functionality can be supported without
ledger changes, as it is in the aforementioned examples.
At the time of writing the proposal states:
> There are off-chain solutions being developed for the purpose of achieving the
> same (major) goals, including fee coverage, atomic swaps, DApp fee
> sponsorship, collateral sponsorship, etc.
This seems reasonable, but its continuation is more moot:
> This gives us indication that it is a worthy pursuit to solve this problem at
> the ledger level, in a way that is cheaper, more convenient, maintains formal
> guarantees, requires less off-chain communication, and does not require
> deposits or interaction with smart contracts.
This is insufficient. All dapp logic can be cheaper, more convenient, _etc_ if
it is written into the ledger.
Token swapping is dominant because we can already do it relatively well, and we
still find other applications very hard to build. In some respect the "singular,
many to many" paradigm is what L1s are designed to handle. You are free to send
funds to anyone and they to you, but its expensive and slow - a necessary
consequence of a secure, decentralised system. (Insert joke here about mockchain
that solves the blockchain trilemma.) Token swapping is one of the few problems
for which we've actually got some solutions. Not perfect (too centralised, too
siloed, too expensive, _etc_), but they exist. Moreover, any such problem could
be solved with vanilla transaction signatures, tooling permitting. Meanwhile,
"on-going, few to few" paradigms have so much potential that is being stifled by
other problems.
Neither of us are providing receipts for our contradictory interpretation of the
dominance of token swapping. The difference is, this is not a CIP.
The onus is on the proposers to make a strong case that either there is some
specific formulation of the use case that is not currently supported and is
critical, or that the proposal will make game changing improvements to what is
already feasible. Neither of these are presented.
### Complexity is the root of some evil
When building software, the primary questions are commonly "what happens if
...". The difficulty to address these questions is directly related to the
scope/ complexity of the execution context. For Cardano dapps, the Plutus script
context has been kept intentionally narrow (ie simple) so that answering "what
happens if ..." questions remains manageable. It is still wide enough to build
many many things.
Each change to the ledger generally increases complexity. Backwards
compatibility is supposedly a must: if the Plutus Code runs today, it should run
"forever". There are many terms and conditions applied to this. The legacy of
Byron has been a ball and chain on many a tool developers' foot. Two different
types of address, different rules on transaction logic _etc_. Since Vasil, we
have two different ways to handle datum; with Chang, three. The more cases that
need to be handled, the more code is needed to the handle them, the higher the
maintenance burden and the higher cognitive load when reasoning about them.
We do not always have the luxury to restrict the aspects of the ledger we are
concern with. When building from scratch and no need to interop with existing
scripts, we likely do have this luxury. We'll use the newest version of Plutus,
and have no concern about what came before. But what happens if the tool we want
to build is a general transaction composer to reduce user fees and chain
traffic? What happens if we're trying to build an application, that will consume
funds from an existing validator address? These are not very exotic examples,
and the differing versions and behaviours are now our problems. What happens if
someone did compose a Plutus V3 and Plutus V4 script in a single transaction? It
couldn't be a nested transaction, but a normal one? An intent might cover
burning tokens, but now the end user, and/ or the tooling, need to know to
handle these different cases. Complexity can grow exponentially, and erodes
confidence that we have made the right assumptions or reasoned correctly.
A ledger change proposal must justify the complexity cost they will "forever"
leave with maintainers and developers.
### Justifying previous changes
There have been multiple previous changes to the ledger. How do previous changes
compare to CIP 118 in terms of scale of problem, and scale of ledger change?
Let's consider Vasil. Three CIPs implemented in Vasil include 31 Reference
Inputs, 32 Inline Datums, and 33 Reference Scripts. Claim: The change was demand
led, it addressed a fundamental and widely shared problem, and it was a
relatively small perturbation of the current design.
The changes were user demand led. Transaction size was **the** bottleneck and it
was for everyone. Transaction size still is frequently the bottleneck in
applications. Of course, one can produce scripts that exhaust ex units, but in
my experience once other factors are optimized for, the hard bound is often the
transaction size. It is still the case that a medium complexity script will
easily be three quarters of the max transaction size.
CIP 31 purportedly addressed the problem of broadcasting state. Plutus script
execution is narrow. When an application needed data from the chain, it has to
be included in the form of spending an input. This was awkward when it came to
making the same state available to concurrent transactions. CIP 31 provided a
much easier and cheaper mechanism for broadcasting state in this sense. The
transaction referencing the input pays in fees and bytes only a fraction of what
it would otherwise cost, particularly with CIP 32.
CIP 32 purports to address an inconvenience caused by the former design's
support only of datum hashes at tip. Quote: "This is also inconvenient for the
spending party, who must watch the whole chain to spot it". I find this argument
incredibly weak. To create a transaction, a user already needs access to the
chain via functions `getUtxosAtTip` and `submitTx`. Having another
`getDatumByHash` is not a big deal - it is just a tooling issue. A more
compelling case is that it reduces the size of transactions. Prior to the change
and in normal application an output datum hash would need to be validated, and
so the datum would be present in the witness set, adding to the transaction
size. The consuming transaction would then need to include the same data. There
are some contexts where this can be improved upon, but CIP 32 essentially halves
this problem by paying for the data just once. The impact of CIP 32 is
compounded when used with CIP 31: any referencing transaction does not pay in
fees nor bytes for the inclusion of the datum.
CIP 33 allowed scripts to be referenced, rather than having to be included in
the transaction. As mentioned, scripts can easily exhaust most if not all the
transaction size limit. Referencing scripts dramatically reduces the size of
script heavy transactions. Generally speaking, of the three CIPs, this was the
most significant.
The ledger changes in Vasil were a small perturbation of what had come before.
CIPs 32 and 33 did not introduce new functionality in and of themselves. They
shifted the need to provide data from the transaction submitter, to the
verifying Cardano node. Nodes already did recall for transaction inputs. Adding
recall for datums and scripts adds a little extra workload to the nodes. It
unlocked new functionality, only in the sense that the same transaction could be
much smaller. It also had network performance benefits with respect to
potentially higher effective throughput, and/or lower bandwidth and storage
requirements. CIP 31, is arguably a slightly larger perturbation than the other
two with respect to ledger design change. It is still, however, small.
A brief comparison with Chang and the changes introducing governance: Chain
governance has long been a key milestone in the vision of Cardano. In many ways
Cardano's focus on governance is the USP in an oversaturated sea of competitor
cryptocurrencies. Governance could not have been reasonably implemented without
substantial changes to ledger rules. These changes are justified because of the
significance of the capability they introduced.
### Ledger change record is wanting
It is a direct trade-off: additional functionality (complexity); additional ways
to shoot yourself in the foot. We do not have a stellar record when it comes to
ledger changes. There are multiple cases in which ledger designs were introduced
only to be deemed incorrect. We list a few.
The Alonzo hardfork brought Plutus V1. Plutus V1 permitted a mint value that had
a zero entry for ada. This is confusing because ada is impossible to mint by
smart contract. A correction was later pushed through.
Plutus V1 permitted 0 value withdraws. It was proposed by the ledger maintainers
that this mistake ought to be fixed, only for it to be pointed out that such a
change would have broken a bunch of dapps.
Reference scripts were introduced in Vasil. They left open a moderate attack
vector resulting in a DDOS attempt. A fix was pushed through in which the new
fee calculation was, afaics, whatever the Haskell code said it was. Reference
inputs were introduced in Vasil. In either Chang 1 or Plomin, these were "fixed"
to prevent an input being both referenced and spent. This broke a dapp I had
previously written.
It is unrealistic to believe there won't ever be mistakes. It is moot whether
these mistakes, or "mistakes", were preventable had more consideration been
given to the changes. Perhaps if there was more demand and more demand driven
development, then these problems might have been addressed before they reached
mainnet.
### Current ledger assumptions are still un- or underdocumented
It is a misdiagnosis to read the lack of products and solutions as the lack of
supported functionality at the ledger level. Cardano development is notorious
for the fraught difficulty it entails. The current ledger assumptions are still
un- or underdocumented. This is a massive hole, down which developers sink their
valuable time. Time that could be spent making better tooling and better
product.
Cardano developers seemingly must perform a rite of passage. Through their own
painful journey each will learn: inputs are lexicographically ordered and lists
are encoded as indefinite length. They will mull:
- Is this fixed behaviour I can rely on or an implementation quirk?
- Where are the docs on the datum integrity hash computation, for which version?
- Which version of Plutus and the ledger was it that the mint value stop
including ada?
There are probably a few dozen people who would be able to answer these. They
would do so with ease since the knowledge gained though trauma is written into
cerebral scar tissue. For everyone else, bon courage: the answers are in Github
issues, dangling code comments, and code itself. Before we dig this hole still
deeper by adding further to ledger complexity, we ought to prioritise
documenting its current behaviour, in a way developers can self serve.
### Systems of intents are always incomplete
CIP 118 would open us up to an never ending drip of ledger changes,
each bringing additional intents yet supported. CIP 118, does not limit us: any
intent not supported can be expressed in an invoked Plutus script. However, I'm
not confident that interested parties would not lobby to have their particularly
favoured intents entrenched in the ledger. Were CIP 118 to be accepted, the bar
for inclusion would seem to be relatively low.
Intents are often an excellent abstraction. The code can clearly communicate the
consequences of the logic they represent, even to non-experts, which is a
particularly admirable goal in relation to smart contracts. A key reason why I
used Plutus Apps long after many others had abandoned it was that its system of
intents (constraints in their vernacular) resulted in code that was far clearer
to a keen reader compared to the few alternatives we had at the time (eg
Plutarch).
Intents are never complete. Until it was abandoned, the list of supported
intents in Plutus Apps kept growing. Worse still, it was not designed to be
extensible. If the logic you required was not supported by the intents exposed,
you were left to fork the repo and add your own. In the long ago era, when I
used Plutus Apps this became my problem when the intents did not support
addresses with stake credentials. It was a massive time sink. I am highly wary
of libraries that use system of intents that aren't extensible via, say, the use
of Rust traits or Haskell classes pattern. Every system of intents I have seen
has grown the list of things it originally intended to support. As addressed,
CIP 118 is extensible via Plutus but in this way it creates a two tier system.
It seems inevitable there would forever be pressure to grow the list of ledger
supported intents.
## Conclusion
CIP 118 needs to make a stronger case that it's a solution worth implementing. I
am skeptical this can be made, but would be happily proved wrong. It would be
far more beneficial to put the efforts and energies that would be spent on
implementing CIP 118 on improving the tooling and accessibility around the
functionality we already have.