Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CIP-0057? | Plutus Smart-Contract Blueprints #258

Merged
merged 1 commit into from
May 6, 2023

Conversation

KtorZ
Copy link
Member

@KtorZ KtorZ commented May 15, 2022

This proposal specifies a language for documenting Plutus contracts in a machine-readable manner. This is akin to what OpenAPI or AsyncAPI are for, documenting HTTP services and asynchronous services respectively. In a similar fashion, A Plutus contract has a binary interface which is mostly defined by its datum and redeemer. Since all interactions with contracts are done through transactions, we can also model endpoints of a contract as transitions from a known state to another purely declaratively.

This document is therefore a meta-specification defining the vocabulary and validation rules with which one can specify a Plutus contract interface, a.k.a Plutus contract blueprint.


see rendered Markdown

@KtorZ KtorZ self-assigned this May 15, 2022
@scarmuega

This comment was marked as resolved.

@satran004

This comment was marked as resolved.

@KtorZ

This comment was marked as outdated.

CIP-0054/README.md Outdated Show resolved Hide resolved
@pgwadapool

This comment was marked as resolved.

@KtorZ KtorZ changed the title Bootstrap first draft of the Plutus contract blueprint. CIP-0057? | On-Chain Script Blueprint Jun 7, 2022
@KtorZ

This comment was marked as resolved.

@satran004

This comment was marked as resolved.

@scarmuega

This comment was marked as outdated.

@KtorZ

This comment was marked as outdated.

@scarmuega

This comment was marked as outdated.

@MitchTurner

This comment was marked as resolved.

@KtorZ KtorZ force-pushed the KtorZ/CIP-0054/plutus-contract-blueprint branch from 345ecc0 to f82334d Compare September 8, 2022 15:03
@KtorZ

This comment was marked as resolved.

@KtorZ KtorZ changed the title CIP-0057? | On-Chain Script Blueprint CIP-0057? | Plutus Smart-Contract Blueprints Sep 8, 2022
L-as

This comment was marked as resolved.

@KtorZ

This comment was marked as resolved.

@L-as

This comment was marked as resolved.

@KtorZ

This comment was marked as resolved.

@KtorZ

This comment was marked as resolved.

@MitchTurner

This comment was marked as resolved.

bladyjoker

This comment was marked as resolved.

@KtorZ

This comment was marked as resolved.

@KtorZ
Copy link
Member Author

KtorZ commented Feb 22, 2023

@nielstron the datum is optional. Only mandatory for spending validators.
So, no, the schema is meant to cover all kind of validators.

@nielstron
Copy link
Contributor

@KtorZ Right I didn't see that. It says that the datum should be present iff purpose=spend - but there appears to be no (machine readable) way to specify the intended script purpose or am I missing that too?

@KtorZ
Copy link
Member Author

KtorZ commented Feb 22, 2023

There was one, and I removed it. So that's an artifact I need to fix. An earlier version of the blueprint used to have a field "purpose". However, we realized that having such a field doesn't make much sense because a same validator is often reused between different purpose (that's especially the case between withdrawals and certificates validators).

The purpose is an intrinsic properties of validators, so it doesn't quite make sense in the outward blueprint. In the end, we truly have two kinds of validators: those who have 2 parameters, and those who have 3.

@nielstron
Copy link
Contributor

nielstron commented Feb 22, 2023

Would it maybe make sense to also allow the anyOf syntax for purposes? I think it would indeed be useful to know what purposes a validator is intended to be used for while I agree there are validators that don't serve a single purpose

The 2/3 parameter distinction is also not entirely true. The wrapped token contract written in eopsin serves both as a minting and as a spending script and conditionally accepts either 2 or 3 parameters.

@KtorZ
Copy link
Member Author

KtorZ commented Feb 22, 2023

Yes indeed. We've been thinking about doing something similar for Aiken-generated validators. Which raises an interesting question w.r.t blueprints. We may need to be able to represent a datum as optional. Right now, it's optional in the meta-schema, but that's different.

I reckon the blueprint should be able to express just what you describe: "this validator can have 2 or 3 arguments", which is another way of saying "this validator can have a datum, or not" and provide the expected format for the datum when it's provided.

@nielstron
Copy link
Contributor

Maybe a better way to describe this behaviour is to generate distinct validator descriptions but with the same validator hash?

In a sense, even though it is the same validator, it validates different things (in the token wrapping case, the spending contract checks that the correct amount of tokens is unlocked, while the minting contract validates the correct amount of wrapped tokens is minted)

This makes the purpose necessary to be specified to describe what this invocation of the validator checks.

@KtorZ
Copy link
Member Author

KtorZ commented Feb 22, 2023

I think it's even wider than the purpose then. You could imagine capturing all possible invocation of a specific validator as separate blueprint object. They'd all have the same validator hash, but the datum / redeemers may be different, as well as the description of the validator.

@nielstron
Copy link
Contributor

More points in favor of explicitly specifying the purpose

  1. I think the fact that the same validator may be used for different purposes should be more or less transparent for the user. The user just wants to perform an action that requires invocation of one or more contracts (for one or more different purposes) and whether or not these are the same doesn't have to bother the user.

  2. The tooling should be able to inform the user that they are using a contract against its intended specification. This is only possible if the tooling can identify the intended usage by combination of contract + purpose.

@nielstron
Copy link
Contributor

nielstron commented Feb 22, 2023

I think it's even wider than the purpose then. You could imagine capturing all possible invocation of a specific validator as separate blueprint object. They'd all have the same validator hash, but the datum / redeemers may be different, as well as the description of the validator.

True. Of course at some point one has to cut a line and abstract.

I just think in practice different datums at the spending contract will be very unlikely to describe entirely different behaviour, because this implies that the same contract is used for completely unrelated things. So even if you were to differentiate based on the datum, most likely not many different descriptions are extracted (imagine a DEX, all datums have the same format per contract). But I would argue that in general a UTxO locked at a contract with a different datum describes a potentially completely different invocation.

The Redeemer describes what the user wants to do with the contract. It makes sense IMO to capture the different redeemers in the same description? But yeah one can imagine that the tooling may output different information about contract invocation based on the type of Redeemer passed into it.

@nielstron
Copy link
Contributor

Speaking in REST terms, in a sense you can imagine contract + purpose + optional datum as a path and the redeemer as method

@nielstron
Copy link
Contributor

nielstron commented Feb 22, 2023

Maybe it makes more sense to consider the contract as a path, the purpose as the method and the Redeemer as auxiliary data that is always passed by the user. The Redeemer modifies how the path behaves but should (!) not cause drastic changes.

The datum is a query parameter, it modifies how a path reacts to the spend method but should (!) also not cause any drastic changes in behaviour.

This does the same as the REST specification: It takes a very powerful protocol and specifies how specific invocations should behave. Of course the webapp or dApp may behave completely different ways. But these are the desired ways that bring some order into the chaos.

@KtorZ
Copy link
Member Author

KtorZ commented Feb 22, 2023

@nielstron Speaking in REST terms, in a sense you can imagine contract + purpose + optional datum as a path and the redeemer as method

I don't think I fully agree here. I put the purpose on the same side as the redeemer. Because it constrains what the validator will do. And unlike the datum & compiled code, the purpose is only truly specified at the moment the validator is executed.


The question w.r.t the blueprints is what to do to make them sufficiently expressive and flexible for all frameworks. One option I see is to attach a purpose field not to the validator object, but to the redeemer and datum objects and allow oneOf to be used to combine multiple redeemers.

So one could write things like:

{
  "validators": [
    {
      "datum": {
        "purpose": "spend",
        "schema": "..."
      },
      "redeemer": {
        "purpose": {
          "oneOf": [ "spend", "mint" ]
        },
        "schema": "..."
      },
      "compiledCode": "...",
      "hash": "..."
    }
  ]
}

or

{
  "validators": [
    {
      "datum": {
        "purpose": "spend",
        "schema": "..."
      },
      "redeemer": {
      	"oneOf": [
	  {
            "purpose": "spend",
            "schema": "..."
	  },
	  { 
	    "purpose": "mint",
	    "schema": "..."
	  }  
	]
      },
      "compiledCode": "...",
      "hash": "..."
    }
  ]
}

@KtorZ KtorZ force-pushed the KtorZ/CIP-0054/plutus-contract-blueprint branch from 1d95fd4 to 3de793a Compare March 2, 2023 16:16
@KtorZ
Copy link
Member Author

KtorZ commented Mar 2, 2023

purpose added as an optional discriminant for validators arguments. As a consequence, datums, redeemers and parameters schemas are now nested under a schema field.

@KtorZ KtorZ added Category: Tools Proposals belonging to the 'Tools' category. and removed Candidate CIP labels Mar 18, 2023
Copy link
Collaborator

@Ryun1 Ryun1 left a comment

Choose a reason for hiding this comment

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

Well written proposal with a good amount of discussion.

Since this is not my area of expertise I don't have any comments to add, so I will approve.

@michele-nuzzi
Copy link

michele-nuzzi commented Apr 21, 2023

@KtorZ I'm starting to implement a very raw version of the CIP in plu-ts.

Question: should we add support for function types and delayed types?

I know these can't be expressed as Data but they could be used as script parameters.

EDIT
(even if that would imply the necessity to deserialize the script in order to apply any function / delayed argument because not being data-serializable that implies it might change the end of the script which includes padding that shouldn't be there)

@KtorZ
Copy link
Member Author

KtorZ commented Apr 21, 2023

@michele-nuzzi I've also pondered about those indeed... Technically speaking, you're right, we can apply any Plutus term to a parameterized validator (including error). Though I did chose to omit them from the blueprint representation and only have constants and data in there.

The reason being that I couldn't really find a use-case (in terms of interoperability) that would justify having them. Do you have any 🤔 ?

@KtorZ
Copy link
Member Author

KtorZ commented Apr 21, 2023

@michele-nuzzi also small note: we noticed some minor discrepancy in the JSON schemas currently specified in annex. I'll try to update them A.S.A.P. but do not hesitate to cross-check things with some Aiken examples and the Aiken implementation at the moment.

@michele-nuzzi
Copy link

For the reasons specified in the edit above, I usually prefer to compile dynamically scripts that might require these parameters, so I never end up having to deserialize just to apply the parameter. So no, I don't have an example, but I believe other languages do not have the option of compiling dynamically.

@KtorZ KtorZ force-pushed the KtorZ/CIP-0054/plutus-contract-blueprint branch from 3de793a to 6116113 Compare May 6, 2023 14:29
  Including meta-schemas and type definitions for existing "builtins"
  Plutus types.
@KtorZ KtorZ force-pushed the KtorZ/CIP-0054/plutus-contract-blueprint branch from 6116113 to b97beca Compare May 6, 2023 14:30
@KtorZ KtorZ merged commit dec8b2e into master May 6, 2023
@KtorZ KtorZ deleted the KtorZ/CIP-0054/plutus-contract-blueprint branch May 6, 2023 14:31
Ryun1 pushed a commit to Ryun1/CIPs that referenced this pull request Jul 28, 2023
…oundation#258)

Including meta-schemas and type definitions for existing "builtins"
  Plutus types.
Ryun1 pushed a commit to Ryun1/CIPs that referenced this pull request Nov 17, 2023
…oundation#258)

Including meta-schemas and type definitions for existing "builtins"
  Plutus types.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Category: Tools Proposals belonging to the 'Tools' category.
Projects
None yet
Development

Successfully merging this pull request may close these issues.