From 2cd9ee7ebf99f68bda8600ceb79efcbc6612097c Mon Sep 17 00:00:00 2001 From: George Flerovsky Date: Tue, 24 Jan 2023 09:15:14 -0500 Subject: [PATCH 1/5] Add CDDL draft file --- CIP-????/cddl/main.cddl | 136 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 CIP-????/cddl/main.cddl diff --git a/CIP-????/cddl/main.cddl b/CIP-????/cddl/main.cddl new file mode 100644 index 000000000..f2bc3e1f6 --- /dev/null +++ b/CIP-????/cddl/main.cddl @@ -0,0 +1,136 @@ +; "????" to be replaced by the CIP number, as a `uint`. +metadata = { ???? : uint => label_metadata } + +; ========================================================================= +; CIP-???? actions +action = + { + ? assign_metadata_oracle : action_oracle, + ? simple_metadata_update : action_simple, + ? regex_metadata_update : action_regex, + ? tabular_metadata_update : action_tabular + } + +action_oracle = { * policy_id => oracle_assignment } + +oracle_assignment = + { + ? main_address : address, + ? update_address : address + } + +action_simple = { * policy_id => { * asset_name => metadata_details } } + +action_regex = { * policy_id => { * asset_regex => metadata_details } } + +action_tabular = { * policy_id => csv_update_opaque } + +; Either fixed-sized text (CIP-25v1) or fixed-sized bytes (CIP-25v2) +; The CIP-???? indexer should normalize all labels to bytes internally. +; It can also provide an API option to format labels as text in its +; response to a client request for current token metadata, if possible. +policy_id = label_64 +asset_name = label_64 +asset_regex = regex_64 + +; ========================================================================= +; Backwards compatibility with CIP-25 (simple and regex metadata updates) +; Definitions for the following fields in `metadata_details` should follow +; the same schema as in CIP-25. +; Other fields can have arbitrary `transaction_metadatum` values. +metadata_details = + { + ? name : text_64, + ? image : text_extendable, + ? mediaType : text_64, + ? description : text_extendable, + ? files : [* files_details], + * (label_64 => transaction_metadatum) + } + +files_details = + { + name : text_64, + mediaType : text_64, + src : text_extendable + } + +; ========================================================================= +; Tabular updates' CSV schema + +; Cardano ledger imposes a fixed size of 64 on text and bytestrings, +; which prevents us from directly encoding a CSV table as a single long +; text. This means that, formally, the CSV in a tabular update +; is just an opaque extendable text (i.e. a fixed text or an array of fixed +; texts). +csv_update_opaque = text_extendable + +; Informally, if we concatenate the `csv_update_opaque` value to a single long +; text, and then split it on unescaped newline characters, +; then it should comply with the following cddl schema. +; (Newline characters inside of a double-quoted field value are considered +; escaped, which means that they do no indicate the start of a new record.) +; +; csv_update = [header, * record] +; header = ["tokenName", * header_field] +; record = [text_64, * record_field] +; header_field = text +; record_field = text + +; For a given `policy_id`, a `csv_update` value can be transformed into a +; `metadata_details` value as follows: +; 1. Pair each `record_field` with its corresponding `header_field` +; (i.e. like zipping two lists). +; 2. Transform each `header_field` into a `[header_field_part]` array, by +; splitting it on the '.' character. +; 3. For each pair of `record_field` and `[header_field_part]` values, construct +; the following nested object: +; csv_nested_object = { header_field_part[0] => +; { header_field_part[1] => +; { header_field_part[2] => +; ... +; { header_field_part[N] => `record_field` } +; ... +; } +; } +; } +; 4. For each record, combine and normalize its record fields' constructed +; nested objects into a single unified object for that record. Nest the +; unified object under the record's "tokenName" value: +; csv_record_object = { text_64 => Union([csv_nested_object]) } +; 5. Unify the `record_object`s into a single object, and then nest it under +; the `policy_id`: +; csv_policy_object = { policy_id => Union([csv_record_object]) } +; 6. Combine the `action_simple_single` values into a single `action_simple` +; value: +; csv_update_simple = Union([csv_policy_object]) +; +; The effect of a `csv_update_opaque` on the token metadata state in the +; CIP-???? indexer must be the same as the effect of the corresponding +; `csv_update_simple`. + +; ========================================================================= +; Imported from cardano-ledger/.../babbage.cddl +transaction_metadatum = + { * transaction_metadatum => transaction_metadatum } + / [ * transaction_metadatum ] + / int + / bytes_64 + / text_64 + +address = bytes + +; ========================================================================= +; Convenient type aliases + +regex_64 = bytes_64 .regexp + +; Fixed-size text and bytes +label_64 = bytes_64 / text_64 + +bytes_64 = bytes .size (0..64) +text_64 = text .size (0..64) + +text_extendable = text_64 / [ * text_64 ] +bytes_extendable = bytes_64 / [ * bytes 64] + From 0042fa182a65446af95c136a7b33ab55fa9bac6e Mon Sep 17 00:00:00 2001 From: George Flerovsky Date: Tue, 24 Jan 2023 14:40:19 -0500 Subject: [PATCH 2/5] Isolate CDDL for text-based (policy_id,asset_name) This corresponds to the CIP-25's version_1.cddl. --- CIP-????/cddl/{main.cddl => version_1.cddl} | 73 +++++++++++++-------- 1 file changed, 45 insertions(+), 28 deletions(-) rename CIP-????/cddl/{main.cddl => version_1.cddl} (68%) diff --git a/CIP-????/cddl/main.cddl b/CIP-????/cddl/version_1.cddl similarity index 68% rename from CIP-????/cddl/main.cddl rename to CIP-????/cddl/version_1.cddl index f2bc3e1f6..24464178c 100644 --- a/CIP-????/cddl/main.cddl +++ b/CIP-????/cddl/version_1.cddl @@ -1,8 +1,9 @@ ; "????" to be replaced by the CIP number, as a `uint`. -metadata = { ???? : uint => label_metadata } +metadata = { ???? => action } ; ========================================================================= ; CIP-???? actions + action = { ? assign_metadata_oracle : action_oracle, @@ -25,18 +26,19 @@ action_regex = { * policy_id => { * asset_regex => metadata_details } } action_tabular = { * policy_id => csv_update_opaque } -; Either fixed-sized text (CIP-25v1) or fixed-sized bytes (CIP-25v2) -; The CIP-???? indexer should normalize all labels to bytes internally. -; It can also provide an API option to format labels as text in its -; response to a client request for current token metadata, if possible. -policy_id = label_64 -asset_name = label_64 -asset_regex = regex_64 +; Technically, both policy IDs and asset names should be 32 bytes long. +; However, this isn't enforced for asset names, and CIP-25 already treats +; these as `text_64`, so we don't enforce the more narrow `bytes_32` type +; here. +policy_id = text_64 +asset_name = text_64 + +asset_regex = text_regex_extendable ; ========================================================================= ; Backwards compatibility with CIP-25 (simple and regex metadata updates) ; Definitions for the following fields in `metadata_details` should follow -; the same schema as in CIP-25. +; the same schema as in CIP-25, except that `name` and `image` are optional. ; Other fields can have arbitrary `transaction_metadatum` values. metadata_details = { @@ -66,16 +68,15 @@ files_details = csv_update_opaque = text_extendable ; Informally, if we concatenate the `csv_update_opaque` value to a single long -; text, and then split it on unescaped newline characters, -; then it should comply with the following cddl schema. +; text, and then split it on unescaped newline characters, then it should comply +; with the following cddl schema. ; (Newline characters inside of a double-quoted field value are considered ; escaped, which means that they do no indicate the start of a new record.) -; -; csv_update = [header, * record] -; header = ["tokenName", * header_field] -; record = [text_64, * record_field] -; header_field = text -; record_field = text +csv_update = [header, * record] +header = ["tokenName", * header_field] +record = [text_64, * record_field] +header_field = text +record_field = text ; For a given `policy_id`, a `csv_update` value can be transformed into a ; `metadata_details` value as follows: @@ -85,15 +86,16 @@ csv_update_opaque = text_extendable ; splitting it on the '.' character. ; 3. For each pair of `record_field` and `[header_field_part]` values, construct ; the following nested object: -; csv_nested_object = { header_field_part[0] => -; { header_field_part[1] => -; { header_field_part[2] => -; ... -; { header_field_part[N] => `record_field` } -; ... +; csv_nested_object = +; { header_field_part[0] => +; { header_field_part[1] => +; { header_field_part[2] => +; ... +; { header_field_part[N] => `record_field` } +; ... +; } ; } ; } -; } ; 4. For each record, combine and normalize its record fields' constructed ; nested objects into a single unified object for that record. Nest the ; unified object under the record's "tokenName" value: @@ -107,7 +109,7 @@ csv_update_opaque = text_extendable ; ; The effect of a `csv_update_opaque` on the token metadata state in the ; CIP-???? indexer must be the same as the effect of the corresponding -; `csv_update_simple`. +; `csv_update_simple` (applied as a simple update action). ; ========================================================================= ; Imported from cardano-ledger/.../babbage.cddl @@ -123,14 +125,29 @@ address = bytes ; ========================================================================= ; Convenient type aliases -regex_64 = bytes_64 .regexp - ; Fixed-size text and bytes -label_64 = bytes_64 / text_64 +label_32 = bytes_32 / text_32 +bytes_32 = bytes .size (0..32) +text_32 = bytes .size (0..32) +label_64 = bytes_64 / text_64 bytes_64 = bytes .size (0..64) text_64 = text .size (0..64) +; Extendable text and bytes text_extendable = text_64 / [ * text_64 ] bytes_extendable = bytes_64 / [ * bytes 64] +; Regex (fixed-size) +; Tag 35 is for regular expressions in Perl Compatible Regular +; Expressions (PCRE) / JavaScript syntax [ECMA262]. +; https://www.rfc-editor.org/rfc/rfc7049#section-2.4.4.3 +; https://www.ecma-international.org/publications-and-standards/standards/ecma-262/ +text_regex = #6.35(text_64) + +; Regex (extendable size) +; Technically, CBOR maps can have arrays as keys. This prevents them from being +; directly convertable to JSON, but we can recover JSON-convertability by +; concatenating the array-valued key into a single UTF-8 text. +; The resulting concatenated text should be interpreted as `#6.35(text)`. +text_regex_extendable = text_extendable From 839218ccabbfde30257077f8e33706cc90e475de Mon Sep 17 00:00:00 2001 From: George Flerovsky Date: Tue, 24 Jan 2023 14:52:48 -0500 Subject: [PATCH 3/5] Add support for bytestring (policy_id, asset_name) This corresponds to CIP-25's version_2.cddl. Note that regex and tabular updates are not supported under this version 2 mode. --- CIP-????/cddl/version_1.cddl | 12 ++--- CIP-????/cddl/version_2.cddl | 85 ++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 6 deletions(-) create mode 100644 CIP-????/cddl/version_2.cddl diff --git a/CIP-????/cddl/version_1.cddl b/CIP-????/cddl/version_1.cddl index 24464178c..069d69fe2 100644 --- a/CIP-????/cddl/version_1.cddl +++ b/CIP-????/cddl/version_1.cddl @@ -27,7 +27,7 @@ action_regex = { * policy_id => { * asset_regex => metadata_details } } action_tabular = { * policy_id => csv_update_opaque } ; Technically, both policy IDs and asset names should be 32 bytes long. -; However, this isn't enforced for asset names, and CIP-25 already treats +; However, this isn't enforced for asset names, and CIP-25v1 already treats ; these as `text_64`, so we don't enforce the more narrow `bytes_32` type ; here. policy_id = text_64 @@ -47,7 +47,7 @@ metadata_details = ? mediaType : text_64, ? description : text_extendable, ? files : [* files_details], - * (label_64 => transaction_metadatum) + * ( label_64 => transaction_metadatum ) } files_details = @@ -72,9 +72,9 @@ csv_update_opaque = text_extendable ; with the following cddl schema. ; (Newline characters inside of a double-quoted field value are considered ; escaped, which means that they do no indicate the start of a new record.) -csv_update = [header, * record] -header = ["tokenName", * header_field] -record = [text_64, * record_field] +csv_update = [ header, * record ] +header = [ "tokenName", * header_field ] +record = [ text_64, * record_field ] header_field = text record_field = text @@ -136,7 +136,7 @@ text_64 = text .size (0..64) ; Extendable text and bytes text_extendable = text_64 / [ * text_64 ] -bytes_extendable = bytes_64 / [ * bytes 64] +bytes_extendable = bytes_64 / [ * bytes 64 ] ; Regex (fixed-size) ; Tag 35 is for regular expressions in Perl Compatible Regular diff --git a/CIP-????/cddl/version_2.cddl b/CIP-????/cddl/version_2.cddl new file mode 100644 index 000000000..353b5671a --- /dev/null +++ b/CIP-????/cddl/version_2.cddl @@ -0,0 +1,85 @@ +; "????" to be replaced by the CIP number, as a `uint`. +metadata = { ???? => action } + +; ========================================================================= +; CIP-???? actions + +; When version 2 mode is enabled for a CIP-???? action, all `policy_id` and +; `asset_name` values are interpreted as `bytes_64`, similar to CIP-25v2. +action = + { + version = 2, + ? assign_metadata_oracle : action_oracle, + ? simple_metadata_update : action_simple, + } + +; Regex and tabular updates are disallowed in version 2, because it is unclear +; how to apply regular expressions to non-UTF-8 bytestrings (or their +; corresponding hex encodings) and it is unclear how to embed raw bytestrings +; in CSV. + +action_oracle = { * policy_id => oracle_assignment } + +oracle_assignment = + { + ? main_address : address, + ? update_address : address + } + +action_simple = { * policy_id => { * asset_name => metadata_details } } + +; Technically, both policy IDs and asset names should be 32 bytes long. +; However, this isn't enforced for asset names, and CIP-25v2 already treats +; these as `bytes_64`, so we don't enforce the more narrow `bytes_32` type +; here. +policy_id = bytes_64 +asset_name = bytes_64 + +; ========================================================================= +; Backwards compatibility with CIP-25 (simple and regex metadata updates) +; Definitions for the following fields in `metadata_details` should follow +; the same schema as in CIP-25, except that `name` and `image` are optional. +; Other fields can have arbitrary `transaction_metadatum` values. +metadata_details = + { + ? name : text_64, + ? image : text_extendable, + ? mediaType : text_64, + ? description : text_extendable, + ? files : [* files_details], + * ( label_64 => transaction_metadatum ) + } + +files_details = + { + name : text_64, + mediaType : text_64, + src : text_extendable + } + +; ========================================================================= +; Imported from cardano-ledger/.../babbage.cddl +transaction_metadatum = + { * transaction_metadatum => transaction_metadatum } + / [ * transaction_metadatum ] + / int + / bytes_64 + / text_64 + +address = bytes + +; ========================================================================= +; Convenient type aliases + +; Fixed-size text and bytes +label_32 = bytes_32 / text_32 +bytes_32 = bytes .size (0..32) +text_32 = bytes .size (0..32) + +label_64 = bytes_64 / text_64 +bytes_64 = bytes .size (0..64) +text_64 = text .size (0..64) + +; Extendable text and bytes +text_extendable = text_64 / [ * text_64 ] +bytes_extendable = bytes_64 / [ * bytes 64 ] From 2fc06b668453f9a59a0f82895d264e0aa46381cf Mon Sep 17 00:00:00 2001 From: Nicolas Ayotte Date: Tue, 24 Jan 2023 22:09:18 -0500 Subject: [PATCH 4/5] Update version_1.cddl typo in text_32 definition --- CIP-????/cddl/version_1.cddl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CIP-????/cddl/version_1.cddl b/CIP-????/cddl/version_1.cddl index 069d69fe2..812622144 100644 --- a/CIP-????/cddl/version_1.cddl +++ b/CIP-????/cddl/version_1.cddl @@ -128,7 +128,7 @@ address = bytes ; Fixed-size text and bytes label_32 = bytes_32 / text_32 bytes_32 = bytes .size (0..32) -text_32 = bytes .size (0..32) +text_32 = text .size (0..32) label_64 = bytes_64 / text_64 bytes_64 = bytes .size (0..64) From 182ccd127147bfddbf71eee0373bd21cd833deb9 Mon Sep 17 00:00:00 2001 From: Nicolas Ayotte Date: Tue, 24 Jan 2023 22:09:40 -0500 Subject: [PATCH 5/5] Update version_2.cddl typo in text_32 definition --- CIP-????/cddl/version_2.cddl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CIP-????/cddl/version_2.cddl b/CIP-????/cddl/version_2.cddl index 353b5671a..99e7eb15a 100644 --- a/CIP-????/cddl/version_2.cddl +++ b/CIP-????/cddl/version_2.cddl @@ -74,7 +74,7 @@ address = bytes ; Fixed-size text and bytes label_32 = bytes_32 / text_32 bytes_32 = bytes .size (0..32) -text_32 = bytes .size (0..32) +text_32 = text .size (0..32) label_64 = bytes_64 / text_64 bytes_64 = bytes .size (0..64)