From 27dec4d1a1369e802589f303272a78048c44a27c Mon Sep 17 00:00:00 2001 From: colll78 Date: Mon, 8 Jan 2024 14:40:51 -0600 Subject: [PATCH 01/22] CIP for observation scripts --- cip-observe-script-type/README.md | 125 ++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 cip-observe-script-type/README.md diff --git a/cip-observe-script-type/README.md b/cip-observe-script-type/README.md new file mode 100644 index 000000000..e3ae734c1 --- /dev/null +++ b/cip-observe-script-type/README.md @@ -0,0 +1,125 @@ +--- +CIP: ? +Title: Observe Script Type +Status: Proposed +Category: Plutus +Authors: + - Philip DiSarro +Implementors: [] +Discussions: [] +Created: 2024-1-8 +License: CC-BY-4.0 +--- + + + + +## Abstract + +We propose to introduce a new Plutus scripts type `Observe` in addition to those currently available e (spending, certifying, rewarding, minting, drep). The purpose of this script type is to allow arbitrary validation logic to be decoupled from any ledger action. +Since observe validators are decoupled from actions, you can run them in a transaction without needing to perform any associated action (ie you don't need to consume a script input, or mint a token, or withdraw from a staking script just to execute this validator). + +## Motivation: why is this CIP necessary? + +Often in a plutus validator you want to check "a particular Plutus script checked this transaction", but it's annoying (and wasteful) to have to have to lock an output in a script and then check if that output is consumed, or mint a token, or whatever else just to trigger script validation. + +Currently the main design pattern used to achieve this is a very obscure trick involving staking validators and the fact that you can withdraw 0 from a staking validator to trigger the script validation. A summary of the trick is: +Implement all the intended validation logic in a Plutus staking validator, we will call this validator `s_v`. To check that this validator was executed in the transaction you check if the credential of `s_v` (`StakingCredential`) is present in `txInfoWdrl`, this guarantees that `s_v` was checked in validation. +This relies on the fact that unlike in `txInfoMint` the ledger does not filter out 0 amount entries in `txInfoWdrl`. This means that you are allowed to build transactions that withdraw zero from a staking credential which in-turn triggers the staking script associated with that credential to execute in the transaction, +which makes it available in `txInfoWdrl`. This is a enables a very efficient design pattern for checking logic that is shared across multiple scripts. + +For instance, a common design pattern is a token based forwarding validator in which the validator defers its logic to another validator by checking that a state token is present in one of the transaction inputs: +```haskell +forwardNFTValidator :: AssetClass -> BuiltinData -> BuiltinData -> ScriptContext -> () +forwardNFTValidator stateToken _ _ ctx = assetClassValueOf stateToken (valueSpent (txInfo ctx)) == 1 +``` +This pattern is common in protocols that use the batcher architecture. Some protocols improve on the pattern by including the index of the input with the state token in the redeemer: +```haskell +forwardNFTValidator :: AssetClass -> BuiltinData -> Integer -> ScriptContext -> () +forwardNFTValidator stateToken _ tkIdx ctx = assetClassValueOf stateToken (txInInfoResolved (elemAt tkIdx (txInfoInputs (txInfo ctx)))) == 1 + +forwardMintPolicy:: AssetClass -> Integer -> ScriptContext -> () +forwardMintPolicy stateToken tkIdx ctx = assetClassValueOf stateToken (txInInfoResolved (elemAt tkIdx (txInfoInputs (txInfo ctx)))) == 1 +``` +With this pattern DApps are able to process roughly 12-30 forwardNFTValidator UTxO's per transaction without exceeding script budget limitations. +The time complexity of this validator is **O(n)** where n is the number of tx inputs. This logic is executed once per input being unlocked / currency symbol being minted. +The redundant execution of searching the inputs for a token is the largest throughput bottleneck for these DApps; it is **O(n*m)** where n is the number of inputs and m is the number of `forwardValidator` inputs + `forwardValidator` minting policies. +Using the stake validator trick, the time complexity of the forwarding logic is improved to **O(1)**. The forwardValidator logic becomes: +```haskell +forwardWithStakeTrick:: StakingCredential -> BuiltinData -> BuiltinData -> ScriptContext -> () +forwardWithStakeTrick obsScriptCred tkIdx ctx = fst (head stakeCertPairs) == obsScriptCred + where + info = txInfo ctx + stakeCertPairs = AssocMap.toList (txInfoWdrl info) +``` +IE check that the StakingCredential is in the first pair in the `txInfoWdrl`. This script is **O(1)** in the case where you limit it to one Observe script, or if you don't want to break composability with other Observe scripts, then it becomes** O(obs_N)** where `obs_N` is the number of Observe validators that are executed in the transaction. + +This proposal just makes this design pattern indepedent from implementation details of stake validators and withdrawals, and improves efficiency and readability for validators that implement it. + +## Specification + +The type signature of this script type will be consistent with the type signature of minting and staking validators, namely: +```haskell +Redeemer -> ScriptContext -> () +``` + +The type signature of the newly introduced `Purpose` will be: +```haskell +Observe Integer -- ^ where integer is the index into the observations +``` + +A new field will be introduced into the script context: + +```haskell +-- | TxInfo for PlutusV3 +data TxInfo = TxInfo + { txInfoInputs :: [V2.TxInInfo] + , txInfoReferenceInputs :: [V2.TxInInfo] + , txInfoOutputs :: [V2.TxOut] + , txInfoFee :: V2.Value + , txInfoMint :: V2.Value + , txInfoTxCerts :: [TxCert] + , txInfoWdrl :: Map V2.Credential Haskell.Integer + , txInfoValidRange :: V2.POSIXTimeRange + , txInfoSignatories :: [V2.PubKeyHash] + , txInfoRedeemers :: Map ScriptPurpose V2.Redeemer + , txInfoData :: Map V2.DatumHash V2.Datum + , txInfoId :: V2.TxId + , txInfoVotingProcedures :: Map Voter (Map GovernanceActionId VotingProcedure) + , txInfoProposalProcedures :: [ProposalProcedure] + , txInfoCurrentTreasuryAmount :: Haskell.Maybe V2.Value + , txInfoTreasuryDonation :: Haskell.Maybe V2.Value + , txInfoObservations :: [ScriptHash] -- ^ newly introduced list of observation scripts that executed in this tx. + } +``` + +## Rationale: how does this CIP achieve its goals? + + +## Path to Active + +### Acceptance Criteria + + +### Implementation Plan + + +## Copyright + + +[CC-BY-4.0]: https://creativecommons.org/licenses/by/4.0/legalcode +[Apache-2.0]: http://www.apache.org/licenses/LICENSE-2.0 From d3ff6dffb20ffb8ccfe6290f2026fc0791c9aced Mon Sep 17 00:00:00 2001 From: colll78 Date: Mon, 22 Jan 2024 16:42:19 -0600 Subject: [PATCH 02/22] Update README.md --- cip-observe-script-type/README.md | 55 ++++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 4 deletions(-) diff --git a/cip-observe-script-type/README.md b/cip-observe-script-type/README.md index e3ae734c1..eef612292 100644 --- a/cip-observe-script-type/README.md +++ b/cip-observe-script-type/README.md @@ -65,7 +65,7 @@ forwardWithStakeTrick obsScriptCred tkIdx ctx = fst (head stakeCertPairs) == obs ``` IE check that the StakingCredential is in the first pair in the `txInfoWdrl`. This script is **O(1)** in the case where you limit it to one Observe script, or if you don't want to break composability with other Observe scripts, then it becomes** O(obs_N)** where `obs_N` is the number of Observe validators that are executed in the transaction. -This proposal just makes this design pattern indepedent from implementation details of stake validators and withdrawals, and improves efficiency and readability for validators that implement it. +This proposal makes this design pattern indepedent from implementation details of stake validators and withdrawals, and improves efficiency and readability for validators that implement it. ## Specification @@ -76,9 +76,21 @@ Redeemer -> ScriptContext -> () The type signature of the newly introduced `Purpose` will be: ```haskell -Observe Integer -- ^ where integer is the index into the observations +Observe Integer -- ^ where integer is the index into the observations list. ``` +### Script context + +Scripts are passed information about transactions via the script context. +We propose to augment the script context to include information about the observation scripts that are executed in the transaction. + +Changing the script context will require a new Plutus language version in the ledger to support the new interface. +The change is: a new field is added to the script context which represents the list of observation scripts that must validate the transaction. +The observation scripts in the list are represented by their hash. + +The interface for old versions of the language will not be changed. +Scripts with old versions cannot be spent in transactions that include observation scripts, attempting to do so will be a phase 1 transaction validation failure. + A new field will be introduced into the script context: ```haskell @@ -104,6 +116,39 @@ data TxInfo = TxInfo } ``` +### CDDL + +The CDDL for transaction body will change as follows to reflect the new field. +``` +transaction_body = + { 0 : set ; inputs + , 1 : [* transaction_output] + , 2 : coin ; fee + , ? 3 : uint ; time to live + , ? 4 : certificates + , ? 5 : withdrawals + , ? 7 : auxiliary_data_hash + , ? 8 : uint ; validity interval start + , ? 9 : mint + , ? 11 : script_data_hash + , ? 13 : nonempty_set ; collateral inputs + , ? 14 : required_signers + , ? 15 : network_id + , ? 16 : transaction_output ; collateral return + , ? 17 : coin ; total collateral + , ? 18 : nonempty_set ; reference inputs + , ? 19 : voting_procedures ; Voting procedures + , ? 20 : proposal_procedures ; Proposal procedures + , ? 21 : coin ; current treasury value + , ? 22 : positive_coin ; donation + , ? 23 : required_observations ; New; observation scripts that must execute in phase 2 validation + } + +required_observations = set +``` + +The required observations (field 23) is a set of script hashes that can be used to require the associated Plutus script to present in the witness set and is executed in the transaction. If a script hash is present but the corresponding Plutus script is not in the witness set, the transaction will fail in phase 1 validation. This way, Plutus validation scripts can know which observation scripts were executed in the transaction. + ## Rationale: how does this CIP achieve its goals? - +- [] Fully implemented in Cardano. + ### Implementation Plan - +- [] Passes all requirements of both Plutus and Ledger teams as agreed to improve Plutus script efficiency and usability. + ## Copyright From 1b1a48825396bb5d683a6e9504e22a63be4292be Mon Sep 17 00:00:00 2001 From: colll78 Date: Mon, 22 Jan 2024 16:43:38 -0600 Subject: [PATCH 03/22] Update README.md --- cip-observe-script-type/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cip-observe-script-type/README.md b/cip-observe-script-type/README.md index eef612292..c480c54db 100644 --- a/cip-observe-script-type/README.md +++ b/cip-observe-script-type/README.md @@ -63,7 +63,7 @@ forwardWithStakeTrick obsScriptCred tkIdx ctx = fst (head stakeCertPairs) == obs info = txInfo ctx stakeCertPairs = AssocMap.toList (txInfoWdrl info) ``` -IE check that the StakingCredential is in the first pair in the `txInfoWdrl`. This script is **O(1)** in the case where you limit it to one Observe script, or if you don't want to break composability with other Observe scripts, then it becomes** O(obs_N)** where `obs_N` is the number of Observe validators that are executed in the transaction. +IE check that the StakingCredential is in the first pair in the `txInfoWdrl`. This script is **O(1)** in the case where you limit it to one Observe script, or if you don't want to break composability with other Observe scripts, then it becomes **O(obs_N)** where `obs_N` is the number of Observe validators that are executed in the transaction. This proposal makes this design pattern indepedent from implementation details of stake validators and withdrawals, and improves efficiency and readability for validators that implement it. From 54d238bc248c452d696f9b18bf34237371ab6fc5 Mon Sep 17 00:00:00 2001 From: colll78 Date: Mon, 22 Jan 2024 16:49:48 -0600 Subject: [PATCH 04/22] Update README.md --- cip-observe-script-type/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cip-observe-script-type/README.md b/cip-observe-script-type/README.md index c480c54db..aefbc9488 100644 --- a/cip-observe-script-type/README.md +++ b/cip-observe-script-type/README.md @@ -6,7 +6,8 @@ Category: Plutus Authors: - Philip DiSarro Implementors: [] -Discussions: [] +Discussions: + - https://github.com/cardano-foundation/CIPs/pull/418/ Created: 2024-1-8 License: CC-BY-4.0 --- From c1482be71fd927654bf4e19b9021bcb20aae063a Mon Sep 17 00:00:00 2001 From: colll78 Date: Mon, 22 Jan 2024 17:10:48 -0600 Subject: [PATCH 05/22] Update README.md --- cip-observe-script-type/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cip-observe-script-type/README.md b/cip-observe-script-type/README.md index aefbc9488..cddaab395 100644 --- a/cip-observe-script-type/README.md +++ b/cip-observe-script-type/README.md @@ -148,7 +148,7 @@ transaction_body = required_observations = set ``` -The required observations (field 23) is a set of script hashes that can be used to require the associated Plutus script to present in the witness set and is executed in the transaction. If a script hash is present but the corresponding Plutus script is not in the witness set, the transaction will fail in phase 1 validation. This way, Plutus validation scripts can know which observation scripts were executed in the transaction. +The required observations (field 23) is a set of script hashes that can be used to require the associated Plutus script to present in the witness set and is executed in the transaction. If a script hash is present but the corresponding Plutus script is not in the witness set, the transaction will fail in phase 1 validation. This way plutus scripts can check the script context to know which observation scripts were executed in the transaction. ## Rationale: how does this CIP achieve its goals? -We propose to introduce a new Plutus scripts type `Observe` in addition to those currently available e (spending, certifying, rewarding, minting, drep). The purpose of this script type is to allow arbitrary validation logic to be decoupled from any ledger action. +We propose to introduce a new Plutus scripts type `Observe` in addition to those currently available (spending, certifying, rewarding, minting, drep). The purpose of this script type is to allow arbitrary validation logic to be decoupled from any ledger action. Since observe validators are decoupled from actions, you can run them in a transaction without needing to perform any associated action (ie you don't need to consume a script input, or mint a token, or withdraw from a staking script just to execute this validator). ## Motivation: why is this CIP necessary? From c7b311fcb4952a385ffe1636d2179a109964086b Mon Sep 17 00:00:00 2001 From: colll78 Date: Mon, 22 Jan 2024 19:10:42 -0600 Subject: [PATCH 10/22] Update README.md --- cip-observe-script-type/README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cip-observe-script-type/README.md b/cip-observe-script-type/README.md index a23a74ce1..3c057769d 100644 --- a/cip-observe-script-type/README.md +++ b/cip-observe-script-type/README.md @@ -63,8 +63,13 @@ forwardWithStakeTrick obsScriptCred tkIdx ctx = fst (head stakeCertPairs) == obs where info = txInfo ctx stakeCertPairs = AssocMap.toList (txInfoWdrl info) + +stakeValidatorWithSharedLogic :: AssetClass -> BuiltinData -> ScriptContext -> () +stakeValidatorWithSharedLogic stateToken _rdmr ctx = assetClassValueOf stateToken (valueSpent (txInfo ctx)) == 1 ``` -IE check that the StakingCredential is in the first pair in the `txInfoWdrl`. This script is **O(1)** in the case where you limit it to one Observe script, or if you don't want to break composability with other Observe scripts, then it becomes **O(obs_N)** where `obs_N` is the number of Observe validators that are executed in the transaction. +For the staking validator trick (demonstrated above), we are simply checking that the StakingCredential of the the staking validator containing the shared validation logic is in the first pair in `txInfoWdrl`. If the StakingCredential is present in `txInfoWdrl`, that means the staking validator (with our shared validation logic) successfully executed in the transaction. This script is **O(1)** in the case where you limit it to one shared logic validator (staking validator), or if you don't want to break composability with other staking validator, +then it becomes** O(obs_N)** where `obs_N` is the number of Observe validators that are executed in the transaction as you have to verify that the StakingCredential is present in `txInfoWdrl`. + This proposal makes this design pattern indepedent from implementation details of stake validators and withdrawals, and improves efficiency and readability for validators that implement it. From 8ff7bc70084bf9610ce157b80b6c942b4aa2aa49 Mon Sep 17 00:00:00 2001 From: colll78 Date: Mon, 22 Jan 2024 21:59:50 -0600 Subject: [PATCH 11/22] Update README.md --- cip-observe-script-type/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cip-observe-script-type/README.md b/cip-observe-script-type/README.md index 3c057769d..b7795dcbc 100644 --- a/cip-observe-script-type/README.md +++ b/cip-observe-script-type/README.md @@ -68,7 +68,7 @@ stakeValidatorWithSharedLogic :: AssetClass -> BuiltinData -> ScriptContext -> ( stakeValidatorWithSharedLogic stateToken _rdmr ctx = assetClassValueOf stateToken (valueSpent (txInfo ctx)) == 1 ``` For the staking validator trick (demonstrated above), we are simply checking that the StakingCredential of the the staking validator containing the shared validation logic is in the first pair in `txInfoWdrl`. If the StakingCredential is present in `txInfoWdrl`, that means the staking validator (with our shared validation logic) successfully executed in the transaction. This script is **O(1)** in the case where you limit it to one shared logic validator (staking validator), or if you don't want to break composability with other staking validator, -then it becomes** O(obs_N)** where `obs_N` is the number of Observe validators that are executed in the transaction as you have to verify that the StakingCredential is present in `txInfoWdrl`. +then it becomes **O(obs_N)** where `obs_N` is the number of Observe validators that are executed in the transaction as you have to verify that the StakingCredential is present in `txInfoWdrl`. This proposal makes this design pattern indepedent from implementation details of stake validators and withdrawals, and improves efficiency and readability for validators that implement it. From 1f90c38bbe1e5fe4c1727535f113bd3bc83d7615 Mon Sep 17 00:00:00 2001 From: colll78 Date: Tue, 23 Jan 2024 08:28:57 -0600 Subject: [PATCH 12/22] Update cip-observe-script-type/README.md Co-authored-by: Ryan Williams <44342099+Ryun1@users.noreply.github.com> --- cip-observe-script-type/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cip-observe-script-type/README.md b/cip-observe-script-type/README.md index b7795dcbc..5afeec8c3 100644 --- a/cip-observe-script-type/README.md +++ b/cip-observe-script-type/README.md @@ -8,7 +8,7 @@ Authors: Implementors: [] Discussions: - https://github.com/cardano-foundation/CIPs/pull/418/ -Created: 2024-1-8 +Created: 2024-01-08 License: CC-BY-4.0 --- From d5d1e7209a0e2afda9d2eb0988c55dcfa5e6e46b Mon Sep 17 00:00:00 2001 From: colll78 Date: Tue, 23 Jan 2024 08:29:12 -0600 Subject: [PATCH 13/22] Update cip-observe-script-type/README.md Co-authored-by: Michael Peyton Jones --- cip-observe-script-type/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cip-observe-script-type/README.md b/cip-observe-script-type/README.md index 5afeec8c3..0596621cd 100644 --- a/cip-observe-script-type/README.md +++ b/cip-observe-script-type/README.md @@ -33,7 +33,7 @@ Since observe validators are decoupled from actions, you can run them in a trans ## Motivation: why is this CIP necessary? -Often in a plutus validator you want to check "a particular Plutus script checked this transaction", but it's annoying (and wasteful) to have to have to lock an output in a script and then check if that output is consumed, or mint a token, or whatever else just to trigger script validation. +Often in a plutus validator you want to check "a particular (different) Plutus script checked this transaction", but it's annoying (and wasteful) to have to have to lock an output in a script and then check if that output is consumed, or mint a token, or whatever else just to trigger script validation. Currently the main design pattern used to achieve this is a very obscure trick involving staking validators and the fact that you can withdraw 0 from a staking validator to trigger the script validation. A summary of the trick is: Implement all the intended validation logic in a Plutus staking validator, we will call this validator `s_v`. To check that this validator was executed in the transaction you check if the credential of `s_v` (`StakingCredential`) is present in `txInfoWdrl`, this guarantees that `s_v` was checked in validation. From 52be316ff816f00c05b738ea90434874799ecf9e Mon Sep 17 00:00:00 2001 From: Robert Phair Date: Tue, 23 Jan 2024 22:59:34 +0530 Subject: [PATCH 14/22] assigned CIP number 112 --- cip-observe-script-type/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cip-observe-script-type/README.md b/cip-observe-script-type/README.md index 0596621cd..5ff070f64 100644 --- a/cip-observe-script-type/README.md +++ b/cip-observe-script-type/README.md @@ -1,5 +1,5 @@ --- -CIP: ? +CIP: 112 Title: Observe Script Type Status: Proposed Category: Plutus From 2333ddb685ac486c61a79bb56e3eaf7c6c44c31d Mon Sep 17 00:00:00 2001 From: colll78 Date: Tue, 23 Jan 2024 11:46:05 -0600 Subject: [PATCH 15/22] Update cip-observe-script-type/README.md Co-authored-by: Ryan Williams <44342099+Ryun1@users.noreply.github.com> --- cip-observe-script-type/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/cip-observe-script-type/README.md b/cip-observe-script-type/README.md index 5ff070f64..7417330b0 100644 --- a/cip-observe-script-type/README.md +++ b/cip-observe-script-type/README.md @@ -173,6 +173,7 @@ It must also explain how the proposal affects the backward compatibility of exis ## Copyright +This CIP is licensed under [CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/legalcode). [CC-BY-4.0]: https://creativecommons.org/licenses/by/4.0/legalcode [Apache-2.0]: http://www.apache.org/licenses/LICENSE-2.0 From 7b1fe46babe5ab90d399d4af95a55402cc19961b Mon Sep 17 00:00:00 2001 From: colll78 Date: Fri, 26 Jan 2024 16:38:08 -0600 Subject: [PATCH 16/22] Update README.md --- cip-observe-script-type/README.md | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/cip-observe-script-type/README.md b/cip-observe-script-type/README.md index 7417330b0..0608ff82b 100644 --- a/cip-observe-script-type/README.md +++ b/cip-observe-script-type/README.md @@ -147,19 +147,28 @@ transaction_body = , ? 20 : proposal_procedures ; Proposal procedures , ? 21 : coin ; current treasury value , ? 22 : positive_coin ; donation - , ? 23 : required_scripts ; New; observation scripts that must execute in phase 2 validation + , ? 23 : required_observers ; New; observation scripts that must execute in phase 2 validation } -required_scripts = set +required_observers = set ``` -The required scripts (field 23) is a set of script hashes that can be used to require the associated Plutus script to present in the witness set or as a reference script and is executed in the transaction. If a script hash is present but the corresponding Plutus script is not in the witness set or present in a reference script, the transaction will fail in phase 1 validation. This way plutus scripts can check the script context to know which observation scripts were executed in the transaction. +The `required_observers` (field 23) is a set of script hashes that can be used to require the associated Plutus script to be present in the witness set or as a reference script and executed in the transaction. If a script hash is present but the corresponding Plutus script is not in the witness set or present in a reference script, the transaction will fail in phase 1 validation. This way plutus scripts can check the script context to know which observation scripts were executed in the transaction. ## Rationale: how does this CIP achieve its goals? +Currently Plutus scripts in a transaction will only execute when the transaction performs the associated ledger action (ie. a Plutus minting policy will only execute if the transaction mints or burns tokens with matching currency symbol). The only exception is the withdraw zero trick which relies on an obscure mechanic where zero amount withdrawals are not filtered by the ledger. Now using `required_observers` we can specify a list of Plutus scripts to be executed in the transaction independent of any ledger actions. The newly introduced `txInfoObservations` field in the script context provides a straightforward way for Plutus scripts to check that "a particular script validated this transaction". + +This change is not backwards-compatible and will need to go into a new Plutus language version. + +### Alternatives + +- We could decide to accept the withdraw-zero staking script trick as an adequate solution, and just preserve the nonsensical withdraw zero case in future language versions. +- The staking script trick could be abstracted away from the developer by smart contract languages that compile to UPLC. + - This can be dangerous since by distancing the developer from what is actually happening you open up the door for the developer to act on misguided assumptions. ## Path to Active From fa1a47c3cf1dcaff71cf950465c4f0391b8009d0 Mon Sep 17 00:00:00 2001 From: colll78 Date: Thu, 1 Feb 2024 13:40:41 -0600 Subject: [PATCH 17/22] Update README.md --- cip-observe-script-type/README.md | 43 ++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/cip-observe-script-type/README.md b/cip-observe-script-type/README.md index 0608ff82b..b5e79dcc3 100644 --- a/cip-observe-script-type/README.md +++ b/cip-observe-script-type/README.md @@ -30,6 +30,7 @@ License: CC-BY-4.0 We propose to introduce a new Plutus scripts type `Observe` in addition to those currently available (spending, certifying, rewarding, minting, drep). The purpose of this script type is to allow arbitrary validation logic to be decoupled from any ledger action. Since observe validators are decoupled from actions, you can run them in a transaction without needing to perform any associated action (ie you don't need to consume a script input, or mint a token, or withdraw from a staking script just to execute this validator). +Additionally, we propose to introduce a new assertion to native scripts that they can use to check that a particular script hash is in `required_observers` (which in turn enforces that the script must be executed successfully in the transaction). This addresses a number of technical issues discussed in other CIPs and CPS such as the redundant execution of spending scripts, and the inability to effectively use native scripts in conjunction with Plutus scripts. ## Motivation: why is this CIP necessary? @@ -53,7 +54,6 @@ forwardNFTValidator stateToken _ tkIdx ctx = assetClassValueOf stateToken (txIn forwardMintPolicy:: AssetClass -> Integer -> ScriptContext -> () forwardMintPolicy stateToken tkIdx ctx = assetClassValueOf stateToken (txInInfoResolved (elemAt tkIdx (txInfoInputs (txInfo ctx)))) == 1 ``` -With this pattern DApps are able to process roughly 12-30 forwardNFTValidator UTxO's per transaction without exceeding script budget limitations. The time complexity of this validator is **O(n)** where n is the number of tx inputs. This logic is executed once per input being unlocked / currency symbol being minted. The redundant execution of searching the inputs for a token is the largest throughput bottleneck for these DApps; it is **O(n*m)** where n is the number of inputs and m is the number of `forwardValidator` inputs + `forwardValidator` minting policies. Using the stake validator trick, the time complexity of the forwarding logic is improved to **O(1)**. The forwardValidator logic becomes: @@ -70,8 +70,20 @@ stakeValidatorWithSharedLogic stateToken _rdmr ctx = assetClassValueOf stateToke For the staking validator trick (demonstrated above), we are simply checking that the StakingCredential of the the staking validator containing the shared validation logic is in the first pair in `txInfoWdrl`. If the StakingCredential is present in `txInfoWdrl`, that means the staking validator (with our shared validation logic) successfully executed in the transaction. This script is **O(1)** in the case where you limit it to one shared logic validator (staking validator), or if you don't want to break composability with other staking validator, then it becomes **O(obs_N)** where `obs_N` is the number of Observe validators that are executed in the transaction as you have to verify that the StakingCredential is present in `txInfoWdrl`. - -This proposal makes this design pattern indepedent from implementation details of stake validators and withdrawals, and improves efficiency and readability for validators that implement it. +The proposed changes in this CIP enable this design pattern to exist indepedently from implementation details of stake validators and withdrawals, and improve efficiency and readability for validators that implement it. Furthermore, with the proposed extension to native scripts, we are able to completely get rid of the redundant spending script executions like so: +```haskell +observationValidator :: AssetClass -> BuiltinData -> ScriptContext -> () +observationValidator stateToken _redeemer ctx = assetClassValueOf stateToken (valueSpent (txInfo ctx)) == 1 +``` +We simply include the script hash of the above `observationValidator` in the `required_observers` field in the transaction body and we lock +all the UTxOs that we would like to share the same spending condition into the following native script: +```json +{ + "type": "observer", + "keyHash": "OUR_OBSERVATION_SCRIPT_HASH" +} +``` +The above solution (enabled by this CIP) is more clear, concise, flexible and efficient than the alternatives discussed above. ## Specification @@ -155,6 +167,31 @@ required_observers = set The `required_observers` (field 23) is a set of script hashes that can be used to require the associated Plutus script to be present in the witness set or as a reference script and executed in the transaction. If a script hash is present but the corresponding Plutus script is not in the witness set or present in a reference script, the transaction will fail in phase 1 validation. This way plutus scripts can check the script context to know which observation scripts were executed in the transaction. +### Native Script Extension + +The BNF notation for the abstract syntax of native scripts change as follows to reflect the new field. + +```BNF + ::= + + | + | + | + + | * + | * + | * +``` + +Native scripts are typically represented in JSON syntax. We propose the following JSON representation for the `RequireObserver` constructor: +```JSON +{ + "type": "observer", + "keyHash": "OBSERVATION_SCRIPT_HASH" +} +``` + + ## Rationale: how does this CIP achieve its goals? -Currently Plutus scripts in a transaction will only execute when the transaction performs the associated ledger action (ie. a Plutus minting policy will only execute if the transaction mints or burns tokens with matching currency symbol). The only exception is the withdraw zero trick which relies on an obscure mechanic where zero amount withdrawals are not filtered by the ledger. Now using `required_observers` we can specify a list of Plutus scripts to be executed in the transaction independent of any ledger actions. The newly introduced `txInfoObservations` field in the script context provides a straightforward way for Plutus scripts to check that "a particular script validated this transaction". +Currently Plutus scripts (and native scripts) in a transaction will only execute when the transaction performs the associated ledger action (ie. a Plutus minting policy will only execute if the transaction mints or burns tokens with matching currency symbol). The only exception is the withdraw zero trick which relies on an obscure mechanic where zero amount withdrawals are not filtered by the ledger. Now using `required_observers` we can specify a list of scripts (supports both native and Plutus scripts) to be executed in the transaction independent of any ledger actions. The newly introduced `txInfoObservations` field in the script context provides a straightforward way for scripts to check that "a particular script validated this transaction". This change is not backwards-compatible and will need to go into a new Plutus language version. From c9decde3aabd081c601e717c12b7b719a26322eb Mon Sep 17 00:00:00 2001 From: colll78 Date: Tue, 19 Mar 2024 10:41:01 -0700 Subject: [PATCH 19/22] Update cip-observe-script-type/README.md Co-authored-by: Robert Phair --- cip-observe-script-type/README.md | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/cip-observe-script-type/README.md b/cip-observe-script-type/README.md index 72b99abcd..005d020ff 100644 --- a/cip-observe-script-type/README.md +++ b/cip-observe-script-type/README.md @@ -12,20 +12,6 @@ Created: 2024-01-08 License: CC-BY-4.0 --- - - - ## Abstract We propose to introduce a new Plutus scripts type `Observe` in addition to those currently available (spending, certifying, rewarding, minting, drep). The purpose of this script type is to allow arbitrary validation logic to be decoupled from any ledger action. From 26694d6e5f2d4aaf9a3e69eae0a3f084ad13c9cb Mon Sep 17 00:00:00 2001 From: colll78 Date: Tue, 19 Mar 2024 10:42:46 -0700 Subject: [PATCH 20/22] Update README.md --- cip-observe-script-type/README.md | 9 --------- 1 file changed, 9 deletions(-) diff --git a/cip-observe-script-type/README.md b/cip-observe-script-type/README.md index 005d020ff..d1abd5c0f 100644 --- a/cip-observe-script-type/README.md +++ b/cip-observe-script-type/README.md @@ -13,13 +13,11 @@ License: CC-BY-4.0 --- ## Abstract - We propose to introduce a new Plutus scripts type `Observe` in addition to those currently available (spending, certifying, rewarding, minting, drep). The purpose of this script type is to allow arbitrary validation logic to be decoupled from any ledger action. Since observe validators are decoupled from actions, you can run them in a transaction without needing to perform any associated action (ie you don't need to consume a script input, or mint a token, or withdraw from a staking script just to execute this validator). Additionally, we propose to introduce a new assertion to native scripts that they can use to check that a particular script hash is in `required_observers` (which in turn enforces that the script must be executed successfully in the transaction). This addresses a number of technical issues discussed in other CIPs and CPS such as the redundant execution of spending scripts, and the inability to effectively use native scripts in conjunction with Plutus scripts. ## Motivation: why is this CIP necessary? - Often in a plutus validator you want to check "a particular (different) Plutus script checked this transaction", but it's annoying (and wasteful) to have to have to lock an output in a script and then check if that output is consumed, or mint a token, or whatever else just to trigger script validation. Currently the main design pattern used to achieve this is a very obscure trick involving staking validators and the fact that you can withdraw 0 from a staking validator to trigger the script validation. A summary of the trick is: @@ -72,7 +70,6 @@ all the UTxOs that we would like to share the same spending condition into the f The above solution (enabled by this CIP) is more clear, concise, flexible and efficient than the alternatives discussed above. ## Specification - The type signature of this script type will be consistent with the type signature of minting and staking validators, namely: ```haskell Redeemer -> ScriptContext -> () @@ -178,10 +175,7 @@ Native scripts are typically represented in JSON syntax. We propose the followin ## Rationale: how does this CIP achieve its goals? - Currently Plutus scripts (and native scripts) in a transaction will only execute when the transaction performs the associated ledger action (ie. a Plutus minting policy will only execute if the transaction mints or burns tokens with matching currency symbol). The only exception is the withdraw zero trick which relies on an obscure mechanic where zero amount withdrawals are not filtered by the ledger. Now using `required_observers` we can specify a list of scripts (supports both native and Plutus scripts) to be executed in the transaction independent of any ledger actions. The newly introduced `txInfoObservations` field in the script context provides a straightforward way for scripts to check that "a particular script validated this transaction". This change is not backwards-compatible and will need to go into a new Plutus language version. @@ -195,15 +189,12 @@ This change is not backwards-compatible and will need to go into a new Plutus la ## Path to Active ### Acceptance Criteria - - [] Fully implemented in Cardano. ### Implementation Plan - - [] Passes all requirements of both Plutus and Ledger teams as agreed to improve Plutus script efficiency and usability. ## Copyright - This CIP is licensed under [CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/legalcode). [CC-BY-4.0]: https://creativecommons.org/licenses/by/4.0/legalcode From 2c5dc69215aa0ef4e20a30ee2925ba04462d3690 Mon Sep 17 00:00:00 2001 From: Robert Phair Date: Tue, 30 Apr 2024 22:41:13 +0530 Subject: [PATCH 21/22] fixing markdown tickbox format --- cip-observe-script-type/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cip-observe-script-type/README.md b/cip-observe-script-type/README.md index d1abd5c0f..0d485792c 100644 --- a/cip-observe-script-type/README.md +++ b/cip-observe-script-type/README.md @@ -192,7 +192,7 @@ This change is not backwards-compatible and will need to go into a new Plutus la - [] Fully implemented in Cardano. ### Implementation Plan -- [] Passes all requirements of both Plutus and Ledger teams as agreed to improve Plutus script efficiency and usability. +- [ ] Passes all requirements of both Plutus and Ledger teams as agreed to improve Plutus script efficiency and usability. ## Copyright This CIP is licensed under [CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/legalcode). From 50f51d833e499f4b13e9dc3bcc3585a912fd76d5 Mon Sep 17 00:00:00 2001 From: colll78 Date: Fri, 3 May 2024 17:36:40 -0700 Subject: [PATCH 22/22] Update cip-observe-script-type/README.md Co-authored-by: Ryan <44342099+Ryun1@users.noreply.github.com> --- cip-observe-script-type/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cip-observe-script-type/README.md b/cip-observe-script-type/README.md index 0d485792c..bdb902217 100644 --- a/cip-observe-script-type/README.md +++ b/cip-observe-script-type/README.md @@ -189,7 +189,7 @@ This change is not backwards-compatible and will need to go into a new Plutus la ## Path to Active ### Acceptance Criteria -- [] Fully implemented in Cardano. +- [ ] These rules included within a official Plutus version, and released via a major hard fork. ### Implementation Plan - [ ] Passes all requirements of both Plutus and Ledger teams as agreed to improve Plutus script efficiency and usability.