Skip to content
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

Open
wants to merge 8 commits into
base: master
Choose a base branch
from

Conversation

colll78
Copy link
Contributor

@colll78 colll78 commented Jan 8, 2024

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)

@colll78 colll78 changed the title CPS-???? | Tag / Redeemer field in TxOut CIP-???? | Tag / Redeemer field in TxOut Jan 8, 2024
@rphair
Copy link
Collaborator

rphair commented Jan 23, 2024

@colll78 we're not adding this for discussion in today's CIP meeting, where new proposals are normally introduced in Triage, because of the Draft status (as also with #749). Please feel free to leave it in this state as long as you need... then we will proceed to meeting discussion as well as more rigorous community review (though leaving it here for public comment now is also welcome).

@colll78 colll78 marked this pull request as ready for review January 23, 2024 14:33
@colll78
Copy link
Contributor Author

colll78 commented Jan 23, 2024

@colll78 we're not adding this for discussion in today's CIP meeting, where new proposals are normally introduced in Triage, because of the Draft status (as also with #749). Please feel free to leave it in this state as long as you need... then we will proceed to meeting discussion as well as more rigorous community review (though leaving it here for public comment now is also welcome).

Whoops, I didn't mean to set this as a draft.

@rphair
Copy link
Collaborator

rphair commented Jan 23, 2024

@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

CIP-output-tagging/README.md Outdated Show resolved Hide resolved
colll78 and others added 3 commits January 23, 2024 11:41
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>
@Ryun1
Copy link
Collaborator

Ryun1 commented Feb 4, 2024

Input from the IOG Plutus and Ledger teams would be appreciated here 🙏
@michaelpj @lehins

Comment on lines +115 to +127
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 ]

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.

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

Copy link
Contributor

@lehins lehins Feb 8, 2024

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.

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

Copy link
Contributor Author

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 in datums (ie adjust script hash integrity check accordingly). I will update this CIP to reflect that.

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

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?

Copy link
Contributor

@michaelpj michaelpj left a 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.
Copy link
Contributor

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".

Copy link
Contributor Author

@colll78 colll78 Feb 9, 2024

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.
Copy link
Contributor

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.
Copy link
Contributor

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:

  1. Anything included in transactions goes in the history of the chain forever, so that would apply to tags as well
  2. 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.

@gitmachtl
Copy link
Contributor

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.

@rphair
Copy link
Collaborator

rphair commented Apr 2, 2024

@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:

  • This is relevant to a "composability" problem of transaction outputs from one dApp to be applied as inputs to a potentially different dApp.
  • Within the CIP process there hasn't yet been any other way of dealing with this composability problem other than the one suggested here.
  • However, people are able to deal with composability issues in other ways that don't require the proposed changes... and therefore this solution might only be applicable to the author's own / preferred implementations.

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants