From 2b5657d759e73d0b57a62f9e6d808adb2a2cd7e3 Mon Sep 17 00:00:00 2001 From: fallen-icarus Date: Wed, 18 Jan 2023 13:15:29 -0500 Subject: [PATCH 01/14] CIP readme --- CIP-????/README.md | 112 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 CIP-????/README.md diff --git a/CIP-????/README.md b/CIP-????/README.md new file mode 100644 index 0000000000..c35c3e7310 --- /dev/null +++ b/CIP-????/README.md @@ -0,0 +1,112 @@ +--- +CIP: ? +Title: Maybe Datum +Category: Plutus, Ledger +Status: Proposed +Authors: + - fallen-icarus +Implementors: [] +Discussions: +Created: 2023-01-18 +License: CC-BY-4.0 +--- +# CIP-XXXX: Maybe Datum + +## Abstract +Currently all plutus spending scripts take a datum directly from the UTxO being spent. While this allows for creating a very simple ledger-script interface, there are a number of use cases where this feature is not just undesired but can also be an obstical to Dapp developement. I propose changing plutus scripts so that they optionally take the datum directly from the UTxO being spent. This single change would solve a number of issues currently motivating different CIPs/CPSs. + +## Motivation: why is this CIP necessary? +As of now, plutus spending scripts take the datum directly from the UTxO being spent. While it allows the ledger-script interface to be very simple, it causes three major problems. + +### Problem 1: Spending Script Redundant Executions +Using the eUTxO architecture, it is currently possible to create spending scripts that validate based off of the transaction as a whole instead of any individual UTxO. Imagine if three UTxOs were spent from such a script's address within the same transaction? Which datum should be passed to the spending script? Currently, the ledger-script interface passes each UTxO's datum to the script individually and executes this "transaction level" spending script three times. Since the transaction context does not change between executions, these additional executions are completely redundant. There is currently no way to use a transaction level spending script so that these redundant exections do not happen. This limitation significantly handicaps Cardano's usage of the eUTxO architecture. While there is a potential workaround, the workaround has its own major drawbacks. You can read more about it in the related CPS [here](https://github.com/fallen-icarus/CIPs/tree/full-eUTxO-potential/CPS-%3F%3F%3F%3F#readme). + +### Problem 2: Wrong/Missing Datums Result in Permanently Locked Script UTxOs +When a script's UTxO is missing a datum or has the wrong datum, the spending script is unable to parse the datum attached to the UTxO and is therefore guaranteed to fail. This results in permanently locked UTxOs at the script address. In order to help prevent accidental locking of script UTxOs, proxies are generally used. However, it is very difficult to use such proxies in a decentralized way. In short, by being forced to use proxies, the Dapp loses some of its decentralization. + +As an addition point, regulators are not going to like any application where it is easy to accidentally lock (lose) users' funds permanentally. Regulators may force certain certifications for Dapp developers as a consequence. The motivation is exactly the same for why finanical advisors need to be licensed. Currently, this ease of accidental locking is the default on Cardano. This needs to be changed if we do not want regulators forcing developer certifications that are inherently centralizing. + +### Problem 3: No Universal Plutus Script +Since spending scripts take a datum while minting and staking scripts do not, it is currently not possible to create a universal script (one that can do all three). There are use cases where the Dapp would be more secure if the same script could be used for both spending and minting. An example is to only mint a token if a deposit is made to the relevant script address. + +Right now, if a developer wanted to do this, he/she would need to hardcode the spending script hash into the minting policy AND the minting policy id needs to be passed to the spending script as a datum. If a universal script could be used, the spending script hash would be the same as the minting policy id. In the former case, the security of this process depends on how well the datum usage can be guarded. In the latter case, the process is secure by default since the hash cannot be faked/wrong. + +## Specification +### `Data` Specification for `Maybe Datum` +Before the ledger-script interface passes the datum to the plutus script, the datum will be wrapped in a `Maybe` data type. Seen as type `Data` this wrapping is: + +``` Haskell +Nothing = Constr 0 [] +Just datum = Constr 1 [datumAsData] +``` + +The datum will only be converted from `BuiltinData` if the `Just` is going to be used. No parsing should be attempted if the `Nothing` is going to be used. + +As an example, to pass the unit datum into a script, the following `Data` would be passed: +``` Haskell +Just () = Constr 1 [Constr 0 []] +``` + +### Creating Universal Plutus Scripts +All plutus scripts will now be written as: +``` +mkUniversalScript :: Maybe Datum -> Redeemer -> ScriptContext -> Bool +mkUniversalScript (Just d) r ctx = ... +mkUniversalScript Nothing r ctx = ... +``` + +### Using Universal Plutus Scripts +#### Minting and Staking +When universal script is to be used for either minting or staking, `Nothing` will automatically be passed into the script. A `plutus-script-v3` flag will be needed to differentiate whether a universal script is being used or a v1/v2 script is being used. + +#### Spending +Using the universal scripts, there will now be two ways to use a spending script. + +1. **UTxO level spending scripts**: These scripts will have the datum attached to the UTxO being spent parsed and passed to the universal script as `Just datum`. These scripts are meant to be executed once per UTxO consumed from the script address. +2. **Transaction level spending scripts**: These scripts will have `Nothing` passed to the universal script without attempting to parse the datums attached to the UTxOs being spent. These scripts are meant to be executed once per transaction. The datums will still be present in the `ScriptContext`. + +#### `cardano-cli` +`cardano-cli` will need to be expanded to add `--utxo-level` and `--tx-level` flags so that users can explicitly say which level of the spending script to use. + +Example UTxO level spending script flag usage: +``` Bash + --tx-in \ + --utxo-level-spending-tx-in-reference \ + --plutus-script-v3 \ + --utxo-level-spending-reference-tx-in-inline-datum-present \ + --utxo-level-spending-reference-tx-in-redeemer-file \ +``` + +Example transaction level spending script flag usage: +``` Bash + --tx-in \ + --tx-in \ + --tx-in \ + --tx-level-spending-tx-in-reference \ + --plutus-script-v3 \ + --tx-level-spending-reference-tx-in-redeemer-file \ +``` + +Since there is no need to parse the datums attached to each UTxO, the datum flags are not needed. Any datums present will still appear in the `ScriptContext` that gets passed to the plutus script. All UTxOs being spent are assumed to be using the same redeemer which is why it is okay to place the redeemer flag at the end. + +Users **MUST** explicitly state which level to use. Building a transaction should fail if the level is not explicitly stated. + +#### Ensuring All Script Witnesses Are Present +The node is already capable of detecting if all required witnesses are present. This tooling will just need to be adapted to allow transaction level scripts to witness all UTxOs while being executed only once. The idea is similar to only one pubkey signature being required no matter how many UTxO are being spent from the corresponding address. + +#### Does This Require A Hardfork? +According to [CIP-0035](https://github.com/michaelpj/CIPs/blob/8e296066c0afc7d2ed46db88eca43f409830e011/CIP-0035/README.md#scripts-in-the-cardano-ledger), what is being suggested here is a change to the ledger-script interface. This means a new Plutus Core ledger language (LL) is required. The CIP states that this requires a hardfork. + +## Rationale: how does this CIP achieve its goals? +The key idea of this CIP is to address multiple developer concerns as simply as possible. There have been (at least) 6 proposals created so far whose motivations can all be addressed by the `Maybe Datum` ([#364](https://github.com/cardano-foundation/CIPs/pull/364),[#423](https://github.com/cardano-foundation/CIPs/issues/423),[#309](https://github.com/cardano-foundation/CIPs/pull/309),[#418](https://github.com/cardano-foundation/CIPs/pull/418),[#310](https://github.com/cardano-foundation/CIPs/pull/310),[#321](https://github.com/cardano-foundation/CIPs/pull/321)). + +By allowing for transaction level spending scripts, redundant executions are eliminated. By not forcing the parsing of datums attached to script UTxOs, the accidental locking is stopped. And by allowing a plutus script to be used as all three types (spending, minting, and staking), more secure-by-default Dapps can be written. + +### `ScriptArgs` Alternative +The `ScriptArgs` proposal ([here](https://github.com/cardano-foundation/CIPs/pull/321)) could also address all three issues motivating this CIP. However, the `ScriptArgs` approach would be much more complicated to implement since it would be a major divergence from the way things are currently implemented. For this reason, I believe the `Maybe Datum` would be a better approach. + +### Backwards Compatibility +Only plutus scripts that use the `plutus-script-v3` flag will have their datums handled in this way. All other plutus version will retain their usage. + +## Copyright +[CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/legalcode) \ No newline at end of file From b5e2bd2c8ca66835b276516e9745dcaeedb9b91a Mon Sep 17 00:00:00 2001 From: fallen-icarus Date: Wed, 18 Jan 2023 13:18:43 -0500 Subject: [PATCH 02/14] Added discussions --- CIP-????/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CIP-????/README.md b/CIP-????/README.md index c35c3e7310..d1542a77ea 100644 --- a/CIP-????/README.md +++ b/CIP-????/README.md @@ -7,6 +7,8 @@ Authors: - fallen-icarus Implementors: [] Discussions: + - https://github.com/cardano-foundation/CIPs/pull/321 + - https://github.com/cardano-foundation/CIPs/pull/418 Created: 2023-01-18 License: CC-BY-4.0 --- From fba3e8551bf234835559715880bfb71fcaabfb0f Mon Sep 17 00:00:00 2001 From: fallen-icarus Date: Thu, 19 Jan 2023 08:13:49 -0500 Subject: [PATCH 03/14] Edits --- CIP-????/README.md | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/CIP-????/README.md b/CIP-????/README.md index d1542a77ea..8b362c612f 100644 --- a/CIP-????/README.md +++ b/CIP-????/README.md @@ -21,21 +21,23 @@ Currently all plutus spending scripts take a datum directly from the UTxO being As of now, plutus spending scripts take the datum directly from the UTxO being spent. While it allows the ledger-script interface to be very simple, it causes three major problems. ### Problem 1: Spending Script Redundant Executions -Using the eUTxO architecture, it is currently possible to create spending scripts that validate based off of the transaction as a whole instead of any individual UTxO. Imagine if three UTxOs were spent from such a script's address within the same transaction? Which datum should be passed to the spending script? Currently, the ledger-script interface passes each UTxO's datum to the script individually and executes this "transaction level" spending script three times. Since the transaction context does not change between executions, these additional executions are completely redundant. There is currently no way to use a transaction level spending script so that these redundant exections do not happen. This limitation significantly handicaps Cardano's usage of the eUTxO architecture. While there is a potential workaround, the workaround has its own major drawbacks. You can read more about it in the related CPS [here](https://github.com/fallen-icarus/CIPs/tree/full-eUTxO-potential/CPS-%3F%3F%3F%3F#readme). +Using the eUTxO model, it is currently possible to create spending scripts that validate based off of the transaction as a whole instead of any individual UTxO. Imagine if three UTxOs were spent from such a script's address within the same transaction. Which datum should be passed to the spending script? Currently, the ledger-script interface passes each UTxO's datum to the script individually and executes this "transaction level" spending script three times. Since the transaction context does not change between executions, these additional executions are completely redundant. There is currently no way to use a transaction level spending script so that these redundant executions do not happen. This limitation significantly handicaps Cardano's usage of the eUTxO model. While there is a potential workaround, the workaround has its own major drawbacks. You can read more about it in the related CPS [here](https://github.com/fallen-icarus/CIPs/tree/full-eUTxO-potential/CPS-%3F%3F%3F%3F#readme). ### Problem 2: Wrong/Missing Datums Result in Permanently Locked Script UTxOs -When a script's UTxO is missing a datum or has the wrong datum, the spending script is unable to parse the datum attached to the UTxO and is therefore guaranteed to fail. This results in permanently locked UTxOs at the script address. In order to help prevent accidental locking of script UTxOs, proxies are generally used. However, it is very difficult to use such proxies in a decentralized way. In short, by being forced to use proxies, the Dapp loses some of its decentralization. +When a script's UTxO is missing a datum or has the wrong datum, the plutus spending script is unable to parse the datum attached to the UTxO and is therefore guaranteed to fail. This results in permanently locked UTxOs at the script's address. In order to help prevent accidental locking of script UTxOs, proxies are generally used. The idea is for users to send their funds to this proxy first. The proxy then attaches the required datum for the users and pass the funds onto the desired script address. However, it is very difficult to use such proxies in a decentralized way. In short, by being forced to use proxies, the Dapp loses some of its decentralization. + +Further, there are a number of use cases where a datum is not needed for the Dapp to function. In these situations, a dummy datum is still required just to prevent locking. As an addition point, regulators are not going to like any application where it is easy to accidentally lock (lose) users' funds permanentally. Regulators may force certain certifications for Dapp developers as a consequence. The motivation is exactly the same for why finanical advisors need to be licensed. Currently, this ease of accidental locking is the default on Cardano. This needs to be changed if we do not want regulators forcing developer certifications that are inherently centralizing. ### Problem 3: No Universal Plutus Script -Since spending scripts take a datum while minting and staking scripts do not, it is currently not possible to create a universal script (one that can do all three). There are use cases where the Dapp would be more secure if the same script could be used for both spending and minting. An example is to only mint a token if a deposit is made to the relevant script address. +Since plutus spending scripts take a datum while plutus minting and staking scripts do not, it is currently not possible to create a universal plutus script (one that can do all three). There are use cases where the Dapp would be more secure if the same script could be used for both spending and minting. An example is to only mint a token if a deposit is made to the relevant script address. Right now, if a developer wanted to do this, he/she would need to hardcode the spending script hash into the minting policy AND the minting policy id needs to be passed to the spending script as a datum. If a universal script could be used, the spending script hash would be the same as the minting policy id. In the former case, the security of this process depends on how well the datum usage can be guarded. In the latter case, the process is secure by default since the hash cannot be faked/wrong. ## Specification ### `Data` Specification for `Maybe Datum` -Before the ledger-script interface passes the datum to the plutus script, the datum will be wrapped in a `Maybe` data type. Seen as type `Data` this wrapping is: +Before the ledger-script interface passes the datum to the plutus script, the datum will be wrapped in a `Maybe` data type. Seen as type `Data`, this wrapping is: ``` Haskell Nothing = Constr 0 [] @@ -44,7 +46,7 @@ Just datum = Constr 1 [datumAsData] The datum will only be converted from `BuiltinData` if the `Just` is going to be used. No parsing should be attempted if the `Nothing` is going to be used. -As an example, to pass the unit datum into a script, the following `Data` would be passed: +As an example, to pass the unit datum into a plutus spending script, the following `Data` would be passed: ``` Haskell Just () = Constr 1 [Constr 0 []] ``` @@ -59,7 +61,7 @@ mkUniversalScript Nothing r ctx = ... ### Using Universal Plutus Scripts #### Minting and Staking -When universal script is to be used for either minting or staking, `Nothing` will automatically be passed into the script. A `plutus-script-v3` flag will be needed to differentiate whether a universal script is being used or a v1/v2 script is being used. +When a universal script is to be used for either minting or staking, `Nothing` will automatically be passed into the script. A `plutus-script-v3` flag will be needed to differentiate whether a universal script is being used or a v1/v2 script is being used. #### Spending Using the universal scripts, there will now be two ways to use a spending script. @@ -102,13 +104,13 @@ According to [CIP-0035](https://github.com/michaelpj/CIPs/blob/8e296066c0afc7d2e ## Rationale: how does this CIP achieve its goals? The key idea of this CIP is to address multiple developer concerns as simply as possible. There have been (at least) 6 proposals created so far whose motivations can all be addressed by the `Maybe Datum` ([#364](https://github.com/cardano-foundation/CIPs/pull/364),[#423](https://github.com/cardano-foundation/CIPs/issues/423),[#309](https://github.com/cardano-foundation/CIPs/pull/309),[#418](https://github.com/cardano-foundation/CIPs/pull/418),[#310](https://github.com/cardano-foundation/CIPs/pull/310),[#321](https://github.com/cardano-foundation/CIPs/pull/321)). -By allowing for transaction level spending scripts, redundant executions are eliminated. By not forcing the parsing of datums attached to script UTxOs, the accidental locking is stopped. And by allowing a plutus script to be used as all three types (spending, minting, and staking), more secure-by-default Dapps can be written. +By allowing for transaction level spending scripts, redundant executions are eliminated. By not always forcing the parsing of datums attached to script UTxOs, the accidental locking is stopped. And by allowing a plutus script to be used as all three types (spending, minting, and staking), more secure-by-default Dapps can be written. ### `ScriptArgs` Alternative -The `ScriptArgs` proposal ([here](https://github.com/cardano-foundation/CIPs/pull/321)) could also address all three issues motivating this CIP. However, the `ScriptArgs` approach would be much more complicated to implement since it would be a major divergence from the way things are currently implemented. For this reason, I believe the `Maybe Datum` would be a better approach. +The `ScriptArgs` proposal ([here](https://github.com/cardano-foundation/CIPs/pull/321)) could also address all three issues motivating this CIP. However, the `ScriptArgs` approach would be much more complicated to implement since passing the arguments as a sum type would be a major divergence from the way things are currently implemented. For this reason, I believe the `Maybe Datum` would be a better approach. ### Backwards Compatibility -Only plutus scripts that use the `plutus-script-v3` flag will have their datums handled in this way. All other plutus version will retain their usage. +Only plutus scripts that use the `plutus-script-v3` flag will have their datums handled in this way. All other plutus version will retain their usage. This flag will be exclusively used with the new universal plutus script. ## Copyright [CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/legalcode) \ No newline at end of file From 8f78a86fad00e78ff4a3d92fc3435022705209df Mon Sep 17 00:00:00 2001 From: fallen-icarus Date: Thu, 19 Jan 2023 10:13:12 -0500 Subject: [PATCH 04/14] Added comments about simple scripts --- CIP-????/README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/CIP-????/README.md b/CIP-????/README.md index 8b362c612f..6947a4e92d 100644 --- a/CIP-????/README.md +++ b/CIP-????/README.md @@ -15,7 +15,7 @@ License: CC-BY-4.0 # CIP-XXXX: Maybe Datum ## Abstract -Currently all plutus spending scripts take a datum directly from the UTxO being spent. While this allows for creating a very simple ledger-script interface, there are a number of use cases where this feature is not just undesired but can also be an obstical to Dapp developement. I propose changing plutus scripts so that they optionally take the datum directly from the UTxO being spent. This single change would solve a number of issues currently motivating different CIPs/CPSs. +Currently all plutus spending scripts take a datum directly from the UTxO being spent. While this allows for creating a very simple ledger-script interface, there are a number of use cases where this feature is not just undesired but can also be an obstacle to Dapp developement. I propose changing all plutus scripts so that they optionally take the datum directly from the UTxO being spent. This single change would solve a number of issues currently motivating different CIPs/CPSs. ## Motivation: why is this CIP necessary? As of now, plutus spending scripts take the datum directly from the UTxO being spent. While it allows the ledger-script interface to be very simple, it causes three major problems. @@ -23,6 +23,8 @@ As of now, plutus spending scripts take the datum directly from the UTxO being s ### Problem 1: Spending Script Redundant Executions Using the eUTxO model, it is currently possible to create spending scripts that validate based off of the transaction as a whole instead of any individual UTxO. Imagine if three UTxOs were spent from such a script's address within the same transaction. Which datum should be passed to the spending script? Currently, the ledger-script interface passes each UTxO's datum to the script individually and executes this "transaction level" spending script three times. Since the transaction context does not change between executions, these additional executions are completely redundant. There is currently no way to use a transaction level spending script so that these redundant executions do not happen. This limitation significantly handicaps Cardano's usage of the eUTxO model. While there is a potential workaround, the workaround has its own major drawbacks. You can read more about it in the related CPS [here](https://github.com/fallen-icarus/CIPs/tree/full-eUTxO-potential/CPS-%3F%3F%3F%3F#readme). +Note: While Cardano simple scripts do not use a datum, they may also suffer from this limitation. + ### Problem 2: Wrong/Missing Datums Result in Permanently Locked Script UTxOs When a script's UTxO is missing a datum or has the wrong datum, the plutus spending script is unable to parse the datum attached to the UTxO and is therefore guaranteed to fail. This results in permanently locked UTxOs at the script's address. In order to help prevent accidental locking of script UTxOs, proxies are generally used. The idea is for users to send their funds to this proxy first. The proxy then attaches the required datum for the users and pass the funds onto the desired script address. However, it is very difficult to use such proxies in a decentralized way. In short, by being forced to use proxies, the Dapp loses some of its decentralization. @@ -95,11 +97,14 @@ Since there is no need to parse the datums attached to each UTxO, the datum flag Users **MUST** explicitly state which level to use. Building a transaction should fail if the level is not explicitly stated. +#### Simple Scripts +Given that Cardano simple scripts are only for multisig and time locking, and both scenarios are ones that validate based off of the transaction as a whole, simple scripts are only usable as transaction level scripts. If the simple scripts language is going to be extended in the future, perhaps it would "future proof" the ledger-script interface to still have the option for using simple scripts at the UTxO level even though there are no use cases right now. + #### Ensuring All Script Witnesses Are Present The node is already capable of detecting if all required witnesses are present. This tooling will just need to be adapted to allow transaction level scripts to witness all UTxOs while being executed only once. The idea is similar to only one pubkey signature being required no matter how many UTxO are being spent from the corresponding address. #### Does This Require A Hardfork? -According to [CIP-0035](https://github.com/michaelpj/CIPs/blob/8e296066c0afc7d2ed46db88eca43f409830e011/CIP-0035/README.md#scripts-in-the-cardano-ledger), what is being suggested here is a change to the ledger-script interface. This means a new Plutus Core ledger language (LL) is required. The CIP states that this requires a hardfork. +According to [CIP-0035](https://github.com/michaelpj/CIPs/blob/8e296066c0afc7d2ed46db88eca43f409830e011/CIP-0035/README.md#scripts-in-the-cardano-ledger), what is being suggested here is a change to the ledger-script interface. This means a new Plutus Core ledger language (LL) is required. The CIP states that this requires a hardfork. However, being that the way things are stored on-chain will not change, this should be a smaller hardfork than the past few. ## Rationale: how does this CIP achieve its goals? The key idea of this CIP is to address multiple developer concerns as simply as possible. There have been (at least) 6 proposals created so far whose motivations can all be addressed by the `Maybe Datum` ([#364](https://github.com/cardano-foundation/CIPs/pull/364),[#423](https://github.com/cardano-foundation/CIPs/issues/423),[#309](https://github.com/cardano-foundation/CIPs/pull/309),[#418](https://github.com/cardano-foundation/CIPs/pull/418),[#310](https://github.com/cardano-foundation/CIPs/pull/310),[#321](https://github.com/cardano-foundation/CIPs/pull/321)). From 0e83bc0aac1a7144cf346c9ae5a14bed861ec07b Mon Sep 17 00:00:00 2001 From: fallen-icarus <108348082+fallen-icarus@users.noreply.github.com> Date: Sun, 22 Jan 2023 09:54:14 -0500 Subject: [PATCH 05/14] Removed Ledger category Co-authored-by: Robert Phair --- CIP-????/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CIP-????/README.md b/CIP-????/README.md index 6947a4e92d..288a4846a4 100644 --- a/CIP-????/README.md +++ b/CIP-????/README.md @@ -1,7 +1,7 @@ --- CIP: ? Title: Maybe Datum -Category: Plutus, Ledger +Category: Plutus Status: Proposed Authors: - fallen-icarus From 8c608838a9e77e91778de1a0033bff6bc81abbbd Mon Sep 17 00:00:00 2001 From: fallen-icarus Date: Mon, 23 Jan 2023 07:38:52 -0500 Subject: [PATCH 06/14] Added needed change to ScriptPurpose --- CIP-????/README.md | 53 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 4 deletions(-) diff --git a/CIP-????/README.md b/CIP-????/README.md index 288a4846a4..e10c0a37a7 100644 --- a/CIP-????/README.md +++ b/CIP-????/README.md @@ -93,9 +93,52 @@ Example transaction level spending script flag usage: --tx-level-spending-reference-tx-in-redeemer-file \ ``` -Since there is no need to parse the datums attached to each UTxO, the datum flags are not needed. Any datums present will still appear in the `ScriptContext` that gets passed to the plutus script. All UTxOs being spent are assumed to be using the same redeemer which is why it is okay to place the redeemer flag at the end. +Since there is no need to parse the datums attached to each UTxO, the datum flags are not needed. Any datums present will still appear in the `ScriptContext` that gets passed to the plutus script. All UTxOs being validated by the transaction level script are assumed to be using the same redeemer which is why it is okay to place the redeemer flag at the end. -Users **MUST** explicitly state which level to use. Building a transaction should fail if the level is not explicitly stated. +Users **MUST** explicitly state which level to use. Building a transaction should fail if the level is not explicitly stated or if both levels are specified for the same UTxO. + +#### Script Context +Currenty, the `ScriptPurpose` part of `ScriptContext` is defined like this: + +``` Haskell +-- | Purpose of the script that is currently running +data ScriptPurpose + = Minting CurrencySymbol + | Spending TxOutRef + | Rewarding StakingCredential + | Certifying DCert +``` + +When the script is a spending script, the `TxOutRef` of the UTxO being validated is used. This setup does not allow for transaction level scripts: if there are three UTxOs being validated, which `TxOutRef` should be used? + +To expand the `ScriptPurpose` to also enable transaction level spending scripts, I propose introducing this new sum type: +``` Haskell +-- | Spending script validation level +data SpendingLevel + = UTxOLevel TxOutRef + | TxLevel ValidatorHash +``` + +Then the `ScriptPurpose` definition will be changed to use this new sum type: +``` Haskell +-- | Purpose of the script that is currently running +data ScriptPurpose + = Minting CurrencySymbol + | Spending SpendingLevel -- ^ Uses new sum type + | Rewarding StakingCredential + | Certifying DCert +``` + +`DCert` is also a sum type so the precedence has already been established for this usage. For the `Data` specification of `SpendingLevel`, I propose: + +``` Haskell +UTxOLevel txOutRef = Constr 0 [txOutRefAsData] +TxLevel validatorHash = Constr 1 [validatorHashAsData] +``` + +Whenever the `--tx-level` flags are used for spending scripts, the `TxLevel` constructor will be used in the `ScriptPurpose`. Conversely, whenever the `--utxo-level` flags are used, the `UTxOLevel` constructor will be used. + +Several functions use the `ScriptPurpose` in order to get certain information in on-chain code. An example is the `ownHash` function that uses the `Spending TxOutRef` to get the hash of the current validator. New plutus v3 versions of these functions will be needed to use the new `ScriptPurpose`. #### Simple Scripts Given that Cardano simple scripts are only for multisig and time locking, and both scenarios are ones that validate based off of the transaction as a whole, simple scripts are only usable as transaction level scripts. If the simple scripts language is going to be extended in the future, perhaps it would "future proof" the ledger-script interface to still have the option for using simple scripts at the UTxO level even though there are no use cases right now. @@ -103,6 +146,8 @@ Given that Cardano simple scripts are only for multisig and time locking, and bo #### Ensuring All Script Witnesses Are Present The node is already capable of detecting if all required witnesses are present. This tooling will just need to be adapted to allow transaction level scripts to witness all UTxOs while being executed only once. The idea is similar to only one pubkey signature being required no matter how many UTxO are being spent from the corresponding address. +The node is also capable of detecting if extraneous witnesses are present. This can be leveraged to make sure only one spending level is used for each UTxO being validated. + #### Does This Require A Hardfork? According to [CIP-0035](https://github.com/michaelpj/CIPs/blob/8e296066c0afc7d2ed46db88eca43f409830e011/CIP-0035/README.md#scripts-in-the-cardano-ledger), what is being suggested here is a change to the ledger-script interface. This means a new Plutus Core ledger language (LL) is required. The CIP states that this requires a hardfork. However, being that the way things are stored on-chain will not change, this should be a smaller hardfork than the past few. @@ -112,10 +157,10 @@ The key idea of this CIP is to address multiple developer concerns as simply as By allowing for transaction level spending scripts, redundant executions are eliminated. By not always forcing the parsing of datums attached to script UTxOs, the accidental locking is stopped. And by allowing a plutus script to be used as all three types (spending, minting, and staking), more secure-by-default Dapps can be written. ### `ScriptArgs` Alternative -The `ScriptArgs` proposal ([here](https://github.com/cardano-foundation/CIPs/pull/321)) could also address all three issues motivating this CIP. However, the `ScriptArgs` approach would be much more complicated to implement since passing the arguments as a sum type would be a major divergence from the way things are currently implemented. For this reason, I believe the `Maybe Datum` would be a better approach. +The `ScriptArgs` proposal ([here](https://github.com/cardano-foundation/CIPs/pull/321)) could also address all three issues motivating this CIP. However, the `ScriptArgs` approach would be much more complicated to implement since passing the arguments to the scripts as a sum type would be a major divergence from the way things are currently implemented. For this reason, I believe the `Maybe Datum` would be a better approach. ### Backwards Compatibility -Only plutus scripts that use the `plutus-script-v3` flag will have their datums handled in this way. All other plutus version will retain their usage. This flag will be exclusively used with the new universal plutus script. +Only plutus scripts that use the `plutus-script-v3` flag will have their datums and `ScriptPurpose` handled in this way. All other plutus version will retain their usage. This flag will be exclusively used with the new universal plutus script. ## Copyright [CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/legalcode) \ No newline at end of file From 268520eb537cc503f04c80fff3b5e17420ef0597 Mon Sep 17 00:00:00 2001 From: fallen-icarus Date: Mon, 23 Jan 2023 12:11:46 -0500 Subject: [PATCH 07/14] Added comment about passing in validator hash for tx level scripts --- CIP-????/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CIP-????/README.md b/CIP-????/README.md index e10c0a37a7..8015889ecf 100644 --- a/CIP-????/README.md +++ b/CIP-????/README.md @@ -136,7 +136,7 @@ UTxOLevel txOutRef = Constr 0 [txOutRefAsData] TxLevel validatorHash = Constr 1 [validatorHashAsData] ``` -Whenever the `--tx-level` flags are used for spending scripts, the `TxLevel` constructor will be used in the `ScriptPurpose`. Conversely, whenever the `--utxo-level` flags are used, the `UTxOLevel` constructor will be used. +Whenever the `--tx-level` flags are used for spending scripts, the `TxLevel` constructor will be used in the `ScriptPurpose`. To make it easy to get the `ValidatorHash` of the transaction level script, a `--tx-level-spending-hash` can also be required when building the transaction. Conversely, whenever the `--utxo-level` flags are used, the `UTxOLevel` constructor will be used. Several functions use the `ScriptPurpose` in order to get certain information in on-chain code. An example is the `ownHash` function that uses the `Spending TxOutRef` to get the hash of the current validator. New plutus v3 versions of these functions will be needed to use the new `ScriptPurpose`. From cf6062e7f3325753e8ba3b495ecf41e6a61f16af Mon Sep 17 00:00:00 2001 From: fallen-icarus Date: Mon, 23 Jan 2023 12:13:17 -0500 Subject: [PATCH 08/14] forgot a word --- CIP-????/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CIP-????/README.md b/CIP-????/README.md index 8015889ecf..d3e685e1b9 100644 --- a/CIP-????/README.md +++ b/CIP-????/README.md @@ -136,7 +136,7 @@ UTxOLevel txOutRef = Constr 0 [txOutRefAsData] TxLevel validatorHash = Constr 1 [validatorHashAsData] ``` -Whenever the `--tx-level` flags are used for spending scripts, the `TxLevel` constructor will be used in the `ScriptPurpose`. To make it easy to get the `ValidatorHash` of the transaction level script, a `--tx-level-spending-hash` can also be required when building the transaction. Conversely, whenever the `--utxo-level` flags are used, the `UTxOLevel` constructor will be used. +Whenever the `--tx-level` flags are used for spending scripts, the `TxLevel` constructor will be used in the `ScriptPurpose`. To make it easy to get the `ValidatorHash` of the transaction level script, a `--tx-level-spending-hash` flag can also be required when building the transaction. Conversely, whenever the `--utxo-level` flags are used, the `UTxOLevel` constructor will be used. Several functions use the `ScriptPurpose` in order to get certain information in on-chain code. An example is the `ownHash` function that uses the `Spending TxOutRef` to get the hash of the current validator. New plutus v3 versions of these functions will be needed to use the new `ScriptPurpose`. From ff548ac1c9eca747b3123eee50d1010d85c7f6e3 Mon Sep 17 00:00:00 2001 From: fallen-icarus Date: Mon, 23 Jan 2023 12:17:06 -0500 Subject: [PATCH 09/14] more comments about new ScriptPurpose --- CIP-????/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CIP-????/README.md b/CIP-????/README.md index d3e685e1b9..db1da5bf71 100644 --- a/CIP-????/README.md +++ b/CIP-????/README.md @@ -136,7 +136,7 @@ UTxOLevel txOutRef = Constr 0 [txOutRefAsData] TxLevel validatorHash = Constr 1 [validatorHashAsData] ``` -Whenever the `--tx-level` flags are used for spending scripts, the `TxLevel` constructor will be used in the `ScriptPurpose`. To make it easy to get the `ValidatorHash` of the transaction level script, a `--tx-level-spending-hash` flag can also be required when building the transaction. Conversely, whenever the `--utxo-level` flags are used, the `UTxOLevel` constructor will be used. +Whenever the `--tx-level` flags are used for spending scripts, the `TxLevel` constructor will be used in the `ScriptPurpose`. To make it easy to get the `ValidatorHash` of the transaction level script, a `--tx-level-spending-hash` flag can also be required when building the transaction. The idea is similar to how building a transaction with a reference script for a minting policy requires the explicit use of the `--policy-id HASH` flag. Conversely, whenever the `--utxo-level` flags are used, the `UTxOLevel` constructor will be used. Several functions use the `ScriptPurpose` in order to get certain information in on-chain code. An example is the `ownHash` function that uses the `Spending TxOutRef` to get the hash of the current validator. New plutus v3 versions of these functions will be needed to use the new `ScriptPurpose`. From a4c1afa47456ba95978d3e46c059ace25d5ac4b1 Mon Sep 17 00:00:00 2001 From: fallen-icarus Date: Tue, 24 Jan 2023 08:00:44 -0500 Subject: [PATCH 10/14] Grammar edits and removed unnecessary comment. --- CIP-????/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CIP-????/README.md b/CIP-????/README.md index db1da5bf71..3d1e12fd95 100644 --- a/CIP-????/README.md +++ b/CIP-????/README.md @@ -26,7 +26,7 @@ Using the eUTxO model, it is currently possible to create spending scripts that Note: While Cardano simple scripts do not use a datum, they may also suffer from this limitation. ### Problem 2: Wrong/Missing Datums Result in Permanently Locked Script UTxOs -When a script's UTxO is missing a datum or has the wrong datum, the plutus spending script is unable to parse the datum attached to the UTxO and is therefore guaranteed to fail. This results in permanently locked UTxOs at the script's address. In order to help prevent accidental locking of script UTxOs, proxies are generally used. The idea is for users to send their funds to this proxy first. The proxy then attaches the required datum for the users and pass the funds onto the desired script address. However, it is very difficult to use such proxies in a decentralized way. In short, by being forced to use proxies, the Dapp loses some of its decentralization. +When a script's UTxO is missing a datum or has the wrong datum, the plutus spending script is unable to parse the datum attached to the UTxO and is therefore guaranteed to fail. This results in permanently locked UTxOs at the script's address. In order to help prevent accidental locking of script UTxOs, proxies are generally used. The idea is for users to send their funds to this proxy first. The proxy then attaches the required datum for the users and passes the funds onto the desired script address. However, it is very difficult to use such proxies in a decentralized way. In short, by being forced to use proxies, the Dapp loses some of its decentralization. Further, there are a number of use cases where a datum is not needed for the Dapp to function. In these situations, a dummy datum is still required just to prevent locking. @@ -35,7 +35,7 @@ As an addition point, regulators are not going to like any application where it ### Problem 3: No Universal Plutus Script Since plutus spending scripts take a datum while plutus minting and staking scripts do not, it is currently not possible to create a universal plutus script (one that can do all three). There are use cases where the Dapp would be more secure if the same script could be used for both spending and minting. An example is to only mint a token if a deposit is made to the relevant script address. -Right now, if a developer wanted to do this, he/she would need to hardcode the spending script hash into the minting policy AND the minting policy id needs to be passed to the spending script as a datum. If a universal script could be used, the spending script hash would be the same as the minting policy id. In the former case, the security of this process depends on how well the datum usage can be guarded. In the latter case, the process is secure by default since the hash cannot be faked/wrong. +Right now, if a developer wanted to do this, he/she would need to hardcode the spending script hash into the minting policy AND the minting policy id would need to be passed to the spending script as a datum. If a universal script could be used, the spending script hash would be the same as the minting policy id. In the former case, the security of this process depends on how well the datum usage can be guarded. In the latter case, the process is secure by default since the hash cannot be faked/wrong. ## Specification ### `Data` Specification for `Maybe Datum` @@ -93,7 +93,7 @@ Example transaction level spending script flag usage: --tx-level-spending-reference-tx-in-redeemer-file \ ``` -Since there is no need to parse the datums attached to each UTxO, the datum flags are not needed. Any datums present will still appear in the `ScriptContext` that gets passed to the plutus script. All UTxOs being validated by the transaction level script are assumed to be using the same redeemer which is why it is okay to place the redeemer flag at the end. +For transaction level scripts, since there is no need to parse the datums attached to each UTxO, the datum flags are not needed. Any datums present will still appear in the `ScriptContext` that gets passed to the plutus script. All UTxOs being validated by the transaction level script are assumed to be using the same redeemer which is why it is okay to place the redeemer flag at the end. Users **MUST** explicitly state which level to use. Building a transaction should fail if the level is not explicitly stated or if both levels are specified for the same UTxO. @@ -129,7 +129,7 @@ data ScriptPurpose | Certifying DCert ``` -`DCert` is also a sum type so the precedence has already been established for this usage. For the `Data` specification of `SpendingLevel`, I propose: +For the `Data` specification of `SpendingLevel`, I propose: ``` Haskell UTxOLevel txOutRef = Constr 0 [txOutRefAsData] From 59071ce552f8d6bb6da900afbfc1576f994c3908 Mon Sep 17 00:00:00 2001 From: fallen-icarus Date: Tue, 24 Jan 2023 18:05:38 -0500 Subject: [PATCH 11/14] Added comments about eopsin to Problem 3 --- CIP-????/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CIP-????/README.md b/CIP-????/README.md index 3d1e12fd95..51f017046d 100644 --- a/CIP-????/README.md +++ b/CIP-????/README.md @@ -35,7 +35,9 @@ As an addition point, regulators are not going to like any application where it ### Problem 3: No Universal Plutus Script Since plutus spending scripts take a datum while plutus minting and staking scripts do not, it is currently not possible to create a universal plutus script (one that can do all three). There are use cases where the Dapp would be more secure if the same script could be used for both spending and minting. An example is to only mint a token if a deposit is made to the relevant script address. -Right now, if a developer wanted to do this, he/she would need to hardcode the spending script hash into the minting policy AND the minting policy id would need to be passed to the spending script as a datum. If a universal script could be used, the spending script hash would be the same as the minting policy id. In the former case, the security of this process depends on how well the datum usage can be guarded. In the latter case, the process is secure by default since the hash cannot be faked/wrong. +The `eopsin` pythonic smart contract tooling has implemented a workaround for this, however, it requires an "ugly hack" that some developers may not be comfortable using. You can read more about it [here](https://github.com/ImperatorLang/eopsin/blob/master/ARCHITECTURE.md#minting-policy---spending-validator-double-function). + +Right now, if a developer wanted to implement the above example without using the "ugly hack", he/she would need to hardcode the spending script hash into the minting policy AND the minting policy id would need to be passed to the spending script as a datum. If a universal script could be used, the spending script hash would be the same as the minting policy id. In the former case, the security of this process depends on how well the datum usage can be guarded. In the latter case, the process is secure by default since the hash cannot be faked/wrong. ## Specification ### `Data` Specification for `Maybe Datum` From 95542123d5b4c6f66744f856a4bef3887e141a6a Mon Sep 17 00:00:00 2001 From: fallen-icarus Date: Mon, 20 Feb 2023 09:44:41 -0500 Subject: [PATCH 12/14] Updated the proposal to only focus on utxos missing datums and universal scripts --- CIP-????/README.md | 156 +++++++++++++-------------------------------- 1 file changed, 43 insertions(+), 113 deletions(-) diff --git a/CIP-????/README.md b/CIP-????/README.md index 51f017046d..14da620962 100644 --- a/CIP-????/README.md +++ b/CIP-????/README.md @@ -15,154 +15,84 @@ License: CC-BY-4.0 # CIP-XXXX: Maybe Datum ## Abstract -Currently all plutus spending scripts take a datum directly from the UTxO being spent. While this allows for creating a very simple ledger-script interface, there are a number of use cases where this feature is not just undesired but can also be an obstacle to Dapp developement. I propose changing all plutus scripts so that they optionally take the datum directly from the UTxO being spent. This single change would solve a number of issues currently motivating different CIPs/CPSs. +Currently all plutus spending scripts take a datum directly from the UTxO being spent. When a user/developer forgets to add a datum to a UTxO being sent to a plutus script's address, this results in the permanent locking of the UTxO. This CIP proposes changing the ledger-script interface so that all plutus scripts take an optional datum argument. Then, if the UTxO being spent is missing a datum or the plutus script is being used to mint/stake, the `Nothing` equivalent for the argument will be passed to the plutus script being executed. This latter part allows for universal plutus scripts. ## Motivation: why is this CIP necessary? -As of now, plutus spending scripts take the datum directly from the UTxO being spent. While it allows the ledger-script interface to be very simple, it causes three major problems. -### Problem 1: Spending Script Redundant Executions -Using the eUTxO model, it is currently possible to create spending scripts that validate based off of the transaction as a whole instead of any individual UTxO. Imagine if three UTxOs were spent from such a script's address within the same transaction. Which datum should be passed to the spending script? Currently, the ledger-script interface passes each UTxO's datum to the script individually and executes this "transaction level" spending script three times. Since the transaction context does not change between executions, these additional executions are completely redundant. There is currently no way to use a transaction level spending script so that these redundant executions do not happen. This limitation significantly handicaps Cardano's usage of the eUTxO model. While there is a potential workaround, the workaround has its own major drawbacks. You can read more about it in the related CPS [here](https://github.com/fallen-icarus/CIPs/tree/full-eUTxO-potential/CPS-%3F%3F%3F%3F#readme). +### Problem 1: Missing Datums Result in Permanently Locked Script UTxOs +When a UTxO locked at a plutus script's address is missing a datum, the plutus spending script is unable to execute since the datum argument is mandatory and it can only be obtained from the UTxO being spent. Therefore, validation of this UTxO is always guaranteed to fail. This results in a permanently locked UTxO at the script's address. This situation makes it risky for users to send funds directly to a plutus script's address. What datum to use needs to be known by every user sending to the associated plutus script address. A few workarounds have been suggested: -Note: While Cardano simple scripts do not use a datum, they may also suffer from this limitation. +- Using an extended address format - the information about what datum to use could be encoded directly into the address users are trying to send to. This approach suffers from being unable to trustlessly verify the correctness of the datum in the extended address used: + 1. How do you verify that the datum in the address is correct? What if the datum is meant to convey information about the owner of the input UTxO? A malicious person can trick users into sending to a malicously crafted extended address. + 2. This increases the need to trust software that is being used to get the datum information from the extended address. A malicious frontend can alter the datum information so that it can steal funds from the user. +- Using a proxy - users send their funds to a middle contract/entity that then attaches the required datum for the users and passes the funds onto the desired script address. Currently, the only way to use proxies in a trustless manner is to use a plutus script as the proxy. But then we are back to where we started: a missing datum will result in the permanent locking of the funds sent to the proxy contract. So the only real proxy workaround for completely preventing locking due to a missing datum is to use a multisig native script or another pubkey address and have the owner(s) attach the proper datum for the users. Both of these options force reliance on centralized parties. -### Problem 2: Wrong/Missing Datums Result in Permanently Locked Script UTxOs -When a script's UTxO is missing a datum or has the wrong datum, the plutus spending script is unable to parse the datum attached to the UTxO and is therefore guaranteed to fail. This results in permanently locked UTxOs at the script's address. In order to help prevent accidental locking of script UTxOs, proxies are generally used. The idea is for users to send their funds to this proxy first. The proxy then attaches the required datum for the users and passes the funds onto the desired script address. However, it is very difficult to use such proxies in a decentralized way. In short, by being forced to use proxies, the Dapp loses some of its decentralization. +As a final point, there are use cases where a datum is not needed for the Dapp to function. In these situations, a dummy datum is still required just to prevent locking. -Further, there are a number of use cases where a datum is not needed for the Dapp to function. In these situations, a dummy datum is still required just to prevent locking. +### Problem 2: No Universal Plutus Script +Since plutus spending scripts take a datum while plutus minting and staking scripts do not, it is currently not possible to create a universal plutus script (one that can do all three). There are use cases where the Dapp would be better able to guarantee proper usage if the same script could be used for both spending and minting. An example is to only mint a token if a deposit is made to the relevant script address. -As an addition point, regulators are not going to like any application where it is easy to accidentally lock (lose) users' funds permanentally. Regulators may force certain certifications for Dapp developers as a consequence. The motivation is exactly the same for why finanical advisors need to be licensed. Currently, this ease of accidental locking is the default on Cardano. This needs to be changed if we do not want regulators forcing developer certifications that are inherently centralizing. +The `eopsin` pythonic smart contract tooling has implemented a workaround for this, however, it requires an "ugly hack" that some developers may not be comfortable using. You can read more about it [here](https://github.com/ImperatorLang/eopsin/blob/master/ARCHITECTURE.md#minting-policy---spending-validator-double-function). -### Problem 3: No Universal Plutus Script -Since plutus spending scripts take a datum while plutus minting and staking scripts do not, it is currently not possible to create a universal plutus script (one that can do all three). There are use cases where the Dapp would be more secure if the same script could be used for both spending and minting. An example is to only mint a token if a deposit is made to the relevant script address. +Right now, if a developer wanted to implement the above example without using the "ugly hack", he/she would need to hardcode the spending script hash into the minting policy AND the minting policy id would need to be passed to the spending script as a datum. But now what would happen if a user accidentally uses the wrong policy id in the datum? Since the plutus script can only know about the associated minting policy through the policy id in the datum, the plutus script has no choice but to treat the incorrect datum as if it was correct. This can produce undesired behavior at best or permanent locking of funds at worst (like when the plutus spending script forces the asset associated to the policy id to be burned instead of being withdrawn from the address). -The `eopsin` pythonic smart contract tooling has implemented a workaround for this, however, it requires an "ugly hack" that some developers may not be comfortable using. You can read more about it [here](https://github.com/ImperatorLang/eopsin/blob/master/ARCHITECTURE.md#minting-policy---spending-validator-double-function). +If a universal script could be used, the spending script hash would be the same as the minting policy id. There would be no need to rely on the datum for the plutus script to know about the proper minting policy. -Right now, if a developer wanted to implement the above example without using the "ugly hack", he/she would need to hardcode the spending script hash into the minting policy AND the minting policy id would need to be passed to the spending script as a datum. If a universal script could be used, the spending script hash would be the same as the minting policy id. In the former case, the security of this process depends on how well the datum usage can be guarded. In the latter case, the process is secure by default since the hash cannot be faked/wrong. +In the former case, the proper usage of this process depends on how well the datum usage can be guarded. In the latter case, the usage is guaranteed by default since the hash cannot be faked/wrong. ## Specification -### `Data` Specification for `Maybe Datum` -Before the ledger-script interface passes the datum to the plutus script, the datum will be wrapped in a `Maybe` data type. Seen as type `Data`, this wrapping is: -``` Haskell -Nothing = Constr 0 [] -Just datum = Constr 1 [datumAsData] -``` - -The datum will only be converted from `BuiltinData` if the `Just` is going to be used. No parsing should be attempted if the `Nothing` is going to be used. +### Creating Universal Plutus Scripts +All plutus scripts, including minting and staking scripts, will be changed to take an optional datum argument. Using the haskell syntax, it would look like this: -As an example, to pass the unit datum into a plutus spending script, the following `Data` would be passed: ``` Haskell -Just () = Constr 1 [Constr 0 []] -``` - -### Creating Universal Plutus Scripts -All plutus scripts will now be written as: -``` mkUniversalScript :: Maybe Datum -> Redeemer -> ScriptContext -> Bool mkUniversalScript (Just d) r ctx = ... mkUniversalScript Nothing r ctx = ... ``` -### Using Universal Plutus Scripts -#### Minting and Staking -When a universal script is to be used for either minting or staking, `Nothing` will automatically be passed into the script. A `plutus-script-v3` flag will be needed to differentiate whether a universal script is being used or a v1/v2 script is being used. - -#### Spending -Using the universal scripts, there will now be two ways to use a spending script. - -1. **UTxO level spending scripts**: These scripts will have the datum attached to the UTxO being spent parsed and passed to the universal script as `Just datum`. These scripts are meant to be executed once per UTxO consumed from the script address. -2. **Transaction level spending scripts**: These scripts will have `Nothing` passed to the universal script without attempting to parse the datums attached to the UTxOs being spent. These scripts are meant to be executed once per transaction. The datums will still be present in the `ScriptContext`. - -#### `cardano-cli` -`cardano-cli` will need to be expanded to add `--utxo-level` and `--tx-level` flags so that users can explicitly say which level of the spending script to use. - -Example UTxO level spending script flag usage: -``` Bash - --tx-in \ - --utxo-level-spending-tx-in-reference \ - --plutus-script-v3 \ - --utxo-level-spending-reference-tx-in-inline-datum-present \ - --utxo-level-spending-reference-tx-in-redeemer-file \ -``` - -Example transaction level spending script flag usage: -``` Bash - --tx-in \ - --tx-in \ - --tx-in \ - --tx-level-spending-tx-in-reference \ - --plutus-script-v3 \ - --tx-level-spending-reference-tx-in-redeemer-file \ -``` - -For transaction level scripts, since there is no need to parse the datums attached to each UTxO, the datum flags are not needed. Any datums present will still appear in the `ScriptContext` that gets passed to the plutus script. All UTxOs being validated by the transaction level script are assumed to be using the same redeemer which is why it is okay to place the redeemer flag at the end. - -Users **MUST** explicitly state which level to use. Building a transaction should fail if the level is not explicitly stated or if both levels are specified for the same UTxO. - -#### Script Context -Currenty, the `ScriptPurpose` part of `ScriptContext` is defined like this: - -``` Haskell --- | Purpose of the script that is currently running -data ScriptPurpose - = Minting CurrencySymbol - | Spending TxOutRef - | Rewarding StakingCredential - | Certifying DCert -``` - -When the script is a spending script, the `TxOutRef` of the UTxO being validated is used. This setup does not allow for transaction level scripts: if there are three UTxOs being validated, which `TxOutRef` should be used? - -To expand the `ScriptPurpose` to also enable transaction level spending scripts, I propose introducing this new sum type: -``` Haskell --- | Spending script validation level -data SpendingLevel - = UTxOLevel TxOutRef - | TxLevel ValidatorHash -``` +### `Data` Specification for `Maybe Datum` +Before the ledger-script interface passes the datum to the plutus script, the datum will be wrapped in a `Maybe` data type. Seen as type `Data`, this wrapping is: -Then the `ScriptPurpose` definition will be changed to use this new sum type: ``` Haskell --- | Purpose of the script that is currently running -data ScriptPurpose - = Minting CurrencySymbol - | Spending SpendingLevel -- ^ Uses new sum type - | Rewarding StakingCredential - | Certifying DCert +Nothing = Constr 0 [] +Just datum = Constr 1 [datumAsData] ``` -For the `Data` specification of `SpendingLevel`, I propose: +### Using Universal Plutus Scripts +#### Spending +If the UTxO being spent is missing a datum, then the `Nothing` constructor will be passed to the plutus script. Otherwise, the datum will be wrapped in the `Just` constructor before being passed to the plutus script. +As an example, to pass the unit datum into the plutus script, the following `Data` would be passed: ``` Haskell -UTxOLevel txOutRef = Constr 0 [txOutRefAsData] -TxLevel validatorHash = Constr 1 [validatorHashAsData] +Just () = Constr 1 [Constr 0 []] ``` -Whenever the `--tx-level` flags are used for spending scripts, the `TxLevel` constructor will be used in the `ScriptPurpose`. To make it easy to get the `ValidatorHash` of the transaction level script, a `--tx-level-spending-hash` flag can also be required when building the transaction. The idea is similar to how building a transaction with a reference script for a minting policy requires the explicit use of the `--policy-id HASH` flag. Conversely, whenever the `--utxo-level` flags are used, the `UTxOLevel` constructor will be used. - -Several functions use the `ScriptPurpose` in order to get certain information in on-chain code. An example is the `ownHash` function that uses the `Spending TxOutRef` to get the hash of the current validator. New plutus v3 versions of these functions will be needed to use the new `ScriptPurpose`. - -#### Simple Scripts -Given that Cardano simple scripts are only for multisig and time locking, and both scenarios are ones that validate based off of the transaction as a whole, simple scripts are only usable as transaction level scripts. If the simple scripts language is going to be extended in the future, perhaps it would "future proof" the ledger-script interface to still have the option for using simple scripts at the UTxO level even though there are no use cases right now. - -#### Ensuring All Script Witnesses Are Present -The node is already capable of detecting if all required witnesses are present. This tooling will just need to be adapted to allow transaction level scripts to witness all UTxOs while being executed only once. The idea is similar to only one pubkey signature being required no matter how many UTxO are being spent from the corresponding address. - -The node is also capable of detecting if extraneous witnesses are present. This can be leveraged to make sure only one spending level is used for each UTxO being validated. +#### Minting and Staking +When a universal script is being used for either minting or staking, `Nothing` will automatically be passed into the plutus script. -#### Does This Require A Hardfork? -According to [CIP-0035](https://github.com/michaelpj/CIPs/blob/8e296066c0afc7d2ed46db88eca43f409830e011/CIP-0035/README.md#scripts-in-the-cardano-ledger), what is being suggested here is a change to the ledger-script interface. This means a new Plutus Core ledger language (LL) is required. The CIP states that this requires a hardfork. However, being that the way things are stored on-chain will not change, this should be a smaller hardfork than the past few. +### Plutus v3 +According to [CIP-0035](https://github.com/michaelpj/CIPs/blob/8e296066c0afc7d2ed46db88eca43f409830e011/CIP-0035/README.md#scripts-in-the-cardano-ledger), what is being suggested here is a change to the ledger-script interface. This means a new Plutus Core ledger language (LL) is required. CIP-0035 states that this requires a hardfork. However, being that the way things are stored on-chain will not change, this should be a smaller hardfork than the past few. ## Rationale: how does this CIP achieve its goals? -The key idea of this CIP is to address multiple developer concerns as simply as possible. There have been (at least) 6 proposals created so far whose motivations can all be addressed by the `Maybe Datum` ([#364](https://github.com/cardano-foundation/CIPs/pull/364),[#423](https://github.com/cardano-foundation/CIPs/issues/423),[#309](https://github.com/cardano-foundation/CIPs/pull/309),[#418](https://github.com/cardano-foundation/CIPs/pull/418),[#310](https://github.com/cardano-foundation/CIPs/pull/310),[#321](https://github.com/cardano-foundation/CIPs/pull/321)). +The key idea of this CIP is to address multiple developer concerns as simply as possible. There have been (at least) 5 proposals created so far whose motivations can all be addressed by the `Maybe Datum` ([#364](https://github.com/cardano-foundation/CIPs/pull/364),[#423](https://github.com/cardano-foundation/CIPs/issues/423),[#309](https://github.com/cardano-foundation/CIPs/pull/309),[#310](https://github.com/cardano-foundation/CIPs/pull/310),[#321](https://github.com/cardano-foundation/CIPs/pull/321)). + +With this change, UTxOs would no longer be permanently locked simply for missing a datum. Further, it would now be possible to use the same plutus script for spending, minting, and staking. -By allowing for transaction level spending scripts, redundant executions are eliminated. By not always forcing the parsing of datums attached to script UTxOs, the accidental locking is stopped. And by allowing a plutus script to be used as all three types (spending, minting, and staking), more secure-by-default Dapps can be written. +### Backwards Compatibility +Only plutus scripts that use the new plutus ledger language will have their datums handled in this way. All other plutus ledger languages will retain their usage. ### `ScriptArgs` Alternative -The `ScriptArgs` proposal ([here](https://github.com/cardano-foundation/CIPs/pull/321)) could also address all three issues motivating this CIP. However, the `ScriptArgs` approach would be much more complicated to implement since passing the arguments to the scripts as a sum type would be a major divergence from the way things are currently implemented. For this reason, I believe the `Maybe Datum` would be a better approach. +The `ScriptArgs` proposal ([here](https://github.com/cardano-foundation/CIPs/pull/321)) could also address the issues motivating this CIP. The `ScriptArgs` approach could allow for easily implementing future changes such as allowing scripts to take other kinds of arguments. However, all of the details have yet to be ironed out. -### Backwards Compatibility -Only plutus scripts that use the `plutus-script-v3` flag will have their datums and `ScriptPurpose` handled in this way. All other plutus version will retain their usage. This flag will be exclusively used with the new universal plutus script. +## Path to Active +### Acceptance Criteria +1. Personally, I would like to see the `ScriptArgs` proposal finished and merged so that the community can properly debate the pros and cons for both proposals. +2. `plutus` and `cardano-ledger` have been updated to the new design. +3. The new design has been incorporated into the new plutus ledger language. + +### Implementation Plan +The Plutus team or an equally qualified group implements the changes. ## Copyright [CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/legalcode) \ No newline at end of file From 9c38bfbe80318fbedaf69e8265b1328f18bf8307 Mon Sep 17 00:00:00 2001 From: fallen-icarus <108348082+fallen-icarus@users.noreply.github.com> Date: Tue, 21 Feb 2023 09:08:52 -0500 Subject: [PATCH 13/14] Gave CIP a number Co-authored-by: Matthias Benkort <5680256+KtorZ@users.noreply.github.com> --- CIP-????/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CIP-????/README.md b/CIP-????/README.md index 14da620962..c093e93b71 100644 --- a/CIP-????/README.md +++ b/CIP-????/README.md @@ -1,5 +1,5 @@ --- -CIP: ? +CIP: 87 Title: Maybe Datum Category: Plutus Status: Proposed From c8e0d80b15230d06d64fd27680ef80f7f92a3e95 Mon Sep 17 00:00:00 2001 From: fallen-icarus <108348082+fallen-icarus@users.noreply.github.com> Date: Tue, 21 Feb 2023 09:09:26 -0500 Subject: [PATCH 14/14] Removed first header Co-authored-by: Matthias Benkort <5680256+KtorZ@users.noreply.github.com> --- CIP-????/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CIP-????/README.md b/CIP-????/README.md index c093e93b71..1eb5ba7ad8 100644 --- a/CIP-????/README.md +++ b/CIP-????/README.md @@ -12,7 +12,6 @@ Discussions: Created: 2023-01-18 License: CC-BY-4.0 --- -# CIP-XXXX: Maybe Datum ## Abstract Currently all plutus spending scripts take a datum directly from the UTxO being spent. When a user/developer forgets to add a datum to a UTxO being sent to a plutus script's address, this results in the permanent locking of the UTxO. This CIP proposes changing the ledger-script interface so that all plutus scripts take an optional datum argument. Then, if the UTxO being spent is missing a datum or the plutus script is being used to mint/stake, the `Nothing` equivalent for the argument will be passed to the plutus script being executed. This latter part allows for universal plutus scripts.