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

@ -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,12 +216,22 @@ impl<'b> MultiEraOutput<'b> {
.collect(),
},
},
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::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(),
}
}