-
Notifications
You must be signed in to change notification settings - Fork 483
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
CIP-0057 Plutus Blueprints support: generate blueprint for a contract. (
#5772) * chore: refine imports, exports, formatting. * refactor: makeIsDataIndexed * Plutus Blueprint data model * JSON Schema attributes * Extra blueprint schema attributes * Rework blueprint generation logic: use safe references * chore: rename test fixture types, add a comment * Fix GHC 8.10 build by adding UndecidableInstances * fixup! Rework blueprint generation logic: use safe references * better haddock comments * fix: blueprint schema for constructors * fix: blueprint schema encoding for #pair * rework CIP-57 Blueprints to address some concerns * allow aeson >= 2.2 * refactor blueprint schemas: use records with labels * refactor: extract Data.Aeson.Extra (optionalField, requiredField) * fix: compilation warnings with GHC 8.10 * Contract blueprint contains a set of validators * refactor: improve wording, add comments * Haddocks * Parametherise Blueprint.Schema by the types that it can refer to. * refactor: remove unnecessary ghc option pragmas * serialise test script with a proper CBOR header * Simplify compiled code hash calculation * s/unique/uniqueItems/ * "fields" is a required field * chore: user OverloadedStrings * refactor: extract and use a helper function `oneOfASet` * refactor: s/HasDataSchema/HasSchema/ * Improve TH that generates HasSchema instance. * Derive JSON instance using `stripPrefix` field label modifier. * Validate contract blueprint with CIP-57 meta schema using AJV * add a comment explaining why NodeJS is gitignored. * refactor: make JSON object construction cleaner. * Detailed haddock for the AsDefinitionsEntries
- Loading branch information
Showing
40 changed files
with
2,234 additions
and
69 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"dependencies": { | ||
"ajv": "^8.12.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
{ | ||
"$schema": "https://cips.cardano.org/cips/cip57/schemas/plutus-blueprint.json", | ||
"$vocabulary": { | ||
"https://cips.cardano.org/cips/cip57": true, | ||
"https://json-schema.org/draft/2020-12/vocab/applicator": true, | ||
"https://json-schema.org/draft/2020-12/vocab/core": true, | ||
"https://json-schema.org/draft/2020-12/vocab/validation": true | ||
}, | ||
"preamble": { | ||
"title": "Acme Contract", | ||
"description": "A contract that does something awesome", | ||
"version": "1.1.0", | ||
"plutusVersion": "v3", | ||
"license": "MIT" | ||
}, | ||
"validators": [ | ||
{ | ||
"title": "Acme Validator", | ||
"description": "A validator that does something awesome", | ||
"redeemer": { | ||
"title": "Acme Redeemer", | ||
"description": "A redeemer that does something awesome", | ||
"purpose": { | ||
"oneOf": [ | ||
"spend", | ||
"mint" | ||
] | ||
}, | ||
"schema": { | ||
"$ref": "#/definitions/String" | ||
} | ||
}, | ||
"datum": { | ||
"title": "Acme Datum", | ||
"description": "A datum that contains something awesome", | ||
"purpose": "spend", | ||
"schema": { | ||
"$ref": "#/definitions/Datum" | ||
} | ||
}, | ||
"parameters": [ | ||
{ | ||
"title": "Acme Parameter", | ||
"description": "A parameter that does something awesome", | ||
"purpose": "spend", | ||
"schema": { | ||
"$ref": "#/definitions/Params" | ||
} | ||
} | ||
], | ||
"compiledCode": "58ec01010032222323232300349103505435003232325333573466e1d200000218000a999ab9a3370e90010010c00cc8c8c94ccd5cd19b874800000860026eb4d5d0800cdd71aba13574400213008491035054310035573c0046aae74004dd51aba100109802a481035054310035573c0046aae74004dd50029919192999ab9a3370e90000010c0004c0112401035054310035573c0046aae74004dd5001119319ab9c001800199999a8911199a891199a89100111111400401600900380140044252005001001400084a400a0020038004008848a400e0050012410101010101010101000498101030048810001", | ||
"hash": "21a5bbebc42a3d916719c975f622508a2c940ced5cd867cd3d87a019" | ||
} | ||
], | ||
"definitions": { | ||
"Bool": { | ||
"dataType": "#boolean" | ||
}, | ||
"ByteString": { | ||
"dataType": "bytes" | ||
}, | ||
"Bytes_Void": { | ||
"title": "SchemaBytes", | ||
"dataType": "bytes" | ||
}, | ||
"Data": {}, | ||
"Datum": { | ||
"oneOf": [ | ||
{ | ||
"$comment": "DatumLeft", | ||
"dataType": "constructor", | ||
"fields": [], | ||
"index": 0 | ||
}, | ||
{ | ||
"$comment": "DatumRight", | ||
"dataType": "constructor", | ||
"fields": [ | ||
{ | ||
"$ref": "#/definitions/DatumPayload" | ||
} | ||
], | ||
"index": 1 | ||
} | ||
] | ||
}, | ||
"DatumPayload": { | ||
"$comment": "MkDatumPayload", | ||
"dataType": "constructor", | ||
"fields": [ | ||
{ | ||
"$ref": "#/definitions/Integer" | ||
}, | ||
{ | ||
"$ref": "#/definitions/Bytes_Void" | ||
} | ||
], | ||
"index": 0 | ||
}, | ||
"Integer": { | ||
"dataType": "integer" | ||
}, | ||
"Params": { | ||
"$comment": "MkParams", | ||
"dataType": "constructor", | ||
"fields": [ | ||
{ | ||
"$ref": "#/definitions/Unit" | ||
}, | ||
{ | ||
"$ref": "#/definitions/Bool" | ||
}, | ||
{ | ||
"$ref": "#/definitions/Integer" | ||
}, | ||
{ | ||
"$ref": "#/definitions/Data" | ||
}, | ||
{ | ||
"$ref": "#/definitions/ByteString" | ||
} | ||
], | ||
"index": 0 | ||
}, | ||
"String": { | ||
"dataType": "#string" | ||
}, | ||
"Unit": { | ||
"dataType": "#unit" | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
{-# LANGUAGE AllowAmbiguousTypes #-} | ||
{-# LANGUAGE DataKinds #-} | ||
{-# LANGUAGE DerivingStrategies #-} | ||
{-# LANGUAGE FlexibleInstances #-} | ||
{-# LANGUAGE MultiParamTypeClasses #-} | ||
{-# LANGUAGE OverloadedStrings #-} | ||
{-# LANGUAGE PolyKinds #-} | ||
{-# LANGUAGE TypeApplications #-} | ||
{-# LANGUAGE TypeFamilies #-} | ||
|
||
module Blueprint.Tests where | ||
|
||
import PlutusTx.Blueprint | ||
import Prelude | ||
|
||
import Blueprint.Tests.Lib qualified as Fixture | ||
import Control.Monad.Reader (asks) | ||
import Data.Set qualified as Set | ||
import Data.Void (Void) | ||
import PlutusTx.Blueprint.Purpose qualified as Purpose | ||
import PlutusTx.Builtins (BuiltinByteString, BuiltinData) | ||
import System.FilePath ((</>)) | ||
import Test.Tasty (TestName) | ||
import Test.Tasty.Extras (TestNested, testNested) | ||
import Test.Tasty.Golden (goldenVsFile) | ||
|
||
goldenTests :: TestNested | ||
goldenTests = testNested "Blueprint" [goldenBlueprint "Acme" contractBlueprint] | ||
|
||
goldenBlueprint :: TestName -> ContractBlueprint types -> TestNested | ||
goldenBlueprint name blueprint = do | ||
goldenPath <- asks $ foldr (</>) name | ||
let actual = goldenPath ++ ".actual.json" | ||
let golden = goldenPath ++ ".golden.json" | ||
pure $ goldenVsFile name golden actual (writeBlueprint actual blueprint) | ||
|
||
{- | All the data types exposed (directly or indirectly) by the type signature of the validator | ||
This type level list is used to: | ||
1. derive the schema definitions for the contract. | ||
2. make "safe" references to the [derived] schema definitions. | ||
-} | ||
type ValidatorTypes = | ||
[ Fixture.Datum | ||
, Fixture.DatumPayload | ||
, Fixture.Params | ||
, Fixture.Redeemer | ||
, Fixture.Bytes Void | ||
, () | ||
, Bool | ||
, Integer | ||
, BuiltinData | ||
, BuiltinByteString | ||
] | ||
|
||
contractBlueprint :: ContractBlueprint ValidatorTypes | ||
contractBlueprint = | ||
MkContractBlueprint | ||
{ contractId = Nothing | ||
, contractPreamble = | ||
MkPreamble | ||
{ preambleTitle = "Acme Contract" | ||
, preambleDescription = Just "A contract that does something awesome" | ||
, preambleVersion = "1.1.0" | ||
, preamblePlutusVersion = PlutusV3 | ||
, preambleLicense = Just "MIT" | ||
} | ||
, contractValidators = Set.singleton validatorBlueprint | ||
, contractDefinitions = deriveSchemaDefinitions | ||
} | ||
|
||
validatorBlueprint :: ValidatorBlueprint ValidatorTypes | ||
validatorBlueprint = | ||
MkValidatorBlueprint | ||
{ validatorTitle = "Acme Validator" | ||
, validatorDescription = Just "A validator that does something awesome" | ||
, validatorParameters = | ||
Just | ||
$ pure | ||
MkParameterBlueprint | ||
{ parameterTitle = Just "Acme Parameter" | ||
, parameterDescription = Just "A parameter that does something awesome" | ||
, parameterPurpose = Set.singleton Purpose.Spend | ||
, parameterSchema = definitionRef @Fixture.Params | ||
} | ||
, validatorRedeemer = | ||
MkArgumentBlueprint | ||
{ argumentTitle = Just "Acme Redeemer" | ||
, argumentDescription = Just "A redeemer that does something awesome" | ||
, argumentPurpose = Set.fromList [Purpose.Spend, Purpose.Mint] | ||
, argumentSchema = definitionRef @Fixture.Redeemer | ||
} | ||
, validatorDatum = | ||
Just | ||
MkArgumentBlueprint | ||
{ argumentTitle = Just "Acme Datum" | ||
, argumentDescription = Just "A datum that contains something awesome" | ||
, argumentPurpose = Set.singleton Purpose.Spend | ||
, argumentSchema = definitionRef @Fixture.Datum | ||
} | ||
, validatorCompiledCode = Just Fixture.serialisedScript | ||
} |
Oops, something went wrong.