From 65e163da84e43d18bb0361ed1a334bfa10fc5fa8 Mon Sep 17 00:00:00 2001 From: Ryan <44342099+Ryun1@users.noreply.github.com> Date: Fri, 19 Apr 2024 22:58:47 +0100 Subject: [PATCH] CIP-0108? | Governance Metadata - Governance Actions (#632) * init governance action metadata * details * add details from first workshop and general clean up * added missing participant from workshop 1 * Update CIP-governance-metadata-actions/README.md Co-authored-by: Robert Phair * align folder name with 108 numbering * add notes from workshop 2 * turn notes to text * added markdown text formatting * add schema and example * add CIP-05 message signing * add note * add examples * Update CIP-0108/README.md * Update CIP-0108/README.md * general tidy throughout * feat: Refactor test vector and examples * improve wording in test vectors * Update CIP-0108/README.md --------- Co-authored-by: Robert Phair --- CIP-0108/README.md | 232 ++++++++++++++++++ CIP-0108/cip-0108.common.jsonld | 49 ++++ CIP-0108/cip-0108.common.schema.json | 122 +++++++++ .../examples/no-confidence.body.canonical | 12 + CIP-0108/examples/no-confidence.body.jsonld | 67 +++++ CIP-0108/examples/no-confidence.canonical | 18 ++ CIP-0108/examples/no-confidence.jsonld | 76 ++++++ .../treasury-withdrawal.body.canonical | 9 + .../examples/treasury-withdrawal.body.jsonld | 62 +++++ .../examples/treasury-withdrawal.canonical | 16 ++ CIP-0108/examples/treasury-withdrawal.jsonld | 73 ++++++ CIP-0108/test-vector.md | 133 ++++++++++ 12 files changed, 869 insertions(+) create mode 100644 CIP-0108/README.md create mode 100644 CIP-0108/cip-0108.common.jsonld create mode 100644 CIP-0108/cip-0108.common.schema.json create mode 100644 CIP-0108/examples/no-confidence.body.canonical create mode 100644 CIP-0108/examples/no-confidence.body.jsonld create mode 100644 CIP-0108/examples/no-confidence.canonical create mode 100644 CIP-0108/examples/no-confidence.jsonld create mode 100644 CIP-0108/examples/treasury-withdrawal.body.canonical create mode 100644 CIP-0108/examples/treasury-withdrawal.body.jsonld create mode 100644 CIP-0108/examples/treasury-withdrawal.canonical create mode 100644 CIP-0108/examples/treasury-withdrawal.jsonld create mode 100644 CIP-0108/test-vector.md diff --git a/CIP-0108/README.md b/CIP-0108/README.md new file mode 100644 index 000000000..6f09d44f6 --- /dev/null +++ b/CIP-0108/README.md @@ -0,0 +1,232 @@ +--- +CIP: 108 +Title: Governance Metadata - Governance Actions +Category: Metadata +Status: Proposed +Authors: + - Ryan Williams +Implementors: [ ] +Discussions: + - https://github.com/cardano-foundation/CIPs/pull/632 + - https://github.com/cardano-foundation/CIPs/pull/748 + - https://github.com/cardano-foundation/CIPs/issues/757 +Created: 2023-11-23 +License: CC-BY-4.0 +--- + +## Abstract +The Conway ledger era ushers in on-chain governance for Cardano via [CIP-1694 | A First Step Towards On-Chain Decentralized Governance](https://github.com/cardano-foundation/CIPs/blob/master/CIP-1694/README.md), with the addition of many new on-chain governance artifacts. +Some of these artifacts support the linking off-chain metadata, as a way to provide context. + +The [CIP-100 | Governance Metadata](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0100) standard provides a base framework for how all off-chain governance metadata should be formed and handled. +But this is intentionally limited in scope, so that it can be expanded upon by more specific subsequent CIPs. + +This proposal aims to provide a specification for off-chain metadata vocabulary that can be used to give context to governance actions. +Without a sufficiently detailed standard for governance actions we introduce the possibility to undermine voters ability to adequately assess governance actions. +Furthermore a lack of such standards risks preventing interoperability between tools, to the detriment of user experiences. + +For the many contributors to this proposal, see [Acknowledgements](#acknowledgements). + +## Motivation: why is this CIP necessary? +Blockchains are poor choices to act as content databases. +This is why governance metadata anchors were chosen to provide a way to attach long form metadata content to on-chain events. +By only supplying an onchain hash of the off-chain we ensure correctness of data whilst minimizing the amount of data posted to the chain. + +### For voters +When observing from the chain level, tooling can only see the content of the governance action and it's anchor. +These on-chain components do not give give any context to the motivation nor off-chain discussion of an governance action. +Although this information would likely be desired context for voters. +By providing rich contextual metadata we enable voters to make well informed decisions. + +### For all participants +By standardizing off-chain metadata formats we facilitate interoperability for tooling which creates and/or renders metadata attached to governance actions. +This intern promotes a rich user experience between tooling. +This is good for all governance participants. + +## Specification +Although there are seven types of governance action defined via CIP-1694, we focus this proposal on defining core properties which must be attached to all types. +We leave room for future standards to refine and specialize further to cater more specific for each type of governance action. + +### New `witness` Type +Here we extend the potential witnesses, with a `witnessAlgorithm` that can be set to include support for [CIP-08 | Message Signing](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0008) standard, indicated by `CIP-0008`. +Here we mimic the restrictions as imposed over the CIP-30's implementation in [.signData()](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#apisigndataaddr-address-payload-bytes-promisedatasignature). + +### Markdown Text Styling +This standard introduces the possibility of using [Github markdown text styling](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#styling-text) within fields. + +### Extended Vocabulary +The following properties extend the potential vocabulary of [CIP-100](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0100)'s `body` property. + +#### `title` +- A very short freefrom text field. Limited to `80` characters. +- This SHOULD NOT support markdown text styling. +- Authors SHOULD use this field to succinctly describe the governance action and its motivation. +- Authors SHOULD attempt to make this field unique whilst also avoiding hyperbolic language. +- i.e; Increase K protocol parameter to `100,000` to increase decentralization of Cardano. + +#### `abstract` +- A short freefrom text field. Limited to `2500` characters. +- This SHOULD support markdown text styling. +- Authors SHOULD use this field to expand upon their `title` by describing the contents of the governance action, its motivation and rationale. + +#### `motivation` +- A freeform text field. +- This SHOULD support markdown text styling. +- This SHOULD be used by the author to encapsulate all context around the problem that is being solved by the on-chain action. +- This SHOULD be used to outline the related stakeholders and use cases. + +#### `rationale` +- A freeform text field. +- This SHOULD support markdown text styling. +- This SHOULD be used by the author to discuss how the content of the governance action addresses the problem outlined within the `motivation`. +- This field SHOULD justify the changes being made to Cardano. +- i.e "by decreasing X parameter by Y we increase Ada earned by SPOs, thus incentivising more people to become SPOs, leading to a more diverse network" +- This SHOULD provide evidence of consensus within the community and discuss significant objections or concerns raised during the discussion. +- This SHOULD include discussion of alternative solutions and related topics/ governance actions. +- This SHOULD include any recommendations made by relevant organizations or committees. + +#### `references` +- We extend CIP-100's references field. +- This SHOULD NOT support markdown text styling. +- To be an OPTIONAL set of objects, using the `@set` property. +- Each object MUST have a `label` field to describe the reference, such as; "blog - Why we must continue to fund Catalyst". +- Each object MUST have a `uri` field. +- Each object MAY have a OPTIONAL `referenceHash` object. + - Each object MUST have a `hashDigest` field. + - Each object MUST have a `hashAlgorithm` field, which is inherited from CIP-100. +- This should be used by the author to link related or supporting work via the URI, and reference this via the index within their freefrom text fields. + +### Application +Governance action metadata must include all compulsory fields to be considered CIP-0108 compliant. +As this is an extension to CIP-100, all CIP-100 fields can be included within CIP-108 compliant metadata. + +### Test Vector +See [test-vector.md](./test-vector.md) for examples. + +### Versioning +This proposal should not be versioned, to update this standard a new CIP should be proposed. +Although through the JSON-LD mechanism further CIPs can add to the common governance metadata vocabulary, + +## Rationale: how does this CIP achieve its goals? +We intentionally have kept this proposal brief and uncomplicated. +This was to reduce the time to develop and deploy this standard. +We think it is better to have a base standard which can be improved, rather than meticulously craft a perfect single standard. +This way we enable tooling which depends on this standard to start development. +Furthermore, it is very difficult to predict future wants/needs now, so by allowing upgrades we build in the ability to improve the standard as new wants/needs arrive. + +The fields which have been chosen for this standard heavily inspired to those used for CIPs. +We did this for two reasons; familiarity and competency. +Those who are involved in Cardano are familiar with the CIP format, meaning they will be intuitively understand these fields being reused here. +These fields in combination have also been fairly battle tested via the CIPs process and thus act as a good standard to describe problems and their solutions. + +### New `witness` type +We introduce a new witness type to be able to reuse existing dApp-Wallet infrastructure. +The type as described allows for reuse of the CIP-30 signData standard, which means that governance dApps are able to implement this without needing any alterations to existing wallets. + +### Markdown Text Styling +We choose to introduce rich text standard here because we see significant value in supporting it. +Rich text styling improves the ability for the author to express themselves. +Furthermore, most potential voters are use to such standards when reviewing metadata. + +### Character Limits +With this design, we wanted to allow for quick and easy differentiation between governance actions. +We achieve this by facilitating users "layers of investigation", where some fields are limited in size. +This encourages tooling providers to show users the small fields before allowing deep investigation of the larger fields. +By allowing this we aim to improve the experience of prospective voters, when sorting though many governance actions. + +The downside of highlighting some fields over others is that we incentivize hyperbolic and eye catching phrases. +Where authors want their governance action to standout in tooling so use overly dramatic phrasing. +This creates an environment where there is a race to the bottom on voter's attention. +Overall this could decrease the perceived legitimacy of the system. +The counter argument is that tooling providers should not use metadata to solely highlight proposals, rather other means such as cryptographically verified submitters. + +### `title` +This should be used by voters to quickly and easily differentiate between two governance actions which may be having the same or similar on-chain effects. +This is why we have chosen a short character limit, as longer titles would reduce the ability for quick reading. + +### `abstract` +This gives voters one step more detail beyond the `title`. +This allows for a compact description of the what, why and how without the voter having to read the larger fields. + +### `motivation` +The `motivation` is a chance for the author to fully describe the problem that is being solved by the governance action. +This is important as all governance actions are a solution to a problem and thus this is a universal field. +By showing relation to stakeholders the author is able to show that they have performed adequate research on the problem. +Voters can use this field to determine if the problem is sizable enough to warrant voting on. + +### `rationale` +This field gives the author the opportunity to explain how the onchain action is addressing the problem outlined in the motivation. +This gives the author a place to discuss any alternative designs or completing governance actions. +Voters should be able to use this field to evaluate the applicability of the solution to the problem. + +### `references` +References give the author ability to point to supporting research or related work. +These should be used by voters to verify the content of supporting research. +The inclusion of a hash allows for the supporting documentation to be cryptographically verified. + +### Open Questions +- Should fields be optional or compulsory? + - Title, abstract, motivation and rationale should be compulsory as they should be very important to the ability +- How much vocabulary can be extended to other onchain governance events? + - It is hard to predict how the scope of future standards before they have been developed. +- How to integrate custom set of HTML tags? to allow formatting of longer text fields. + - Since CIP-100 does not intend to support rich text fields such an inclusion would not fit, so we have included such format here. + +## Path to Active + +### Acceptance Criteria +- [ ] This standard is supported by two different tooling providers used to submit governance actions to chain. +- [ ] This standard is supported by two different chain indexing tools, used to read and render metadata. + - DB-Sync via [db-sync-sancho-4.1.0](https://github.com/IntersectMBO/cardano-db-sync/releases/tag/sancho-4.1.0) + +### Implementation Plan +Solicitation of feedback +- [x] Run two online workshops to gather insights from stakeholders. +- [x] Seek community answers on all [Open Questions](#open-questions). +Implementation +- [x] Author to provide example metadata and schema files. + +## Acknowledgments + +
+ Governance Metadata Working Group - Workshop #1 2023-12-04 + + I would like to thank those that contributed to the Governance Metadata Working Group Workshop #1 hosted by Ryan Williams ([see presentation slides with notes](https://docs.google.com/presentation/d/18OK3vXexCc8ZXq-dC00RDPPKcy2Zu4DiMo8PeIZ47_4/)). + + Thank you to the co-hosts: + - Adam Dean + - Thomas Upfield + + Thank you to the participants: + - Carlos Lopez de Lara + - Igor Veličković + - Johnny Kelly + - Kenric Nelson + - Kevin Hammond + - Lorenzo Bruno + - Mike Susko + - Rhys Morgan + - Eric Alton + - Samuel Leathers + - Vladimir Kalnitsky + +
+ +
+ Governance Metadata Working Group - Workshop #2 2023-12-14 + + I would like to thank those that contributed to the Governance Metadata Working Group Workshop #2 hosted by Ryan Williams ([see presentation slides with notes](https://docs.google.com/presentation/d/1tFsyQnONjwyTm7zKrnxxedzWsoonO6-8vXw5vYzB3qs)). + + Thank you to the co-host: + - Adam Dean + + Thank you to the participants: + - Mark Byers + - Nils Codes + + Thank you to the bots that joined also. + +
+ +## Copyright +This CIP is licensed under [CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/legalcode). \ No newline at end of file diff --git a/CIP-0108/cip-0108.common.jsonld b/CIP-0108/cip-0108.common.jsonld new file mode 100644 index 000000000..f0b2dcc1b --- /dev/null +++ b/CIP-0108/cip-0108.common.jsonld @@ -0,0 +1,49 @@ +{ + "@context": { + "CIP100": "https://github.com/cardano-foundation/CIPs/blob/master/CIP-0100/README.md#", + "CIP108": "https://github.com/cardano-foundation/CIPs/blob/master/CIP-0108/README.md#", + "hashAlgorithm": "CIP100:hashAlgorithm", + "body": { + "@id": "CIP108:body", + "@context": { + "references": { + "@id": "CIP108:references", + "@container": "@set", + "@context": { + "GovernanceMetadata": "CIP100:GovernanceMetadataReference", + "Other": "CIP100:OtherReference", + "label": "CIP100:reference-label", + "uri": "CIP100:reference-uri", + "referenceHash": { + "@id": "CIP108:referenceHash", + "@context": { + "hashDigest": "CIP108:hashDigest", + "hashAlgorithm": "CIP100:hashAlgorithm" + } + } + } + }, + "title": "CIP108:title", + "abstract": "CIP108:abstract", + "motivation": "CIP108:motivation", + "rationale": "CIP108:rationale" + } + }, + "authors": { + "@id": "CIP100:authors", + "@container": "@set", + "@context": { + "did": "@id", + "name": "http://xmlns.com/foaf/0.1/name", + "witness": { + "@id": "CIP100:witness", + "@context": { + "witnessAlgorithm": "CIP100:witnessAlgorithm", + "publicKey": "CIP100:publicKey", + "signature": "CIP100:signature" + } + } + } + } + } +} \ No newline at end of file diff --git a/CIP-0108/cip-0108.common.schema.json b/CIP-0108/cip-0108.common.schema.json new file mode 100644 index 000000000..1f6c7b7dd --- /dev/null +++ b/CIP-0108/cip-0108.common.schema.json @@ -0,0 +1,122 @@ +{ + "title": "CIP-108 Common", + "description": "Metadata document for Cardano governance actions, extending CIP-100", + "type": "object", + "required": ["hashAlgorithm", "authors", "body"], + "properties": { + "hashAlgorithm": { + "$ref": "#/definitions/hashAlgorithm" + }, + "authors": { + "$ref": "#/definitions/authors" + }, + "body": { + "$ref": "#/definitions/body" + } + }, + "definitions": { + "hashAlgorithm": { + "type": "string", + "enum": ["blake2b-256"], + "title": "Hash Algorithm", + "description": "The algorithm used to authenticate this document externally (CIP-100)" + }, + "authors": { + "title": "Authors", + "description": "The authors of this governance metadata (CIP-100)", + "type": "array", + "items": { + "$ref": "#/definitions/author" + } + }, + "author": { + "title": "Author", + "description": "An author endorsing the content of a metadata document (CIP-100)", + "type": "object", + "required": ["name", "witness"], + "properties": { + "name": { + "type": "string", + "title": "Name" + }, + "witness": { + "$ref": "#/definitions/witness" + } + } + }, + "body": { + "title": "Body", + "description": "The body of the metadata document that is hashed to produce a signature (CIP-100)", + "type": "object", + "required": ["title", "abstract", "motivation", "rationale"], + "properties": { + "title": { + "type": "string", + "title": "Title", + "description": "A brief introduction to the motivation for the governance action" + }, + "abstract": { + "type": "string", + "title": "Abstract", + "description": "A concise summary of the motivation and rationale for the governance action" + }, + "motivation": { + "type": "string", + "title": "Motivation", + "description": "Context around the problem being addressed by the on-chain action" + }, + "rationale": { + "type": "string", + "title": "Rationale", + "description": "Explanation of how the governance action addresses the problem outlined in 'motivation'" + }, + "references": { + "type": "array", + "title": "References", + "items": { + "$ref": "#/definitions/reference" + } + } + } + }, + "reference": { + "title": "Reference", + "description": "A reference to a document", + "type": "object", + "required": ["type", "label", "uri"], + "properties": { + "type": { + "type": "string", + "enum": ["GovernanceMetadata", "Other"], + "title": "Type" + }, + "label": { + "type": "string", + "title": "Label" + }, + "uri": { + "type": "string", + "title": "URI" + }, + "referenceHash": { + "$ref": "#/definitions/referenceHash" + } + } + }, + "referenceHash": { + "title": "Reference Hash", + "description": "A hash of a reference document", + "type": "object", + "required": ["hashDigest", "hashAlgorithm"], + "properties": { + "hashDigest": { + "type": "string", + "title": "Hash" + }, + "hashAlgorithm": { + "$ref": "#/definitions/hashAlgorithm" + } + } + } + } +} \ No newline at end of file diff --git a/CIP-0108/examples/no-confidence.body.canonical b/CIP-0108/examples/no-confidence.body.canonical new file mode 100644 index 000000000..d30d16631 --- /dev/null +++ b/CIP-0108/examples/no-confidence.body.canonical @@ -0,0 +1,12 @@ +_:c14n0 "blake2b-256"@en-us . +_:c14n0 "70e79c1f12ff3c8c955bc2178a542b5994a21be163dd7655af2c5308d2643323"@en-us . +_:c14n1 "The current constitutional committee have not voted for the last 100 epochs, causing an inability to pass any proposals. This is a waste of resources and must be removed."@en-us . +_:c14n1 "In order for governance to work an __active__ constitutional committee is required, without them the system grinds to a halt and important governance actions cannot be passed."@en-us . +_:c14n1 "By moving into a state of no confidence, **we** the DReps are able to vote in a new constitutional committee."@en-us . +_:c14n1 _:c14n3 . +_:c14n1 "We must remove the ineffective Constitutional Committee"@en-us . +_:c14n2 _:c14n1 . +_:c14n3 . +_:c14n3 "A governance action that has been unable to pass"@en-us . +_:c14n3 "https://raw.githubusercontent.com/cardano-foundation/CIPs/blob/master/CIP-0108/examples/treasury-withdrawal.jsonld"@en-us . +_:c14n3 _:c14n0 . diff --git a/CIP-0108/examples/no-confidence.body.jsonld b/CIP-0108/examples/no-confidence.body.jsonld new file mode 100644 index 000000000..755555029 --- /dev/null +++ b/CIP-0108/examples/no-confidence.body.jsonld @@ -0,0 +1,67 @@ +{ + "@context": { + "@language": "en-us", + "CIP100": "https://github.com/cardano-foundation/CIPs/blob/master/CIP-0100/README.md#", + "CIP108": "https://github.com/cardano-foundation/CIPs/blob/master/CIP-0108/README.md#", + "hashAlgorithm": "CIP100:hashAlgorithm", + "body": { + "@id": "CIP108:body", + "@context": { + "references": { + "@id": "CIP108:references", + "@container": "@set", + "@context": { + "GovernanceMetadata": "CIP100:GovernanceMetadataReference", + "Other": "CIP100:OtherReference", + "label": "CIP100:reference-label", + "uri": "CIP100:reference-uri", + "referenceHash": { + "@id": "CIP108:referenceHash", + "@context": { + "hashDigest": "CIP108:hashDigest", + "hashAlgorithm": "CIP100:hashAlgorithm" + } + } + } + }, + "title": "CIP108:title", + "abstract": "CIP108:abstract", + "motivation": "CIP108:motivation", + "rationale": "CIP108:rationale" + } + }, + "authors": { + "@id": "CIP100:authors", + "@container": "@set", + "@context": { + "name": "http://xmlns.com/foaf/0.1/name", + "witness": { + "@id": "CIP100:witness", + "@context": { + "witnessAlgorithm": "CIP100:witnessAlgorithm", + "publicKey": "CIP100:publicKey", + "signature": "CIP100:signature" + } + } + } + } + }, + "body": { + "title": "We must remove the ineffective Constitutional Committee", + "abstract": "The current constitutional committee have not voted for the last 100 epochs, causing an inability to pass any proposals. This is a waste of resources and must be removed.", + "motivation": "In order for governance to work an __active__ constitutional committee is required, without them the system grinds to a halt and important governance actions cannot be passed.", + "rationale": "By moving into a state of no confidence, **we** the DReps are able to vote in a new constitutional committee.", + "references": [ + { + "@type": "Other", + "label": "A governance action that has been unable to pass", + "uri": "https://raw.githubusercontent.com/cardano-foundation/CIPs/blob/master/CIP-0108/examples/treasury-withdrawal.jsonld", + "referenceHash": { + "hashDigest": "70e79c1f12ff3c8c955bc2178a542b5994a21be163dd7655af2c5308d2643323", + "hashAlgorithm": "blake2b-256" + } + } + ] + } +} + \ No newline at end of file diff --git a/CIP-0108/examples/no-confidence.canonical b/CIP-0108/examples/no-confidence.canonical new file mode 100644 index 000000000..cfc8fe202 --- /dev/null +++ b/CIP-0108/examples/no-confidence.canonical @@ -0,0 +1,18 @@ +_:c14n0 "blake2b-256"@en-us . +_:c14n0 "70e79c1f12ff3c8c955bc2178a542b5994a21be163dd7655af2c5308d2643323"@en-us . +_:c14n1 "The current constitutional committee have not voted for the last 100 epochs, causing an inability to pass any proposals. This is a waste of resources and must be removed."@en-us . +_:c14n1 "In order for governance to work an __active__ constitutional committee is required, without them the system grinds to a halt and important governance actions cannot be passed."@en-us . +_:c14n1 "By moving into a state of no confidence, **we** the DReps are able to vote in a new constitutional committee."@en-us . +_:c14n1 _:c14n5 . +_:c14n1 "We must remove the ineffective Constitutional Committee"@en-us . +_:c14n2 _:c14n3 . +_:c14n2 "blake2b-256"@en-us . +_:c14n2 _:c14n1 . +_:c14n3 _:c14n4 . +_:c14n4 "7ea09a34aebb13c9841c71397b1cabfec5ddf950405293dee496cac2f437480a"@en-us . +_:c14n4 "84582aa201276761646472657373581d610fdc780023d8be7c9ff3a6bdc0d8d3b263bd0cc12448c40948efbf42a166686173686564f458204a7ecc544559df67ece3f7f90f76c4e3e7e329a274c79a06dcfbf28351db600e5840a5dc881ddabdec69e0e4dabdd43a922ef474f7be1029facdbb9106429e17ec61deda22f2778eda21005127f0c6d10f8a4b0210b8177d03d2ae4618d2423d0807"@en-us . +_:c14n4 "cip-0008"@en-us . +_:c14n5 . +_:c14n5 "A governance action that has been unable to pass"@en-us . +_:c14n5 "https://raw.githubusercontent.com/cardano-foundation/CIPs/blob/master/CIP-0108/examples/treasury-withdrawal.jsonld"@en-us . +_:c14n5 _:c14n0 . diff --git a/CIP-0108/examples/no-confidence.jsonld b/CIP-0108/examples/no-confidence.jsonld new file mode 100644 index 000000000..89e18705b --- /dev/null +++ b/CIP-0108/examples/no-confidence.jsonld @@ -0,0 +1,76 @@ +{ + "@context": { + "@language": "en-us", + "CIP100": "https://github.com/cardano-foundation/CIPs/blob/master/CIP-0100/README.md#", + "CIP108": "https://github.com/cardano-foundation/CIPs/blob/master/CIP-0108/README.md#", + "hashAlgorithm": "CIP100:hashAlgorithm", + "body": { + "@id": "CIP108:body", + "@context": { + "references": { + "@id": "CIP108:references", + "@container": "@set", + "@context": { + "GovernanceMetadata": "CIP100:GovernanceMetadataReference", + "Other": "CIP100:OtherReference", + "label": "CIP100:reference-label", + "uri": "CIP100:reference-uri", + "referenceHash": { + "@id": "CIP108:referenceHash", + "@context": { + "hashDigest": "CIP108:hashDigest", + "hashAlgorithm": "CIP100:hashAlgorithm" + } + } + } + }, + "title": "CIP108:title", + "abstract": "CIP108:abstract", + "motivation": "CIP108:motivation", + "rationale": "CIP108:rationale" + } + }, + "authors": { + "@id": "CIP100:authors", + "@container": "@set", + "@context": { + "name": "http://xmlns.com/foaf/0.1/name", + "witness": { + "@id": "CIP100:witness", + "@context": { + "witnessAlgorithm": "CIP100:witnessAlgorithm", + "publicKey": "CIP100:publicKey", + "signature": "CIP100:signature" + } + } + } + } + }, + "hashAlgorithm": "blake2b-256", + "body": { + "title": "We must remove the ineffective Constitutional Committee", + "abstract": "The current constitutional committee have not voted for the last 100 epochs, causing an inability to pass any proposals. This is a waste of resources and must be removed.", + "motivation": "In order for governance to work an __active__ constitutional committee is required, without them the system grinds to a halt and important governance actions cannot be passed.", + "rationale": "By moving into a state of no confidence, **we** the DReps are able to vote in a new constitutional committee.", + "references": [ + { + "@type": "Other", + "label": "A governance action that has been unable to pass", + "uri": "https://raw.githubusercontent.com/cardano-foundation/CIPs/blob/master/CIP-0108/examples/treasury-withdrawal.jsonld", + "referenceHash": { + "hashDigest": "70e79c1f12ff3c8c955bc2178a542b5994a21be163dd7655af2c5308d2643323", + "hashAlgorithm": "blake2b-256" + } + } + ] + }, + "authors": [ + { + "witness": { + "witnessAlgorithm": "cip-0008", + "publicKey": "7ea09a34aebb13c9841c71397b1cabfec5ddf950405293dee496cac2f437480a", + "signature": "84582aa201276761646472657373581d610fdc780023d8be7c9ff3a6bdc0d8d3b263bd0cc12448c40948efbf42a166686173686564f458204a7ecc544559df67ece3f7f90f76c4e3e7e329a274c79a06dcfbf28351db600e5840a5dc881ddabdec69e0e4dabdd43a922ef474f7be1029facdbb9106429e17ec61deda22f2778eda21005127f0c6d10f8a4b0210b8177d03d2ae4618d2423d0807" + } + } + ] +} diff --git a/CIP-0108/examples/treasury-withdrawal.body.canonical b/CIP-0108/examples/treasury-withdrawal.body.canonical new file mode 100644 index 000000000..55f3ec84c --- /dev/null +++ b/CIP-0108/examples/treasury-withdrawal.body.canonical @@ -0,0 +1,9 @@ +_:c14n0 "Withdraw 200000000000 ADA from the treasury so Ryan can buy an island."@en-us . +_:c14n0 "The current problem is that Ryan does not have an island, but he would really like an island."@en-us . +_:c14n0 "With these funds from the treasury will be sold for **cold hard cash**, this cash can then be used to purchase an island for Ryan. An example of this island is provided in the references."@en-us . +_:c14n0 _:c14n2 . +_:c14n0 "Buy Ryan a island"@en-us . +_:c14n1 _:c14n0 . +_:c14n2 . +_:c14n2 "A cool island for Ryan"@en-us . +_:c14n2 "https://www.google.com/maps/place/World's+only+5th+order+recursive+island/@62.6511465,-97.7946829,15.75z/data=!4m14!1m7!3m6!1s0x5216a167810cee39:0x11431abdfe4c7421!2sWorld's+only+5th+order+recursive+island!8m2!3d62.651114!4d-97.7872244!16s%2Fg%2F11spwk2b6n!3m5!1s0x5216a167810cee39:0x11431abdfe4c7421!8m2!3d62.651114!4d-97.7872244!16s%2Fg%2F11spwk2b6n?authuser=0&entry=ttu"@en-us . diff --git a/CIP-0108/examples/treasury-withdrawal.body.jsonld b/CIP-0108/examples/treasury-withdrawal.body.jsonld new file mode 100644 index 000000000..e5b0cda78 --- /dev/null +++ b/CIP-0108/examples/treasury-withdrawal.body.jsonld @@ -0,0 +1,62 @@ +{ + "@context": { + "@language": "en-us", + "CIP100": "https://github.com/cardano-foundation/CIPs/blob/master/CIP-0100/README.md#", + "CIP108": "https://github.com/cardano-foundation/CIPs/blob/master/CIP-0108/README.md#", + "hashAlgorithm": "CIP100:hashAlgorithm", + "body": { + "@id": "CIP108:body", + "@context": { + "references": { + "@id": "CIP108:references", + "@container": "@set", + "@context": { + "GovernanceMetadata": "CIP100:GovernanceMetadataReference", + "Other": "CIP100:OtherReference", + "label": "CIP100:reference-label", + "uri": "CIP100:reference-uri", + "referenceHash": { + "@id": "CIP108:referenceHash", + "@context": { + "hashDigest": "CIP108:hashDigest", + "hashAlgorithm": "CIP100:hashAlgorithm" + } + } + } + }, + "title": "CIP108:title", + "abstract": "CIP108:abstract", + "motivation": "CIP108:motivation", + "rationale": "CIP108:rationale" + } + }, + "authors": { + "@id": "CIP100:authors", + "@container": "@set", + "@context": { + "name": "http://xmlns.com/foaf/0.1/name", + "witness": { + "@id": "CIP100:witness", + "@context": { + "witnessAlgorithm": "CIP100:witnessAlgorithm", + "publicKey": "CIP100:publicKey", + "signature": "CIP100:signature" + } + } + } + } + }, + "body": { + "title": "Buy Ryan a island", + "abstract": "Withdraw 200000000000 ADA from the treasury so Ryan can buy an island.", + "motivation": "The current problem is that Ryan does not have an island, but he would really like an island.", + "rationale": "With these funds from the treasury will be sold for **cold hard cash**, this cash can then be used to purchase an island for Ryan. An example of this island is provided in the references.", + "references": [ + { + "@type": "Other", + "label": "A cool island for Ryan", + "uri": "https://www.google.com/maps/place/World's+only+5th+order+recursive+island/@62.6511465,-97.7946829,15.75z/data=!4m14!1m7!3m6!1s0x5216a167810cee39:0x11431abdfe4c7421!2sWorld's+only+5th+order+recursive+island!8m2!3d62.651114!4d-97.7872244!16s%2Fg%2F11spwk2b6n!3m5!1s0x5216a167810cee39:0x11431abdfe4c7421!8m2!3d62.651114!4d-97.7872244!16s%2Fg%2F11spwk2b6n?authuser=0&entry=ttu" + } + ] + } +} diff --git a/CIP-0108/examples/treasury-withdrawal.canonical b/CIP-0108/examples/treasury-withdrawal.canonical new file mode 100644 index 000000000..f12c0673e --- /dev/null +++ b/CIP-0108/examples/treasury-withdrawal.canonical @@ -0,0 +1,16 @@ +_:c14n0 _:c14n2 . +_:c14n0 "blake2b-256"@en-us . +_:c14n0 _:c14n1 . +_:c14n1 "Withdraw 200000000000 ADA from the treasury so Ryan can buy an island."@en-us . +_:c14n1 "The current problem is that Ryan does not have an island, but he would really like an island."@en-us . +_:c14n1 "With these funds from the treasury will be sold for **cold hard cash**, this cash can then be used to purchase an island for Ryan. An example of this island is provided in the references."@en-us . +_:c14n1 _:c14n4 . +_:c14n1 "Buy Ryan a island"@en-us . +_:c14n2 "Ryan Williams"@en-us . +_:c14n2 _:c14n3 . +_:c14n3 "7ea09a34aebb13c9841c71397b1cabfec5ddf950405293dee496cac2f437480a"@en-us . +_:c14n3 "a476985b4cc0d457f247797611799a6f6a80fc8cb7ec9dcb5a8223888d0618e30de165f3d869c4a0d9107d8a5b612ad7c5e42441907f5b91796f0d7187d64a01"@en-us . +_:c14n3 "ed25519"@en-us . +_:c14n4 . +_:c14n4 "A cool island for Ryan"@en-us . +_:c14n4 "https://www.google.com/maps/place/World's+only+5th+order+recursive+island/@62.6511465,-97.7946829,15.75z/data=!4m14!1m7!3m6!1s0x5216a167810cee39:0x11431abdfe4c7421!2sWorld's+only+5th+order+recursive+island!8m2!3d62.651114!4d-97.7872244!16s%2Fg%2F11spwk2b6n!3m5!1s0x5216a167810cee39:0x11431abdfe4c7421!8m2!3d62.651114!4d-97.7872244!16s%2Fg%2F11spwk2b6n?authuser=0&entry=ttu"@en-us . diff --git a/CIP-0108/examples/treasury-withdrawal.jsonld b/CIP-0108/examples/treasury-withdrawal.jsonld new file mode 100644 index 000000000..594a48287 --- /dev/null +++ b/CIP-0108/examples/treasury-withdrawal.jsonld @@ -0,0 +1,73 @@ +{ + "@context": { + "@language": "en-us", + "CIP100": "https://github.com/cardano-foundation/CIPs/blob/master/CIP-0100/README.md#", + "CIP108": "https://github.com/cardano-foundation/CIPs/blob/master/CIP-0108/README.md#", + "hashAlgorithm": "CIP100:hashAlgorithm", + "body": { + "@id": "CIP108:body", + "@context": { + "references": { + "@id": "CIP108:references", + "@container": "@set", + "@context": { + "GovernanceMetadata": "CIP100:GovernanceMetadataReference", + "Other": "CIP100:OtherReference", + "label": "CIP100:reference-label", + "uri": "CIP100:reference-uri", + "referenceHash": { + "@id": "CIP108:referenceHash", + "@context": { + "hashDigest": "CIP108:hashDigest", + "hashAlgorithm": "CIP100:hashAlgorithm" + } + } + } + }, + "title": "CIP108:title", + "abstract": "CIP108:abstract", + "motivation": "CIP108:motivation", + "rationale": "CIP108:rationale" + } + }, + "authors": { + "@id": "CIP100:authors", + "@container": "@set", + "@context": { + "name": "http://xmlns.com/foaf/0.1/name", + "witness": { + "@id": "CIP100:witness", + "@context": { + "witnessAlgorithm": "CIP100:witnessAlgorithm", + "publicKey": "CIP100:publicKey", + "signature": "CIP100:signature" + } + } + } + } + }, + "hashAlgorithm": "blake2b-256", + "body": { + "title": "Buy Ryan a island", + "abstract": "Withdraw 200000000000 ADA from the treasury so Ryan can buy an island.", + "motivation": "The current problem is that Ryan does not have an island, but he would really like an island.", + "rationale": "With these funds from the treasury will be sold for **cold hard cash**, this cash can then be used to purchase an island for Ryan. An example of this island is provided in the references.", + "references": [ + { + "@type": "Other", + "label": "A cool island for Ryan", + "uri": "https://www.google.com/maps/place/World's+only+5th+order+recursive+island/@62.6511465,-97.7946829,15.75z/data=!4m14!1m7!3m6!1s0x5216a167810cee39:0x11431abdfe4c7421!2sWorld's+only+5th+order+recursive+island!8m2!3d62.651114!4d-97.7872244!16s%2Fg%2F11spwk2b6n!3m5!1s0x5216a167810cee39:0x11431abdfe4c7421!8m2!3d62.651114!4d-97.7872244!16s%2Fg%2F11spwk2b6n?authuser=0&entry=ttu" + } + ] + }, + "authors": [ + { + "name": "Ryan Williams", + "witness": { + "witnessAlgorithm": "ed25519", + "publicKey": "7ea09a34aebb13c9841c71397b1cabfec5ddf950405293dee496cac2f437480a", + "signature": "a476985b4cc0d457f247797611799a6f6a80fc8cb7ec9dcb5a8223888d0618e30de165f3d869c4a0d9107d8a5b612ad7c5e42441907f5b91796f0d7187d64a01" + } + } + ] +} diff --git a/CIP-0108/test-vector.md b/CIP-0108/test-vector.md new file mode 100644 index 000000000..c09b608cf --- /dev/null +++ b/CIP-0108/test-vector.md @@ -0,0 +1,133 @@ +# Test Vector for CIP-0108 + +Here we create some useful definitions and some examples. + +## Common Context + +### Common Fields + +The context fields which could be added to CIP-108 compliant jsonld files. +See [cip-0108.common.jsonld](./cip-0108.common.jsonld). + +### Common Fields Schema + +A json schema for the common context fields. +See [cip-0108.common.schema.json](./cip-0108.common.schema.json). + +## Examples + +### Treasury Withdrawal + +Example metadata document file: [treasury-withdrawal.jsonld](./examples/treasury-withdrawal.jsonld). +Blake2b-256 of the canonicalized document (to go onchain): `6685960f5884922e135a951f8acb581ff7202fc111ec405a7e014ae725927aae` + +#### Intermediate files + +Files produced to articulate process, these are not necessary in implementations. + +Body files, used to correctly generate author's witness: +- [treasury-withdrawal.body.jsonld](./examples/treasury-withdrawal.body.jsonld) +- [treasury-withdrawal.body.nq](./examples/treasury-withdrawal.body.nq) + +Blake2b-256 hash digest of canonicalized body: `68d6fe27087457acf0164e65414238c43573192c99f30341926d1524924d71ca` + +Whole document canonical representation, used to generate final hash: +- [treasury-withdrawal.nq](./examples/treasury-withdrawal.nq) + +### Motion of No-Confidence + +Example metadata document file: [no-confidence.jsonld](./examples/no-confidence.jsonld). +Blake2b-256 of the canonicalized document (to go onchain): `c382be96dd98c4bbd6d3afe81f0c8143e70fbb6b8855303e69a6606991a4e909` + +#### Intermediate files + +Files produced to articulate process, these are not necessary in implementations. + +Body files, used to correctly generate author's witness: +- [no-confidence.body.jsonld](./examples/no-confidence.body.jsonld) +- [no-confidence.body.nq](./examples/no-confidence.body.nq) + +Blake2b-256 hash digest of canonicalized body: `4a7ecc544559df67ece3f7f90f76c4e3e7e329a274c79a06dcfbf28351db600e` + +Whole document canonical representation, used to generate final hash: +- [no-confidence.nq](./examples/no-confidence.nq) + +## How-to Recreate Examples + +This tutorial creates additional intermediate files, these are not required in implementations but are shown here to articulate the process. + +### Author + +Keys used for author property, provided here for convenience. + +Private extended signing key (hex): `105d2ef2192150655a926bca9cccf5e2f6e496efa9580508192e1f4a790e6f53de06529129511d1cacb0664bcf04853fdc0055a47cc6d2c6d205127020760652` + +Public verification key (hex): +`7ea09a34aebb13c9841c71397b1cabfec5ddf950405293dee496cac2f437480a` + + +Public verification key hash (hex): `0fdc780023d8be7c9ff3a6bdc0d8d3b263bd0cc12448c40948efbf42` + +Mainnet public enterprize address (hex): +`610fdc780023d8be7c9ff3a6bdc0d8d3b263bd0cc12448c40948efbf42` + +### 1. Create the example.jsonld's `body` + +Create the `example.jsonld` file adding in all available values. +Then remove from this document any top-level field that is not `@context` or `body`. + +If recreating the [Treasury Withdrawal](#treasury-withdrawal), this will result in the intermediate file of [treasury-withdrawal.body.jsonld](./examples/treasury-withdrawal.body.jsonld). + +### 2. Canonicalize the `body` + +Using a tool which complies with the [RDF Dataset Canonicalization](https://w3c-ccg.github.io/rdf-dataset-canonicalization/spec/), create a canonicalized representation of `example.body.jsonld`. +One such tool is the [JSON-LD Playground](https://json-ld.org/playground/). +Ensure the results ends in a newline. + +This creates `example.body.nq`. + +For [Treasury Withdrawal](#treasury-withdrawal), this will result in the intermediate file of [treasury-withdrawal.body.nq](./examples/treasury-withdrawal.body.nq). + +### 3. Hash the canonicalized `body` + +Using a tool create a Blake2b-256 hash of the canonicalized `example.body.nq`. +One such tool is the [ToolKit Bay](https://toolkitbay.com/tkb/tool/BLAKE2b_256). + +For [Treasury Withdrawal](#treasury-withdrawal), this will result in: `68d6fe27087457acf0164e65414238c43573192c99f30341926d1524924d71ca`. + +### 4. Authors witness over the hash of canonicalized `body` + +Use the hash produced in [3.](#3-hash-the-canonicalized-body) as the payload for the witnessing. For a `witnessAlgorithm` of `ed25519` refer to [CIP-100 Hashing and Signatures](https://github.com/cardano-foundation/CIPs/blob/master/CIP-0100/README.md#hashing-and-signatures), for `cip-0008` refer to [CIP-108 New Witness Type](./README.md#new-witness-type). + +For [Treasury Withdrawal](#treasury-withdrawal), we use the keys described in [Author](#author) resulting in: `a476985b4cc0d457f247797611799a6f6a80fc8cb7ec9dcb5a8223888d0618e30de165f3d869c4a0d9107d8a5b612ad7c5e42441907f5b91796f0d7187d64a01`. + +### 5. Add other properties to example.jsonld + +We can go back to our `example.body.jsonld` and now add in all missing properties, from outside of `body`. +- Adding the `hashAlgorithm` of `blake2b-256`. +- Adding the `authors` with a single entry, including information of our `witness` goes into the `signature`. + +By adding this information we create our `example.jsonld`. + +For [Treasury Withdrawal](#treasury-withdrawal), this will result in [treasury-withdrawal.jsonld](./examples/treasury-withdrawal.jsonld). + +### 6. Canonicalize example.jsonld + +To be able to create a final metadata hash which can be attached on-chain we must first canonicalize the `example.jsonld`. +Ensure the results ends in a newline. + +This creates `example.nq`. + +For [Treasury Withdrawal](#treasury-withdrawal), this will result in the intermediate file of [treasury-withdrawal.nq](./examples/treasury-withdrawal.nq). + +### 7. Hash the canonicalized example.jsonld + +We then use the specified `hashAlgorithm` on `example.nq`. + +For [Treasury Withdrawal](#treasury-withdrawal), this will result in `6685960f5884922e135a951f8acb581ff7202fc111ec405a7e014ae725927aae`. + +### 8. Submit to chain + +We can then host `example.jsonld` somewhere easily accessible following [CIP-100 Best Practices](https://github.com/cardano-foundation/CIPs/blob/master/CIP-0100/README.md#best-practices). + +Then at submission time of the governance metadata anchor we can provide the on-chain transaction both the URI to the hosted `example.jsonld` but also the hash generated via [7.](#7-hash-the-canonicalized-examplejsonld). \ No newline at end of file