diff --git a/pallas-network/src/miniprotocols/blockfetch/client.rs b/pallas-network/src/miniprotocols/blockfetch/client.rs index 11b8c89..abaff77 100644 --- a/pallas-network/src/miniprotocols/blockfetch/client.rs +++ b/pallas-network/src/miniprotocols/blockfetch/client.rs @@ -1,5 +1,5 @@ use thiserror::Error; -use tracing::{debug, info, warn}; +use tracing::{debug, warn}; use crate::miniprotocols::common::Point; use crate::multiplexer; @@ -138,7 +138,7 @@ impl Client { pub async fn recv_while_busy(&mut self) -> Result { match self.recv_message().await? { Message::StartBatch => { - info!("batch start"); + debug!("batch start"); self.0 = State::Streaming; Ok(Some(())) } diff --git a/pallas-primitives/src/babbage/model.rs b/pallas-primitives/src/babbage/model.rs index 2cf4946..959243a 100644 --- a/pallas-primitives/src/babbage/model.rs +++ b/pallas-primitives/src/babbage/model.rs @@ -1,4 +1,4 @@ -//! Ledger primitives and cbor codec for the Alonzo era +//! Ledger primitives and cbor codec for the Babbage era //! //! Handcrafted, idiomatic rust artifacts based on based on the [Babbage CDDL](https://github.com/input-output-hk/cardano-ledger/blob/master/eras/babbage/test-suite/cddl-files/babbage.cddl) file in IOHK repo. diff --git a/pallas-primitives/src/conway/defs.cddl b/pallas-primitives/src/conway/defs.cddl new file mode 100644 index 0000000..5fd38a6 --- /dev/null +++ b/pallas-primitives/src/conway/defs.cddl @@ -0,0 +1,594 @@ +; fetched 11 sep 2023 + +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 ; inputs + , 1 : [* transaction_output] + , 2 : coin ; fee + , ? 3 : uint ; time to live + , ? 4 : [+ certificate] + , ? 5 : withdrawals + , ? 7 : auxiliary_data_hash + , ? 8 : uint ; validity interval start + , ? 9 : mint + , ? 11 : script_data_hash + , ? 13 : nonempty_set ; collateral inputs + , ? 14 : required_signers + , ? 15 : network_id + , ? 16 : transaction_output ; collateral return + , ? 17 : coin ; total collateral + , ? 18 : nonempty_set ; reference inputs + , ? 19 : voting_procedures ; New; Voting procedures + , ? 20 : [+ proposal_procedure] ; 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 + ] + +gov_action = + [ parameter_change_action + // hard_fork_initiation_action + // treasury_withdrawals_action + // no_confidence + // new_committee + // new_constitution + // info_action + ] + +parameter_change_action = (0, gov_action_id / null, protocol_param_update) + +hard_fork_initiation_action = (1, gov_action_id / null, [protocol_version]) + +treasury_withdrawals_action = (2, { $reward_account => coin }) + +no_confidence = (3, gov_action_id / null) + +new_committee = (4, gov_action_id / null, set<$committee_cold_credential>, committee) + +new_constitution = (5, gov_action_id / null, constitution) + +committee = [{ $committee_cold_credential => epoch }, unit_interval] + +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) +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 + , relays: [* relay] + , pool_metadata: pool_metadata / null + ) + +port = uint .le 65535 +ipv4 = bytes .size 4 +ipv6 = bytes .size 16 +dns_name = tstr .size (0..64) + +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..64) + +withdrawals = { + reward_account => coin } + +protocol_param_update = + { ? 0: uint ; minfee A + , ? 1: uint ; 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: rational ; 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: uint ; 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 + ] + +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: [* vkeywitness ] + , ? 1: [* native_script ] + , ? 2: [* bootstrap_witness ] + , ? 3: [* plutus_v1_script ] + , ? 4: [* plutus_data ] + , ? 5: [* redeemer ] + , ? 6: [* plutus_v2_script ] + , ? 7: [* plutus_v3_script ] + } + +plutus_v1_script = bytes +plutus_v2_script = bytes +plutus_v3_script = bytes + +plutus_data = + constr + / { * 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 = + #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]]) + +redeemer = [ tag: redeemer_tag, index: uint, data: plutus_data, ex_units: ex_units ] +redeemer_tag = + 0 ; inputTag "Spend" + / 1 ; mintTag "Mint" + / 2 ; certTag "Cert" + / 3 ; wdrlTag "Reward" + ; TODO / 4 ; drepTag "DRep" +ex_units = [mem: uint, steps: uint] + +ex_unit_prices = + [ mem_price: sub_coin, step_price: sub_coin ] + +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. +; +; To construct valid cost models, however, you must restrict to: +; +; { ? 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 : [ 179* int ] ; Plutus v3, only 179 integers are used, but more are accepted (and ignored) +; } +costmdls = { * potential_languages => [int] } + +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 + +sub_coin = positive_interval + +multiasset = { + 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 = positive_coin / [positive_coin,multiasset] + +mint = multiasset + +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 ] \ No newline at end of file diff --git a/pallas-primitives/src/conway/mod.rs b/pallas-primitives/src/conway/mod.rs new file mode 100644 index 0000000..4a7ebf6 --- /dev/null +++ b/pallas-primitives/src/conway/mod.rs @@ -0,0 +1,3 @@ +mod model; + +pub use model::*; diff --git a/pallas-primitives/src/conway/model.rs b/pallas-primitives/src/conway/model.rs new file mode 100644 index 0000000..cef2a31 --- /dev/null +++ b/pallas-primitives/src/conway/model.rs @@ -0,0 +1,1579 @@ +//! Ledger primitives and cbor codec for the Conway era +//! +//! Handcrafted, idiomatic rust artifacts based on based on the [Conway CDDL](https://github.com/input-output-hk/cardano-ledger/blob/master/eras/conway/test-suite/cddl-files/conway.cddl) file in IOHK repo. + +use serde::{Deserialize, Serialize}; + +use pallas_codec::minicbor::{Decode, Encode}; +use pallas_crypto::hash::Hash; + +use pallas_codec::utils::{Bytes, CborWrap, KeepRaw, KeyValuePairs, MaybeIndefArray, Nullable}; + +// required for derive attrs to work +use pallas_codec::minicbor; + +pub use crate::alonzo::VrfCert; + +pub use crate::babbage::HeaderBody; + +pub use crate::babbage::OperationalCert; + +pub use crate::alonzo::ProtocolVersion; + +pub use crate::alonzo::KesSignature; + +pub use crate::babbage::Header; + +pub use crate::alonzo::TransactionInput; + +pub use crate::alonzo::NonceVariant; + +pub use crate::alonzo::Nonce; + +pub use crate::alonzo::ScriptHash; + +pub use crate::alonzo::PolicyId; + +pub use crate::alonzo::AssetName; + +pub use crate::alonzo::Multiasset; + +pub use crate::alonzo::Mint; + +pub use crate::alonzo::Coin; + +pub use crate::alonzo::Value; + +pub use crate::alonzo::TransactionOutput as LegacyTransactionOutput; + +pub use crate::alonzo::PoolKeyhash; + +pub use crate::alonzo::Epoch; + +pub use crate::alonzo::Genesishash; + +pub use crate::alonzo::GenesisDelegateHash; + +pub use crate::alonzo::VrfKeyhash; + +pub use crate::alonzo::InstantaneousRewardSource; + +pub use crate::alonzo::InstantaneousRewardTarget; + +pub use crate::alonzo::MoveInstantaneousReward; + +pub use crate::alonzo::RewardAccount; + +pub type Withdrawals = KeyValuePairs; + +pub type RequiredSigners = Vec; + +pub use crate::alonzo::Port; + +pub use crate::alonzo::IPv4; + +pub use crate::alonzo::IPv6; + +pub use crate::alonzo::DnsName; + +pub use crate::alonzo::Relay; + +pub use crate::alonzo::PoolMetadataHash; + +pub use crate::alonzo::PoolMetadata; + +pub use crate::alonzo::AddrKeyhash; + +pub use crate::alonzo::Scripthash; + +pub use crate::alonzo::RationalNumber; + +pub use crate::alonzo::UnitInterval; + +pub use crate::alonzo::PositiveInterval; + +pub use crate::alonzo::StakeCredential; + +#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] +pub enum Certificate { + StakeRegistration(StakeCredential), + StakeDeregistration(StakeCredential), + StakeDelegation(StakeCredential, PoolKeyhash), + PoolRegistration { + operator: PoolKeyhash, + vrf_keyhash: VrfKeyhash, + pledge: Coin, + cost: Coin, + margin: UnitInterval, + reward_account: RewardAccount, + pool_owners: Vec, + relays: Vec, + pool_metadata: Option, + }, + PoolRetirement(PoolKeyhash, Epoch), + + Reg(StakeCredential, Coin), + UnReg(StakeCredential, Coin), + VoteDeleg(StakeCredential, DRep), + StakeVoteDeleg(StakeCredential, PoolKeyhash, DRep), + StakeRegDeleg(StakeCredential, PoolKeyhash, Coin), + VoteRegDeleg(StakeCredential, DRep, Coin), + StakeVoteRegDeleg(StakeCredential, PoolKeyhash, DRep, Coin), + + AuthCommitteeHot(CommitteeColdCredential, CommitteeHotCredential), + ResignCommitteeCold(CommitteeColdCredential), + RegDRepCert(DRepCredential, Coin, Option), + UnRegDRepCert(DRepCredential, Coin), + UpdateDRepCert(StakeCredential, Option), +} + +impl<'b, C> minicbor::decode::Decode<'b, C> for Certificate { + fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result { + d.array()?; + let variant = d.u16()?; + + match variant { + 0 => { + let a = d.decode_with(ctx)?; + Ok(Certificate::StakeRegistration(a)) + } + 1 => { + let a = d.decode_with(ctx)?; + Ok(Certificate::StakeDeregistration(a)) + } + 2 => { + let a = d.decode_with(ctx)?; + let b = d.decode_with(ctx)?; + Ok(Certificate::StakeDelegation(a, b)) + } + 3 => { + let operator = d.decode_with(ctx)?; + let vrf_keyhash = d.decode_with(ctx)?; + let pledge = d.decode_with(ctx)?; + let cost = d.decode_with(ctx)?; + let margin = d.decode_with(ctx)?; + let reward_account = d.decode_with(ctx)?; + let pool_owners = d.decode_with(ctx)?; + let relays = d.decode_with(ctx)?; + let pool_metadata = d.decode_with(ctx)?; + + Ok(Certificate::PoolRegistration { + operator, + vrf_keyhash, + pledge, + cost, + margin, + reward_account, + pool_owners, + relays, + pool_metadata, + }) + } + 4 => { + let a = d.decode_with(ctx)?; + let b = d.decode_with(ctx)?; + Ok(Certificate::PoolRetirement(a, b)) + } + + 7 => { + let a = d.decode_with(ctx)?; + let b = d.decode_with(ctx)?; + Ok(Certificate::Reg(a, b)) + } + 8 => { + let a = d.decode_with(ctx)?; + let b = d.decode_with(ctx)?; + Ok(Certificate::UnReg(a, b)) + } + 9 => { + let a = d.decode_with(ctx)?; + let b = d.decode_with(ctx)?; + Ok(Certificate::VoteDeleg(a, b)) + } + 10 => { + let a = d.decode_with(ctx)?; + let b = d.decode_with(ctx)?; + let c = d.decode_with(ctx)?; + Ok(Certificate::StakeVoteDeleg(a, b, c)) + } + 11 => { + let a = d.decode_with(ctx)?; + let b = d.decode_with(ctx)?; + let c = d.decode_with(ctx)?; + Ok(Certificate::StakeRegDeleg(a, b, c)) + } + 12 => { + let a = d.decode_with(ctx)?; + let b = d.decode_with(ctx)?; + let c = d.decode_with(ctx)?; + Ok(Certificate::VoteRegDeleg(a, b, c)) + } + 13 => { + let a = d.decode_with(ctx)?; + let b = d.decode_with(ctx)?; + let c = d.decode_with(ctx)?; + let d = d.decode_with(ctx)?; + Ok(Certificate::StakeVoteRegDeleg(a, b, c, d)) + } + 14 => { + let a = d.decode_with(ctx)?; + let b = d.decode_with(ctx)?; + Ok(Certificate::AuthCommitteeHot(a, b)) + } + 15 => { + let a = d.decode_with(ctx)?; + Ok(Certificate::ResignCommitteeCold(a)) + } + 16 => { + let a = d.decode_with(ctx)?; + let b = d.decode_with(ctx)?; + let c = d.decode_with(ctx)?; + Ok(Certificate::RegDRepCert(a, b, c)) + } + 17 => { + let a = d.decode_with(ctx)?; + let b = d.decode_with(ctx)?; + Ok(Certificate::UnRegDRepCert(a, b)) + } + 18 => { + let a = d.decode_with(ctx)?; + let b = d.decode_with(ctx)?; + Ok(Certificate::UpdateDRepCert(a, b)) + } + _ => Err(minicbor::decode::Error::message( + "unknown variant id for certificate", + )), + } + } +} + +impl minicbor::encode::Encode for Certificate { + fn encode( + &self, + e: &mut minicbor::Encoder, + ctx: &mut C, + ) -> Result<(), minicbor::encode::Error> { + match self { + Certificate::StakeRegistration(a) => { + e.array(2)?; + e.u16(0)?; + e.encode_with(a, ctx)?; + } + Certificate::StakeDeregistration(a) => { + e.array(2)?; + e.u16(1)?; + e.encode_with(a, ctx)?; + } + Certificate::StakeDelegation(a, b) => { + e.array(3)?; + e.u16(2)?; + e.encode_with(a, ctx)?; + e.encode_with(b, ctx)?; + } + Certificate::PoolRegistration { + operator, + vrf_keyhash, + pledge, + cost, + margin, + reward_account, + pool_owners, + relays, + pool_metadata, + } => { + e.array(10)?; + e.u16(3)?; + + e.encode_with(operator, ctx)?; + e.encode_with(vrf_keyhash, ctx)?; + e.encode_with(pledge, ctx)?; + e.encode_with(cost, ctx)?; + e.encode_with(margin, ctx)?; + e.encode_with(reward_account, ctx)?; + e.encode_with(pool_owners, ctx)?; + e.encode_with(relays, ctx)?; + e.encode_with(pool_metadata, ctx)?; + } + Certificate::PoolRetirement(a, b) => { + e.array(3)?; + e.u16(4)?; + e.encode_with(a, ctx)?; + e.encode_with(b, ctx)?; + } + // 5 and 6 removed in conway + Certificate::Reg(a, b) => { + e.array(3)?; + e.u16(7)?; + e.encode_with(a, ctx)?; + e.encode_with(b, ctx)?; + } + Certificate::UnReg(a, b) => { + e.array(3)?; + e.u16(8)?; + e.encode_with(a, ctx)?; + e.encode_with(b, ctx)?; + } + Certificate::VoteDeleg(a, b) => { + e.array(3)?; + e.u16(9)?; + e.encode_with(a, ctx)?; + e.encode_with(b, ctx)?; + } + Certificate::StakeVoteDeleg(a, b, c) => { + e.array(4)?; + e.u16(10)?; + e.encode_with(a, ctx)?; + e.encode_with(b, ctx)?; + e.encode_with(c, ctx)?; + } + Certificate::StakeRegDeleg(a, b, c) => { + e.array(4)?; + e.u16(11)?; + e.encode_with(a, ctx)?; + e.encode_with(b, ctx)?; + e.encode_with(c, ctx)?; + } + Certificate::VoteRegDeleg(a, b, c) => { + e.array(4)?; + e.u16(12)?; + e.encode_with(a, ctx)?; + e.encode_with(b, ctx)?; + e.encode_with(c, ctx)?; + } + Certificate::StakeVoteRegDeleg(a, b, c, d) => { + e.array(5)?; + e.u16(13)?; + e.encode_with(a, ctx)?; + e.encode_with(b, ctx)?; + e.encode_with(c, ctx)?; + e.encode_with(d, ctx)?; + } + Certificate::AuthCommitteeHot(a, b) => { + e.array(3)?; + e.u16(14)?; + e.encode_with(a, ctx)?; + e.encode_with(b, ctx)?; + } + Certificate::ResignCommitteeCold(a) => { + e.array(2)?; + e.u16(15)?; + e.encode_with(a, ctx)?; + } + Certificate::RegDRepCert(a, b, c) => { + e.array(4)?; + e.u16(16)?; + e.encode_with(a, ctx)?; + e.encode_with(b, ctx)?; + e.encode_with(c, ctx)?; + } + Certificate::UnRegDRepCert(a, b) => { + e.array(3)?; + e.u16(17)?; + e.encode_with(a, ctx)?; + e.encode_with(b, ctx)?; + } + Certificate::UpdateDRepCert(a, b) => { + e.array(3)?; + e.u16(18)?; + e.encode_with(a, ctx)?; + e.encode_with(b, ctx)?; + } + } + + Ok(()) + } +} + +#[derive(Serialize, Deserialize, Debug, PartialEq, PartialOrd, Eq, Ord, Clone)] +pub enum DRep { + Key(AddrKeyhash), + Script(Scripthash), + Abstain, + NoConfidence, +} + +impl<'b, C> minicbor::decode::Decode<'b, C> for DRep { + fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result { + d.array()?; + let variant = d.u16()?; + + match variant { + 0 => Ok(DRep::Key(d.decode_with(ctx)?)), + 1 => Ok(DRep::Script(d.decode_with(ctx)?)), + 2 => Ok(DRep::Abstain), + 3 => Ok(DRep::NoConfidence), + _ => Err(minicbor::decode::Error::message( + "invalid variant id for DRep", + )), + } + } +} + +impl minicbor::encode::Encode for DRep { + fn encode( + &self, + e: &mut minicbor::Encoder, + ctx: &mut C, + ) -> Result<(), minicbor::encode::Error> { + match self { + DRep::Key(h) => { + e.array(2)?; + e.encode_with(0, ctx)?; + e.encode_with(h, ctx)?; + + Ok(()) + } + DRep::Script(h) => { + e.array(2)?; + e.encode_with(1, ctx)?; + e.encode_with(h, ctx)?; + + Ok(()) + } + DRep::Abstain => { + e.array(1)?; + e.encode_with(2, ctx)?; + + Ok(()) + } + DRep::NoConfidence => { + e.array(1)?; + e.encode_with(3, ctx)?; + + Ok(()) + } + } + } +} + +pub type DRepCredential = StakeCredential; + +pub type CommitteeColdCredential = StakeCredential; + +pub type CommitteeHotCredential = StakeCredential; + +pub use crate::alonzo::NetworkId; + +#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)] +#[cbor(index_only)] +pub enum Language { + #[n(0)] + PlutusV1, + + #[n(1)] + PlutusV2, + + #[n(2)] + PlutusV3, +} + +pub use crate::alonzo::CostModel; + +#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)] +#[cbor(map)] +pub struct CostMdls { + #[n(0)] + pub plutus_v1: Option, + + #[n(1)] + pub plutus_v2: Option, + + #[n(2)] + pub plutus_v3: Option, +} + +#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)] +#[cbor(map)] +pub struct ProtocolParamUpdate { + #[n(0)] + pub minfee_a: Option, + #[n(1)] + pub minfee_b: Option, + #[n(2)] + pub max_block_body_size: Option, + #[n(3)] + pub max_transaction_size: Option, + #[n(4)] + pub max_block_header_size: Option, + #[n(5)] + pub key_deposit: Option, + #[n(6)] + pub pool_deposit: Option, + #[n(7)] + pub maximum_epoch: Option, + #[n(8)] + pub desired_number_of_stake_pools: Option, + #[n(9)] + pub pool_pledge_influence: Option, + #[n(10)] + pub expansion_rate: Option, + #[n(11)] + pub treasury_growth_rate: Option, + + #[n(16)] + pub min_pool_cost: Option, + #[n(17)] + pub ada_per_utxo_byte: Option, + #[n(18)] + pub cost_models_for_script_languages: Option, + #[n(19)] + pub execution_costs: Option, + #[n(20)] + pub max_tx_ex_units: Option, + #[n(21)] + pub max_block_ex_units: Option, + #[n(22)] + pub max_value_size: Option, + #[n(23)] + pub collateral_percentage: Option, + #[n(24)] + pub max_collateral_inputs: Option, + + #[n(25)] + pub pool_voting_thresholds: Option, + #[n(26)] + pub drep_voting_thresholds: Option, + #[n(27)] + pub min_committee_size: Option, + #[n(28)] + pub committee_term_limit: Option, + #[n(29)] + pub governance_action_validity_period: Option, + #[n(30)] + pub governance_action_deposit: Option, + #[n(31)] + pub drep_deposit: Option, + #[n(32)] + pub drep_inactivity_period: Option, +} + +#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] +pub struct PoolVotingThresholds { + pub motion_no_confidence: UnitInterval, + pub committee_normal: UnitInterval, + pub committee_no_confidence: UnitInterval, + pub hard_fork_initiation: UnitInterval, +} + +impl<'b, C> minicbor::Decode<'b, C> for PoolVotingThresholds { + fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result { + d.array()?; + + Ok(Self { + motion_no_confidence: d.decode_with(ctx)?, + committee_normal: d.decode_with(ctx)?, + committee_no_confidence: d.decode_with(ctx)?, + hard_fork_initiation: d.decode_with(ctx)?, + }) + } +} + +impl minicbor::Encode for PoolVotingThresholds { + fn encode( + &self, + e: &mut minicbor::Encoder, + ctx: &mut C, + ) -> Result<(), minicbor::encode::Error> { + e.array(4)?; + + e.encode_with(&self.motion_no_confidence, ctx)?; + e.encode_with(&self.committee_normal, ctx)?; + e.encode_with(&self.committee_no_confidence, ctx)?; + e.encode_with(&self.hard_fork_initiation, ctx)?; + + Ok(()) + } +} + +#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] +pub struct DRepVotingThresholds { + pub motion_no_confidence: UnitInterval, + pub committee_normal: UnitInterval, + pub committee_no_confidence: UnitInterval, + pub update_constitution: UnitInterval, + pub hard_fork_initiation: UnitInterval, + pub pp_network_group: UnitInterval, + pub pp_economic_group: UnitInterval, + pub pp_technical_group: UnitInterval, + pub pp_governance_group: UnitInterval, + pub treasury_withdrawal: UnitInterval, +} + +impl<'b, C> minicbor::Decode<'b, C> for DRepVotingThresholds { + fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result { + d.array()?; + + Ok(Self { + motion_no_confidence: d.decode_with(ctx)?, + committee_normal: d.decode_with(ctx)?, + committee_no_confidence: d.decode_with(ctx)?, + update_constitution: d.decode_with(ctx)?, + hard_fork_initiation: d.decode_with(ctx)?, + pp_network_group: d.decode_with(ctx)?, + pp_economic_group: d.decode_with(ctx)?, + pp_technical_group: d.decode_with(ctx)?, + pp_governance_group: d.decode_with(ctx)?, + treasury_withdrawal: d.decode_with(ctx)?, + }) + } +} + +impl minicbor::Encode for DRepVotingThresholds { + fn encode( + &self, + e: &mut minicbor::Encoder, + ctx: &mut C, + ) -> Result<(), minicbor::encode::Error> { + e.array(10)?; + + e.encode_with(&self.motion_no_confidence, ctx)?; + e.encode_with(&self.committee_normal, ctx)?; + e.encode_with(&self.committee_no_confidence, ctx)?; + e.encode_with(&self.update_constitution, ctx)?; + e.encode_with(&self.hard_fork_initiation, ctx)?; + e.encode_with(&self.pp_network_group, ctx)?; + e.encode_with(&self.pp_economic_group, ctx)?; + e.encode_with(&self.pp_technical_group, ctx)?; + e.encode_with(&self.pp_governance_group, ctx)?; + e.encode_with(&self.treasury_withdrawal, ctx)?; + + Ok(()) + } +} + +#[derive(Encode, Decode, Debug, PartialEq, Clone)] +#[cbor(map)] +pub struct PseudoTransactionBody { + #[n(0)] + pub inputs: Vec, + + #[n(1)] + pub outputs: Vec, + + #[n(2)] + pub fee: Coin, + + #[n(3)] + pub ttl: Option, + + #[n(4)] + pub certificates: Option>, // TODO: NON EMPTY + + #[n(5)] + pub withdrawals: Option>, // TODO: NON EMPTY + + // #[n(6)] + // pub update: Option, + #[n(7)] + pub auxiliary_data_hash: Option, + + #[n(8)] + pub validity_interval_start: Option, + + #[n(9)] + pub mint: Option>, // TODO: MULTI ASSET NON EMPTY + + #[n(11)] + pub script_data_hash: Option>, + + #[n(13)] + pub collateral: Option>, // TODO: NON EMPTY SET + + #[n(14)] + pub required_signers: Option>, // TODO: NON EMPTY SET + + #[n(15)] + pub network_id: Option, + + #[n(16)] + pub collateral_return: Option, + + #[n(17)] + pub total_collateral: Option, + + #[n(18)] + pub reference_inputs: Option>, // TODO: NON EMPTY SET + + // -- NEW IN CONWAY + #[n(19)] + pub voting_procedures: Option, + + #[n(20)] + pub proposal_procedures: Option>, // TODO: NON EMPTY MAP + + #[n(21)] + pub treasury_value: Option, + + #[n(22)] + pub donation: Option, // TODO: NON ZERO (POSITIVE COIN) +} + +pub type TransactionBody = PseudoTransactionBody; + +pub type MintedTransactionBody<'a> = PseudoTransactionBody>; + +impl<'a> From> for TransactionBody { + fn from(value: MintedTransactionBody<'a>) -> Self { + Self { + inputs: value.inputs, + outputs: value.outputs.into_iter().map(|x| x.into()).collect(), + fee: value.fee, + ttl: value.ttl, + certificates: value.certificates, + withdrawals: value.withdrawals, + auxiliary_data_hash: value.auxiliary_data_hash, + validity_interval_start: value.validity_interval_start, + mint: value.mint, + script_data_hash: value.script_data_hash, + collateral: value.collateral, + required_signers: value.required_signers, + network_id: value.network_id, + collateral_return: value.collateral_return.map(|x| x.into()), + total_collateral: value.total_collateral, + reference_inputs: value.reference_inputs, + voting_procedures: value.voting_procedures, + proposal_procedures: value.proposal_procedures, + treasury_value: value.treasury_value, + donation: value.donation, + } + } +} + +#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] +pub enum Vote { + No, + Yes, + Abstain, +} + +impl<'b, C> minicbor::Decode<'b, C> for Vote { + fn decode( + d: &mut minicbor::Decoder<'b>, + _ctx: &mut C, + ) -> Result { + match d.u8()? { + 0 => Ok(Self::No), + 1 => Ok(Self::Yes), + 2 => Ok(Self::Abstain), + _ => Err(minicbor::decode::Error::message( + "invalid number for Vote kind", + )), + } + } +} + +impl minicbor::Encode for Vote { + fn encode( + &self, + e: &mut minicbor::Encoder, + _ctx: &mut C, + ) -> Result<(), minicbor::encode::Error> { + match &self { + Self::No => e.u8(0)?, + Self::Yes => e.u8(1)?, + Self::Abstain => e.u8(2)?, + }; + + Ok(()) + } +} + +pub type VotingProcedures = KeyValuePairs>; + +#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] +pub struct VotingProcedure { + pub vote: Vote, + pub anchor: Option, +} + +impl<'b, C> minicbor::Decode<'b, C> for VotingProcedure { + fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result { + d.array()?; + + Ok(Self { + vote: d.decode_with(ctx)?, + anchor: d.decode_with(ctx)?, + }) + } +} + +impl minicbor::Encode for VotingProcedure { + fn encode( + &self, + e: &mut minicbor::Encoder, + ctx: &mut C, + ) -> Result<(), minicbor::encode::Error> { + e.array(2)?; + + e.encode_with(&self.vote, ctx)?; + e.encode_with(&self.anchor, ctx)?; + + Ok(()) + } +} + +#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] +pub struct ProposalProcedure { + pub deposit: Coin, + pub reward_account: RewardAccount, + pub gov_action: GovAction, + pub anchor: Anchor, +} + +impl<'b, C> minicbor::Decode<'b, C> for ProposalProcedure { + fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result { + d.array()?; + + Ok(Self { + deposit: d.decode_with(ctx)?, + reward_account: d.decode_with(ctx)?, + gov_action: d.decode_with(ctx)?, + anchor: d.decode_with(ctx)?, + }) + } +} + +impl minicbor::Encode for ProposalProcedure { + fn encode( + &self, + e: &mut minicbor::Encoder, + ctx: &mut C, + ) -> Result<(), minicbor::encode::Error> { + e.array(4)?; + + e.encode_with(&self.deposit, ctx)?; + e.encode_with(&self.reward_account, ctx)?; + e.encode_with(&self.gov_action, ctx)?; + e.encode_with(&self.anchor, ctx)?; + + Ok(()) + } +} + +#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] +pub enum GovAction { + ParameterChange(Option, ProtocolParamUpdate), + HardForkInitiation(Option, Vec), + TreasuryWithdrawals(KeyValuePairs), + NoConfidence(Option), + UpdateCommittee( + Option, + Vec, + KeyValuePairs, + UnitInterval, + ), + NewConstitution(Option, Constitution), + Information, +} + +impl<'b, C> minicbor::decode::Decode<'b, C> for GovAction { + fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result { + d.array()?; + let variant = d.u16()?; + + match variant { + 0 => { + let a = d.decode_with(ctx)?; + let b = d.decode_with(ctx)?; + Ok(GovAction::ParameterChange(a, b)) + } + 1 => { + let a = d.decode_with(ctx)?; + let b = d.decode_with(ctx)?; + Ok(GovAction::HardForkInitiation(a, b)) + } + 2 => { + let a = d.decode_with(ctx)?; + Ok(GovAction::TreasuryWithdrawals(a)) + } + 3 => { + let a = d.decode_with(ctx)?; + Ok(GovAction::NoConfidence(a)) + } + 4 => { + let a = d.decode_with(ctx)?; + let b = d.decode_with(ctx)?; + let c = d.decode_with(ctx)?; + let d = d.decode_with(ctx)?; + Ok(GovAction::UpdateCommittee(a, b, c, d)) + } + 5 => { + let a = d.decode_with(ctx)?; + let b = d.decode_with(ctx)?; + Ok(GovAction::NewConstitution(a, b)) + } + 6 => Ok(GovAction::Information), + _ => Err(minicbor::decode::Error::message( + "unknown variant id for certificate", + )), + } + } +} + +impl minicbor::encode::Encode for GovAction { + fn encode( + &self, + e: &mut minicbor::Encoder, + ctx: &mut C, + ) -> Result<(), minicbor::encode::Error> { + match self { + GovAction::ParameterChange(a, b) => { + e.array(3)?; + e.u16(0)?; + e.encode_with(a, ctx)?; + e.encode_with(b, ctx)?; + } + GovAction::HardForkInitiation(a, b) => { + e.array(3)?; + e.u16(1)?; + e.encode_with(a, ctx)?; + e.encode_with(b, ctx)?; + } + GovAction::TreasuryWithdrawals(a) => { + e.array(2)?; + e.u16(2)?; + e.encode_with(a, ctx)?; + } + GovAction::NoConfidence(a) => { + e.array(2)?; + e.u16(3)?; + e.encode_with(a, ctx)?; + } + GovAction::UpdateCommittee(a, b, c, d) => { + e.array(5)?; + e.u16(4)?; + e.encode_with(a, ctx)?; + e.encode_with(b, ctx)?; + e.encode_with(c, ctx)?; + e.encode_with(d, ctx)?; + } + GovAction::NewConstitution(a, b) => { + e.array(3)?; + e.u16(5)?; + e.encode_with(a, ctx)?; + e.encode_with(b, ctx)?; + } + // TODO: CDDL SAYS JUST "6", no group (array) + GovAction::Information => { + e.array(1)?; + e.u16(6)?; + } + } + + Ok(()) + } +} + +#[derive(Serialize, Deserialize, Debug, PartialEq, PartialOrd, Eq, Ord, Clone)] +pub struct Constitution(Anchor, Option); + +impl<'b, C> minicbor::Decode<'b, C> for Constitution { + fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result { + d.array()?; + + Ok(Self(d.decode_with(ctx)?, d.decode_with(ctx)?)) + } +} + +impl minicbor::Encode for Constitution { + fn encode( + &self, + e: &mut minicbor::Encoder, + ctx: &mut C, + ) -> Result<(), minicbor::encode::Error> { + e.array(2)?; + + e.encode_with(&self.0, ctx)?; + e.encode_with(&self.1, ctx)?; + + Ok(()) + } +} + +#[derive(Serialize, Deserialize, Debug, PartialEq, PartialOrd, Eq, Ord, Clone)] +pub enum Voter { + ConstitutionalCommitteeKey(AddrKeyhash), + ConstitutionalCommitteeScript(ScriptHash), + DRepKey(AddrKeyhash), + DRepScript(ScriptHash), + StakePoolKey(AddrKeyhash), +} + +impl<'b, C> minicbor::decode::Decode<'b, C> for Voter { + fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result { + d.array()?; + let variant = d.u16()?; + + match variant { + 0 => Ok(Voter::ConstitutionalCommitteeKey(d.decode_with(ctx)?)), + 1 => Ok(Voter::ConstitutionalCommitteeScript(d.decode_with(ctx)?)), + 2 => Ok(Voter::DRepKey(d.decode_with(ctx)?)), + 3 => Ok(Voter::DRepScript(d.decode_with(ctx)?)), + 4 => Ok(Voter::StakePoolKey(d.decode_with(ctx)?)), + _ => Err(minicbor::decode::Error::message( + "invalid variant id for DRep", + )), + } + } +} + +impl minicbor::encode::Encode for Voter { + fn encode( + &self, + e: &mut minicbor::Encoder, + ctx: &mut C, + ) -> Result<(), minicbor::encode::Error> { + e.array(2)?; + + match self { + Voter::ConstitutionalCommitteeKey(h) => { + e.encode_with(0, ctx)?; + e.encode_with(h, ctx)?; + + Ok(()) + } + Voter::ConstitutionalCommitteeScript(h) => { + e.encode_with(1, ctx)?; + e.encode_with(h, ctx)?; + + Ok(()) + } + Voter::DRepKey(h) => { + e.encode_with(2, ctx)?; + e.encode_with(h, ctx)?; + + Ok(()) + } + Voter::DRepScript(h) => { + e.encode_with(3, ctx)?; + e.encode_with(h, ctx)?; + + Ok(()) + } + Voter::StakePoolKey(h) => { + e.encode_with(4, ctx)?; + e.encode_with(h, ctx)?; + + Ok(()) + } + } + } +} + +#[derive(Serialize, Deserialize, Debug, PartialEq, PartialOrd, Eq, Ord, Clone)] +pub struct Anchor(String, Hash<32>); + +impl<'b, C> minicbor::Decode<'b, C> for Anchor { + fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result { + d.array()?; + + Ok(Self(d.decode_with(ctx)?, d.decode_with(ctx)?)) + } +} + +impl minicbor::Encode for Anchor { + fn encode( + &self, + e: &mut minicbor::Encoder, + ctx: &mut C, + ) -> Result<(), minicbor::encode::Error> { + e.array(2)?; + + e.encode_with(&self.0, ctx)?; + e.encode_with(&self.1, ctx)?; + + Ok(()) + } +} + +#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] +pub struct GovActionId(Hash<32>, u32); + +impl<'b, C> minicbor::Decode<'b, C> for GovActionId { + fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result { + d.array()?; + + Ok(Self(d.decode_with(ctx)?, d.decode_with(ctx)?)) + } +} + +impl minicbor::Encode for GovActionId { + fn encode( + &self, + e: &mut minicbor::Encoder, + ctx: &mut C, + ) -> Result<(), minicbor::encode::Error> { + e.array(2)?; + + e.encode_with(&self.0, ctx)?; + e.encode_with(&self.1, ctx)?; + + Ok(()) + } +} + +#[derive(Debug, PartialEq, Clone)] +pub enum PseudoTransactionOutput { + Legacy(LegacyTransactionOutput), + PostAlonzo(T), +} + +impl<'b, C, T> minicbor::Decode<'b, C> for PseudoTransactionOutput +where + T: minicbor::Decode<'b, C>, +{ + fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result { + match d.datatype()? { + minicbor::data::Type::Array | minicbor::data::Type::ArrayIndef => { + Ok(PseudoTransactionOutput::Legacy(d.decode_with(ctx)?)) + } + minicbor::data::Type::Map | minicbor::data::Type::MapIndef => { + Ok(PseudoTransactionOutput::PostAlonzo(d.decode_with(ctx)?)) + } + _ => Err(minicbor::decode::Error::message( + "invalid type for transaction output struct", + )), + } + } +} + +impl minicbor::Encode for PseudoTransactionOutput +where + T: minicbor::Encode, +{ + fn encode( + &self, + e: &mut minicbor::Encoder, + ctx: &mut C, + ) -> Result<(), minicbor::encode::Error> { + match self { + PseudoTransactionOutput::Legacy(x) => x.encode(e, ctx), + PseudoTransactionOutput::PostAlonzo(x) => x.encode(e, ctx), + } + } +} + +pub use crate::babbage::TransactionOutput; + +pub use crate::babbage::MintedTransactionOutput; + +pub use crate::babbage::PseudoPostAlonzoTransactionOutput; + +pub use crate::babbage::PostAlonzoTransactionOutput; + +pub use crate::babbage::MintedPostAlonzoTransactionOutput; + +pub use crate::alonzo::VKeyWitness; + +pub use crate::alonzo::NativeScript; + +pub use crate::alonzo::PlutusScript as PlutusV1Script; + +pub use crate::babbage::PlutusV2Script; + +#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)] +#[cbor(transparent)] +pub struct PlutusV3Script(#[n(0)] pub Bytes); + +impl AsRef<[u8]> for PlutusV3Script { + fn as_ref(&self) -> &[u8] { + self.0.as_slice() + } +} + +pub use crate::alonzo::BigInt; + +pub use crate::alonzo::PlutusData; + +pub use crate::alonzo::Constr; + +pub use crate::alonzo::ExUnits; + +pub use crate::alonzo::ExUnitPrices; + +#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)] +#[cbor(index_only)] +pub enum RedeemerTag { + #[n(0)] + Spend, + #[n(1)] + Mint, + #[n(2)] + Cert, + #[n(3)] + Reward, + #[n(4)] + DRep, + #[n(5)] + VotingProposal, +} + +#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)] +pub struct Redeemer { + #[n(0)] + pub tag: RedeemerTag, + + #[n(1)] + pub index: u32, + + #[n(2)] + pub data: PlutusData, + + #[n(3)] + pub ex_units: ExUnits, +} + +pub use crate::alonzo::BootstrapWitness; + +#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Clone)] +#[cbor(map)] +pub struct WitnessSet { + #[n(0)] + pub vkeywitness: Option>, + + #[n(1)] + pub native_script: Option>, + + #[n(2)] + pub bootstrap_witness: Option>, + + #[n(3)] + pub plutus_v1_script: Option>, + + #[n(4)] + pub plutus_data: Option>, + + #[n(5)] + pub redeemer: Option>, + + #[n(6)] + pub plutus_v2_script: Option>, + + #[n(7)] + pub plutus_v3_script: Option>, +} + +#[derive(Encode, Decode, Debug, PartialEq, Clone)] +#[cbor(map)] +pub struct MintedWitnessSet<'b> { + #[n(0)] + pub vkeywitness: Option>, + + #[n(1)] + pub native_script: Option>, + + #[n(2)] + pub bootstrap_witness: Option>, + + #[n(3)] + pub plutus_v1_script: Option>, + + #[b(4)] + pub plutus_data: Option>>, + + #[n(5)] + pub redeemer: Option>, + + #[n(6)] + pub plutus_v2_script: Option>, + + #[n(7)] + pub plutus_v3_script: Option>, +} + +impl<'b> From> for WitnessSet { + fn from(x: MintedWitnessSet<'b>) -> Self { + WitnessSet { + vkeywitness: x.vkeywitness, + native_script: x.native_script, + bootstrap_witness: x.bootstrap_witness, + plutus_v1_script: x.plutus_v1_script, + plutus_data: x + .plutus_data + .map(|x| x.into_iter().map(|x| x.unwrap()).collect()), + redeemer: x.redeemer, + plutus_v2_script: x.plutus_v2_script, + plutus_v3_script: x.plutus_v3_script, + } + } +} + +#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Clone)] +#[cbor(map)] +pub struct PostAlonzoAuxiliaryData { + #[n(0)] + pub metadata: Option, + + #[n(1)] + pub native_scripts: Option>, + + #[n(2)] + pub plutus_v1_scripts: Option>, + + #[n(3)] + pub plutus_v2_scripts: Option>, + + #[n(4)] + pub plutus_v3_scripts: Option>, +} + +pub type DatumHash = Hash<32>; + +//pub type Data = CborWrap; + +// datum_option = [ 0, $hash32 // 1, data ] +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum PseudoDatumOption { + Hash(Hash<32>), + Data(CborWrap), +} + +impl<'b, C, T> minicbor::Decode<'b, C> for PseudoDatumOption +where + T: minicbor::Decode<'b, C>, +{ + fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result { + d.array()?; + + match d.u8()? { + 0 => Ok(Self::Hash(d.decode_with(ctx)?)), + 1 => Ok(Self::Data(d.decode_with(ctx)?)), + _ => Err(minicbor::decode::Error::message( + "invalid variant for datum option enum", + )), + } + } +} + +impl minicbor::Encode for PseudoDatumOption +where + T: minicbor::Encode, +{ + fn encode( + &self, + e: &mut minicbor::Encoder, + ctx: &mut C, + ) -> Result<(), minicbor::encode::Error> { + match self { + Self::Hash(x) => e.encode_with((0, x), ctx)?, + Self::Data(x) => e.encode_with((1, x), ctx)?, + }; + + Ok(()) + } +} + +pub type DatumOption = PseudoDatumOption; + +pub type MintedDatumOption<'b> = PseudoDatumOption>; + +impl<'b> From> for DatumOption { + fn from(value: MintedDatumOption<'b>) -> Self { + match value { + PseudoDatumOption::Hash(x) => Self::Hash(x), + PseudoDatumOption::Data(x) => Self::Data(CborWrap(x.unwrap().unwrap())), + } + } +} + +// script_ref = #6.24(bytes .cbor script) +pub type ScriptRef = CborWrap