feat: add Conway 2024-03 CDDL conformity (#424)

This commit is contained in:
Harper 2024-04-01 18:02:52 +01:00 committed by GitHub
parent 1a0fc322fa
commit c31e773ce2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 920 additions and 222 deletions

View file

@ -528,7 +528,7 @@ fn check_redeemers(
Some(redeemers) => redeemers
.iter()
.map(|x| RedeemerPointer {
tag: x.tag.clone(),
tag: x.tag,
index: x.index,
})
.collect(),

View file

@ -934,7 +934,7 @@ fn check_redeemers(
Some(redeemers) => redeemers
.iter()
.map(|x| RedeemerPointer {
tag: x.tag.clone(),
tag: x.tag,
index: x.index,
})
.collect(),

View file

@ -158,6 +158,139 @@ where
}
}
/// Custom collection to ensure ordered pairs of values (non-empty)
///
/// Since the ordering of the entries requires a particular order to maintain
/// canonicalization for isomorphic decoding / encoding operators, we use a Vec
/// as the underlaying struct for storage of the items (as opposed to a BTreeMap
/// or HashMap).
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[serde(try_from = "Vec::<(K, V)>", into = "Vec::<(K, V)>")]
pub enum NonEmptyKeyValuePairs<K, V>
where
K: Clone,
V: Clone,
{
Def(Vec<(K, V)>),
Indef(Vec<(K, V)>),
}
impl<K, V> NonEmptyKeyValuePairs<K, V>
where
K: Clone,
V: Clone,
{
pub fn to_vec(self) -> Vec<(K, V)> {
self.into()
}
}
impl<K, V> From<NonEmptyKeyValuePairs<K, V>> for Vec<(K, V)>
where
K: Clone,
V: Clone,
{
fn from(other: NonEmptyKeyValuePairs<K, V>) -> Self {
match other {
NonEmptyKeyValuePairs::Def(x) => x,
NonEmptyKeyValuePairs::Indef(x) => x,
}
}
}
impl<K, V> TryFrom<Vec<(K, V)>> for NonEmptyKeyValuePairs<K, V>
where
K: Clone,
V: Clone,
{
type Error = String;
fn try_from(value: Vec<(K, V)>) -> Result<Self, Self::Error> {
if value.is_empty() {
Err("NonEmptyKeyValuePairs must contain at least one element".into())
} else {
Ok(NonEmptyKeyValuePairs::Def(value))
}
}
}
impl<K, V> Deref for NonEmptyKeyValuePairs<K, V>
where
K: Clone,
V: Clone,
{
type Target = Vec<(K, V)>;
fn deref(&self) -> &Self::Target {
match self {
NonEmptyKeyValuePairs::Def(x) => x,
NonEmptyKeyValuePairs::Indef(x) => x,
}
}
}
impl<'b, C, K, V> minicbor::decode::Decode<'b, C> for NonEmptyKeyValuePairs<K, V>
where
K: Decode<'b, C> + Clone,
V: Decode<'b, C> + Clone,
{
fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result<Self, minicbor::decode::Error> {
let datatype = d.datatype()?;
let items: Result<Vec<_>, _> = d.map_iter_with::<C, K, V>(ctx)?.collect();
let items = items?;
if items.is_empty() {
return Err(Error::message(
"decoding empty map as NonEmptyKeyValuePairs",
));
}
match datatype {
minicbor::data::Type::Map => Ok(NonEmptyKeyValuePairs::Def(items)),
minicbor::data::Type::MapIndef => Ok(NonEmptyKeyValuePairs::Indef(items)),
_ => Err(minicbor::decode::Error::message(
"invalid data type for nonemptykeyvaluepairs",
)),
}
}
}
impl<C, K, V> minicbor::encode::Encode<C> for NonEmptyKeyValuePairs<K, V>
where
K: Encode<C> + Clone,
V: Encode<C> + Clone,
{
fn encode<W: minicbor::encode::Write>(
&self,
e: &mut minicbor::Encoder<W>,
ctx: &mut C,
) -> Result<(), minicbor::encode::Error<W::Error>> {
match self {
NonEmptyKeyValuePairs::Def(x) => {
e.map(x.len() as u64)?;
for (k, v) in x.iter() {
k.encode(e, ctx)?;
v.encode(e, ctx)?;
}
}
NonEmptyKeyValuePairs::Indef(x) => {
e.begin_map()?;
for (k, v) in x.iter() {
k.encode(e, ctx)?;
v.encode(e, ctx)?;
}
e.end()?;
}
}
Ok(())
}
}
/// A struct that maintains a reference to whether a cbor array was indef or not
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub enum MaybeIndefArray<A> {
@ -557,6 +690,95 @@ where
}
}
/// Non-empty Set
///
/// Optional 258 tag (until era after Conway, at which point is it required)
/// with a vec of items which should contain no duplicates
#[derive(Debug, PartialEq, Eq, Clone, PartialOrd, Serialize, Deserialize)]
pub struct NonEmptySet<T>(Vec<T>);
impl<T> NonEmptySet<T> {
pub fn to_vec(self) -> Vec<T> {
self.0
}
}
impl<T> Deref for NonEmptySet<T> {
type Target = Vec<T>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T> TryFrom<Vec<T>> for NonEmptySet<T> {
type Error = Vec<T>;
fn try_from(value: Vec<T>) -> Result<Self, Self::Error> {
if value.is_empty() {
Err(value)
} else {
Ok(NonEmptySet(value))
}
}
}
impl<T> From<NonEmptySet<KeepRaw<'_, T>>> for NonEmptySet<T> {
fn from(value: NonEmptySet<KeepRaw<'_, T>>) -> Self {
let inner = value.0.into_iter().map(|x| x.unwrap()).collect();
Self(inner)
}
}
impl<'a, T> IntoIterator for &'a NonEmptySet<T> {
type Item = &'a T;
type IntoIter = std::slice::Iter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter()
}
}
impl<'b, C, T> minicbor::decode::Decode<'b, C> for NonEmptySet<T>
where
T: Decode<'b, C>,
{
fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result<Self, minicbor::decode::Error> {
// decode optional set tag (this will be required in era following Conway)
if d.datatype()? == Type::Tag {
let found_tag = d.tag()?;
if found_tag != Tag::Unassigned(TAG_SET) {
return Err(Error::message(format!("Unrecognised tag: {found_tag:?}")));
}
}
let inner: Vec<T> = d.decode_with(ctx)?;
if inner.is_empty() {
return Err(Error::message("decoding empty set as NonEmptySet"));
}
Ok(Self(inner))
}
}
impl<C, T> minicbor::encode::Encode<C> for NonEmptySet<T>
where
T: Encode<C>,
{
fn encode<W: minicbor::encode::Write>(
&self,
e: &mut minicbor::Encoder<W>,
ctx: &mut C,
) -> Result<(), minicbor::encode::Error<W::Error>> {
e.tag(Tag::Unassigned(TAG_SET))?;
e.encode_with(&self.0, ctx)?;
Ok(())
}
}
/// A uint structure that preserves original int length
#[derive(Debug, PartialEq, Copy, Clone, PartialOrd, Eq, Ord, Hash)]
pub enum AnyUInt {
@ -665,6 +887,110 @@ impl From<&AnyUInt> for u64 {
}
}
/// Introduced in Conway
/// positive_coin = 1 .. 18446744073709551615
#[derive(Debug, PartialEq, Copy, Clone, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)]
#[serde(transparent)]
pub struct PositiveCoin(u64);
impl TryFrom<u64> for PositiveCoin {
type Error = u64;
fn try_from(value: u64) -> Result<Self, Self::Error> {
if value == 0 {
return Err(value);
}
Ok(Self(value))
}
}
impl From<PositiveCoin> for u64 {
fn from(value: PositiveCoin) -> Self {
value.0
}
}
impl<'b, C> minicbor::decode::Decode<'b, C> for PositiveCoin {
fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result<Self, minicbor::decode::Error> {
let n = d.decode_with(ctx)?;
if n == 0 {
return Err(Error::message("decoding 0 as PositiveCoin"));
}
Ok(Self(n))
}
}
impl<C> minicbor::encode::Encode<C> for PositiveCoin {
fn encode<W: minicbor::encode::Write>(
&self,
e: &mut minicbor::Encoder<W>,
_ctx: &mut C,
) -> Result<(), minicbor::encode::Error<W::Error>> {
e.encode(self.0)?;
Ok(())
}
}
/// Introduced in Conway
/// negInt64 = -9223372036854775808 .. -1
/// posInt64 = 1 .. 9223372036854775807
/// nonZeroInt64 = negInt64 / posInt64 ; this is the same as the current int64 definition but without zero
#[derive(Debug, PartialEq, Copy, Clone, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)]
#[serde(transparent)]
pub struct NonZeroInt(i64);
impl TryFrom<i64> for NonZeroInt {
type Error = i64;
fn try_from(value: i64) -> Result<Self, Self::Error> {
if value == 0 {
return Err(value);
}
Ok(Self(value))
}
}
impl From<NonZeroInt> for i64 {
fn from(value: NonZeroInt) -> Self {
value.0
}
}
impl From<&NonZeroInt> for i64 {
fn from(x: &NonZeroInt) -> Self {
i64::from(*x)
}
}
impl<'b, C> minicbor::decode::Decode<'b, C> for NonZeroInt {
fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result<Self, minicbor::decode::Error> {
let n = d.decode_with(ctx)?;
if n == 0 {
return Err(Error::message("decoding 0 as NonZeroInt"));
}
Ok(Self(n))
}
}
impl<C> minicbor::encode::Encode<C> for NonZeroInt {
fn encode<W: minicbor::encode::Write>(
&self,
e: &mut minicbor::Encoder<W>,
_ctx: &mut C,
) -> Result<(), minicbor::encode::Error<W::Error>> {
e.encode(self.0)?;
Ok(())
}
}
/// Decodes a struct while preserving original CBOR
///
/// # Examples
@ -812,7 +1138,7 @@ impl<C> minicbor::Encode<C> for AnyCbor {
}
}
#[derive(Serialize, Deserialize, Clone, Debug)]
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
#[serde(from = "Option::<T>", into = "Option::<T>")]
pub enum Nullable<T>
where

View file

@ -110,7 +110,7 @@ pub struct Nonce {
pub hash: Option<Hash<32>>,
}
pub type ScriptHash = Bytes;
pub type ScriptHash = Hash<28>;
pub type PolicyId = Hash<28>;
@ -298,8 +298,8 @@ pub type DnsName = String;
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub enum Relay {
SingleHostAddr(Option<Port>, Option<IPv4>, Option<IPv6>),
SingleHostName(Option<Port>, DnsName),
SingleHostAddr(Nullable<Port>, Nullable<IPv4>, Nullable<IPv6>),
SingleHostName(Nullable<Port>, DnsName),
MultiHostName(DnsName),
}
@ -473,7 +473,7 @@ pub enum Certificate {
reward_account: RewardAccount,
pool_owners: Vec<AddrKeyhash>,
relays: Vec<Relay>,
pool_metadata: Option<PoolMetadata>,
pool_metadata: Nullable<PoolMetadata>,
},
PoolRetirement(PoolKeyhash, Epoch),
GenesisKeyDelegation(Genesishash, GenesisDelegateHash, VrfKeyhash),
@ -1197,7 +1197,7 @@ where
}
}
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone, Copy)]
pub struct ExUnits {
#[n(0)]
pub mem: u32,
@ -1214,7 +1214,7 @@ pub struct ExUnitPrices {
step_price: PositiveInterval,
}
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone, Copy)]
#[cbor(index_only)]
pub enum RedeemerTag {
#[n(0)]
@ -1242,7 +1242,7 @@ pub struct Redeemer {
pub ex_units: ExUnits,
}
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone, Copy)]
pub struct RedeemerPointer {
#[n(0)]
pub tag: RedeemerTag,

View file

@ -1,4 +1,4 @@
; fetched 11 sep 2023
; fetched 19 mar 2024
block =
[ header
@ -40,24 +40,24 @@ header_body =
]
operational_cert =
( hot_vkey : $kes_vkey
[ 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)
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 : [+ certificate]
, ? 4 : certificates
, ? 5 : withdrawals
, ? 7 : auxiliary_data_hash
, ? 8 : uint ; validity interval start
@ -70,7 +70,7 @@ transaction_body =
, ? 17 : coin ; total collateral
, ? 18 : nonempty_set<transaction_input> ; reference inputs
, ? 19 : voting_procedures ; New; Voting procedures
, ? 20 : [+ proposal_procedure] ; New; Proposal procedures
, ? 20 : proposal_procedures ; New; Proposal procedures
, ? 21 : coin ; New; current treasury value
, ? 22 : positive_coin ; New; donation
}
@ -89,30 +89,34 @@ proposal_procedure =
, 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
// new_committee
// update_committee
// new_constitution
// info_action
]
parameter_change_action = (0, gov_action_id / null, protocol_param_update)
policy_hash = scripthash
hard_fork_initiation_action = (1, gov_action_id / null, [protocol_version])
parameter_change_action = (0, gov_action_id / null, protocol_param_update, policy_hash / null)
treasury_withdrawals_action = (2, { $reward_account => coin })
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)
new_committee = (4, gov_action_id / null, set<$committee_cold_credential>, committee)
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)
committee = [{ $committee_cold_credential => epoch }, unit_interval]
constitution =
[ anchor
, scripthash / null
@ -148,15 +152,17 @@ gov_action_id =
, gov_action_index : uint
]
required_signers = nonempty_set<$addr_keyhash>
required_signers = nonempty_set<addr_keyhash>
transaction_input = [ transaction_id : $hash32
, index : uint
]
transaction_output = legacy_transaction_output / post_alonzo_transaction_output
; 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
legacy_transaction_output =
pre_babbage_transaction_output =
[ address
, amount : value
, ? datum_hash : $hash32
@ -310,7 +316,7 @@ 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)
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)
@ -349,7 +355,7 @@ pool_params = ( operator: pool_keyhash
port = uint .le 65535
ipv4 = bytes .size 4
ipv6 = bytes .size 16
dns_name = tstr .size (0..64)
dns_name = tstr .size (0..128)
single_host_addr = ( 0
, port / null
@ -370,13 +376,13 @@ relay =
]
pool_metadata = [url, pool_metadata_hash]
url = tstr .size (0..64)
url = tstr .size (0..128)
withdrawals = { + reward_account => coin }
protocol_param_update =
{ ? 0: uint ; minfee A
, ? 1: uint ; minfee B
{ ? 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
@ -384,7 +390,7 @@ protocol_param_update =
, ? 6: coin ; pool deposit
, ? 7: epoch ; maximum epoch
, ? 8: uint ; n_opt: desired number of stake pools
, ? 9: rational ; pool pledge influence
, ? 9: nonnegative_interval ; pool pledge influence
, ? 10: unit_interval ; expansion rate
, ? 11: unit_interval ; treasury growth rate
, ? 16: coin ; min pool cost
@ -399,11 +405,12 @@ protocol_param_update =
, ? 25: pool_voting_thresholds ; pool voting thresholds
, ? 26: drep_voting_thresholds ; DRep voting thresholds
, ? 27: uint ; min committee size
, ? 28: uint ; committee term limit
, ? 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 =
@ -411,6 +418,7 @@ pool_voting_thresholds =
, unit_interval ; committee normal
, unit_interval ; committee no confidence
, unit_interval ; hard fork initiation
, unit_interval ; security relevant parameter voting threshold
]
drep_voting_thresholds =
@ -427,19 +435,23 @@ drep_voting_thresholds =
]
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 ]
{ ? 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>
}
plutus_v1_script = bytes
plutus_v2_script = bytes
plutus_v3_script = bytes
; 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>
@ -463,17 +475,24 @@ constr<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 ]
; 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 ; inputTag "Spend"
/ 1 ; mintTag "Mint"
/ 2 ; certTag "Cert"
/ 3 ; wdrlTag "Reward"
; TODO / 4 ; drepTag "DRep"
0 ; Spending
/ 1 ; Minting
/ 2 ; Certifying
/ 3 ; Rewarding
/ 4 ; Voting
/ 5 ; Proposing
ex_units = [mem: uint, steps: uint]
ex_unit_prices =
[ mem_price: sub_coin, step_price: sub_coin ]
[ mem_price: nonnegative_interval, step_price: nonnegative_interval ]
language = 0 ; Plutus v1
/ 1 ; Plutus v2
@ -484,13 +503,12 @@ 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] }
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 }
@ -545,8 +563,6 @@ invalid_hereafter = (5, uint)
coin = uint
sub_coin = positive_interval
multiasset<a> = { + policy_id => { + asset_name => a } }
policy_id = scripthash
asset_name = bytes .size (0..32)
@ -557,7 +573,7 @@ nonZeroInt64 = negInt64 / posInt64 ; this is the same as the current int64 defin
positive_coin = 1 .. 18446744073709551615
value = positive_coin / [positive_coin,multiasset<positive_coin>]
value = coin / [coin, multiasset<positive_coin>]
mint = multiasset<nonZeroInt64>

View file

@ -2,18 +2,25 @@
//!
//! 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 std::ops::Deref;
use pallas_codec::minicbor::decode::Error;
use serde::{Deserialize, Serialize};
use pallas_codec::minicbor::{Decode, Encode};
use pallas_crypto::hash::Hash;
use pallas_codec::utils::{Bytes, KeepRaw, KeyValuePairs, MaybeIndefArray, Nullable, Set};
use pallas_codec::utils::{
Bytes, CborWrap, KeepRaw, KeyValuePairs, MaybeIndefArray, NonEmptyKeyValuePairs, NonEmptySet,
NonZeroInt, Nullable, PositiveCoin, Set,
};
// required for derive attrs to work
use pallas_codec::minicbor;
pub use crate::alonzo::VrfCert;
use crate::babbage;
pub use crate::babbage::HeaderBody;
pub use crate::babbage::OperationalCert;
@ -36,13 +43,59 @@ pub use crate::alonzo::PolicyId;
pub use crate::alonzo::AssetName;
pub use crate::alonzo::Multiasset;
pub type Multiasset<A> = NonEmptyKeyValuePairs<PolicyId, NonEmptyKeyValuePairs<AssetName, A>>;
pub use crate::alonzo::Mint;
pub use crate::alonzo::Coin;
pub use crate::alonzo::Value;
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub enum Value {
Coin(Coin),
Multiasset(Coin, Multiasset<PositiveCoin>),
}
impl<'b, C> minicbor::decode::Decode<'b, C> for Value {
fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result<Self, minicbor::decode::Error> {
match d.datatype()? {
minicbor::data::Type::U8 => Ok(Value::Coin(d.decode_with(ctx)?)),
minicbor::data::Type::U16 => Ok(Value::Coin(d.decode_with(ctx)?)),
minicbor::data::Type::U32 => Ok(Value::Coin(d.decode_with(ctx)?)),
minicbor::data::Type::U64 => Ok(Value::Coin(d.decode_with(ctx)?)),
minicbor::data::Type::Array => {
d.array()?;
let coin = d.decode_with(ctx)?;
let multiasset = d.decode_with(ctx)?;
Ok(Value::Multiasset(coin, multiasset))
}
_ => Err(minicbor::decode::Error::message(
"unknown cbor data type for Alonzo Value enum",
)),
}
}
}
impl<C> minicbor::encode::Encode<C> for Value {
fn encode<W: minicbor::encode::Write>(
&self,
e: &mut minicbor::Encoder<W>,
ctx: &mut C,
) -> Result<(), minicbor::encode::Error<W::Error>> {
// TODO: check how to deal with uint variants (u32 vs u64)
match self {
Value::Coin(coin) => {
e.encode_with(coin, ctx)?;
}
Value::Multiasset(coin, other) => {
e.array(2)?;
e.encode_with(coin, ctx)?;
e.encode_with(other, ctx)?;
}
};
Ok(())
}
}
pub use crate::alonzo::TransactionOutput as LegacyTransactionOutput;
@ -64,9 +117,9 @@ pub use crate::alonzo::MoveInstantaneousReward;
pub use crate::alonzo::RewardAccount;
pub type Withdrawals = KeyValuePairs<RewardAccount, Coin>;
pub type Withdrawals = NonEmptyKeyValuePairs<RewardAccount, Coin>;
pub type RequiredSigners = Set<AddrKeyhash>; // TODO: NON EMPTY SET
pub type RequiredSigners = NonEmptySet<AddrKeyhash>;
pub use crate::alonzo::Port;
@ -108,7 +161,7 @@ pub enum Certificate {
reward_account: RewardAccount,
pool_owners: Set<AddrKeyhash>,
relays: Vec<Relay>,
pool_metadata: Option<PoolMetadata>,
pool_metadata: Nullable<PoolMetadata>,
},
PoolRetirement(PoolKeyhash, Epoch),
@ -121,10 +174,10 @@ pub enum Certificate {
StakeVoteRegDeleg(StakeCredential, PoolKeyhash, DRep, Coin),
AuthCommitteeHot(CommitteeColdCredential, CommitteeHotCredential),
ResignCommitteeCold(CommitteeColdCredential),
RegDRepCert(DRepCredential, Coin, Option<Anchor>),
ResignCommitteeCold(CommitteeColdCredential, Nullable<Anchor>),
RegDRepCert(DRepCredential, Coin, Nullable<Anchor>),
UnRegDRepCert(DRepCredential, Coin),
UpdateDRepCert(StakeCredential, Option<Anchor>),
UpdateDRepCert(StakeCredential, Nullable<Anchor>),
}
impl<'b, C> minicbor::decode::Decode<'b, C> for Certificate {
@ -222,7 +275,8 @@ impl<'b, C> minicbor::decode::Decode<'b, C> for Certificate {
}
15 => {
let a = d.decode_with(ctx)?;
Ok(Certificate::ResignCommitteeCold(a))
let b = d.decode_with(ctx)?;
Ok(Certificate::ResignCommitteeCold(a, b))
}
16 => {
let a = d.decode_with(ctx)?;
@ -354,10 +408,11 @@ impl<C> minicbor::encode::Encode<C> for Certificate {
e.encode_with(a, ctx)?;
e.encode_with(b, ctx)?;
}
Certificate::ResignCommitteeCold(a) => {
e.array(2)?;
Certificate::ResignCommitteeCold(a, b) => {
e.array(3)?;
e.u16(15)?;
e.encode_with(a, ctx)?;
e.encode_with(b, ctx)?;
}
Certificate::RegDRepCert(a, b, c) => {
e.array(4)?;
@ -536,7 +591,7 @@ pub struct ProtocolParamUpdate {
#[n(27)]
pub min_committee_size: Option<u32>,
#[n(28)]
pub committee_term_limit: Option<u32>,
pub committee_term_limit: Option<Epoch>,
#[n(29)]
pub governance_action_validity_period: Option<Epoch>,
#[n(30)]
@ -545,6 +600,8 @@ pub struct ProtocolParamUpdate {
pub drep_deposit: Option<Coin>,
#[n(32)]
pub drep_inactivity_period: Option<Epoch>,
#[n(33)]
pub minfee_refscript_cost_per_byte: Option<Epoch>,
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
@ -553,6 +610,7 @@ pub struct PoolVotingThresholds {
pub committee_normal: UnitInterval,
pub committee_no_confidence: UnitInterval,
pub hard_fork_initiation: UnitInterval,
pub security_voting_threshold: UnitInterval,
}
impl<'b, C> minicbor::Decode<'b, C> for PoolVotingThresholds {
@ -564,6 +622,7 @@ impl<'b, C> minicbor::Decode<'b, C> for PoolVotingThresholds {
committee_normal: d.decode_with(ctx)?,
committee_no_confidence: d.decode_with(ctx)?,
hard_fork_initiation: d.decode_with(ctx)?,
security_voting_threshold: d.decode_with(ctx)?,
})
}
}
@ -574,12 +633,13 @@ impl<C> minicbor::Encode<C> for PoolVotingThresholds {
e: &mut minicbor::Encoder<W>,
ctx: &mut C,
) -> Result<(), minicbor::encode::Error<W::Error>> {
e.array(4)?;
e.array(5)?;
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)?;
e.encode_with(&self.security_voting_threshold, ctx)?;
Ok(())
}
@ -657,13 +717,11 @@ pub struct PseudoTransactionBody<T1> {
pub ttl: Option<u64>,
#[n(4)]
pub certificates: Option<Set<Certificate>>, // TODO: NON EMPTY ORDERED SET
pub certificates: Option<NonEmptySet<Certificate>>,
#[n(5)]
pub withdrawals: Option<KeyValuePairs<RewardAccount, Coin>>, // TODO: NON EMPTY
// #[n(6)]
// pub update: Option<Update>,
#[n(7)]
pub auxiliary_data_hash: Option<Bytes>,
@ -671,16 +729,16 @@ pub struct PseudoTransactionBody<T1> {
pub validity_interval_start: Option<u64>,
#[n(9)]
pub mint: Option<Multiasset<i64>>, // TODO: MULTI ASSET NON EMPTY
pub mint: Option<Multiasset<NonZeroInt>>,
#[n(11)]
pub script_data_hash: Option<Hash<32>>,
#[n(13)]
pub collateral: Option<Set<TransactionInput>>, // TODO: NON EMPTY SET
pub collateral: Option<NonEmptySet<TransactionInput>>,
#[n(14)]
pub required_signers: Option<Vec<AddrKeyhash>>, // TODO: NON EMPTY SET
pub required_signers: Option<RequiredSigners>,
#[n(15)]
pub network_id: Option<NetworkId>,
@ -692,20 +750,20 @@ pub struct PseudoTransactionBody<T1> {
pub total_collateral: Option<Coin>,
#[n(18)]
pub reference_inputs: Option<Set<TransactionInput>>, // TODO: NON EMPTY SET
pub reference_inputs: Option<NonEmptySet<TransactionInput>>,
// -- NEW IN CONWAY
#[n(19)]
pub voting_procedures: Option<VotingProcedures>,
#[n(20)]
pub proposal_procedures: Option<Set<ProposalProcedure>>, // TODO: NON EMPTY ORDERED SET
pub proposal_procedures: Option<NonEmptySet<ProposalProcedure>>,
#[n(21)]
pub treasury_value: Option<Coin>,
#[n(22)]
pub donation: Option<u64>, // TODO: NON ZERO (POSITIVE COIN)
pub donation: Option<PositiveCoin>,
}
pub type TransactionBody = PseudoTransactionBody<TransactionOutput>;
@ -778,12 +836,13 @@ impl<C> minicbor::Encode<C> for Vote {
}
}
pub type VotingProcedures = KeyValuePairs<Voter, KeyValuePairs<GovActionId, VotingProcedure>>;
pub type VotingProcedures =
NonEmptyKeyValuePairs<Voter, NonEmptyKeyValuePairs<GovActionId, VotingProcedure>>;
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub struct VotingProcedure {
pub vote: Vote,
pub anchor: Option<Anchor>,
pub anchor: Nullable<Anchor>,
}
impl<'b, C> minicbor::Decode<'b, C> for VotingProcedure {
@ -852,17 +911,21 @@ impl<C> minicbor::Encode<C> for ProposalProcedure {
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub enum GovAction {
ParameterChange(Option<GovActionId>, Box<ProtocolParamUpdate>),
HardForkInitiation(Option<GovActionId>, Vec<ProtocolVersion>),
TreasuryWithdrawals(KeyValuePairs<RewardAccount, Coin>),
NoConfidence(Option<GovActionId>),
ParameterChange(
Nullable<GovActionId>,
Box<ProtocolParamUpdate>,
Nullable<ScriptHash>,
),
HardForkInitiation(Nullable<GovActionId>, ProtocolVersion),
TreasuryWithdrawals(KeyValuePairs<RewardAccount, Coin>, Nullable<ScriptHash>),
NoConfidence(Nullable<GovActionId>),
UpdateCommittee(
Option<GovActionId>,
Nullable<GovActionId>,
Set<CommitteeColdCredential>,
KeyValuePairs<CommitteeColdCredential, Epoch>,
UnitInterval,
),
NewConstitution(Option<GovActionId>, Constitution),
NewConstitution(Nullable<GovActionId>, Constitution),
Information,
}
@ -875,7 +938,8 @@ impl<'b, C> minicbor::decode::Decode<'b, C> for GovAction {
0 => {
let a = d.decode_with(ctx)?;
let b = d.decode_with(ctx)?;
Ok(GovAction::ParameterChange(a, b))
let c = d.decode_with(ctx)?;
Ok(GovAction::ParameterChange(a, b, c))
}
1 => {
let a = d.decode_with(ctx)?;
@ -884,7 +948,8 @@ impl<'b, C> minicbor::decode::Decode<'b, C> for GovAction {
}
2 => {
let a = d.decode_with(ctx)?;
Ok(GovAction::TreasuryWithdrawals(a))
let b = d.decode_with(ctx)?;
Ok(GovAction::TreasuryWithdrawals(a, b))
}
3 => {
let a = d.decode_with(ctx)?;
@ -917,11 +982,12 @@ impl<C> minicbor::encode::Encode<C> for GovAction {
ctx: &mut C,
) -> Result<(), minicbor::encode::Error<W::Error>> {
match self {
GovAction::ParameterChange(a, b) => {
e.array(3)?;
GovAction::ParameterChange(a, b, c) => {
e.array(4)?;
e.u16(0)?;
e.encode_with(a, ctx)?;
e.encode_with(b, ctx)?;
e.encode_with(c, ctx)?;
}
GovAction::HardForkInitiation(a, b) => {
e.array(3)?;
@ -929,10 +995,11 @@ impl<C> minicbor::encode::Encode<C> for GovAction {
e.encode_with(a, ctx)?;
e.encode_with(b, ctx)?;
}
GovAction::TreasuryWithdrawals(a) => {
e.array(2)?;
GovAction::TreasuryWithdrawals(a, b) => {
e.array(3)?;
e.u16(2)?;
e.encode_with(a, ctx)?;
e.encode_with(b, ctx)?;
}
GovAction::NoConfidence(a) => {
e.array(2)?;
@ -953,7 +1020,7 @@ impl<C> minicbor::encode::Encode<C> for GovAction {
e.encode_with(a, ctx)?;
e.encode_with(b, ctx)?;
}
// TODO: CDDL SAYS JUST "6", no group (array)
// TODO: CDDL says just "6", not group/array "(6)"?
GovAction::Information => {
e.array(1)?;
e.u16(6)?;
@ -964,8 +1031,8 @@ impl<C> minicbor::encode::Encode<C> for GovAction {
}
}
#[derive(Serialize, Deserialize, Debug, PartialEq, PartialOrd, Eq, Ord, Clone)]
pub struct Constitution(Anchor, Option<ScriptHash>);
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub struct Constitution(Anchor, Nullable<ScriptHash>);
impl<'b, C> minicbor::Decode<'b, C> for Constitution {
fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result<Self, minicbor::decode::Error> {
@ -1153,15 +1220,37 @@ where
}
}
pub use crate::babbage::TransactionOutput;
pub use crate::babbage::MintedTransactionOutput;
pub use crate::babbage::PseudoPostAlonzoTransactionOutput;
pub use crate::babbage::PostAlonzoTransactionOutput;
pub type TransactionOutput = PseudoTransactionOutput<PostAlonzoTransactionOutput>;
pub use crate::babbage::MintedPostAlonzoTransactionOutput;
pub type MintedTransactionOutput<'b> =
PseudoTransactionOutput<MintedPostAlonzoTransactionOutput<'b>>;
impl<'b> From<MintedTransactionOutput<'b>> for TransactionOutput {
fn from(value: MintedTransactionOutput<'b>) -> Self {
match value {
PseudoTransactionOutput::Legacy(x) => Self::Legacy(x),
PseudoTransactionOutput::PostAlonzo(x) => Self::PostAlonzo(x.into()),
}
}
}
pub type PostAlonzoTransactionOutput = PseudoPostAlonzoTransactionOutput<DatumOption, ScriptRef>;
pub type MintedPostAlonzoTransactionOutput<'b> =
PseudoPostAlonzoTransactionOutput<MintedDatumOption<'b>, MintedScriptRef<'b>>;
impl<'b> From<MintedPostAlonzoTransactionOutput<'b>> for PostAlonzoTransactionOutput {
fn from(value: MintedPostAlonzoTransactionOutput<'b>) -> Self {
Self {
address: value.address,
value: value.value,
datum_option: value.datum_option.map(|x| x.into()),
script_ref: value.script_ref.map(|x| CborWrap(x.unwrap().into())),
}
}
}
pub use crate::alonzo::VKeyWitness;
@ -1189,9 +1278,16 @@ pub use crate::alonzo::Constr;
pub use crate::alonzo::ExUnits;
pub use crate::alonzo::ExUnitPrices;
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
pub struct ExUnitPrices {
#[n(0)]
mem_price: RationalNumber,
#[n(1)]
step_price: RationalNumber,
}
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone, Copy)]
#[cbor(index_only)]
pub enum RedeemerTag {
#[n(0)]
@ -1203,9 +1299,9 @@ pub enum RedeemerTag {
#[n(3)]
Reward,
#[n(4)]
DRep,
Vote,
#[n(5)]
VotingProposal,
Propose,
}
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
@ -1223,62 +1319,145 @@ pub struct Redeemer {
pub ex_units: ExUnits,
}
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
pub struct RedeemersKey {
#[n(0)]
pub tag: RedeemerTag,
#[n(1)]
pub index: u32,
}
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
pub struct RedeemersValue {
#[n(0)]
pub data: PlutusData,
#[n(1)]
pub ex_units: ExUnits,
}
// TODO: Redeemers needs to be KeepRaw because of script data hash
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
#[serde(transparent)]
pub struct Redeemers(NonEmptyKeyValuePairs<RedeemersKey, RedeemersValue>);
impl Deref for Redeemers {
type Target = NonEmptyKeyValuePairs<RedeemersKey, RedeemersValue>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl From<NonEmptyKeyValuePairs<RedeemersKey, RedeemersValue>> for Redeemers {
fn from(value: NonEmptyKeyValuePairs<RedeemersKey, RedeemersValue>) -> Self {
Redeemers(value)
}
}
impl<'b, C> minicbor::Decode<'b, C> for Redeemers {
fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result<Self, minicbor::decode::Error> {
match d.datatype()? {
minicbor::data::Type::Array | minicbor::data::Type::ArrayIndef => {
let redeemers: Vec<Redeemer> = d.decode_with(ctx)?;
let kvs = redeemers
.into_iter()
.map(|x| {
(
RedeemersKey {
tag: x.tag,
index: x.index,
},
RedeemersValue {
data: x.data,
ex_units: x.ex_units,
},
)
})
.collect::<Vec<_>>()
.try_into()
.map_err(|_| Error::message("decoding empty redeemers"))?;
Ok(Self(kvs))
}
minicbor::data::Type::Map | minicbor::data::Type::MapIndef => {
Ok(Self(d.decode_with(ctx)?))
}
_ => Err(minicbor::decode::Error::message(
"invalid type for redeemers struct",
)),
}
}
}
impl<C> minicbor::Encode<C> for Redeemers {
fn encode<W: minicbor::encode::Write>(
&self,
e: &mut minicbor::Encoder<W>,
ctx: &mut C,
) -> Result<(), minicbor::encode::Error<W::Error>> {
e.encode_with(&self.0, ctx)?;
Ok(())
}
}
pub use crate::alonzo::BootstrapWitness;
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Clone)]
#[cbor(map)]
pub struct WitnessSet {
#[n(0)]
pub vkeywitness: Option<Set<VKeyWitness>>, // TODO: NON EMPTY SET
pub vkeywitness: Option<NonEmptySet<VKeyWitness>>,
#[n(1)]
pub native_script: Option<Set<NativeScript>>, // TODO: NON EMPTY SET
pub native_script: Option<NonEmptySet<NativeScript>>,
#[n(2)]
pub bootstrap_witness: Option<Set<BootstrapWitness>>, // TODO: NON EMPTY SET
pub bootstrap_witness: Option<NonEmptySet<BootstrapWitness>>,
#[n(3)]
pub plutus_v1_script: Option<Set<PlutusV1Script>>, // TODO: NON EMPTY SET
pub plutus_v1_script: Option<NonEmptySet<PlutusV1Script>>,
#[n(4)]
pub plutus_data: Option<Set<PlutusData>>, // TODO: NON EMPTY SET
pub plutus_data: Option<NonEmptySet<PlutusData>>,
#[n(5)]
pub redeemer: Option<Vec<Redeemer>>,
pub redeemer: Option<Redeemers>,
#[n(6)]
pub plutus_v2_script: Option<Set<PlutusV2Script>>, // TODO: NON EMPTY SET
pub plutus_v2_script: Option<NonEmptySet<PlutusV2Script>>,
#[n(7)]
pub plutus_v3_script: Option<Set<PlutusV3Script>>, // TODO: NON EMPTY SET
pub plutus_v3_script: Option<NonEmptySet<PlutusV3Script>>,
}
#[derive(Encode, Decode, Debug, PartialEq, Clone)]
#[cbor(map)]
pub struct MintedWitnessSet<'b> {
#[n(0)]
pub vkeywitness: Option<Set<VKeyWitness>>, // TODO: NON EMPTY SET
pub vkeywitness: Option<NonEmptySet<VKeyWitness>>,
#[n(1)]
pub native_script: Option<Set<KeepRaw<'b, NativeScript>>>, // TODO: NON EMPTY SET
pub native_script: Option<NonEmptySet<KeepRaw<'b, NativeScript>>>,
#[n(2)]
pub bootstrap_witness: Option<Set<BootstrapWitness>>, // TODO: NON EMPTY SET
pub bootstrap_witness: Option<NonEmptySet<BootstrapWitness>>,
#[n(3)]
pub plutus_v1_script: Option<Set<PlutusV1Script>>, // TODO: NON EMPTY SET
pub plutus_v1_script: Option<NonEmptySet<PlutusV1Script>>,
#[b(4)]
pub plutus_data: Option<Set<KeepRaw<'b, PlutusData>>>, // TODO: NON EMPTY SET
pub plutus_data: Option<NonEmptySet<KeepRaw<'b, PlutusData>>>,
#[n(5)]
pub redeemer: Option<Vec<Redeemer>>,
pub redeemer: Option<KeepRaw<'b, Redeemers>>,
#[n(6)]
pub plutus_v2_script: Option<Set<PlutusV2Script>>, // TODO: NON EMPTY SET
pub plutus_v2_script: Option<NonEmptySet<PlutusV2Script>>,
#[n(7)]
pub plutus_v3_script: Option<Set<PlutusV3Script>>, // TODO: NON EMPTY SET
pub plutus_v3_script: Option<NonEmptySet<PlutusV3Script>>,
}
impl<'b> From<MintedWitnessSet<'b>> for WitnessSet {
@ -1289,7 +1468,7 @@ impl<'b> From<MintedWitnessSet<'b>> for WitnessSet {
bootstrap_witness: x.bootstrap_witness,
plutus_v1_script: x.plutus_v1_script,
plutus_data: x.plutus_data.map(Into::into),
redeemer: x.redeemer,
redeemer: x.redeemer.map(|x| x.unwrap()),
plutus_v2_script: x.plutus_v2_script,
plutus_v3_script: x.plutus_v3_script,
}
@ -1348,6 +1527,17 @@ impl<'b> From<MintedScriptRef<'b>> for ScriptRef {
}
}
// TODO: Remove in favour of multierascriptref
impl<'b> From<babbage::MintedScriptRef<'b>> for MintedScriptRef<'b> {
fn from(value: babbage::MintedScriptRef<'b>) -> Self {
match value {
babbage::MintedScriptRef::NativeScript(x) => Self::NativeScript(x),
babbage::MintedScriptRef::PlutusV1Script(x) => Self::PlutusV1Script(x),
babbage::MintedScriptRef::PlutusV2Script(x) => Self::PlutusV2Script(x),
}
}
}
impl<'b, C, T> minicbor::Decode<'b, C> for PseudoScript<T>
where
T: minicbor::Decode<'b, ()>,
@ -1363,9 +1553,10 @@ where
1 => Ok(Self::PlutusV1Script(d.decode()?)),
2 => Ok(Self::PlutusV2Script(d.decode()?)),
3 => Ok(Self::PlutusV3Script(d.decode()?)),
_ => Err(minicbor::decode::Error::message(
"invalid variant for script enum",
)),
x => Err(minicbor::decode::Error::message(format!(
"invalid variant for script enum: {}",
x
))),
}
}
}
@ -1518,7 +1709,7 @@ mod tests {
fn block_isomorphic_decoding_encoding() {
let test_blocks = [
include_str!("../../../test_data/conway1.block"),
include_str!("../../../test_data/conway1.artificial.block"),
include_str!("../../../test_data/conway2.block"),
];
for (idx, block_str) in test_blocks.iter().enumerate() {

View file

@ -7,13 +7,15 @@ impl<'b> MultiEraPolicyAssets<'b> {
match self {
MultiEraPolicyAssets::AlonzoCompatibleMint(x, _) => x,
MultiEraPolicyAssets::AlonzoCompatibleOutput(x, _) => x,
MultiEraPolicyAssets::ConwayMint(x, _) => x,
}
}
pub fn is_output(&self) -> bool {
match self {
MultiEraPolicyAssets::AlonzoCompatibleOutput(_, _) => true,
MultiEraPolicyAssets::AlonzoCompatibleMint(_, _) => false,
MultiEraPolicyAssets::AlonzoCompatibleOutput(_, _) => true,
MultiEraPolicyAssets::ConwayMint(_, _) => false,
}
}
@ -21,6 +23,7 @@ impl<'b> MultiEraPolicyAssets<'b> {
match self {
MultiEraPolicyAssets::AlonzoCompatibleMint(_, _) => true,
MultiEraPolicyAssets::AlonzoCompatibleOutput(_, _) => false,
MultiEraPolicyAssets::ConwayMint(_, _) => true,
}
}
@ -34,6 +37,10 @@ impl<'b> MultiEraPolicyAssets<'b> {
.iter()
.map(|(k, v)| MultiEraAsset::AlonzoCompatibleOutput(p, k, *v))
.collect(),
MultiEraPolicyAssets::ConwayMint(p, x) => x
.iter()
.map(|(k, v)| MultiEraAsset::ConwayMint(p, k, *v))
.collect(),
}
}
@ -48,6 +55,10 @@ impl<'b> MultiEraPolicyAssets<'b> {
MultiEraPolicyAssets::AlonzoCompatibleOutput(_, x) => {
x.iter().map(|(k, v)| (k.as_slice(), *v as i128)).collect()
}
MultiEraPolicyAssets::ConwayMint(_, x) => x
.iter()
.map(|(k, v)| (k.as_slice(), i64::from(v) as i128))
.collect(),
}
}
}
@ -57,20 +68,23 @@ impl<'b> MultiEraAsset<'b> {
match self {
MultiEraAsset::AlonzoCompatibleMint(x, ..) => x,
MultiEraAsset::AlonzoCompatibleOutput(x, ..) => x,
MultiEraAsset::ConwayMint(x, ..) => x,
}
}
pub fn name(&self) -> &[u8] {
match self {
MultiEraAsset::AlonzoCompatibleOutput(_, x, _) => x,
MultiEraAsset::AlonzoCompatibleMint(_, x, _) => x,
MultiEraAsset::AlonzoCompatibleOutput(_, x, _) => x,
MultiEraAsset::ConwayMint(_, x, _) => x,
}
}
pub fn is_output(&self) -> bool {
match self {
MultiEraAsset::AlonzoCompatibleOutput(..) => true,
MultiEraAsset::AlonzoCompatibleMint(..) => false,
MultiEraAsset::AlonzoCompatibleOutput(..) => true,
MultiEraAsset::ConwayMint(..) => false,
}
}
@ -78,6 +92,7 @@ impl<'b> MultiEraAsset<'b> {
match self {
MultiEraAsset::AlonzoCompatibleMint(..) => true,
MultiEraAsset::AlonzoCompatibleOutput(..) => false,
MultiEraAsset::ConwayMint(..) => true,
}
}
@ -85,20 +100,23 @@ impl<'b> MultiEraAsset<'b> {
match self {
MultiEraAsset::AlonzoCompatibleMint(_, _, x) => Some(*x),
MultiEraAsset::AlonzoCompatibleOutput(_, _, _) => None,
MultiEraAsset::ConwayMint(_, _, x) => Some(x.into()),
}
}
pub fn output_coin(&self) -> Option<u64> {
match self {
MultiEraAsset::AlonzoCompatibleOutput(_, _, x) => Some(*x),
MultiEraAsset::AlonzoCompatibleMint(_, _, _) => None,
MultiEraAsset::AlonzoCompatibleOutput(_, _, x) => Some(*x),
MultiEraAsset::ConwayMint(_, _, _) => None,
}
}
pub fn any_coin(&self) -> i128 {
match self {
MultiEraAsset::AlonzoCompatibleOutput(_, _, x) => *x as i128,
MultiEraAsset::AlonzoCompatibleMint(_, _, x) => *x as i128,
MultiEraAsset::AlonzoCompatibleOutput(_, _, x) => *x as i128,
MultiEraAsset::ConwayMint(_, _, x) => i64::from(x) as i128,
}
}

View file

@ -4,7 +4,7 @@ use std::{borrow::Cow, fmt::Display, hash::Hash as StdHash};
use thiserror::Error;
use pallas_codec::utils::{KeepRaw, KeyValuePairs};
use pallas_codec::utils::{KeepRaw, KeyValuePairs, NonEmptyKeyValuePairs, NonZeroInt};
use pallas_crypto::hash::Hash;
use pallas_primitives::{alonzo, babbage, byron, conway};
@ -22,6 +22,7 @@ pub mod input;
pub mod meta;
pub mod output;
pub mod probe;
pub mod redeemers;
pub mod signers;
pub mod size;
pub mod time;
@ -90,6 +91,7 @@ pub enum MultiEraTx<'b> {
pub enum MultiEraOutput<'b> {
AlonzoCompatible(Box<Cow<'b, alonzo::TransactionOutput>>),
Babbage(Box<Cow<'b, babbage::MintedTransactionOutput<'b>>>),
Conway(Box<Cow<'b, conway::MintedTransactionOutput<'b>>>),
Byron(Box<Cow<'b, byron::TxOut>>),
}
@ -108,6 +110,16 @@ pub enum MultiEraCert<'b> {
Conway(Box<Cow<'b, conway::Certificate>>),
}
#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum MultiEraRedeemer<'b> {
AlonzoCompatible(Box<Cow<'b, alonzo::Redeemer>>),
Conway(
Box<Cow<'b, conway::RedeemersKey>>,
Box<Cow<'b, conway::RedeemersValue>>,
),
}
#[derive(Debug, Clone, Default)]
#[non_exhaustive]
pub enum MultiEraMeta<'b> {
@ -128,6 +140,10 @@ pub enum MultiEraPolicyAssets<'b> {
&'b alonzo::PolicyId,
&'b KeyValuePairs<alonzo::AssetName, u64>,
),
ConwayMint(
&'b alonzo::PolicyId,
&'b NonEmptyKeyValuePairs<alonzo::AssetName, NonZeroInt>,
),
}
#[derive(Debug, Clone)]
@ -135,6 +151,7 @@ pub enum MultiEraPolicyAssets<'b> {
pub enum MultiEraAsset<'b> {
AlonzoCompatibleOutput(&'b alonzo::PolicyId, &'b alonzo::AssetName, u64),
AlonzoCompatibleMint(&'b alonzo::PolicyId, &'b alonzo::AssetName, i64),
ConwayMint(&'b alonzo::PolicyId, &'b alonzo::AssetName, NonZeroInt),
}
#[derive(Debug, Clone)]

View file

@ -2,7 +2,7 @@ use std::{borrow::Cow, ops::Deref};
use pallas_addresses::{Address, ByronAddress, Error as AddressError};
use pallas_codec::minicbor;
use pallas_primitives::{alonzo, babbage, byron};
use pallas_primitives::{alonzo, babbage, byron, conway};
use crate::{Era, MultiEraOutput, MultiEraPolicyAssets};
@ -19,6 +19,10 @@ impl<'b> MultiEraOutput<'b> {
Self::Babbage(Box::new(Cow::Borrowed(output)))
}
pub fn from_conway(output: &'b conway::MintedTransactionOutput<'b>) -> Self {
Self::Conway(Box::new(Cow::Borrowed(output)))
}
pub fn datum(&self) -> Option<babbage::MintedDatumOption> {
match self {
MultiEraOutput::AlonzoCompatible(x) => {
@ -30,19 +34,32 @@ impl<'b> MultiEraOutput<'b> {
}
babbage::MintedTransactionOutput::PostAlonzo(x) => x.datum_option.clone(),
},
_ => None,
MultiEraOutput::Byron(_) => None,
MultiEraOutput::Conway(x) => match x.deref().deref() {
conway::MintedTransactionOutput::Legacy(x) => {
x.datum_hash.map(babbage::MintedDatumOption::Hash)
}
conway::MintedTransactionOutput::PostAlonzo(x) => x.datum_option.clone(),
},
}
}
pub fn script_ref(&self) -> Option<babbage::MintedScriptRef> {
pub fn script_ref(&self) -> Option<conway::MintedScriptRef> {
match &self {
MultiEraOutput::AlonzoCompatible(_) => None,
MultiEraOutput::Babbage(x) => match x.deref().deref() {
babbage::MintedTransactionOutput::Legacy(_) => None,
babbage::MintedTransactionOutput::PostAlonzo(x) => {
x.script_ref.clone().map(|x| x.unwrap().into())
}
},
MultiEraOutput::Byron(_) => None,
MultiEraOutput::Conway(x) => match x.deref().deref() {
conway::MintedTransactionOutput::Legacy(_) => None,
conway::MintedTransactionOutput::PostAlonzo(x) => {
x.script_ref.clone().map(|x| x.unwrap())
}
},
_ => None,
}
}
@ -56,14 +73,10 @@ impl<'b> MultiEraOutput<'b> {
MultiEraOutput::Byron(x) => {
Ok(ByronAddress::new(&x.address.payload.0, x.address.crc).into())
}
}
}
pub fn as_babbage(&self) -> Option<&babbage::MintedTransactionOutput> {
match self {
MultiEraOutput::AlonzoCompatible(_) => None,
MultiEraOutput::Babbage(x) => Some(x),
MultiEraOutput::Byron(_) => None,
MultiEraOutput::Conway(x) => match x.deref().deref() {
conway::MintedTransactionOutput::Legacy(x) => Address::from_bytes(&x.address),
conway::MintedTransactionOutput::PostAlonzo(x) => Address::from_bytes(&x.address),
},
}
}
@ -72,6 +85,16 @@ impl<'b> MultiEraOutput<'b> {
MultiEraOutput::AlonzoCompatible(x) => Some(x),
MultiEraOutput::Babbage(_) => None,
MultiEraOutput::Byron(_) => None,
MultiEraOutput::Conway(_) => None,
}
}
pub fn as_babbage(&self) -> Option<&babbage::MintedTransactionOutput> {
match self {
MultiEraOutput::AlonzoCompatible(_) => None,
MultiEraOutput::Babbage(x) => Some(x),
MultiEraOutput::Byron(_) => None,
MultiEraOutput::Conway(_) => None,
}
}
@ -80,6 +103,16 @@ impl<'b> MultiEraOutput<'b> {
MultiEraOutput::AlonzoCompatible(_) => None,
MultiEraOutput::Babbage(_) => None,
MultiEraOutput::Byron(x) => Some(x),
MultiEraOutput::Conway(_) => None,
}
}
pub fn as_conway(&self) -> Option<&conway::MintedTransactionOutput> {
match self {
MultiEraOutput::AlonzoCompatible(_) => None,
MultiEraOutput::Babbage(_) => None,
MultiEraOutput::Byron(_) => None,
MultiEraOutput::Conway(x) => Some(x),
}
}
@ -89,6 +122,7 @@ impl<'b> MultiEraOutput<'b> {
Self::AlonzoCompatible(x) => minicbor::to_vec(x).unwrap(),
Self::Babbage(x) => minicbor::to_vec(x).unwrap(),
Self::Byron(x) => minicbor::to_vec(x).unwrap(),
Self::Conway(x) => minicbor::to_vec(x).unwrap(),
}
}
@ -104,11 +138,16 @@ impl<'b> MultiEraOutput<'b> {
let tx = Box::new(Cow::Owned(tx));
Ok(Self::AlonzoCompatible(tx))
}
Era::Babbage | Era::Conway => {
Era::Babbage => {
let tx = minicbor::decode(cbor)?;
let tx = Box::new(Cow::Owned(tx));
Ok(Self::Babbage(tx))
}
Era::Conway => {
let tx = minicbor::decode(cbor)?;
let tx = Box::new(Cow::Owned(tx));
Ok(Self::Conway(tx))
}
}
}
@ -119,7 +158,10 @@ impl<'b> MultiEraOutput<'b> {
/// lovelace).
pub fn lovelace_amount(&self) -> u64 {
match self {
MultiEraOutput::Byron(x) => x.amount,
MultiEraOutput::AlonzoCompatible(x) => match x.amount {
alonzo::Value::Coin(c) => c,
alonzo::Value::Multiasset(c, _) => c,
},
MultiEraOutput::Babbage(x) => match x.deref().deref() {
babbage::MintedTransactionOutput::Legacy(x) => match x.amount {
babbage::Value::Coin(c) => c,
@ -130,9 +172,16 @@ impl<'b> MultiEraOutput<'b> {
babbage::Value::Multiasset(c, _) => c,
},
},
MultiEraOutput::AlonzoCompatible(x) => match x.amount {
alonzo::Value::Coin(c) => c,
alonzo::Value::Multiasset(c, _) => c,
MultiEraOutput::Byron(x) => x.amount,
MultiEraOutput::Conway(x) => match x.deref().deref() {
conway::MintedTransactionOutput::Legacy(x) => match x.amount {
babbage::Value::Coin(c) => c,
babbage::Value::Multiasset(c, _) => c,
},
conway::MintedTransactionOutput::PostAlonzo(x) => match x.value {
babbage::Value::Coin(c) => c,
babbage::Value::Multiasset(c, _) => c,
},
},
}
}
@ -144,7 +193,13 @@ impl<'b> MultiEraOutput<'b> {
/// list.
pub fn non_ada_assets(&self) -> Vec<MultiEraPolicyAssets> {
match self {
MultiEraOutput::Byron(_) => vec![],
MultiEraOutput::AlonzoCompatible(x) => match &x.amount {
alonzo::Value::Coin(_) => vec![],
alonzo::Value::Multiasset(_, x) => x
.iter()
.map(|(k, v)| MultiEraPolicyAssets::AlonzoCompatibleOutput(k, v))
.collect(),
},
MultiEraOutput::Babbage(x) => match x.deref().deref() {
babbage::MintedTransactionOutput::Legacy(x) => match &x.amount {
babbage::Value::Coin(_) => vec![],
@ -161,13 +216,23 @@ impl<'b> MultiEraOutput<'b> {
.collect(),
},
},
MultiEraOutput::AlonzoCompatible(x) => match &x.amount {
alonzo::Value::Coin(_) => vec![],
alonzo::Value::Multiasset(_, x) => x
MultiEraOutput::Byron(_) => vec![],
MultiEraOutput::Conway(x) => match x.deref().deref() {
conway::MintedTransactionOutput::Legacy(x) => match &x.amount {
babbage::Value::Coin(_) => vec![],
babbage::Value::Multiasset(_, x) => x
.iter()
.map(|(k, v)| MultiEraPolicyAssets::AlonzoCompatibleOutput(k, v))
.collect(),
},
conway::MintedTransactionOutput::PostAlonzo(x) => match &x.value {
babbage::Value::Coin(_) => vec![],
babbage::Value::Multiasset(_, x) => x
.iter()
.map(|(k, v)| MultiEraPolicyAssets::AlonzoCompatibleOutput(k, v))
.collect(),
},
},
}
}
}

View file

@ -113,7 +113,7 @@ mod tests {
#[test]
fn conway_block_detected() {
let block_str = include_str!("../../test_data/conway1.artificial.block");
let block_str = include_str!("../../test_data/conway1.block");
let bytes = hex::decode(block_str).unwrap();
let inference = block_era(bytes.as_slice());

View file

@ -0,0 +1,68 @@
use std::borrow::Cow;
use pallas_primitives::{alonzo, conway};
use crate::MultiEraRedeemer;
impl<'b> MultiEraRedeemer<'b> {
pub fn tag(&self) -> conway::RedeemerTag {
match &self {
Self::AlonzoCompatible(x) => match x.tag {
alonzo::RedeemerTag::Cert => conway::RedeemerTag::Cert,
alonzo::RedeemerTag::Spend => conway::RedeemerTag::Spend,
alonzo::RedeemerTag::Mint => conway::RedeemerTag::Mint,
alonzo::RedeemerTag::Reward => conway::RedeemerTag::Reward,
},
Self::Conway(x, _) => x.tag,
}
}
pub fn data(&self) -> &alonzo::PlutusData {
match &self {
Self::AlonzoCompatible(x) => &x.data,
Self::Conway(_, x) => &x.data,
}
}
pub fn ex_units(&self) -> alonzo::ExUnits {
match &self {
Self::AlonzoCompatible(x) => x.ex_units,
Self::Conway(_, x) => x.ex_units,
}
}
pub fn index(&self) -> u32 {
match self {
Self::AlonzoCompatible(x) => x.index,
Self::Conway(x, _) => x.index,
}
}
pub fn as_alonzo(&self) -> Option<&alonzo::Redeemer> {
match self {
Self::AlonzoCompatible(x) => Some(x),
Self::Conway(..) => None,
}
}
pub fn as_conway(&self) -> Option<(&conway::RedeemersKey, &conway::RedeemersValue)> {
match self {
Self::AlonzoCompatible(_) => None,
Self::Conway(x, y) => Some((x, y)),
}
}
pub fn from_alonzo_compatible(redeemer: &'b alonzo::Redeemer) -> Self {
Self::AlonzoCompatible(Box::new(Cow::Borrowed(redeemer)))
}
pub fn from_conway(
redeemers_key: &'b conway::RedeemersKey,
redeemers_val: &'b conway::RedeemersValue,
) -> Self {
Self::Conway(
Box::new(Cow::Borrowed(redeemers_key)),
Box::new(Cow::Borrowed(redeemers_val)),
)
}
}

View file

@ -134,7 +134,7 @@ impl<'b> MultiEraTx<'b> {
.transaction_body
.outputs
.iter()
.map(MultiEraOutput::from_babbage)
.map(MultiEraOutput::from_conway)
.collect(),
}
}
@ -160,7 +160,7 @@ impl<'b> MultiEraTx<'b> {
.transaction_body
.outputs
.get(index)
.map(MultiEraOutput::from_babbage),
.map(MultiEraOutput::from_conway),
}
}
@ -281,13 +281,12 @@ impl<'b> MultiEraTx<'b> {
.flat_map(|x| x.iter())
.map(|(k, v)| MultiEraPolicyAssets::AlonzoCompatibleMint(k, v))
.collect(),
// TODO: Is this still AlonzoCompatible? Zero vals not allowed or something
MultiEraTx::Conway(x) => x
.transaction_body
.mint
.iter()
.flat_map(|x| x.iter())
.map(|(k, v)| MultiEraPolicyAssets::AlonzoCompatibleMint(k, v))
.map(|(k, v)| MultiEraPolicyAssets::ConwayMint(k, v))
.collect(),
}
}
@ -334,7 +333,7 @@ impl<'b> MultiEraTx<'b> {
.transaction_body
.collateral_return
.as_ref()
.map(MultiEraOutput::from_babbage),
.map(MultiEraOutput::from_conway),
_ => None,
}
}
@ -523,12 +522,11 @@ impl<'b> MultiEraTx<'b> {
.map(MultiEraSigners::AlonzoCompatible)
.unwrap_or_default(),
MultiEraTx::Byron(_) => MultiEraSigners::NotApplicable,
// TODO: still compat?
MultiEraTx::Conway(x) => x
.transaction_body
.required_signers
.as_ref()
.map(MultiEraSigners::AlonzoCompatible)
.map(|x| MultiEraSigners::AlonzoCompatible(x.deref()))
.unwrap_or_default(),
}
}

View file

@ -1,11 +1,11 @@
use pallas_codec::utils::KeepRaw;
use pallas_primitives::{
alonzo::{self, BootstrapWitness, NativeScript, PlutusData, VKeyWitness},
babbage::{PlutusV2Script, Redeemer},
conway::{self, PlutusV3Script},
babbage::PlutusV2Script,
conway::PlutusV3Script,
};
use crate::MultiEraTx;
use crate::{MultiEraRedeemer, MultiEraTx};
impl<'b> MultiEraTx<'b> {
pub fn vkey_witnesses(&self) -> &[VKeyWitness] {
@ -128,37 +128,30 @@ impl<'b> MultiEraTx<'b> {
}
}
// TODO: MultiEraRedeemer?
pub fn redeemers(&self) -> &[Redeemer] {
pub fn redeemers(&self) -> Vec<MultiEraRedeemer> {
match self {
Self::Byron(_) => &[],
Self::Byron(_) => vec![],
Self::AlonzoCompatible(x, _) => x
.transaction_witness_set
.redeemer
.as_ref()
.map(|x| x.as_ref())
.unwrap_or(&[]),
.iter()
.flat_map(|x| x.iter())
.map(MultiEraRedeemer::from_alonzo_compatible)
.collect(),
Self::Babbage(x) => x
.transaction_witness_set
.redeemer
.as_ref()
.map(|x| x.as_ref())
.unwrap_or(&[]),
Self::Conway(_) => &[],
}
}
pub fn conway_redeemers(&self) -> &[conway::Redeemer] {
match self {
Self::Byron(_) => &[],
Self::AlonzoCompatible(_, _) => &[],
Self::Babbage(_) => &[],
.iter()
.flat_map(|x| x.iter())
.map(MultiEraRedeemer::from_alonzo_compatible)
.collect(),
Self::Conway(x) => x
.transaction_witness_set
.redeemer
.as_ref()
.map(|x| x.as_ref())
.unwrap_or(&[]),
.iter()
.flat_map(|x| x.iter())
.map(|(k, v)| MultiEraRedeemer::from_conway(k, v))
.collect(),
}
}

View file

@ -1,34 +1,35 @@
use std::ops::Deref;
use pallas_codec::utils::KeyValuePairs;
use pallas_primitives::{alonzo, babbage};
use pallas_primitives::{alonzo, babbage, conway};
use pallas_traverse as trv;
use trv::OriginalHash;
use utxorpc_spec::utxorpc::v1alpha::cardano as u5c;
pub fn map_purpose(x: &alonzo::RedeemerTag) -> u5c::RedeemerPurpose {
pub fn map_purpose(x: &conway::RedeemerTag) -> u5c::RedeemerPurpose {
match x {
babbage::RedeemerTag::Spend => u5c::RedeemerPurpose::Spend,
babbage::RedeemerTag::Mint => u5c::RedeemerPurpose::Mint,
babbage::RedeemerTag::Cert => u5c::RedeemerPurpose::Cert,
babbage::RedeemerTag::Reward => u5c::RedeemerPurpose::Reward,
conway::RedeemerTag::Spend => u5c::RedeemerPurpose::Spend,
conway::RedeemerTag::Mint => u5c::RedeemerPurpose::Mint,
conway::RedeemerTag::Cert => u5c::RedeemerPurpose::Cert,
conway::RedeemerTag::Reward => u5c::RedeemerPurpose::Reward,
conway::RedeemerTag::Vote => todo!(),
conway::RedeemerTag::Propose => todo!(),
}
}
pub fn map_redeemer(x: &alonzo::Redeemer) -> u5c::Redeemer {
pub fn map_redeemer(x: &trv::MultiEraRedeemer) -> u5c::Redeemer {
u5c::Redeemer {
purpose: map_purpose(&x.tag).into(),
datum: map_plutus_datum(&x.data).into(),
purpose: map_purpose(&x.tag()).into(),
datum: map_plutus_datum(x.data()).into(),
}
}
pub fn map_tx_input(i: &trv::MultiEraInput, tx: &trv::MultiEraTx) -> u5c::TxInput {
let redeemer = tx
.redeemers()
.iter()
.find(|r| (r.index as u64) == i.index());
let redeemers = tx.redeemers();
let redeemer = redeemers.iter().find(|r| (r.index() as u64) == i.index());
u5c::TxInput {
tx_hash: i.hash().to_vec().into(),
@ -57,19 +58,20 @@ pub fn map_tx_output(x: &trv::MultiEraOutput) -> u5c::TxOutput {
_ => vec![].into(),
},
script: match x.script_ref() {
Some(babbage::PseudoScript::NativeScript(x)) => u5c::Script {
Some(conway::PseudoScript::NativeScript(x)) => u5c::Script {
script: u5c::script::Script::Native(map_native_script(&x)).into(),
}
.into(),
Some(babbage::PseudoScript::PlutusV1Script(x)) => u5c::Script {
Some(conway::PseudoScript::PlutusV1Script(x)) => u5c::Script {
script: u5c::script::Script::PlutusV1(x.0.to_vec().into()).into(),
}
.into(),
Some(babbage::PseudoScript::PlutusV2Script(x)) => u5c::Script {
Some(conway::PseudoScript::PlutusV2Script(x)) => u5c::Script {
script: u5c::script::Script::PlutusV2(x.0.to_vec().into()).into(),
}
.into(),
_ => None,
Some(conway::PseudoScript::PlutusV3Script(_)) => todo!(),
None => None,
},
}
}
@ -92,16 +94,17 @@ pub fn map_stake_credential(x: &babbage::StakeCredential) -> u5c::StakeCredentia
pub fn map_relay(x: &alonzo::Relay) -> u5c::Relay {
match x {
babbage::Relay::SingleHostAddr(port, v4, v6) => u5c::Relay {
ip_v4: v4.as_ref().map(|x| x.to_vec().into()).unwrap_or_default(),
ip_v6: v6.as_ref().map(|x| x.to_vec().into()).unwrap_or_default(),
// ip_v4: v4.map(|x| x.to_vec().into()).into().unwrap_or_default(),
ip_v4: Option::from(v4.clone().map(|x| x.to_vec().into())).unwrap_or_default(),
ip_v6: Option::from(v6.clone().map(|x| x.to_vec().into())).unwrap_or_default(),
dns_name: String::default(),
port: port.unwrap_or_default(),
port: Option::from(port.clone()).unwrap_or_default(),
},
babbage::Relay::SingleHostName(port, name) => u5c::Relay {
ip_v4: Default::default(),
ip_v6: Default::default(),
dns_name: name.clone(),
port: port.unwrap_or_default(),
port: Option::from(port.clone()).unwrap_or_default(),
},
babbage::Relay::MultiHostName(name) => u5c::Relay {
ip_v4: Default::default(),
@ -149,10 +152,13 @@ pub fn map_cert(x: &trv::MultiEraCert) -> u5c::Certificate {
reward_account: reward_account.to_vec().into(),
pool_owners: pool_owners.iter().map(|x| x.to_vec().into()).collect(),
relays: relays.iter().map(map_relay).collect(),
pool_metadata: pool_metadata.as_ref().map(|x| u5c::PoolMetadata {
pool_metadata: pool_metadata
.clone()
.map(|x| u5c::PoolMetadata {
url: x.url.clone(),
hash: x.hash.to_vec().into(),
}),
})
.into(),
}),
babbage::Certificate::PoolRetirement(a, b) => {
u5c::certificate::Certificate::PoolRetirement(u5c::PoolRetirementCert {

File diff suppressed because one or more lines are too long

1
test_data/conway2.block Normal file
View file

@ -0,0 +1 @@
820785828a1a00120f0b1a016dc6a35820758bc1310101e0f7936f86fd98c107fd8afed20a6834995ed4c24ed142c1318258204aa6b5dbdcd388f380141bd2cb3fa5b241340fac92c27b5469fe73eff565f4675820b578942b49a57735cb4d96de30faafa5fab3097389743cde5447258e902be5bb82584099f90365a06bad67307a8dc282d260a948f2166891c00fa4b897afd62d94d243a5b4d3f6f03d36434fb9f4b2cb2927ed30b6bd0bd27f835b22cb705aa2e5c03958504110edda16d5886109322503f8b564400c1cfd86abe6b1becfdcd750a6dd2f3176f1dffadb6b6e28d1b1d5850ec5780e1236306fd1db7f0a15167908765de967257dccd729d2fb95add164cb8e2103041901505820e65a86a416e6134b634b980c47481192d1e76a8dfb9271b8238b97b4ccb5503e84582055bbc058b524a50351600ea242e7c2410136bf020c57e82a9ae7f4aa8fc4bd530018a158400907bf340838d6a7e8005eb14f6562e7156eac0d15f1b28318ec275a6bae24cc8b5b228d0828dc0fc0b9388eb270a8bb52802ce75592b84aa488f9c28da0c70c8209005901c0b42732ad68ad1d026fa64a6b495b7d627ead721a8a006d5e66474b8dbd9fa51964e3f2edeb653dff4e66b415e54ee5f30b0fa8a6780ce79374070ff429ed280731881ffb28e0f8f753f332e0a5bded5b2ee500635da2abdda5b9572448ffcaf737137891efa1403e79103559d066ccf7f7744ca3b3f5f08e8e90d6ed2f67b0ef893d7e78ad04d414f5adae25f9d684384cc3999991343e19fa1e601a1040398510436fd137de03b7b47bb1fc68f51c20e7aa2b3c5ae33562090a7e2f90a55468c9f5d7bc9e0465af512dbaef10bdc539d90f25da66d99ddb558584e8dc2b3771a41121be407da1dcfdfc5ea7275b4b1ec28501ee6b375cb392e2264e09336471cfaff50fee8073c9fd43a83c8e16567b0c96094752dfe597a13e4f457f60d057236a9d4ba127e9f1208781a7934f8a749af51335a7f2bdc6db0142ff4ab1c5cc3a5e0457aad99c69d7e12c952739b8157788792e5421081c473be36574e580335ee445a64ca663dc5f8e2ae37972d6fd49150349d7f38884934a4083025d383dfe9e5e4ee3fded389eea87cf13238233ea1888ad1915ff81e9acf21f506f8f325dccd8cfea20fb7e44412c9d49f3649f49f62096566f9703acdf5dde7d7fbd4681a400d9010281825820d1c5bf73e34357190fe9c55ea9da64c26306663c4e42f5c4aa82095f963e96b800018182583900db1bc3c3f99ce68977ceaf27ab4dd917123ef9e73f85c304236eab2397a993b0c8166aa8c48345be19257a4025ab764c86e799beab15b3031b00000001661f931e021a0002985d14d9010281841a3b9aca00581de0db1bc3c3f99ce68977ceaf27ab4dd917123ef9e73f85c304236eab238301f6820901827668747470733a2f2f6269742e6c792f337a434832484c5820111111111111111111111111111111111111111111111111111111111111111181a100d90102818258205f89ea8c6ab580e2e7a32c3586869eb95fae54f42ac982639b6665359601f63e58409d45b4846cd2ab8260d6f684c6c083dad6938bc07428606ce1c90f6805814a517ff2cb6e8cdabf28a3aadada7957f338685180df4f357a53db276c7516d2e508a080