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-???? | SpendMany script purpose (replace Spend) #858

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

Conversation

matteocoppola
Copy link

This CIP proposes to replace the current Spend purpose with another one called SpendMany, removing the need of computational waste and higher fees when a transaction validates multiple inputs coming from the same script.

If adopted, Cardano smart contract development would be more efficient, less prone to security issues and easier from a Dev experience.


(rendered proposal in branch)

Copy link

@fallen-icarus fallen-icarus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be possible for users to specify multiple spendMany groups for the same script in a single transaction? For example, perhaps they want to sub-divide a group of inputs being spent by a single script (possibly by redeemer used).


SpendMany is executed only once for the whole transaction and it comes with 2 parameters:
- The current script hash
- The list of the indexes of the inputs that are being spent from this script

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some scripts allow composing with itself where inputs use different redeemers. It sounds like this CIP will require all inputs from the script in this transaction to use the same redeemer.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the current CIP version requires 1 redeemer for all the inputs from the smart contract.
Can't we just use a single redeemer that contains lists for each field, indexed by the order of the inputs?
We already do like that and it works smoothly: as we know the inputs and their order in advance, it's easy to setup such a redeemer.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't we just use a single redeemer that contains lists for each field, indexed by the order of the inputs?

I'd rather not use the redeemer like this since it must always be validated at run-time to verify all of the inputs are properly accounted for. If an input is accidentally/maliciously omitted from the redeemer, the smart contract can return true without actually validating that input. In other words, the security of this approach depends on the DApp developer. It is possible for one DApp to be secure while another DApp is missing checks.

Instead, the ledger can do the checks before running the scripts if separate spending groups are used. One of the plutus/ledger devs can correct me if I am wrong, but if the rule is that all inputs in a spending group must use the same redeemer, wouldn't this be a very cheap check that can be part of phase 1 validation? You can just hash the redeemer used for each input in the group and then compare the hashes. If an input is not tagged by a redeemer, the ledger will immediately catch it and fail the transaction.

I have not used the redeemer index pattern very much, so if I am misunderstanding something please correct me.

@rphair rphair added the Category: Plutus Proposals belonging to the 'Plutus' category. label Jul 17, 2024
Copy link
Collaborator

@rphair rphair left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks @matteocoppola - putting on agenda to introduce at next CIP meeting, as titled in the document without the "replace" clause (which might be debatable): https://hackmd.io/@cip-editors/93 - you would be very welcome at the meeting.

We should eventually make the PR & document titles consistent, but in the meantime I think it helps to have (replace Spend) in the PR title to call attention to this fact. I don't have the skill set to suggest whether Spend and SpendMany could or should coexist but I think it would be a good discussion point for the meeting.

CIP-spendMany-script-purpose (replace Spend)/README.md Outdated Show resolved Hide resolved
CIP-spendMany-script-purpose (replace Spend)/README.md Outdated Show resolved Hide resolved

Even if it's not a dependency, this CIP works very well with the [CIP for Transaction Inputs as Unordered Set](https://github.com/cardano-foundation/CIPs/pull/758).

Even if this CIP looks as an alternative to [CIP-112](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0112), they can perfectly co-exist. Additionally this CIP drastically simplifies the development experience.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Even if this CIP looks as an alternative to [CIP-112](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0112), they can perfectly co-exist. Additionally this CIP drastically simplifies the development experience.
Even if this CIP looks as an alternative to [CIP-112 | Observe Script Type](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0112), they can perfectly co-exist. Additionally this CIP drastically simplifies the development experience.

just helps for those who struggle to remember every number 😆

## Rationale: how does this CIP achieve its goals?

This CIP removes the need of unprofessional hacks to achieve whole-transaction validation while also achieving better computational efficiency.
A simple chnage of the Spend purpose in SpendMany can simplify the developer experience, giving visibility of all the inputs to validate at once.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
A simple chnage of the Spend purpose in SpendMany can simplify the developer experience, giving visibility of all the inputs to validate at once.
A simple change of the Spend purpose in SpendMany can simplify the developer experience, giving visibility of all the inputs to validate at once.

typo!

@rphair
Copy link
Collaborator

rphair commented Jul 23, 2024

@matteocoppola following up from my #858 (review) from CIP meeting today (re: does SpendMany "replace" Spend, add to it, modify it, supersede it and/or deprecate it...):

Consensus is that Ledger input (cc @lehins @WhatisRT) is needed to decide how to go ahead with this. Everyone agrees the newly defined purpose is an improvement on the old one, with the old use cases being definable with the new script purpose, but can't be sure if there aren't "edge cases" that would break backwards compatibility: and therefore a requirement for versioning and/or supporting both the old & new script purpose.

Because of this question of scope, as well as feasibility of doing this in the Ledger, we've decided to wait for Ledger's initial feedback with some kind of endorsement before assigning this a candidate CIP number. Once we get to this stage I'll be sure it's on the next CIP meeting agenda.

@WhatisRT
Copy link
Contributor

I'll need to think a bit more about this, but my first thoughts are that this is a great idea. The issue with the redeemer is a bit bigger though, since Ledger also needs to match redeemers to inputs. One idea would be to allow an input to be a list of inputs locked by the same script. Then one can still run the same script with different redeemers while the logic that matches redeemers could be unchanged.

@lehins
Copy link
Contributor

lehins commented Jul 24, 2024

This is definitely a sensible proposal. That being said, we can't do this change for PlutusV1..PlutusV3, since we can't change the context for those versions and addition of a new script purpose is a change to the plutus context. So, we can't "replace Spend", as the title suggests. But, that doesn't mean we can't implement it for PlutusV4. In the matter of fact, I just made a comment on another CIP that we could solve those two proposals with the same solution.

New script purpose could look something like this for plutus:

PV4.SpendingMany [(Integer, TxIn)]

where Integer would refer to the index in the inputs

While for Ledger's redeemer pointer/plutus purpose (i.e. Ledger's script purpose) would look like this:

SpendingMany (Set Word32)

There are a few issues that come with this approach off top my head, neither of which might be an actual problem, but something developers and users need to be aware of. In all of the examples below I assume all inputs are locked by the same script, which would be enforced by ledger:

  • Same redeemer is expected for multiple inputs. Naturally, datum supplied and execution units must be the same for an identical execution of a script, so this is something to be expected:
Map.fromList [(SpendingMany [1,2,3], (_ :: Data, ExUnits 123 456))]
  • When different behavior is desired it would still be possible to split it up into multiple purposes:
Map.fromList
  [ (SpendingMany [1,2], (a :: Data, ExUnits 123 456)
  , (SpendingMany [3], (b :: Data, ExUnits 1230 4560)
  ]
  • Incorrect usage could lead to execution of the same script for the same input multiple times:
Map.fromList
  [ (SpendingMany [1,2], (a :: Data, ExUnits 123 456)
  , (SpendingMany [1,3], (b :: Data, ExUnits 1230 4560)

In this example the script that locks input 1 would be executed twice: once with redeemer (a :: Data, ExUnits 123 456) and the other time with redeemer (b :: Data, ExUnits 1230 4560). That being said, there could be some use cases for this and people actually want this behavior or we could add some ledger rules that prevent duplicate execution. Something that would have to be decided.

@fallen-icarus
Copy link

fallen-icarus commented Jul 25, 2024

  • Incorrect usage could lead to execution of the same script for the same input multiple times: ...

... there could be some use cases for this and people actually want this behavior or we could add some ledger rules that prevent duplicate execution. Something that would have to be decided.

@lehins My first thought is I'd be concerned of this increasing the double satisfaction attack surface. From a smart contract's perspective, I don't see how this is different than double spending the input. DApps that don't want this behavior would likely need extra logic to account for the same input being used to satisfy two separate script executions. In other words, these DApps would be burdened by these extra checks just to support the DApps that actually want this behavior. I think this feature will likely be too niche to impose this burden on the remaining DApps.

I would rather the ledger disallow this feature by guaranteeing an input gets exactly one script execution.

@rphair rphair added the State: Unconfirmed Triaged at meeting but not confirmed (or assigned CIP number) yet. label Aug 20, 2024
@rphair
Copy link
Collaborator

rphair commented Aug 20, 2024

@matteocoppola it's noted by @fallen-icarus (#418 (comment)) that this should be considered a solution for candiate CPS-0004. By convention that CIP & CPS would be linked in the header & CIP Rationale so please keep that in mind for future revisions as these documents evolve.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Category: Plutus Proposals belonging to the 'Plutus' category. State: Unconfirmed Triaged at meeting but not confirmed (or assigned CIP number) yet.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants