Skip to content

Instantly share code, notes, and snippets.

@Soupstraw
Last active April 3, 2025 12:49
Show Gist options
  • Select an option

  • Save Soupstraw/d1fbaea0396bf8807427dea3e653d2d6 to your computer and use it in GitHub Desktop.

Select an option

Save Soupstraw/d1fbaea0396bf8807427dea3e653d2d6 to your computer and use it in GitHub Desktop.
new formatting for conway.cddl
; crypto.cddl
$hash28 /= bytes .size 28
$hash32 /= bytes .size 32
$vkey /= bytes .size 32
$vrf_vkey /= bytes .size 32
$vrf_cert /= [bytes, bytes .size 80]
$kes_vkey /= bytes .size 32
$kes_signature /= bytes .size 448
signkeyKES = bytes .size 64
$signature /= bytes .size 64
; extra.cddl
; Conway era introduces an optional 258 tag for sets, which will become mandatory in the
; second era after Conway. We recommend all the tooling to account for this future breaking
; change sooner rather than later, in order to provide a smooth transition for their users.
; This is an unordered set. Duplicate elements are not allowed and the order of elements is implementation specific.
set<a> = #6.258([* a]) / [* a]
; Just like `set`, but must contain at least one element.
nonempty_set<a> = #6.258([+ a]) / [+ a]
; This is a non-empty ordered set. Duplicate elements are not allowed and the order of elements will be preserved.
nonempty_oset<a> = #6.258([+ a]) / [+ a]
positive_int = 1 .. 18446744073709551615
unit_interval = #6.30([1, 2])
; unit_interval = #6.30([uint, uint])
;
; Comment above depicts the actual definition for `unit_interval`.
;
; Unit interval is a number in the range between 0 and 1, which
; means there are two extra constraints:
; * numerator <= denominator
; * denominator > 0
;
; Relation between numerator and denominator cannot be expressed in CDDL, which
; poses a problem for testing. We need to be able to generate random valid data
; for testing implementation of our encoders/decoders. Which means we cannot use
; the actual definition here and we hard code the value to 1/2
nonnegative_interval = #6.30([uint, positive_int])
address =
h'001000000000000000000000000000000000000000000000000000000011000000000000000000000000000000000000000000000000000000' /
h'102000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000' /
h'203000000000000000000000000000000000000000000000000000000033000000000000000000000000000000000000000000000000000000' /
h'304000000000000000000000000000000000000000000000000000000044000000000000000000000000000000000000000000000000000000' /
h'405000000000000000000000000000000000000000000000000000000087680203' /
h'506000000000000000000000000000000000000000000000000000000087680203' /
h'6070000000000000000000000000000000000000000000000000000000' /
h'7080000000000000000000000000000000000000000000000000000000'
reward_account =
h'E090000000000000000000000000000000000000000000000000000000' /
h'F0A0000000000000000000000000000000000000000000000000000000'
bounded_bytes = bytes .size (0 .. 64)
; the real bounded_bytes does not have this limit. it instead has a different
; limit which cannot be expressed in CDDL.
; The limit is as follows:
; - bytes with a definite-length encoding are limited to size 0..64
; - for bytes with an indefinite-length CBOR encoding, each chunk is
; limited to size 0..64
; ( reminder: in CBOR, the indefinite-length encoding of bytestrings
; consists of a token #2.31 followed by a sequence of definite-length
; encoded bytestrings and a stop code )
; a type for distinct values.
; The type parameter must support .size, for example: bytes or uint
distinct<a> =
a .size 8 / a .size 16 / a .size 20 / a .size 24 / a .size 30 / a .size 32
; conway.cddl
block =
[ header
, transaction_bodies : [* transaction_body]
, transaction_witness_sets : [* transaction_witness_set]
, auxiliary_data_set : {* transaction_index => auxiliary_data}
, invalid_transactions : [* transaction_index]
]
; Valid blocks must also satisfy the following two constraints:
; 1) the length of transaction_bodies and transaction_witness_sets
; must be the same
; 2) every transaction_index must be strictly smaller than the
; length of transaction_bodies
transaction =
[transaction_body, transaction_witness_set, bool, auxiliary_data / null]
transaction_index = uint .size 2
header = [header_body, body_signature : $kes_signature]
header_body =
[ block_number : uint
, slot : uint
, prev_hash : $hash32 / null
, issuer_vkey : $vkey
, vrf_vkey : $vrf_vkey
, vrf_result : $vrf_cert ; replaces nonce_vrf and leader_vrf
, block_body_size : uint
, block_body_hash : $hash32 ; merkle triple root
, operational_cert
, [protocol_version]
]
operational_cert =
[ hot_vkey : $kes_vkey
, sequence_number : uint
, kes_period : uint
, sigma : $signature
]
next_major_protocol_version = 10
major_protocol_version = 1 .. next_major_protocol_version
protocol_version = (major_protocol_version, uint)
transaction_body =
{ 0 : set<transaction_input> ; 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<transaction_input> ; collateral inputs
, ? 14 : required_signers
, ? 15 : network_id
, ? 16 : transaction_output ; collateral return
, ? 17 : coin ; total collateral
, ? 18 : nonempty_set<transaction_input> ; reference inputs
, ? 19 : voting_procedures ; New; Voting procedures
, ? 20 : proposal_procedures ; New; Proposal procedures
, ? 21 : coin ; New; current treasury value
, ? 22 : positive_coin ; New; donation
}
voting_procedures = {+ voter => {+ gov_action_id => voting_procedure}}
voting_procedure = [vote, anchor / null]
proposal_procedure = [deposit : coin, reward_account, gov_action, anchor]
proposal_procedures = nonempty_set<proposal_procedure>
certificates = nonempty_set<certificate>
gov_action =
[ parameter_change_action
// hard_fork_initiation_action
// treasury_withdrawals_action
// no_confidence
// update_committee
// new_constitution
// info_action
]
policy_hash = scripthash
parameter_change_action =
(0, gov_action_id / null, protocol_param_update, policy_hash / null)
hard_fork_initiation_action = (1, gov_action_id / null, [protocol_version])
treasury_withdrawals_action = (2, {reward_account => coin}, policy_hash / null)
no_confidence = (3, gov_action_id / null)
update_committee =
( 4
, gov_action_id / null
, set<committee_cold_credential>
, {committee_cold_credential => epoch}
, unit_interval
)
new_constitution = (5, gov_action_id / null, constitution)
constitution = [anchor, scripthash / null]
info_action = 6
; Constitutional Committee Hot KeyHash: 0
; Constitutional Committee Hot ScriptHash: 1
; DRep KeyHash: 2
; DRep ScriptHash: 3
; StakingPool KeyHash: 4
voter =
[ 0, addr_keyhash
// 1, scripthash
// 2, addr_keyhash
// 3, scripthash
// 4, addr_keyhash
]
anchor = [anchor_url : url, anchor_data_hash : $hash32]
; no - 0
; yes - 1
; abstain - 2
vote = 0 .. 2
gov_action_id = [transaction_id : $hash32, gov_action_index : uint]
required_signers = nonempty_set<addr_keyhash>
transaction_input = [transaction_id : $hash32, index : uint]
transaction_output = legacy_transaction_output / post_alonzo_transaction_output
legacy_transaction_output = [ address, amount : value, ? datum_hash : $hash32]
post_alonzo_transaction_output =
{ 0 : address
, 1 : value
, ? 2 : datum_option ; datum option
, ? 3 : script_ref ; script reference
}
script_data_hash = $hash32
; This is a hash of data which may affect evaluation of a script.
; This data consists of:
; - The redeemers from the transaction_witness_set (the value of field 5).
; - The datums from the transaction_witness_set (the value of field 4).
; - The value in the costmdls map corresponding to the script's language
; (in field 18 of protocol_param_update.)
; (In the future it may contain additional protocol parameters.)
;
; Since this data does not exist in contiguous form inside a transaction, it needs
; to be independently constructed by each recipient.
;
; The bytestring which is hashed is the concatenation of three things:
; redeemers || datums || language views
; The redeemers are exactly the data present in the transaction witness set.
; Similarly for the datums, if present. If no datums are provided, the middle
; field is omitted (i.e. it is the empty/null bytestring).
;
; language views CDDL:
; { * language => script_integrity_data }
;
; This must be encoded canonically, using the same scheme as in
; RFC7049 section 3.9:
; - Maps, strings, and bytestrings must use a definite-length encoding
; - Integers must be as small as possible.
; - The expressions for map length, string length, and bytestring length
; must be as short as possible.
; - The keys in the map must be sorted as follows:
; - If two keys have different lengths, the shorter one sorts earlier.
; - If two keys have the same length, the one with the lower value
; in (byte-wise) lexical order sorts earlier.
;
; For PlutusV1 (language id 0), the language view is the following:
; - the value of costmdls map at key 0 (in other words, the script_integrity_data)
; is encoded as an indefinite length list and the result is encoded as a bytestring.
; (our apologies)
; For example, the script_integrity_data corresponding to the all zero costmodel for V1
; would be encoded as (in hex):
; 58a89f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ff
; - the language ID tag is also encoded twice. first as a uint then as
; a bytestring. (our apologies)
; Concretely, this means that the language version for V1 is encoded as
; 4100 in hex.
; For PlutusV2 (language id 1), the language view is the following:
; - the value of costmdls map at key 1 is encoded as an definite length list.
; For example, the script_integrity_data corresponding to the all zero costmodel for V2
; would be encoded as (in hex):
; 98af0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
; - the language ID tag is encoded as expected.
; Concretely, this means that the language version for V2 is encoded as
; 01 in hex.
; For PlutusV3 (language id 2), the language view is the following:
; - the value of costmdls map at key 2 is encoded as a definite length list.
;
; Note that each Plutus language represented inside a transaction must have
; a cost model in the costmdls protocol parameter in order to execute,
; regardless of what the script integrity data is.
;
; Finally, note that in the case that a transaction includes datums but does not
; include the redeemers field, the script data format becomes (in hex):
; [ 80 | datums | A0 ]
; corresponding to a CBOR empty list and an empty map.
; Note that a transaction might include the redeemers field and it to the
; empty map, in which case the user supplied encoding of the empty map is used.
; address = bytes
; reward_account = bytes
; address format:
; [ 8 bit header | payload ];
;
; shelley payment addresses:
; bit 7: 0
; bit 6: base/other
; bit 5: pointer/enterprise [for base: stake cred is keyhash/scripthash]
; bit 4: payment cred is keyhash/scripthash
; bits 3-0: network id
;
; reward addresses:
; bits 7-5: 111
; bit 4: credential is keyhash/scripthash
; bits 3-0: network id
;
; byron addresses:
; bits 7-4: 1000
; 0000: base address: keyhash28,keyhash28
; 0001: base address: scripthash28,keyhash28
; 0010: base address: keyhash28,scripthash28
; 0011: base address: scripthash28,scripthash28
; 0100: pointer address: keyhash28, 3 variable length uint
; 0101: pointer address: scripthash28, 3 variable length uint
; 0110: enterprise address: keyhash28
; 0111: enterprise address: scripthash28
; 1000: byron address
; 1110: reward account: keyhash28
; 1111: reward account: scripthash28
; 1001 - 1101: future formats
certificate =
[ stake_registration
// stake_deregistration
// stake_delegation
// pool_registration
// pool_retirement
// reg_cert
// unreg_cert
// vote_deleg_cert
// stake_vote_deleg_cert
// stake_reg_deleg_cert
// vote_reg_deleg_cert
// stake_vote_reg_deleg_cert
// auth_committee_hot_cert
// resign_committee_cold_cert
// reg_drep_cert
// unreg_drep_cert
// update_drep_cert
]
stake_registration = (0, stake_credential)
; to be deprecated in era after Conway
stake_deregistration = (1, stake_credential)
; to be deprecated in era after Conway
stake_delegation = (2, stake_credential, pool_keyhash)
; POOL
pool_registration = (3, pool_params)
pool_retirement = (4, pool_keyhash, epoch)
; numbers 5 and 6 used to be the Genesis and MIR certificates respectively,
; which were deprecated in Conway
; DELEG
reg_cert = (7, stake_credential, coin)
unreg_cert = (8, stake_credential, coin)
vote_deleg_cert = (9, stake_credential, drep)
stake_vote_deleg_cert = (10, stake_credential, pool_keyhash, drep)
stake_reg_deleg_cert = (11, stake_credential, pool_keyhash, coin)
vote_reg_deleg_cert = (12, stake_credential, drep, coin)
stake_vote_reg_deleg_cert = (13, stake_credential, pool_keyhash, drep, coin)
; GOVCERT
auth_committee_hot_cert =
(14, committee_cold_credential, committee_hot_credential)
resign_committee_cold_cert = (15, committee_cold_credential, anchor / null)
reg_drep_cert = (16, drep_credential, coin, anchor / null)
unreg_drep_cert = (17, drep_credential, coin)
update_drep_cert = (18, drep_credential, anchor / null)
delta_coin = int
credential = [0, addr_keyhash // 1, scripthash]
drep =
[ 0, addr_keyhash
// 1, scripthash
// 2 ; always abstain
// 3 ; always no confidence
]
stake_credential = credential
drep_credential = credential
committee_cold_credential = credential
committee_hot_credential = credential
pool_params =
( operator : pool_keyhash
, vrf_keyhash : vrf_keyhash
, pledge : coin
, cost : coin
, margin : unit_interval
, reward_account : reward_account
, pool_owners : set<addr_keyhash>
, relays : [* relay]
, pool_metadata : pool_metadata / null
)
port = uint .le 65535
ipv4 = bytes .size 4
ipv6 = bytes .size 16
dns_name = tstr .size (0 .. 128)
single_host_addr = (0, port / null, ipv4 / null, ipv6 / null)
single_host_name = (1, port / null, dns_name ; An A or AAAA DNS record)
multi_host_name = (2, dns_name ; A SRV DNS record)
relay = [single_host_addr // single_host_name // multi_host_name]
pool_metadata = [url, pool_metadata_hash]
url = tstr .size (0 .. 128)
withdrawals = {+ reward_account => coin}
protocol_param_update =
{ ? 0 : coin ; minfee A
, ? 1 : coin ; minfee B
, ? 2 : uint ; max block body size
, ? 3 : uint ; max transaction size
, ? 4 : uint ; max block header size
, ? 5 : coin ; key deposit
, ? 6 : coin ; pool deposit
, ? 7 : epoch ; maximum epoch
, ? 8 : uint ; n_opt: desired number of stake pools
, ? 9 : nonnegative_interval ; pool pledge influence
, ? 10 : unit_interval ; expansion rate
, ? 11 : unit_interval ; treasury growth rate
, ? 16 : coin ; min pool cost
, ? 17 : coin ; ada per utxo byte
, ? 18 : costmdls ; cost models for script languages
, ? 19 : ex_unit_prices ; execution costs
, ? 20 : ex_units ; max tx ex units
, ? 21 : ex_units ; max block ex units
, ? 22 : uint ; max value size
, ? 23 : uint ; collateral percentage
, ? 24 : uint ; max collateral inputs
, ? 25 : pool_voting_thresholds ; pool voting thresholds
, ? 26 : drep_voting_thresholds ; DRep voting thresholds
, ? 27 : uint ; min committee size
, ? 28 : epoch ; committee term limit
, ? 29 : epoch ; governance action validity period
, ? 30 : coin ; governance action deposit
, ? 31 : coin ; DRep deposit
, ? 32 : epoch ; DRep inactivity period
}
pool_voting_thresholds =
[ unit_interval ; motion no confidence
, unit_interval ; committee normal
, unit_interval ; committee no confidence
, unit_interval ; hard fork initiation
, unit_interval ; security relevant parameter voting threshold
]
drep_voting_thresholds =
[ unit_interval ; motion no confidence
, unit_interval ; committee normal
, unit_interval ; committee no confidence
, unit_interval ; update constitution
, unit_interval ; hard fork initiation
, unit_interval ; PP network group
, unit_interval ; PP economic group
, unit_interval ; PP technical group
, unit_interval ; PP governance group
, unit_interval ; treasury withdrawal
]
transaction_witness_set =
{ ? 0 : nonempty_set<vkeywitness>
, ? 1 : nonempty_set<native_script>
, ? 2 : nonempty_set<bootstrap_witness>
, ? 3 : nonempty_set<plutus_v1_script>
, ? 4 : nonempty_set<plutus_data>
, ? 5 : redeemers
, ? 6 : nonempty_set<plutus_v2_script>
, ? 7 : nonempty_set<plutus_v3_script>
}
; The real type of plutus_v1_script, plutus_v2_script and plutus_v3_script is bytes.
; However, because we enforce uniqueness when many scripts are supplied,
; we need to hack around for tests in order to avoid generating duplicates,
; since the cddl tool we use for roundtrip testing doesn't generate distinct collections.
plutus_v1_script = distinct<bytes>
plutus_v2_script = distinct<bytes>
plutus_v3_script = distinct<bytes>
plutus_data =
constr<plutus_data> /
{* plutus_data => plutus_data} /
[* plutus_data] /
big_int /
bounded_bytes
big_int = int / big_uint / big_nint
big_uint = #6.2(bounded_bytes)
big_nint = #6.3(bounded_bytes)
constr<a> =
#6.121([* a]) /
#6.122([* a]) /
#6.123([* a]) /
#6.124([* a]) /
#6.125([* a]) /
#6.126([* a]) /
#6.127([* a]) /
#6.102([uint, [* a]])
redeemers =
[ + [ tag : redeemer_tag
, index : uint
, data : plutus_data
, ex_units : ex_units
]
]
; TODO: Add alternative implementation that reflects the reality more accuratly:
; / { + [ tag: redeemer_tag, index: uint ] => [ data: plutus_data, ex_units: ex_units ] }
redeemer_tag = 0 / 1 / 2 / 3 / 4 / 5
; Proposing
ex_units = [mem : uint, steps : uint]
ex_unit_prices =
[mem_price : nonnegative_interval, step_price : nonnegative_interval]
language = 0 / 1 / 2
; Plutus v3
potential_languages = 0 .. 255
; The format for costmdls is flexible enough to allow adding Plutus built-ins and language
; versions in the future.
;
costmdls =
{ ? 0 : [ 166* int
] ; Plutus v1, only 166 integers are used, but more are accepted (and ignored)
, ? 1 : [ 175* int
] ; Plutus v2, only 175 integers are used, but more are accepted (and ignored)
, ? 2 : [ 223* int
] ; Plutus v3, only 223 integers are used, but more are accepted (and ignored)
, ? 3 : [int] ; Any 8-bit unsigned number can be used as a key.
}
transaction_metadatum =
{* transaction_metadatum => transaction_metadatum} /
[* transaction_metadatum] /
int /
bytes .size (0 .. 64) /
text .size (0 .. 64)
transaction_metadatum_label = uint
metadata = {* transaction_metadatum_label => transaction_metadatum}
auxiliary_data =
metadata /
[ transaction_metadata : metadata ; Shelley-ma
, auxiliary_scripts : [* native_script]
] /
#6.259(
{ ? 0 => metadata ; Alonzo and beyond
, ? 1 => [* native_script]
, ? 2 => [* plutus_v1_script]
, ? 3 => [* plutus_v2_script]
, ? 4 => [* plutus_v3_script]
}
)
vkeywitness = [$vkey, $signature]
bootstrap_witness =
[ public_key : $vkey
, signature : $signature
, chain_code : bytes .size 32
, attributes : bytes
]
native_script =
[ script_pubkey
// script_all
// script_any
// script_n_of_k
// invalid_before
// invalid_hereafter
]
script_pubkey = (0, addr_keyhash)
script_all = (1, [* native_script])
script_any = (2, [* native_script])
script_n_of_k = (3, n : uint, [* native_script])
invalid_before = (4, uint)
invalid_hereafter = (5, uint)
coin = uint
multiasset<a> = {+ policy_id => {+ asset_name => a}}
policy_id = scripthash
asset_name = bytes .size (0 .. 32)
negInt64 = -9223372036854775808 .. -1
posInt64 = 1 .. 9223372036854775807
nonZeroInt64 = negInt64 / posInt64
; this is the same as the current int64 definition but without zero
positive_coin = 1 .. 18446744073709551615
value = coin / [coin, multiasset<positive_coin>]
mint = multiasset<nonZeroInt64>
int64 = -9223372036854775808 .. 9223372036854775807
network_id = 0 / 1
epoch = uint
addr_keyhash = $hash28
pool_keyhash = $hash28
vrf_keyhash = $hash32
auxiliary_data_hash = $hash32
pool_metadata_hash = $hash32
; To compute a script hash, note that you must prepend
; a tag to the bytes of the script before hashing.
; The tag is determined by the language.
; The tags in the Conway era are:
; "\x00" for multisig scripts
; "\x01" for Plutus V1 scripts
; "\x02" for Plutus V2 scripts
; "\x03" for Plutus V3 scripts
scripthash = $hash28
datum_hash = $hash32
data = #6.24(bytes .cbor plutus_data)
datum_option = [0, $hash32 // 1, data]
script_ref = #6.24(bytes .cbor script)
script =
[ 0, native_script
// 1, plutus_v1_script
// 2, plutus_v2_script
// 3, plutus_v3_script
]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment