-
Notifications
You must be signed in to change notification settings - Fork 327
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-???? | 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 <44342099+Ryun1@users.noreply.github.com>
Co-authored-by: Ryan Williams <44342099+Ryun1@users.noreply.github.com>
Co-authored-by: Ryan Williams <44342099+Ryun1@users.noreply.github.com>
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.
the idea would be for the user to sign this information the exact same way they sign redeemers in datums (ie adjust script hash integrity check accordingly
@colll78 please don't
scriptDataHash
is already a pain, I would suggest instead to move the field as is inside the 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?
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.
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.
```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.
## 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 |
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)