-
Notifications
You must be signed in to change notification settings - Fork 343
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CIP-0148? | Tag / Redeemer field in TxOut #735
base: master
Are you sure you want to change the base?
Conversation
@colll78 we're not adding this for discussion in today's CIP meeting, where new proposals are normally introduced in Triage, because of the |
Whoops, I didn't mean to set this as a draft. |
@colll78 Due to last minute status change this has been added to Triage (not time for full technical review; just an introduction) at today's meeting: https://hackmd.io/@cip-editors/80 |
Co-authored-by: Ryan Williams <[email protected]>
Co-authored-by: Ryan Williams <[email protected]>
Co-authored-by: Ryan Williams <[email protected]>
Input from the IOG Plutus and Ledger teams would be appreciated here 🙏 |
transaction_witness_set = | ||
{ ? 0: [* vkeywitness ] | ||
, ? 1: [* native_script ] | ||
, ? 2: [* bootstrap_witness ] | ||
, ? 3: [* plutus_v1_script ] | ||
, ? 4: [* plutus_data ] | ||
, ? 5: [* redeemer ] | ||
, ? 6: [* plutus_v2_script ] | ||
, ? 7: [* plutus_v3_script ] | ||
, ? 8: [* output_tag ] ; | ||
} | ||
|
||
output_tag = [ index: unit, data: plutus_data ] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Including this information in the witness set might be an attack vector.
The user signs the transaction body, not the witness set.
That means that once transaction is signed the witness set might still change, and the signature would be correct.
That implies the user agreed to sign something that is later modified.
This is not a problem for redeemers because usually the information present on redeemers is validated in the contract, so if an attacker modifies it, a carefully designed contract will fail.
In the example use case of the "TxOutRef
in output datum" that information is indeed in the datum, which is part of the tx body, which is signed and hence immutable once signed (or else the signature is invalid).
if we move this info outside the body the TxOutRef
can be modified after signing, leaving the contract vulnerable to double satisfaction.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also modifying the redeemer indirectly causes the body to be invalid, because redeemers and datums in the witness set are used to calculate the scriptDataHash
modifying these will result in a different scriptDataHash
, hence the body is invalid
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The user signs the transaction body, not the witness set.
The user does sign some parts of the witness set (redeemers and datums) indirectly through the script hash integrity check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes that is correct I corrected myself in the coment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right the idea would be for the user to sign this information the exact same way they sign redeemers and datums (ie adjust script hash integrity check accordingly). I will update this CIP to reflect that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe also move the redeemer in the body in the process?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that it would be best if redeemers were directly in the transaction body and I would fully support a separate CIP to that end, however, given that currently they are signed via scriptDataHash
I don't want to introduce inconsistency by moving these into the body in which case tooling would have to accommodate them differently than they do normal redeemers. The idea is to keep them as close from an implementation perspective to transaction redeemers to lower the implementation burden.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@colll78 trust me, scriptDataHash
is much worse than a small inconsistency
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we not then create a CIP to move redeemers into the tx body?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe also move the redeemer in the body in the process?
Should we not then create a CIP to move redeemers into the tx body?
I've discussed this very same idea on multiple occasions.
I am not sure if we need a CIP about it, since it shouldn't be that complicated to implement and I suspect everyone would be in favor. But, it might be a good idea to create a CIP for visibility. So, if you still think we need a CIP for it, then I can create one or maybe someone from the community would be willing to step in.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like it: it adds a kind of weird dangling feature that is useful in this one specific case, and otherwise doesn't mean anything. But I acknowledge that it's a reification of the pattern people currently use.
What I would like is some more principled solution to the double satisfaction problem, which we don't have.
So I guess it's a -0 from me: I would prefer not to do this but if there's lots of support and no alternative I wouldn't block something like this.
``` | ||
The intention of the above contract is much clearer, the contract itself is more efficient, and associated transactions do not need to permanently add unwanted data to the chain (unlike the inline datum, reference script solutions). The tags can also be used more generally to convey information about the output to all the validators in the transaction (ie `tag = FullfilledSwapOrder` might signify that this is a fulfilled swap order from protocol XYZ or `tag = SignedOracleObservation BuiltinByteString Integer` might contain a signed message from an oracle that attests that the Value contained in the output is worth X USD). | ||
|
||
We already have redeemers associated with each script to provide the smart contract with information that is only relevant during execution for similar reasons (ie redeemers allow us to associate arbitrary data with a script). This would be to TxOuts what Redeemers are for scripts, allowing us to associate arbitrary data (relevant only during Phase 2 validation) to outputs. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This made me wonder why you can't in fact use redeemers.
If a particular script execution needs to know which transaction output is "it's" output for some purpose, then you can put the index of that output into the redeemer.
The answer (I think) is that for double-satisfaction you need exclusivity: with the redeemer solution each redeemer has its own mapping and nothing ensures they don't overlap. With output tags you have (I assume) a single tag.
That does sit a little awkwardly, however. Why shouldn't you have multiple tags? What if you do want to use a single output for two purposes in a legitimate way? e.g. "this is the payout address for the Ada" and "the permission token goes here".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The type of output_tag
is data, so you can have any arbitrary information you want in the output so you can store whatever you want there.
What if you do want to use a single output for two purposes in a legitimate way? e.g. "this is the payout address for the Ada" and "the permission token goes here".
That is two outputs though right? IE 1 output is "payout for ada" and 1 is "permission token output", in which case you tag each output accordingly.
The issue is that matching the redeemers to the outputs is very expensive and they aren't really designed to facilitate this time data association with outputs so the interface would be awkward.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please elaborate on why using redeemers for this purpose would be awkward?
We can always work on improving the interface, but I want to know why conceptually redeemers can't be used for this purpose?
```haskell | ||
outputTags :: [ (Integer, BuiltinData) ] | ||
``` | ||
The `Integer` represents the index of the output in the transaction outputs for which the data is associated to. The issue with this is that without any support for constant-time index lookup, iterating through this list in a plutus validator will eat into the script budget (ex-units/mem/size). This issue becomes especially bad when there are multiple validators that need to lookup the data associated with an output (or outputs) since the traversal of this list must be done redundantly across all such validators. One of the biggest efficiency improvements that DApps received in Plutus V2 was from the fact that Inline Datums made it no longer necessary to iterate through the datum map to find the datum associated with each output. If we went with this approach, we would be reintroducing that bottleneck which seems clearly undesirable. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I would prefer this approach, and for us to just solve the lookup time problem properly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Solving lookup problem would be a good thing to do. It has been a year since that comment was made, anyone knows if there any progress in that direction?
CC @zliu41
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes - builtin arrays with constant time lookup is coming at the next HF.
## Motivation: why is this CIP necessary? | ||
Often smart contract logic for most DApps involves associating arbitrary data with transaction outputs. Currently, there are a number of design patterns that are used to achieve this association, but each of these design patterns have significant drawbacks. The limitations of existing solutions have made a wide variety of DApps and design patterns infeasable in practice due to script budget constraints and high complexity of required code. | ||
|
||
One obvious use-cases for output tags is to prevent the double satisfaction problem. Currently, the most popular solution for double satisfaction is to include the `TxOutRef` of the input in the datum of the corresponding output and then when validating that the output correctly satisfies the spending conditions for the corresponding input the validator checks that the `TxOutRef` of the input matches the `TxOutRef` in the datum of the output. One issue with this solution to double satisfaction is that it breaks general composability since the output won't be able to contain datums used by other protocols (since the datum is already occupied by the TxOutRef of the corresponding input). Another issue with this approach is that this data permanently bloats the size of the chain even though it is only relevant during the execution of smart contracts. The only reason this data is stored in the datum is so that it can be accessed in the context of Phase 2 validation; the data is not actually relevant to future transactions and thus there is no real reason for it to be permenantly stored on the blockchain in UTxOs. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure the bloat complain quite lands:
- Anything included in transactions goes in the history of the chain forever, so that would apply to tags as well
- But: information in datums does bloat the UTXO set, which can be a problem
That is, I would say it's not so much the permanency that's a problem (that happens anyway), so much as the (temporary, but ongoing) UTXO set bloat.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I did not make it clear I was referring to the UTxO set size which is often what is most impactful on the efficiency of indexers for dApps.
just wanna ask if this affects in any way also hardware wallets? because of the memory constrains, hardwarewallets cannot look at whole utxo sets while performing the signing action. |
@colll78 this is lagging in progress a bit and there was a question in the CIP meeting today over some resolutions that weren't recorded. A couple editors including @Ryun1 & @Crypto2099 (I was just taking some notes) + @michaelpj and @fallen-icarus as I remember made the following points:
Assuming the above reservations are valid, both @Ryun1 and I (and maybe others) thought this might then be better off as a CPS dealing with composability (and peripherally the "double satisfaction problem"), and suggesting this tagging approach as one means of dealing with it. |
I would like to clarify that this CIP is not designed specifically as a solution to the double satisfaction problem / dApp composability problem. This is a general improvement to the smart contract platform on Cardano that enables a huge range of use-cases that are currently in-feasible. The core value add is the ability to associate arbitrary data with outputs without permanently writing that data to the UTxO set. Sure, it can be used to solve double satisfaction without sacrificing dApp composability (a property that is currently unique to this solution to DS); however, more generally it can be used to do things like tag specific outputs with the USD price of the multi-asset value they contain via a signed oracle message which is associated to the output via this It also enables things such as dependent transaction chaining which is a pre-requisite for babel fees. To achieve this, you could use this field to store a Likewise this CIP is of critical importance to intent-based operations / smart contract account abstraction. Both of these involve expressing intent offchain which reduces the number of transactions required to execute a user action. For instance, right now when a user wants to interact with a DEX / orderbook they first must create their order (which conveys their intent i.e. to swap X asset A to Y asset B in DEX pool P, or to sell asset A for asset B at exchange rate of E on an orderbook) in a preliminary transaction, and then a second transaction is required to actually fulfil their request (i.e. batch process orders against the pool on an AMM DEX or match orders on an orderbook DEX), furthermore if you want to update your intent (ie. you want to swap your asset A for asset C instead of asset B or you want to increase slippage or update your sell price or even change the asset you are selling) all of these things will require an additional transaction (perhaps multiple). With this CIP, you can provide your intent as a signed message which in turns allows all aforementioned user operations to be fulfilled in a single transaction. The user doesn't need to submit and pay for a transaction to create a swap request / limit order, the instead they can just publicize a signed message that describes their intent (i.e. swap order with XYZ constraints) which can be consumed by dApps directly to allow them to spend funds from the account as long as they do so exactly as intended by the user (as described by the user's signed message). The user can then update their intent without performing a transaction by producing a new signed message that can then (with this CIP) be associated with the relevant input / outputs. |
My reading of @colll78's #735 (comment) is that this proposal is still interesting to the community. However, I still have no idea how this would be validated as a candidate. Since all the prior response was from the Plutus team I'm tagging this as In the meantime marking this as |
Can we have a re-review on this please? Intent systems are an extremely hot topic right now, and this CIP would provide huge value for all such applications. |
oops clicked wrong button to submit "comment" review
--- | ||
|
||
## Abstract | ||
We propose to allow the attachment of arbitrary, temporary data to transaction outputs within the script context. This data, akin to redeemers in their operational context, is intended to be used exclusively during the execution of Plutus scripts and thus are not recorded by the ledger. This will facilitate a wide variety of smart contract design patterns, one of which can be used as a general solution for double satisfaction without sacrificing script composability. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be useful to add a link to an article or something that describes the double satisfaction problem for those who are not familiar with it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"recorded by the ledger" is an incorrect statement. Every bit from every transaction is recorded by the ledger in the blockchain. Instead, it should state: "not recorded in the ledger state".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will facilitate a wide variety of smart contract design patterns
This statement is way too ambiguous. It is unclear what those use cases are. If they are unknown, then we should be stating it clearly. If they are known then then they must be listed here. Most importantly I would like ta have clarity how this Tag will be used for those multiple problems in the same transaction at the same time.
I read through the CIP and I fail to see a drastic difference between this Tag and the spending Datum or Redeemer. When comparing to inline datum the only difference I see Tag would not contribute to the size of UTxO, which is nice, but if the UTxO overhead is the concern then why regular spending datum hash is not a suitable solution? Is it the fact that spending datum must be known upon TxOut creation, while an arbitrary Tag can be supplied during TxOut spending? If that is the case, thenwhy regular redeemers are not a suitable fit? I read this comment, but I can't understand why redeemers are not suitable fit for this purpose either. FYI. I am not trying to put holes into the CIP, I am just trying to understand it. I don't really write plutus scripts, so it is hard for me to see the use case. With respect to implementation, as far as I understand it, there are a few things that would have to be done on the ledger side in order to accomodate this CIP:
Final question is why it would be a useful concept only for outputs? Why not add this feature to all other spending purposes? For example a more general solution that I could envision would be adding an extra field to a redeemer: an optional Tag and then on the Plutus side we would add this Tag to all the matching places that are unlocked with a script in that transaction. Or even avoid adding a concept of Tag completely and just add that Data from redeemers to each individual thing that is locked by a script. To sum up my understanding of this CIP and how it compares to existing features:
Is this a correct summary? The reason why I am asking all these questions is to see if this is indeed the simplest and most versatile approach that we can take in order to solve the problem that is outlined in the "Motivation".
I would like to invite the author of the CIP and other parties that interested in this CIP to join the next Ledger Working Group Meeting #13 on March 10th, so we could discuss this in more detail. Without proper understanding of this feature it will be hard for us to create an accurate implementation, so I would really like to understand what is this we are getting into here. |
I was thinking more about it and maybe my confusion stems from misunderstanding which outputs will be getting the Tag? Is it the desire of this CIP to add Tags to outputs that are being created by the transaction or the ones that are being spent by the transaction? |
Co-authored-by: Robert Phair <[email protected]>
Co-authored-by: Robert Phair <[email protected]>
Co-authored-by: Alexey Kuleshevich <[email protected]>
Co-authored-by: Alexey Kuleshevich <[email protected]>
Co-authored-by: Alexey Kuleshevich <[email protected]>
Fundamentally, a redeemer exists to provide information relevant for the execution of the associated script. It is a mechanism by which users can express how they would like to interact with that script. The redeemer often describes the type of interaction the user would like to perform, and information relevant to the successful execution of that action. Furthermore, the information contained by the redeemer is only relevant for the execution of the specific transaction and is entirely irrelevant for subsequent transactions (otherwise it would be stored in the datum). This CIP proposes the introduction of information that, like redeemers is only relevant to the current transaction (and thus should not be stored in the UTxO set) but where redeemers provide information relevant to the execution of a particular script, the optional Tags proposed by this CIP provide information relevant to a given The core use-cases I have detailed so far are:
I will expand on why redeemer / spending datums are not adequate for the above use-cases in the CIP meeting next Tuesday.
Unlike redeemer (which provides information relevant to the execution of a specific script, Tag provides information about a given newtype DoubleSatisfactionTag = DoubleSatisfactionTag TxOutRef This indicates to all the scripts executed in the transaction that this tag should only be used to satisfy the spending conditions of the specific input (identified by the The orderbook redeemer is:
The NFT marketplace redeemer is:
Someone comes along and builds a transaction that spends the UTxO at the orderbook contract with my 5 Foo tokens and in the same transaction spends the UTxO with my NFT at the marketplace contract and includes one output to my Okay no problem, let's fix this using spending datums, now we modify the orderbook contract and the marketplace contracts as follows: Great! Now we have solved the double satisfaction problem! Whoops, the
So the orderbook contract, and the NFT marketplace contract were able to solve the double-satisfaction problem by using the spending datum of the output to uniquely tag the UTxOs being unlocked, but in doing-so they broke composability, because they now enforce conditions on the structure of the datum of the outputs that are satisfying the spending conditions (namely they are enforcing that the datum of those outputs must be the What if we use tags? Well, now the output is tagged with the |
@colll78 Thank you for your response. Your comment definitely made it clearer for me why spending datums are not a suitable solution to the problem. It is still unclear to me why redeemers can't be used to solve this problem. It might be a very naive question, but please bare with me. As a thought experiment, in order for me to understand the problem better, here is how I could envision redeemer being used for attacking this problem. Note, I am not trying to argue that this is a better approach to what is being suggested in the CIP. I just want to see if my understanding is sound through checking with you whether such a solution could work at all. Imagine this transaction with UTxO, where
So, in such a transaction both I can see how this Tag solution is a more "type safe" and more efficient approach to dealing with problem, when comparing to the one that uses redeemers. But, it doesn't really feel to me versatile enough. For example:
It feels to me like this problem is a more fundamental one that could use a more versatile and standardized solution. I am not going to pretend like I have a better solution at this moment, but I have never thought about this problem until now. |
An idea just popped into my mind. I haven't thought it through very well yet, but, I think it sounds sensible. What if we add a concept of a "Claim". Every script would have a capability to claim parts of the transaction and no two scripts could claim the same part of the transaction. Here is a sample data type: data Claim =
= ClaimInput TxIn Value
-- ^ Specifies which input to claim and which portion of it will be claimed by the script
| ClaimWithdrawal RewardAccount Coin
-- ^ Claim ADA that is coming out of a withdrawal
| ClaimRefund CertIx Coin
-- ^ Claim ADA that was refunded in one of the unregistration certificates (either DRep or Staking Credential)
| ClaimMint Value
-- ^ Claim a positive value that was minted in this transaction Then we'd add this claim to a redeemer: data Redeemer = Redeemers
{ unRedeemers :: Map (PlutusPurpose AsIx era) (Data era, ExUnits, [Claim])} This would allow for a whole lot more flexibility:
Ledger rules would then verify that there are no overlaps between any two claims:
Two things that I like about this solution is that it would be standardized and there would be no extra logic required from the DApp writers (thus practically free from the perspective of execution units). It would be up to transaction builder to specify which part of the transaction maps to which validator. Naturally, those claims would be available to the script, so if desired those scripts would be able to confirm that enough resources were claimed to satisfy the validator, but at least they wouldn't need to worry about any other script claiming the same resources. I also believe that those claims could be specified for all plutus versions, with one limitation that only PlutusV4 would be able to see those claims in their context. FYI, current CIP is quite a bit easier to implement from the Ledger perspective, so in a sense I am piling up more work on our shoulders, but I believe that it would be totally worth it. What I am suggesting above would be a much safer solution IMHO, since there would be no ambiguities on how this feature suppose to be used, which is not the case with Tags. This approach as I described does not provide a mechanism to check where the money is going (i.e. ADA went to Alice that spend her NFTs), but I don't think it should even matter. In other words checking that no resource is used for two different purposes, sounds to me like a well defined solution to the double satisfaction problem. @colll78 Thoughts? CC @WhatisRT What's your opinion on this suggestion. If this solution sounds sensible to you guys I could write up a more detailed CIP. |
The redeemer exists to provide information relevant to the execution of a specific script, as such it, it contains a format that is only comprehensible to the script itself. In the above example, fooScript can barScript can indeed view the redeemers list, but for Even in an ideal world, where we get every single script author to follow a standard that enforces the redeemer is encoded in constructor format, and that the first field in the constructor of any spending redeemer should be a Again, I would like to explicitly clarify that the purpose of tags is not exclusively as a solution to double-satisfaction, this is just a single example in which the ability to provide information relevant to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@colll78 as per Tuesday's CIP meeting this was acknowledged as ready for merge as soon as the formalities like CIP number & directory renaming (to CIP-0148
) are in place. 🎉
@lehins our understanding of your latest comments is that these are an exploration of this issue with an eye for best practice that @colll78 and colleagues have worked out through engineering trial & error over 3 years or so. So we're assuming that you have no real objections to this unless stated explicitly.
I'm tagging Last Check
which puts it on the next meeting agenda (https://hackmd.io/@cip-editors/108) as a failsafe, but @Crypto2099 @Ryun1 as you recall from the meeting (cc @perturbing) this was declared ready to merge before then if there's full editor support & no last-minute objections.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@colll78, sorry I got distracted by other things and forgot to respond. Thank you for your explanation, it does make it clear to me why existing solutions are unsuitable. I figured that the problem with redeemers would be the fact that data supplied is weekly typed and it would be very hard to have all script writers to agree on a common format. With that in mind, can you please explain to me how is this also not a problem for Tags proposed in this CIP. Tags are expected to be a weekly typed Data as well as redeemers are:
if the redeemer of a script is BuiltinData encoded in constructor format (ie. Constr Index [BuiltinData]) then the fooScript will need to know what field the fields in barScript mean to meaningfully interact with them
What if other scripts try to use tags for something else which would conflict with the solution for double satisfaction that your script is relying on? In other words, from my understanding of this CIP, it also suffers from the exact same problem as redeemers do.
@rphair I understand that @colll78 and other have a lot of experience with this problem and with DApp writing in general, but I am still not yet convinced that this is the best approach possible.
Last thing I want is to implement a feature that we have to support forever, which we end up replacing with something different in a feature era, because this approach turned out to be suboptimal.
What I would like to see is the list of all problems that this approach solves. Cause I was under impression from reading this CIP that the sole reason why it is needed was to solve double satisfaction problem, which turns out is not the case: "The alternative that you are proposing cannot address the other use-cases I mentioned (intent-based operations, account-abstraction, etc)." @colll78 Please forgive me, but I can't find any mention of "account-abstraction" in this CIP.
For example, unless we are talking about something else, intents as I know them, will be solved by a CIP that is already planned to be implemented CIP-118, so this CIP no longer needs to solve it and I am not even sure how it would solve it, to be honest with you.
"account-abstraction" - what is this and how this Tag approach solves it and why is it a problem that we need to solve to begin with?
@rphair In other words, I do object this CIP as it stands right now, because in my opinion it does not have enough information on how it solves the problems it claims to be solving. It does not compare to any other approach that we can take that would solve those problems in alternative ways. For example, what the alternative approach that I suggested that would solve double satisfaction problem has not been considered so far or properly compared to. Are there other solutions that are known to solve the same problem(s).
If this CIP is not clear to me, as a ledger expert, I am sure it will be unclear to many others. So at the very least I would expect some better explanations of the problems and the solution with some examples. In particular:
- how solving double satisfaction plays together with other purposes Tags will be used for?
- how this feature works for solving double satisfaction when partial matches of many TxOuts to many TxIns are desired?
- why we only want to solve these problems for TxOuts and not other sources of value: withdrawals, deposits/refunds, minting?
Keep in mind, that I am not trying to push back on the feature, I am asking for this CIP to be improved, with proper comparison to alternative approaches that we can take (i.e. not the ones that are already available today).
--- | ||
|
||
## Abstract | ||
We propose to allow the attachment of arbitrary, temporary data to transaction outputs within the script context. This data, akin to redeemers in their operational context, is intended to be used exclusively during the execution of Plutus scripts and thus are not recorded by the ledger. This will facilitate a wide variety of smart contract design patterns, one of which can be used as a general solution for double satisfaction without sacrificing script composability. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"recorded by the ledger" is an incorrect statement. Every bit from every transaction is recorded by the ledger in the blockchain. Instead, it should state: "not recorded in the ledger state".
--- | ||
|
||
## Abstract | ||
We propose to allow the attachment of arbitrary, temporary data to transaction outputs within the script context. This data, akin to redeemers in their operational context, is intended to be used exclusively during the execution of Plutus scripts and thus are not recorded by the ledger. This will facilitate a wide variety of smart contract design patterns, one of which can be used as a general solution for double satisfaction without sacrificing script composability. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will facilitate a wide variety of smart contract design patterns
This statement is way too ambiguous. It is unclear what those use cases are. If they are unknown, then we should be stating it clearly. If they are known then then they must be listed here. Most importantly I would like ta have clarity how this Tag will be used for those multiple problems in the same transaction at the same time.
```haskell | ||
spendValidator :: BuiltinData -> Integer -> ScriptContext -> () | ||
spendValidator _ outIdx ctx = | ||
let ownOutputTag = txOutTag ownOutput |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How do you enforce uniqueness of the Tag? Nothing prevents a user from creating a transaction where all supplied and expected tags have the same value?
|
||
If this CIP is adopted, the above validator could be simplified to: | ||
```haskell | ||
spendValidator :: BuiltinData -> Integer -> ScriptContext -> () |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I fail to see with this example how it is possible to match the many-to-many relationship that we have for inputs and ouptuts. This example assumes one-to-one relationship.
We already have redeemers associated with each script to provide the smart contract with information that is only relevant during execution for similar reasons (ie redeemers allow us to associate arbitrary data with a script). This would be to TxOuts what Redeemers are for scripts, allowing us to associate arbitrary data (relevant only during Phase 2 validation) to outputs. | ||
|
||
## Specification | ||
We extend transaction witness set with a new list of arbitrary data associated with transaction outputs (`output_tags`). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest we put them in the TxBody instead of the witnesses. There is no reason why it must be in the witness set. In fact even redeemers didn't have any business being placed in the witness set, so we are considering moving them into TxBody, which would simplify calculation of the script integrity check. Although, this decision is not set in stone yet.
transaction_witness_set = | ||
{ ? 0: [* vkeywitness ] | ||
, ? 1: [* native_script ] | ||
, ? 2: [* bootstrap_witness ] | ||
, ? 3: [* plutus_v1_script ] | ||
, ? 4: [* plutus_data ] | ||
, ? 5: [* redeemer ] | ||
, ? 6: [* plutus_v2_script ] | ||
, ? 7: [* plutus_v3_script ] | ||
, ? 8: [* output_tag ] ; | ||
} | ||
|
||
output_tag = [ index: unit, data: plutus_data ] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe also move the redeemer in the body in the process?
Should we not then create a CIP to move redeemers into the tx body?
I've discussed this very same idea on multiple occasions.
I am not sure if we need a CIP about it, since it shouldn't be that complicated to implement and I suspect everyone would be in favor. But, it might be a good idea to create a CIP for visibility. So, if you still think we need a CIP for it, then I can create one or maybe someone from the community would be willing to step in.
|
||
Note that although we propose to add `tag` as a field to `TxOut`s in the script context, we don't actually put them there in the CDDL. This is because the purpose of `output_tag` is to hold arbitrary data that associated to the output that is only relevant in the context of evaluating Plutus validators during Phase 2 validation. This data is not meant to be stored in UTxOs. | ||
|
||
This means that when constructing the script context the ledger must add each the data in each `output_tag` to the `TxOut` at the matching index in the transaction outputs. If there is a compelling case to be made to introduce this tagging for `TxOut`s in the transaction inputs in the script context (ie to associate arbitrary data to transaction inputs during Plutus validator execution) then this can be extended to introduce a 9th field to the witness set `[* output_tag]` to contain the arbitrary data that the ledger can then associate with `TxOut`s in transaction inputs in the script context. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That would be a 10th field with an index 9
😉
ownOutput :: TxOut | ||
ownOutput = elemAt outIdx (txInfoOutputs (txInfo ctx)) | ||
``` | ||
The intention of the above contract is much clearer, the contract itself is more efficient, and associated transactions do not need to permanently add unwanted data to the chain (unlike the inline datum, reference script solutions). The tags can also be used more generally to convey information about the output to all the validators in the transaction (ie `tag = FullfilledSwapOrder` might signify that this is a fulfilled swap order from protocol XYZ or `tag = SignedOracleObservation BuiltinByteString Integer` might contain a signed message from an oracle that attests that the Value contained in the output is worth X USD). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens when one script expects the tag to be FullfilledSwapOrder
, while another expects it to be ProtectAgainsDoubleSatsfaction
Moreover we have a much more versatile approach planned to satisfy the swaps/intents use case, which is described in CIP-118
Just i -> i | ||
|
||
ownOutput :: TxOut | ||
ownOutput = elemAt outIdx (txInfoOutputs (txInfo ctx)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would suggest not to change the TxOut
type itself, this way inputs would not be affected
Is there an assumption that all outputs will require a tag? i.e does it have this type txInfoOutputs :: [(TxOut, Tag)]
or this type txInfoOutputs :: [(TxOut, Maybe Tag)]
?
```haskell | ||
outputTags :: [ (Integer, BuiltinData) ] | ||
``` | ||
The `Integer` represents the index of the output in the transaction outputs for which the data is associated to. The issue with this is that without any support for constant-time index lookup, iterating through this list in a plutus validator will eat into the script budget (ex-units/mem/size). This issue becomes especially bad when there are multiple validators that need to lookup the data associated with an output (or outputs) since the traversal of this list must be done redundantly across all such validators. One of the biggest efficiency improvements that DApps received in Plutus V2 was from the fact that Inline Datums made it no longer necessary to iterate through the datum map to find the datum associated with each output. If we went with this approach, we would be reintroducing that bottleneck which seems clearly undesirable. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Solving lookup problem would be a good thing to do. It has been a year since that comment was made, anyone knows if there any progress in that direction?
CC @zliu41
thanks @lehins for clarifying the position we had assumed in #735 (review). We will consider your latest round of review a checklist for things that need to be agreed upon before moving forward. - cc @WhatisRT (and @polinavino if you want to jump into the discussion about how this might affect the development of "intents" & #862) @colll78 I'll dial this back from |
We propose to allow the attachment of arbitrary, temporary data to transaction outputs within the script context. This data, akin to redeemers in their operational context, is intended to be used exclusively during the execution of Plutus scripts and thus are not recorded by the ledger. This will facilitate a wide variety of smart contract design patterns, one of which can be used as a general solution for double satisfaction without sacrificing script composability.
(proposal rendered from branch)