; fetched 19 mar 2024

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_oset<proposal_procedure>

certificates = nonempty_oset<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
                    ]

; Both of the Alonzo and Babbage style TxOut formats are equally valid
; and can be used interchangeably
transaction_output = pre_babbage_transaction_output / post_alonzo_transaction_output

pre_babbage_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
  , ? 33: nonnegative_interval   ; MinFee RefScriptCostPerByte
  }

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])
  ; similarly for tag range: 6.1280 .. 6.1400 inclusive
  / #6.102([uint, [* a]])

; Flat Array support is included for backwards compatibility and will be removed in the next era.
; It is recommended for tools to adopt using a Map instead of Array going forward.
redeemers =
  [ + [ tag: redeemer_tag, index: uint, data: plutus_data, ex_units: ex_units ] ]
  / { + [ tag: redeemer_tag, index: uint ] => [ data: plutus_data, ex_units: ex_units ] }

redeemer_tag =
    0 ; Spending
  / 1 ; Minting
  / 2 ; Certifying
  / 3 ; Rewarding
  / 4 ; Voting
  / 5 ; Proposing

ex_units = [mem: uint, steps: uint]

ex_unit_prices =
  [ mem_price: nonnegative_interval, step_price: nonnegative_interval ]

language = 0 ; Plutus v1
         / 1 ; Plutus v2
         / 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 : [ 233* int ] ; Plutus v3, only 233 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 ; Shelley
  / [ 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
     ; Timelock validity intervals are half-open intervals [a, b).
     ; This field specifies the left (included) endpoint a.
  // invalid_hereafter
     ; Timelock validity intervals are half-open intervals [a, b).
     ; This field specifies the right (excluded) endpoint b.
  ]

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 ]