From c4b85bb32156e57d07f31bc06b0f6fec7621c1c4 Mon Sep 17 00:00:00 2001 From: rooooooooob Date: Thu, 26 Oct 2023 18:31:24 -0700 Subject: [PATCH 1/3] Multi-Era expanded functionality + Shelley Metadata set fix All multi-era functionality besides updates/governance should now be exposed. e.g now the blocks can have the tx bodies/metadata/witnesses inspected and tx bodies can have all their fields (bar update/gov) inspected through era-agnostic wrappers. WASM wrappers are also provided. ShelleyBlock's metadataset was not wrapped in the tx index map for some reason. This still passed the deserialization tests since this still ended up being able to parse the metadata as the metadatum label map/tx index map are the same and then the inner label was also valid regular metadata by itself. After the fix mainnet shelley was retested just in case and there were no issues. --- chain/wasm/Cargo.toml | 2 +- core/rust/src/ordered_hash_map.rs | 10 + multi-era/rust/src/allegra/mod.rs | 1 + multi-era/rust/src/allegra/utils.rs | 22 + multi-era/rust/src/alonzo/mod.rs | 1 + multi-era/rust/src/alonzo/utils.rs | 35 + multi-era/rust/src/babbage/mod.rs | 1 + multi-era/rust/src/babbage/utils.rs | 72 ++ multi-era/rust/src/byron/mod.rs | 3 +- .../src/byron/transaction/serialization.rs | 4 +- multi-era/rust/src/lib.rs | 51 +- multi-era/rust/src/serialization.rs | 118 ++++ multi-era/rust/src/shelley/cbor_encodings.rs | 2 + multi-era/rust/src/shelley/mod.rs | 6 +- multi-era/rust/src/shelley/serialization.rs | 96 ++- multi-era/rust/src/shelley/utils.rs | 44 ++ multi-era/rust/src/utils.rs | 630 +++++++++++++++++- multi-era/wasm/src/byron/mod.rs | 3 +- multi-era/wasm/src/lib.rs | 165 ++++- multi-era/wasm/src/shelley/mod.rs | 9 +- multi-era/wasm/src/utils.rs | 452 ++++++++++++- specs/multiera/cml_chain/byron.cddl | 3 +- specs/multiera/cml_chain/transaction.cddl | 1 + specs/multiera/lib.cddl | 11 +- specs/multiera/shelley/mod.cddl | 2 +- 25 files changed, 1717 insertions(+), 27 deletions(-) create mode 100644 multi-era/rust/src/allegra/utils.rs create mode 100644 multi-era/rust/src/alonzo/utils.rs create mode 100644 multi-era/rust/src/babbage/utils.rs create mode 100644 multi-era/rust/src/shelley/utils.rs diff --git a/chain/wasm/Cargo.toml b/chain/wasm/Cargo.toml index c5724c5f..15c8f315 100644 --- a/chain/wasm/Cargo.toml +++ b/chain/wasm/Cargo.toml @@ -18,4 +18,4 @@ cbor_event = "2.4.0" wasm-bindgen = { version = "=0.2.83", features = ["serde-serialize"] } linked-hash-map = "0.5.3" serde_json = "1.0.57" -serde-wasm-bindgen = "0.4.5" \ No newline at end of file +serde-wasm-bindgen = "0.4.5" diff --git a/core/rust/src/ordered_hash_map.rs b/core/rust/src/ordered_hash_map.rs index 5efc0dcc..0e387a6b 100644 --- a/core/rust/src/ordered_hash_map.rs +++ b/core/rust/src/ordered_hash_map.rs @@ -1,4 +1,5 @@ use core::hash::{Hash, Hasher}; +use std::iter::FromIterator; // allowing this since PartialEq equality here still implies hash equality #[allow(clippy::derived_hash_with_manual_eq)] @@ -105,3 +106,12 @@ where std::collections::BTreeMap::::is_referenceable() } } + +impl FromIterator<(K, V)> for OrderedHashMap +where + K: Hash + Eq + Ord, +{ + fn from_iter>(iter: T) -> Self { + Self(linked_hash_map::LinkedHashMap::from_iter(iter)) + } +} diff --git a/multi-era/rust/src/allegra/mod.rs b/multi-era/rust/src/allegra/mod.rs index d8a673f5..0cfe0b01 100644 --- a/multi-era/rust/src/allegra/mod.rs +++ b/multi-era/rust/src/allegra/mod.rs @@ -3,6 +3,7 @@ pub mod cbor_encodings; pub mod serialization; +pub mod utils; use crate::shelley::{ GenesisKeyDelegation, ShelleyHeader, ShelleyTransactionOutput, ShelleyUpdate, diff --git a/multi-era/rust/src/allegra/utils.rs b/multi-era/rust/src/allegra/utils.rs new file mode 100644 index 00000000..1ca78594 --- /dev/null +++ b/multi-era/rust/src/allegra/utils.rs @@ -0,0 +1,22 @@ +use cml_chain::{auxdata::AuxiliaryData, transaction::TransactionWitnessSet}; + +use super::{AllegraAuxiliaryData, AllegraTransactionWitnessSet}; + +impl From for AuxiliaryData { + fn from(aux: AllegraAuxiliaryData) -> Self { + match aux { + AllegraAuxiliaryData::Shelley(md) => AuxiliaryData::new_shelley(md), + AllegraAuxiliaryData::ShelleyMA(md) => AuxiliaryData::new_shelley_m_a(md), + } + } +} + +impl From for TransactionWitnessSet { + fn from(wits: AllegraTransactionWitnessSet) -> Self { + let mut new_wits = TransactionWitnessSet::new(); + new_wits.vkeywitnesses = wits.vkeywitnesses; + new_wits.native_scripts = wits.native_scripts; + new_wits.bootstrap_witnesses = wits.bootstrap_witnesses; + new_wits + } +} diff --git a/multi-era/rust/src/alonzo/mod.rs b/multi-era/rust/src/alonzo/mod.rs index a5721fe0..596d7798 100644 --- a/multi-era/rust/src/alonzo/mod.rs +++ b/multi-era/rust/src/alonzo/mod.rs @@ -3,6 +3,7 @@ pub mod cbor_encodings; pub mod serialization; +pub mod utils; use cml_core::Int; diff --git a/multi-era/rust/src/alonzo/utils.rs b/multi-era/rust/src/alonzo/utils.rs new file mode 100644 index 00000000..ab2f213f --- /dev/null +++ b/multi-era/rust/src/alonzo/utils.rs @@ -0,0 +1,35 @@ +use cml_chain::{ + auxdata::{AuxiliaryData, ConwayFormatAuxData}, + transaction::TransactionWitnessSet, +}; + +use super::{AlonzoAuxiliaryData, AlonzoTransactionWitnessSet}; + +impl From for AuxiliaryData { + fn from(aux: AlonzoAuxiliaryData) -> Self { + match aux { + AlonzoAuxiliaryData::Shelley(md) => AuxiliaryData::new_shelley(md.clone()), + AlonzoAuxiliaryData::ShelleyMA(md) => AuxiliaryData::new_shelley_m_a(md.clone()), + AlonzoAuxiliaryData::Alonzo(md) => AuxiliaryData::new_conway({ + let mut conway = ConwayFormatAuxData::new(); + conway.metadata = md.metadata.clone(); + conway.native_scripts = md.native_scripts.clone(); + conway.plutus_v1_scripts = md.plutus_v1_scripts.clone(); + conway + }), + } + } +} + +impl From for TransactionWitnessSet { + fn from(wits: AlonzoTransactionWitnessSet) -> Self { + let mut new_wits = TransactionWitnessSet::new(); + new_wits.vkeywitnesses = wits.vkeywitnesses; + new_wits.native_scripts = wits.native_scripts; + new_wits.bootstrap_witnesses = wits.bootstrap_witnesses; + new_wits.redeemers = wits.redeemers; + new_wits.plutus_datums = wits.plutus_datums; + new_wits.plutus_v1_scripts = wits.plutus_v1_scripts; + new_wits + } +} diff --git a/multi-era/rust/src/babbage/mod.rs b/multi-era/rust/src/babbage/mod.rs index 1b2f18af..9e193d50 100644 --- a/multi-era/rust/src/babbage/mod.rs +++ b/multi-era/rust/src/babbage/mod.rs @@ -3,6 +3,7 @@ pub mod cbor_encodings; pub mod serialization; +pub mod utils; use crate::allegra::AllegraCertificate; use crate::shelley::ProtocolVersionStruct; diff --git a/multi-era/rust/src/babbage/utils.rs b/multi-era/rust/src/babbage/utils.rs new file mode 100644 index 00000000..7a1fd6fc --- /dev/null +++ b/multi-era/rust/src/babbage/utils.rs @@ -0,0 +1,72 @@ +use cml_chain::{ + auxdata::{AuxiliaryData, ConwayFormatAuxData}, + transaction::TransactionWitnessSet, + Script, +}; + +use super::{BabbageAuxiliaryData, BabbageScript, BabbageTransactionWitnessSet}; + +impl From for Script { + fn from(script: BabbageScript) -> Script { + match script { + BabbageScript::Native { + script, + len_encoding, + tag_encoding, + } => Script::Native { + script, + len_encoding, + tag_encoding, + }, + BabbageScript::PlutusV1 { + script, + len_encoding, + tag_encoding, + } => Script::PlutusV1 { + script, + len_encoding, + tag_encoding, + }, + BabbageScript::PlutusV2 { + script, + len_encoding, + tag_encoding, + } => Script::PlutusV2 { + script, + len_encoding, + tag_encoding, + }, + } + } +} + +impl From for AuxiliaryData { + fn from(aux: BabbageAuxiliaryData) -> Self { + match aux { + BabbageAuxiliaryData::Shelley(md) => AuxiliaryData::new_shelley(md.clone()), + BabbageAuxiliaryData::ShelleyMA(md) => AuxiliaryData::new_shelley_m_a(md.clone()), + BabbageAuxiliaryData::Babbage(md) => AuxiliaryData::new_conway({ + let mut conway = ConwayFormatAuxData::new(); + conway.metadata = md.metadata.clone(); + conway.native_scripts = md.native_scripts.clone(); + conway.plutus_v1_scripts = md.plutus_v1_scripts.clone(); + conway.plutus_v2_scripts = md.plutus_v2_scripts.clone(); + conway + }), + } + } +} + +impl From for TransactionWitnessSet { + fn from(wits: BabbageTransactionWitnessSet) -> Self { + let mut new_wits = TransactionWitnessSet::new(); + new_wits.vkeywitnesses = wits.vkeywitnesses; + new_wits.native_scripts = wits.native_scripts; + new_wits.bootstrap_witnesses = wits.bootstrap_witnesses; + new_wits.redeemers = wits.redeemers; + new_wits.plutus_datums = wits.plutus_datums; + new_wits.plutus_v1_scripts = wits.plutus_v1_scripts; + new_wits.plutus_v2_scripts = wits.plutus_v2_scripts; + new_wits + } +} diff --git a/multi-era/rust/src/byron/mod.rs b/multi-era/rust/src/byron/mod.rs index a131490a..acdd0fe7 100644 --- a/multi-era/rust/src/byron/mod.rs +++ b/multi-era/rust/src/byron/mod.rs @@ -9,6 +9,7 @@ pub mod transaction; pub mod update; pub mod utils; +use cml_crypto::TransactionHash; pub use utils::*; pub type ByronBlockId = Blake2b256; @@ -29,7 +30,7 @@ impl ByronSlotId { } } -pub type ByronTxId = Blake2b256; +pub type ByronTxId = TransactionHash; pub type ByronUpdateId = Blake2b256; diff --git a/multi-era/rust/src/byron/transaction/serialization.rs b/multi-era/rust/src/byron/transaction/serialization.rs index 6daeed68..47ea8aa1 100644 --- a/multi-era/rust/src/byron/transaction/serialization.rs +++ b/multi-era/rust/src/byron/transaction/serialization.rs @@ -7,7 +7,7 @@ use cbor_event::de::Deserializer; use cbor_event::se::{Serialize, Serializer}; use cml_core::error::*; use cml_core::serialization::*; -use cml_crypto::RawBytesEncoding; +use cml_crypto::{RawBytesEncoding, TransactionHash}; use std::io::{BufRead, Seek, SeekFrom, Write}; impl cbor_event::se::Serialize for ByronPkWitness { @@ -703,7 +703,7 @@ impl Deserialize for ByronTxOutPtr { .bytes() .map_err(Into::::into) .and_then(|bytes| { - Blake2b256::from_raw_bytes(&bytes) + TransactionHash::from_raw_bytes(&bytes) .map_err(|e| DeserializeFailure::InvalidStructure(Box::new(e)).into()) }) .map_err(|e: DeserializeError| e.annotate("byron_tx_id"))?; diff --git a/multi-era/rust/src/lib.rs b/multi-era/rust/src/lib.rs index 16161492..62bf0a80 100644 --- a/multi-era/rust/src/lib.rs +++ b/multi-era/rust/src/lib.rs @@ -13,12 +13,16 @@ pub mod utils; // https://github.com/dcSpark/cddl-codegen use crate::{ - allegra::AllegraBlock, alonzo::AlonzoBlock, babbage::BabbageBlock, byron::block::ByronBlock, - mary::MaryBlock, shelley::ShelleyBlock, + allegra::{AllegraBlock, AllegraTransactionBody}, + alonzo::{AlonzoBlock, AlonzoTransactionBody}, + babbage::{BabbageBlock, BabbageTransactionBody}, + byron::{block::ByronBlock, transaction::ByronTx}, + mary::{MaryBlock, MaryTransactionBody}, + shelley::{ShelleyBlock, ShelleyTransactionBody}, }; -use cml_chain::address::RewardAccount; use cml_chain::block::Block; use cml_chain::crypto::GenesisHash; +use cml_chain::{address::RewardAccount, transaction::TransactionBody}; pub type GenesisHashList = Vec; @@ -64,3 +68,44 @@ impl MultiEraBlock { Self::Conway(conway) } } + +#[derive(Clone, Debug, serde::Deserialize, serde::Serialize, schemars::JsonSchema)] +pub enum MultiEraTransactionBody { + Byron(ByronTx), + Shelley(ShelleyTransactionBody), + Allegra(AllegraTransactionBody), + Mary(MaryTransactionBody), + Alonzo(AlonzoTransactionBody), + Babbage(BabbageTransactionBody), + Conway(TransactionBody), +} + +impl MultiEraTransactionBody { + pub fn new_byron(byron: ByronTx) -> Self { + Self::Byron(byron) + } + + pub fn new_shelley(shelley: ShelleyTransactionBody) -> Self { + Self::Shelley(shelley) + } + + pub fn new_allegra(allegra: AllegraTransactionBody) -> Self { + Self::Allegra(allegra) + } + + pub fn new_mary(mary: MaryTransactionBody) -> Self { + Self::Mary(mary) + } + + pub fn new_alonzo(alonzo: AlonzoTransactionBody) -> Self { + Self::Alonzo(alonzo) + } + + pub fn new_babbage(babbage: BabbageTransactionBody) -> Self { + Self::Babbage(babbage) + } + + pub fn new_conway(conway: TransactionBody) -> Self { + Self::Conway(conway) + } +} diff --git a/multi-era/rust/src/serialization.rs b/multi-era/rust/src/serialization.rs index 429b4405..fe2e25b0 100644 --- a/multi-era/rust/src/serialization.rs +++ b/multi-era/rust/src/serialization.rs @@ -106,3 +106,121 @@ impl Deserialize for MultiEraBlock { .map_err(|e| e.annotate("MultiEraBlock")) } } + +impl Serialize for MultiEraTransactionBody { + fn serialize<'se, W: Write>( + &self, + serializer: &'se mut Serializer, + force_canonical: bool, + ) -> cbor_event::Result<&'se mut Serializer> { + match self { + MultiEraTransactionBody::Byron(byron) => { + cbor_event::se::Serialize::serialize(byron, serializer) + } + MultiEraTransactionBody::Shelley(shelley) => { + shelley.serialize(serializer, force_canonical) + } + MultiEraTransactionBody::Allegra(allegra) => { + allegra.serialize(serializer, force_canonical) + } + MultiEraTransactionBody::Mary(mary) => mary.serialize(serializer, force_canonical), + MultiEraTransactionBody::Alonzo(alonzo) => { + alonzo.serialize(serializer, force_canonical) + } + MultiEraTransactionBody::Babbage(babbage) => { + babbage.serialize(serializer, force_canonical) + } + MultiEraTransactionBody::Conway(conway) => { + conway.serialize(serializer, force_canonical) + } + } + } +} + +impl Deserialize for MultiEraTransactionBody { + fn deserialize(raw: &mut Deserializer) -> Result { + (|| -> Result<_, DeserializeError> { + let initial_position = raw.as_mut_ref().stream_position().unwrap(); + let mut errs = Vec::new(); + let deser_variant: Result<_, DeserializeError> = ByronTx::deserialize(raw); + match deser_variant { + Ok(byron) => return Ok(Self::Byron(byron)), + Err(e) => { + errs.push(e.annotate("Byron")); + raw.as_mut_ref() + .seek(SeekFrom::Start(initial_position)) + .unwrap(); + } + }; + let deser_variant: Result<_, DeserializeError> = + ShelleyTransactionBody::deserialize(raw); + match deser_variant { + Ok(shelley) => return Ok(Self::Shelley(shelley)), + Err(e) => { + errs.push(e.annotate("Shelley")); + raw.as_mut_ref() + .seek(SeekFrom::Start(initial_position)) + .unwrap(); + } + }; + let deser_variant: Result<_, DeserializeError> = + AllegraTransactionBody::deserialize(raw); + match deser_variant { + Ok(allegra) => return Ok(Self::Allegra(allegra)), + Err(e) => { + errs.push(e.annotate("Allegra")); + raw.as_mut_ref() + .seek(SeekFrom::Start(initial_position)) + .unwrap(); + } + }; + let deser_variant: Result<_, DeserializeError> = MaryTransactionBody::deserialize(raw); + match deser_variant { + Ok(mary) => return Ok(Self::Mary(mary)), + Err(e) => { + errs.push(e.annotate("Mary")); + raw.as_mut_ref() + .seek(SeekFrom::Start(initial_position)) + .unwrap(); + } + }; + let deser_variant: Result<_, DeserializeError> = + AlonzoTransactionBody::deserialize(raw); + match deser_variant { + Ok(alonzo) => return Ok(Self::Alonzo(alonzo)), + Err(e) => { + errs.push(e.annotate("Alonzo")); + raw.as_mut_ref() + .seek(SeekFrom::Start(initial_position)) + .unwrap(); + } + }; + let deser_variant: Result<_, DeserializeError> = + BabbageTransactionBody::deserialize(raw); + match deser_variant { + Ok(babbage) => return Ok(Self::Babbage(babbage)), + Err(e) => { + errs.push(e.annotate("Babbage")); + raw.as_mut_ref() + .seek(SeekFrom::Start(initial_position)) + .unwrap(); + } + }; + let deser_variant: Result<_, DeserializeError> = TransactionBody::deserialize(raw); + match deser_variant { + Ok(conway) => return Ok(Self::Conway(conway)), + Err(e) => { + errs.push(e.annotate("Conway")); + raw.as_mut_ref() + .seek(SeekFrom::Start(initial_position)) + .unwrap(); + } + }; + Err(DeserializeError::new( + "MultiEraTransactionBody", + DeserializeFailure::NoVariantMatchedWithCauses(errs), + )) + })() + .map_err(|e| e.annotate("MultiEraTransactionBody")) + } +} diff --git a/multi-era/rust/src/shelley/cbor_encodings.rs b/multi-era/rust/src/shelley/cbor_encodings.rs index b743c8ac..7dc548a2 100644 --- a/multi-era/rust/src/shelley/cbor_encodings.rs +++ b/multi-era/rust/src/shelley/cbor_encodings.rs @@ -53,6 +53,8 @@ pub struct ShelleyBlockEncoding { pub len_encoding: LenEncoding, pub transaction_bodies_encoding: LenEncoding, pub transaction_witness_sets_encoding: LenEncoding, + pub transaction_metadata_set_encoding: LenEncoding, + pub transaction_metadata_set_key_encodings: BTreeMap>, } #[derive(Clone, Debug, Default)] diff --git a/multi-era/rust/src/shelley/mod.rs b/multi-era/rust/src/shelley/mod.rs index 773a7632..23985e7c 100644 --- a/multi-era/rust/src/shelley/mod.rs +++ b/multi-era/rust/src/shelley/mod.rs @@ -3,6 +3,7 @@ pub mod cbor_encodings; pub mod serialization; +pub mod utils; use cbor_encodings::{ MultisigAllEncoding, MultisigAnyEncoding, MultisigNOfKEncoding, MultisigPubkeyEncoding, @@ -25,6 +26,7 @@ use cml_chain::crypto::{ use cml_chain::transaction::TransactionInput; use cml_chain::{Epoch, LenEncoding, Rational, UnitInterval, Withdrawals}; use cml_core::ordered_hash_map::OrderedHashMap; +use cml_core::TransactionIndex; use cml_crypto::{GenesisDelegateHash, VRFKeyHash}; use std::collections::BTreeMap; @@ -171,7 +173,7 @@ pub struct ShelleyBlock { pub header: ShelleyHeader, pub transaction_bodies: Vec, pub transaction_witness_sets: Vec, - pub transaction_metadata_set: Metadata, + pub transaction_metadata_set: OrderedHashMap, #[serde(skip)] pub encodings: Option, } @@ -181,7 +183,7 @@ impl ShelleyBlock { header: ShelleyHeader, transaction_bodies: Vec, transaction_witness_sets: Vec, - transaction_metadata_set: Metadata, + transaction_metadata_set: OrderedHashMap, ) -> Self { Self { header, diff --git a/multi-era/rust/src/shelley/serialization.rs b/multi-era/rust/src/shelley/serialization.rs index 00bbf491..0e56f732 100644 --- a/multi-era/rust/src/shelley/serialization.rs +++ b/multi-era/rust/src/shelley/serialization.rs @@ -864,8 +864,52 @@ impl Serialize for ShelleyBlock { .map(|encs| encs.transaction_witness_sets_encoding) .unwrap_or_default() .end(serializer, force_canonical)?; - self.transaction_metadata_set - .serialize(serializer, force_canonical)?; + serializer.write_map_sz( + self.encodings + .as_ref() + .map(|encs| encs.transaction_metadata_set_encoding) + .unwrap_or_default() + .to_len_sz(self.transaction_metadata_set.len() as u64, force_canonical), + )?; + let mut key_order = self + .transaction_metadata_set + .iter() + .map(|(k, v)| { + let mut buf = cbor_event::se::Serializer::new_vec(); + let transaction_metadata_set_key_encoding = self + .encodings + .as_ref() + .and_then(|encs| encs.transaction_metadata_set_key_encodings.get(k)) + .cloned() + .unwrap_or_default(); + buf.write_unsigned_integer_sz( + *k as u64, + fit_sz( + *k as u64, + transaction_metadata_set_key_encoding, + force_canonical, + ), + )?; + Ok((buf.finalize(), k, v)) + }) + .collect::, &_, &_)>, cbor_event::Error>>()?; + if force_canonical { + key_order.sort_by(|(lhs_bytes, _, _), (rhs_bytes, _, _)| { + match lhs_bytes.len().cmp(&rhs_bytes.len()) { + std::cmp::Ordering::Equal => lhs_bytes.cmp(rhs_bytes), + diff_ord => diff_ord, + } + }); + } + for (key_bytes, _key, value) in key_order { + serializer.write_raw_bytes(&key_bytes)?; + value.serialize(serializer, force_canonical)?; + } + self.encodings + .as_ref() + .map(|encs| encs.transaction_metadata_set_encoding) + .unwrap_or_default() + .end(serializer, force_canonical)?; self.encodings .as_ref() .map(|encs| encs.len_encoding) @@ -926,8 +970,50 @@ impl Deserialize for ShelleyBlock { )) })() .map_err(|e| e.annotate("transaction_witness_sets"))?; - let transaction_metadata_set = Metadata::deserialize(raw) - .map_err(|e: DeserializeError| e.annotate("transaction_metadata_set"))?; + let ( + transaction_metadata_set, + transaction_metadata_set_encoding, + transaction_metadata_set_key_encodings, + ) = (|| -> Result<_, DeserializeError> { + let mut transaction_metadata_set_table = OrderedHashMap::new(); + let transaction_metadata_set_len = raw.map_sz()?; + let transaction_metadata_set_encoding = transaction_metadata_set_len.into(); + let mut transaction_metadata_set_key_encodings = BTreeMap::new(); + while match transaction_metadata_set_len { + cbor_event::LenSz::Len(n, _) => { + (transaction_metadata_set_table.len() as u64) < n + } + cbor_event::LenSz::Indefinite => true, + } { + if raw.cbor_type()? == cbor_event::Type::Special { + assert_eq!(raw.special()?, cbor_event::Special::Break); + break; + } + let (transaction_metadata_set_key, transaction_metadata_set_key_encoding) = raw + .unsigned_integer_sz() + .map(|(x, enc)| (x as u16, Some(enc)))?; + let transaction_metadata_set_value = Metadata::deserialize(raw)?; + if transaction_metadata_set_table + .insert(transaction_metadata_set_key, transaction_metadata_set_value) + .is_some() + { + return Err(DeserializeFailure::DuplicateKey(Key::Str(String::from( + "some complicated/unsupported type", + ))) + .into()); + } + transaction_metadata_set_key_encodings.insert( + transaction_metadata_set_key, + transaction_metadata_set_key_encoding, + ); + } + Ok(( + transaction_metadata_set_table, + transaction_metadata_set_encoding, + transaction_metadata_set_key_encodings, + )) + })() + .map_err(|e| e.annotate("transaction_metadata_set"))?; match len { cbor_event::LenSz::Len(_, _) => (), cbor_event::LenSz::Indefinite => match raw.special()? { @@ -944,6 +1030,8 @@ impl Deserialize for ShelleyBlock { len_encoding, transaction_bodies_encoding, transaction_witness_sets_encoding, + transaction_metadata_set_encoding, + transaction_metadata_set_key_encodings, }), }) })() diff --git a/multi-era/rust/src/shelley/utils.rs b/multi-era/rust/src/shelley/utils.rs new file mode 100644 index 00000000..f8ee4dfe --- /dev/null +++ b/multi-era/rust/src/shelley/utils.rs @@ -0,0 +1,44 @@ +use cml_chain::transaction::{NativeScript, TransactionWitnessSet}; + +use super::{MultisigScript, ShelleyTransactionWitnessSet}; + +impl From for TransactionWitnessSet { + fn from(wits: ShelleyTransactionWitnessSet) -> Self { + let mut new_wits = TransactionWitnessSet::new(); + new_wits.vkeywitnesses = wits.vkeywitnesses; + new_wits.native_scripts = wits + .native_scripts + .map(|native_scripts| native_scripts.into_iter().map(NativeScript::from).collect()); + new_wits.bootstrap_witnesses = wits.bootstrap_witnesses; + new_wits + } +} + +impl From for NativeScript { + fn from(script: MultisigScript) -> Self { + match script { + MultisigScript::MultisigPubkey(key) => { + NativeScript::new_script_pubkey(key.ed25519_key_hash) + } + MultisigScript::MultisigAll(all) => NativeScript::new_script_all( + all.multisig_scripts + .into_iter() + .map(NativeScript::from) + .collect(), + ), + MultisigScript::MultisigAny(any) => NativeScript::new_script_any( + any.multisig_scripts + .into_iter() + .map(NativeScript::from) + .collect(), + ), + MultisigScript::MultisigNOfK(nok) => NativeScript::new_script_n_of_k( + nok.n, + nok.multisig_scripts + .into_iter() + .map(NativeScript::from) + .collect(), + ), + } + } +} diff --git a/multi-era/rust/src/utils.rs b/multi-era/rust/src/utils.rs index b375417b..32f471ea 100644 --- a/multi-era/rust/src/utils.rs +++ b/multi-era/rust/src/utils.rs @@ -1,12 +1,35 @@ -use crate::MultiEraBlock; +use crate::allegra::{ + AllegraCertificate, MIRAction, MoveInstantaneousReward, MoveInstantaneousRewardsCert, +}; +use crate::babbage::BabbageTransactionOutput; +use crate::byron::transaction::ByronTxIn; +use crate::mary::MaryTransactionOutput; +use crate::shelley::{GenesisKeyDelegation, ShelleyCertificate, ShelleyTransactionOutput}; use crate::{ allegra::AllegraBlock, alonzo::AlonzoBlock, babbage::BabbageBlock, byron::block::ByronBlock, mary::MaryBlock, shelley::ShelleyBlock, }; +use crate::{MultiEraBlock, MultiEraTransactionBody}; use cbor_event::de::Deserializer; +use cml_chain::address::Address; +use cml_chain::assets::Mint; +use cml_chain::auxdata::AuxiliaryData; use cml_chain::block::Block; +use cml_chain::byron::ByronTxOut; +use cml_chain::certs::{ + AuthCommitteeHotCert, Certificate, PoolRegistration, PoolRetirement, RegCert, RegDrepCert, + ResignCommitteeColdCert, StakeDelegation, StakeDeregistration, StakeRegDelegCert, + StakeRegistration, StakeVoteDelegCert, StakeVoteRegDelegCert, UnregCert, UnregDrepCert, + UpdateDrepCert, VoteDelegCert, VoteRegDelegCert, +}; +use cml_chain::transaction::{ + AlonzoFormatTxOut, RequiredSigners, TransactionInput, TransactionOutput, TransactionWitnessSet, +}; +use cml_chain::{Coin, NetworkId, OrderedHashMap, Value, Withdrawals}; use cml_core::error::{DeserializeError, DeserializeFailure}; use cml_core::serialization::{CBORReadLen, Deserialize}; +use cml_core::{Int, TransactionIndex}; +use cml_crypto::{AuxiliaryDataHash, ScriptDataHash, TransactionHash}; impl MultiEraBlock { /** @@ -60,6 +83,611 @@ impl MultiEraBlock { } Ok(block) } + + pub fn transaction_bodies(&self) -> Vec { + match self { + Self::Byron(block) => match block { + ByronBlock::EpochBoundary(_) => vec![], + ByronBlock::Main(main) => main + .body + .tx_payload + .iter() + .map(|tx| MultiEraTransactionBody::Byron(tx.byron_tx.clone())) + .collect(), + }, + Self::Shelley(block) => block + .transaction_bodies + .iter() + .map(|i| MultiEraTransactionBody::Shelley(i.clone())) + .collect(), + Self::Allegra(block) => block + .transaction_bodies + .iter() + .map(|i| MultiEraTransactionBody::Allegra(i.clone())) + .collect(), + Self::Mary(block) => block + .transaction_bodies + .iter() + .map(|i| MultiEraTransactionBody::Mary(i.clone())) + .collect(), + Self::Alonzo(block) => block + .transaction_bodies + .iter() + .map(|i| MultiEraTransactionBody::Alonzo(i.clone())) + .collect(), + Self::Babbage(block) => block + .transaction_bodies + .iter() + .map(|i| MultiEraTransactionBody::Babbage(i.clone())) + .collect(), + Self::Conway(block) => block + .transaction_bodies + .iter() + .map(|i| MultiEraTransactionBody::Conway(i.clone())) + .collect(), + } + } + + pub fn transaction_witness_sets(&self) -> Vec { + match self { + Self::Byron(_block) => todo!(), + Self::Shelley(block) => block + .transaction_witness_sets + .iter() + .map(|wits| wits.clone().into()) + .collect(), + Self::Allegra(block) => block + .transaction_witness_sets + .iter() + .map(|wits| wits.clone().into()) + .collect(), + Self::Mary(block) => block + .transaction_witness_sets + .iter() + .map(|wits| wits.clone().into()) + .collect(), + Self::Alonzo(block) => block + .transaction_witness_sets + .iter() + .map(|wits| wits.clone().into()) + .collect(), + Self::Babbage(block) => block + .transaction_witness_sets + .iter() + .map(|wits| wits.clone().into()) + .collect(), + Self::Conway(block) => block.transaction_witness_sets.clone(), + } + } + + pub fn auxiliary_data_set(&self) -> OrderedHashMap { + match self { + Self::Byron(_block) => OrderedHashMap::default(), + Self::Shelley(block) => block + .transaction_metadata_set + .iter() + .map(|(i, md)| (*i, AuxiliaryData::new_shelley(md.clone()))) + .collect(), + Self::Allegra(block) => block + .auxiliary_data_set + .iter() + .map(|(i, md)| (*i, md.clone().into())) + .collect(), + Self::Mary(block) => block + .auxiliary_data_set + .iter() + .map(|(i, md)| (*i, md.clone().into())) + .collect(), + Self::Alonzo(block) => block + .auxiliary_data_set + .iter() + .map(|(i, md)| (*i, md.clone().into())) + .collect(), + Self::Babbage(block) => block + .auxiliary_data_set + .iter() + .map(|(i, md)| (*i, md.clone().into())) + .collect(), + Self::Conway(block) => block.auxiliary_data_set.clone(), + } + } + + pub fn invalid_transactions(&self) -> Vec { + match self { + Self::Byron(_block) => vec![], + Self::Shelley(_block) => vec![], + Self::Allegra(_block) => vec![], + Self::Mary(_block) => vec![], + Self::Alonzo(block) => block.invalid_transactions.clone(), + Self::Babbage(block) => block.invalid_transactions.clone(), + Self::Conway(block) => block.invalid_transactions.clone(), + } + } +} + +impl MultiEraTransactionBody { + pub fn inputs(&self) -> Vec { + match self { + Self::Byron(tx) => tx + .inputs + .iter() + .map(|i| MultiEraTransactionInput::Byron(i.clone())) + .collect(), + Self::Shelley(tx) => tx + .inputs + .iter() + .map(|i| MultiEraTransactionInput::Shelley(i.clone())) + .collect(), + Self::Allegra(tx) => tx + .inputs + .iter() + .map(|i| MultiEraTransactionInput::Shelley(i.clone())) + .collect(), + Self::Mary(tx) => tx + .inputs + .iter() + .map(|i| MultiEraTransactionInput::Shelley(i.clone())) + .collect(), + Self::Alonzo(tx) => tx + .inputs + .iter() + .map(|i| MultiEraTransactionInput::Shelley(i.clone())) + .collect(), + Self::Babbage(tx) => tx + .inputs + .iter() + .map(|i| MultiEraTransactionInput::Shelley(i.clone())) + .collect(), + Self::Conway(tx) => tx + .inputs + .iter() + .map(|i| MultiEraTransactionInput::Shelley(i.clone())) + .collect(), + } + } + + pub fn outputs(&self) -> Vec { + match self { + Self::Byron(tx) => tx + .outputs + .iter() + .map(|o| MultiEraTransactionOutput::Byron(o.clone())) + .collect(), + Self::Shelley(tx) => tx + .outputs + .clone() + .into_iter() + .map(MultiEraTransactionOutput::from) + .collect(), + Self::Allegra(tx) => tx + .outputs + .clone() + .into_iter() + .map(MultiEraTransactionOutput::from) + .collect(), + Self::Mary(tx) => tx + .outputs + .clone() + .into_iter() + .map(MultiEraTransactionOutput::from) + .collect(), + Self::Alonzo(tx) => tx + .outputs + .clone() + .into_iter() + .map(MultiEraTransactionOutput::from) + .collect(), + Self::Babbage(tx) => tx + .outputs + .clone() + .into_iter() + .map(MultiEraTransactionOutput::from) + .collect(), + Self::Conway(tx) => tx + .outputs + .iter() + .map(|o| MultiEraTransactionOutput::Shelley(o.clone())) + .collect(), + } + } + + pub fn fee(&self) -> Option { + match self { + Self::Byron(_tx) => None, + Self::Shelley(tx) => Some(tx.fee), + Self::Allegra(tx) => Some(tx.fee), + Self::Mary(tx) => Some(tx.fee), + Self::Alonzo(tx) => Some(tx.fee), + Self::Babbage(tx) => Some(tx.fee), + Self::Conway(tx) => Some(tx.fee), + } + } + + pub fn ttl(&self) -> Option { + match self { + Self::Byron(_tx) => None, + Self::Shelley(tx) => Some(tx.ttl), + Self::Allegra(tx) => tx.ttl, + Self::Mary(tx) => tx.ttl, + Self::Alonzo(tx) => tx.ttl, + Self::Babbage(tx) => tx.ttl, + Self::Conway(tx) => tx.ttl, + } + } + + pub fn certs(&self) -> Option> { + match self { + Self::Byron(_tx) => None, + Self::Shelley(tx) => tx.certs.as_ref().map(|certs| { + certs + .iter() + .map(|c| MultiEraCertificate::from(c.clone())) + .collect() + }), + Self::Allegra(tx) => tx.certs.as_ref().map(|certs| { + certs + .iter() + .map(|c| MultiEraCertificate::from(c.clone())) + .collect() + }), + Self::Mary(tx) => tx.certs.as_ref().map(|certs| { + certs + .iter() + .map(|c| MultiEraCertificate::from(c.clone())) + .collect() + }), + Self::Alonzo(tx) => tx.certs.as_ref().map(|certs| { + certs + .iter() + .map(|c| MultiEraCertificate::from(c.clone())) + .collect() + }), + Self::Babbage(tx) => tx.certs.as_ref().map(|certs| { + certs + .iter() + .map(|c| MultiEraCertificate::from(c.clone())) + .collect() + }), + Self::Conway(tx) => tx.certs.as_ref().map(|certs| { + certs + .iter() + .map(|c| MultiEraCertificate::from(c.clone())) + .collect() + }), + } + } + + pub fn withdrawals(&self) -> Option<&Withdrawals> { + match self { + Self::Byron(_tx) => None, + Self::Shelley(tx) => tx.withdrawals.as_ref(), + Self::Allegra(tx) => tx.withdrawals.as_ref(), + Self::Mary(tx) => tx.withdrawals.as_ref(), + Self::Alonzo(tx) => tx.withdrawals.as_ref(), + Self::Babbage(tx) => tx.withdrawals.as_ref(), + Self::Conway(tx) => tx.withdrawals.as_ref(), + } + } + + pub fn auxiliary_data_hash(&self) -> Option<&AuxiliaryDataHash> { + match self { + Self::Byron(_tx) => None, + Self::Shelley(tx) => tx.auxiliary_data_hash.as_ref(), + Self::Allegra(tx) => tx.auxiliary_data_hash.as_ref(), + Self::Mary(tx) => tx.auxiliary_data_hash.as_ref(), + Self::Alonzo(tx) => tx.auxiliary_data_hash.as_ref(), + Self::Babbage(tx) => tx.auxiliary_data_hash.as_ref(), + Self::Conway(tx) => tx.auxiliary_data_hash.as_ref(), + } + } + + pub fn validity_interval_start(&self) -> Option { + match self { + Self::Byron(_tx) => None, + Self::Shelley(_tx) => None, + Self::Allegra(tx) => tx.validity_interval_start, + Self::Mary(tx) => tx.validity_interval_start, + Self::Alonzo(tx) => tx.validity_interval_start, + Self::Babbage(tx) => tx.validity_interval_start, + Self::Conway(tx) => tx.validity_interval_start, + } + } + + pub fn mint(&self) -> Option<&Mint> { + match self { + Self::Byron(_tx) => None, + Self::Shelley(_tx) => None, + Self::Allegra(_tx) => None, + Self::Mary(tx) => tx.mint.as_ref(), + Self::Alonzo(tx) => tx.mint.as_ref(), + Self::Babbage(tx) => tx.mint.as_ref(), + Self::Conway(tx) => tx.mint.as_ref(), + } + } + + pub fn script_data_hash(&self) -> Option { + match self { + Self::Byron(_tx) => None, + Self::Shelley(_tx) => None, + Self::Allegra(_tx) => None, + Self::Mary(_tx) => None, + Self::Alonzo(tx) => tx.script_data_hash, + Self::Babbage(tx) => tx.script_data_hash, + Self::Conway(tx) => tx.script_data_hash, + } + } + + pub fn collateral_inputs(&self) -> Option<&Vec> { + match self { + Self::Byron(_tx) => None, + Self::Shelley(_tx) => None, + Self::Allegra(_tx) => None, + Self::Mary(_tx) => None, + Self::Alonzo(tx) => tx.collateral_inputs.as_ref(), + Self::Babbage(tx) => tx.collateral_inputs.as_ref(), + Self::Conway(tx) => tx.collateral_inputs.as_ref(), + } + } + + pub fn required_signers(&self) -> Option<&RequiredSigners> { + match self { + Self::Byron(_tx) => None, + Self::Shelley(_tx) => None, + Self::Allegra(_tx) => None, + Self::Mary(_tx) => None, + Self::Alonzo(tx) => tx.required_signers.as_ref(), + Self::Babbage(tx) => tx.required_signers.as_ref(), + Self::Conway(tx) => tx.required_signers.as_ref(), + } + } + + pub fn network_id(&self) -> Option { + match self { + Self::Byron(_tx) => None, + Self::Shelley(_tx) => None, + Self::Allegra(_tx) => None, + Self::Mary(_tx) => None, + Self::Alonzo(tx) => tx.network_id, + Self::Babbage(tx) => tx.network_id, + Self::Conway(tx) => tx.network_id, + } + } + + pub fn collateral_return(&self) -> Option { + match self { + Self::Byron(_tx) => None, + Self::Shelley(_tx) => None, + Self::Allegra(_tx) => None, + Self::Mary(_tx) => None, + Self::Alonzo(_tx) => None, + Self::Babbage(tx) => tx.collateral_return.as_ref().map(|ret| ret.clone().into()), + Self::Conway(tx) => tx.collateral_return.as_ref().map(|ret| ret.clone().into()), + } + } + + pub fn total_collateral(&self) -> Option { + match self { + Self::Byron(_tx) => None, + Self::Shelley(_tx) => None, + Self::Allegra(_tx) => None, + Self::Mary(_tx) => None, + Self::Alonzo(_tx) => None, + Self::Babbage(tx) => tx.total_collateral, + Self::Conway(tx) => tx.total_collateral, + } + } + + pub fn reference_inputs(&self) -> Option<&Vec> { + match self { + Self::Byron(_tx) => None, + Self::Shelley(_tx) => None, + Self::Allegra(_tx) => None, + Self::Mary(_tx) => None, + Self::Alonzo(_tx) => None, + Self::Babbage(tx) => tx.reference_inputs.as_ref(), + Self::Conway(tx) => tx.reference_inputs.as_ref(), + } + } +} + +#[allow(clippy::large_enum_variant)] +#[derive(Clone, Debug, serde::Deserialize, serde::Serialize, schemars::JsonSchema)] +pub enum MultiEraCertificate { + StakeRegistration(StakeRegistration), + StakeDeregistration(StakeDeregistration), + StakeDelegation(StakeDelegation), + PoolRegistration(PoolRegistration), + PoolRetirement(PoolRetirement), + GenesisKeyDelegation(GenesisKeyDelegation), + MoveInstantaneousRewardsCert(MoveInstantaneousRewardsCert), + RegCert(RegCert), + UnregCert(UnregCert), + VoteDelegCert(VoteDelegCert), + StakeVoteDelegCert(StakeVoteDelegCert), + StakeRegDelegCert(StakeRegDelegCert), + VoteRegDelegCert(VoteRegDelegCert), + StakeVoteRegDelegCert(StakeVoteRegDelegCert), + AuthCommitteeHotCert(AuthCommitteeHotCert), + ResignCommitteeColdCert(ResignCommitteeColdCert), + RegDrepCert(RegDrepCert), + UnregDrepCert(UnregDrepCert), + UpdateDrepCert(UpdateDrepCert), +} + +impl From for MultiEraCertificate { + fn from(cert: ShelleyCertificate) -> Self { + match cert { + ShelleyCertificate::StakeRegistration(cert) => Self::StakeRegistration(cert), + ShelleyCertificate::StakeDeregistration(cert) => Self::StakeDeregistration(cert), + ShelleyCertificate::StakeDelegation(cert) => Self::StakeDelegation(cert), + ShelleyCertificate::PoolRegistration(cert) => Self::PoolRegistration(cert), + ShelleyCertificate::PoolRetirement(cert) => Self::PoolRetirement(cert), + ShelleyCertificate::GenesisKeyDelegation(cert) => Self::GenesisKeyDelegation(cert), + ShelleyCertificate::ShelleyMoveInstantaneousRewardsCert { + shelley_move_instantaneous_rewards_cert, + .. + } => Self::MoveInstantaneousRewardsCert(MoveInstantaneousRewardsCert::new( + MoveInstantaneousReward::new( + shelley_move_instantaneous_rewards_cert + .shelley_move_instantaneous_reward + .pot, + MIRAction::new_to_stake_credentials( + shelley_move_instantaneous_rewards_cert + .shelley_move_instantaneous_reward + .to_stake_credentials + .iter() + .map(|(k, v)| (k.clone(), Int::from(*v))) + .collect(), + ), + ), + )), + } + } +} + +impl From for MultiEraCertificate { + fn from(cert: AllegraCertificate) -> Self { + match cert { + AllegraCertificate::StakeRegistration(cert) => Self::StakeRegistration(cert), + AllegraCertificate::StakeDeregistration(cert) => Self::StakeDeregistration(cert), + AllegraCertificate::StakeDelegation(cert) => Self::StakeDelegation(cert), + AllegraCertificate::PoolRegistration(cert) => Self::PoolRegistration(cert), + AllegraCertificate::PoolRetirement(cert) => Self::PoolRetirement(cert), + AllegraCertificate::GenesisKeyDelegation(cert) => Self::GenesisKeyDelegation(cert), + AllegraCertificate::MoveInstantaneousRewardsCert(cert) => { + Self::MoveInstantaneousRewardsCert(cert) + } + } + } +} + +impl From for MultiEraCertificate { + fn from(cert: Certificate) -> Self { + match cert { + Certificate::StakeRegistration(cert) => Self::StakeRegistration(cert), + Certificate::StakeDeregistration(cert) => Self::StakeDeregistration(cert), + Certificate::StakeDelegation(cert) => Self::StakeDelegation(cert), + Certificate::PoolRegistration(cert) => Self::PoolRegistration(cert), + Certificate::PoolRetirement(cert) => Self::PoolRetirement(cert), + Certificate::RegCert(cert) => Self::RegCert(cert), + Certificate::UnregCert(cert) => Self::UnregCert(cert), + Certificate::VoteDelegCert(cert) => Self::VoteDelegCert(cert), + Certificate::StakeVoteDelegCert(cert) => Self::StakeVoteDelegCert(cert), + Certificate::StakeRegDelegCert(cert) => Self::StakeRegDelegCert(cert), + Certificate::VoteRegDelegCert(cert) => Self::VoteRegDelegCert(cert), + Certificate::StakeVoteRegDelegCert(cert) => Self::StakeVoteRegDelegCert(cert), + Certificate::AuthCommitteeHotCert(cert) => Self::AuthCommitteeHotCert(cert), + Certificate::ResignCommitteeColdCert(cert) => Self::ResignCommitteeColdCert(cert), + Certificate::RegDrepCert(cert) => Self::RegDrepCert(cert), + Certificate::UnregDrepCert(cert) => Self::UnregDrepCert(cert), + Certificate::UpdateDrepCert(cert) => Self::UpdateDrepCert(cert), + } + } +} + +#[derive(Clone, Debug, serde::Deserialize, serde::Serialize, schemars::JsonSchema)] +pub enum MultiEraTransactionInput { + Byron(ByronTxIn), + /// All eras from Shelley onward have the same tx in format + Shelley(TransactionInput), +} + +impl MultiEraTransactionInput { + /// Transaction hash this input was created in + /// Will return None only for Byron Genesis inputs + pub fn hash(&self) -> Option<&TransactionHash> { + match self { + Self::Byron(input) => match input { + ByronTxIn::ByronTxInRegular(reg) => Some(®.index_1.byron_tx_id), + ByronTxIn::ByronTxInGenesis(_gen) => None, + }, + Self::Shelley(input) => Some(&input.transaction_id), + } + } + + /// Transaction index into the tx that this input was created in + /// Will return None for only Byron Genesis inputs + pub fn index(&self) -> Option { + match self { + Self::Byron(input) => match input { + ByronTxIn::ByronTxInRegular(reg) => Some(reg.index_1.u32.into()), + ByronTxIn::ByronTxInGenesis(_gen) => None, + }, + Self::Shelley(input) => Some(input.index), + } + } +} + +#[derive(Clone, Debug, serde::Deserialize, serde::Serialize, schemars::JsonSchema)] +pub enum MultiEraTransactionOutput { + Byron(ByronTxOut), + Shelley(TransactionOutput), +} + +impl MultiEraTransactionOutput { + pub fn address(&self) -> Address { + match self { + Self::Byron(output) => output.address.clone().to_address(), + Self::Shelley(output) => output.address().clone(), + } + } + + pub fn amount(&self) -> Value { + match self { + Self::Byron(output) => output.amount.into(), + Self::Shelley(output) => output.amount().clone(), + } + } +} + +impl From for MultiEraTransactionOutput { + fn from(o: ShelleyTransactionOutput) -> Self { + MultiEraTransactionOutput::Shelley(TransactionOutput::new( + o.address.clone(), + Value::from(o.amount), + None, + None, + )) + } +} + +impl From for MultiEraTransactionOutput { + fn from(o: MaryTransactionOutput) -> Self { + MultiEraTransactionOutput::Shelley(TransactionOutput::new( + o.address.clone(), + o.amount.clone(), + None, + None, + )) + } +} + +impl From for MultiEraTransactionOutput { + fn from(o: AlonzoFormatTxOut) -> Self { + MultiEraTransactionOutput::Shelley(o.clone().into()) + } +} + +impl From for MultiEraTransactionOutput { + fn from(o: BabbageTransactionOutput) -> Self { + MultiEraTransactionOutput::Shelley(match o { + BabbageTransactionOutput::AlonzoFormatTxOut(alonzo) => { + TransactionOutput::AlonzoFormatTxOut(alonzo.clone()) + } + BabbageTransactionOutput::BabbageFormatTxOut(babbage) => TransactionOutput::new( + babbage.address.clone(), + babbage.amount.clone(), + babbage.datum_option.clone(), + babbage.script_reference.clone().map(Into::into), + ), + }) + } +} + +impl From for MultiEraTransactionOutput { + fn from(o: TransactionOutput) -> Self { + MultiEraTransactionOutput::Shelley(o) + } } #[cfg(test)] diff --git a/multi-era/wasm/src/byron/mod.rs b/multi-era/wasm/src/byron/mod.rs index e90ee40e..151c8057 100644 --- a/multi-era/wasm/src/byron/mod.rs +++ b/multi-era/wasm/src/byron/mod.rs @@ -16,6 +16,7 @@ use cml_core_wasm::{ impl_wasm_cbor_json_api_cbor_event_serialize, impl_wasm_conversions, impl_wasm_list, impl_wasm_map_btree, }; +use cml_crypto_wasm::TransactionHash; pub use utils::{Blake2b224, Blake2b256, ByronAny}; pub type SystemTag = String; @@ -49,7 +50,7 @@ impl ByronSlotId { } } -pub type ByronTxId = Blake2b256; +pub type ByronTxId = TransactionHash; pub type ByronUpdateId = Blake2b256; diff --git a/multi-era/wasm/src/lib.rs b/multi-era/wasm/src/lib.rs index d7dc16a9..a3c7a253 100644 --- a/multi-era/wasm/src/lib.rs +++ b/multi-era/wasm/src/lib.rs @@ -25,7 +25,7 @@ use crate::{ BabbageAuxiliaryData, BabbageBlock, BabbageTransactionBody, BabbageTransactionOutput, BabbageTransactionWitnessSet, }, - byron::block::ByronBlock, + byron::{block::ByronBlock, transaction::ByronTx}, mary::{MaryBlock, MaryTransactionBody, MaryTransactionOutput}, shelley::{ MultisigScript, ShelleyBlock, ShelleyCertificate, ShelleyTransactionBody, @@ -33,8 +33,10 @@ use crate::{ }, }; use cml_chain_wasm::{ - block::Block, certs::StakeCredential, transaction::AlonzoFormatTxOut, Coin, - StakeCredentialList, TransactionIndex, + block::Block, + certs::StakeCredential, + transaction::{AlonzoFormatTxOut, TransactionBody}, + Coin, StakeCredentialList, TransactionIndex, }; use cml_core_wasm::{ impl_wasm_cbor_json_api, impl_wasm_conversions, impl_wasm_list, impl_wasm_map, @@ -150,6 +152,19 @@ impl_wasm_map!( false ); +impl_wasm_map!( + cml_chain::TransactionIndex, + cml_core::metadata::Metadata, + TransactionIndex, + cml_core_wasm::metadata::Metadata, + Vec, + MapTransactionIndexToMetadata, + true, + false, + true, + false +); + impl_wasm_list!( cml_multi_era::mary::MaryTransactionOutput, MaryTransactionOutput, @@ -291,6 +306,150 @@ pub enum MultiEraBlockKind { Conway, } +#[derive(Clone, Debug)] +#[wasm_bindgen] +pub struct MultiEraTransactionBody(cml_multi_era::MultiEraTransactionBody); + +impl_wasm_cbor_json_api!(MultiEraTransactionBody); + +impl_wasm_conversions!( + cml_multi_era::MultiEraTransactionBody, + MultiEraTransactionBody +); + +#[wasm_bindgen] +impl MultiEraTransactionBody { + pub fn new_byron(byron: &ByronTx) -> Self { + Self(cml_multi_era::MultiEraTransactionBody::new_byron( + byron.clone().into(), + )) + } + + pub fn new_shelley(shelley: &ShelleyTransactionBody) -> Self { + Self(cml_multi_era::MultiEraTransactionBody::new_shelley( + shelley.clone().into(), + )) + } + + pub fn new_allegra(allegra: &AllegraTransactionBody) -> Self { + Self(cml_multi_era::MultiEraTransactionBody::new_allegra( + allegra.clone().into(), + )) + } + + pub fn new_mary(mary: &MaryTransactionBody) -> Self { + Self(cml_multi_era::MultiEraTransactionBody::new_mary( + mary.clone().into(), + )) + } + + pub fn new_alonzo(alonzo: &AlonzoTransactionBody) -> Self { + Self(cml_multi_era::MultiEraTransactionBody::new_alonzo( + alonzo.clone().into(), + )) + } + + pub fn new_babbage(babbage: &BabbageTransactionBody) -> Self { + Self(cml_multi_era::MultiEraTransactionBody::new_babbage( + babbage.clone().into(), + )) + } + + pub fn new_conway(conway: &TransactionBody) -> Self { + Self(cml_multi_era::MultiEraTransactionBody::new_conway( + conway.clone().into(), + )) + } + + pub fn kind(&self) -> MultiEraTransactionBodyKind { + match &self.0 { + cml_multi_era::MultiEraTransactionBody::Byron(_) => MultiEraTransactionBodyKind::Byron, + cml_multi_era::MultiEraTransactionBody::Shelley(_) => { + MultiEraTransactionBodyKind::Shelley + } + cml_multi_era::MultiEraTransactionBody::Allegra(_) => { + MultiEraTransactionBodyKind::Allegra + } + cml_multi_era::MultiEraTransactionBody::Mary(_) => MultiEraTransactionBodyKind::Mary, + cml_multi_era::MultiEraTransactionBody::Alonzo(_) => { + MultiEraTransactionBodyKind::Alonzo + } + cml_multi_era::MultiEraTransactionBody::Babbage(_) => { + MultiEraTransactionBodyKind::Babbage + } + cml_multi_era::MultiEraTransactionBody::Conway(_) => { + MultiEraTransactionBodyKind::Conway + } + } + } + + pub fn as_byron(&self) -> Option { + match &self.0 { + cml_multi_era::MultiEraTransactionBody::Byron(byron) => Some(byron.clone().into()), + _ => None, + } + } + + pub fn as_shelley(&self) -> Option { + match &self.0 { + cml_multi_era::MultiEraTransactionBody::Shelley(shelley) => { + Some(shelley.clone().into()) + } + _ => None, + } + } + + pub fn as_allegra(&self) -> Option { + match &self.0 { + cml_multi_era::MultiEraTransactionBody::Allegra(allegra) => { + Some(allegra.clone().into()) + } + _ => None, + } + } + + pub fn as_mary(&self) -> Option { + match &self.0 { + cml_multi_era::MultiEraTransactionBody::Mary(mary) => Some(mary.clone().into()), + _ => None, + } + } + + pub fn as_alonzo(&self) -> Option { + match &self.0 { + cml_multi_era::MultiEraTransactionBody::Alonzo(alonzo) => Some(alonzo.clone().into()), + _ => None, + } + } + + pub fn as_babbage(&self) -> Option { + match &self.0 { + cml_multi_era::MultiEraTransactionBody::Babbage(babbage) => { + Some(babbage.clone().into()) + } + _ => None, + } + } + + pub fn as_conway(&self) -> Option { + match &self.0 { + cml_multi_era::MultiEraTransactionBody::Conway(conway) => Some(conway.clone().into()), + _ => None, + } + } +} + +#[wasm_bindgen] +pub enum MultiEraTransactionBodyKind { + Byron, + Shelley, + Allegra, + Mary, + Alonzo, + Babbage, + Conway, +} + impl_wasm_list!( cml_multi_era::shelley::ShelleyCertificate, ShelleyCertificate, diff --git a/multi-era/wasm/src/shelley/mod.rs b/multi-era/wasm/src/shelley/mod.rs index 8bf30e6a..668ed08f 100644 --- a/multi-era/wasm/src/shelley/mod.rs +++ b/multi-era/wasm/src/shelley/mod.rs @@ -2,8 +2,9 @@ // https://github.com/dcSpark/cddl-codegen use crate::{ - GenesisHashList, MapStakeCredentialToCoin, MultisigScriptList, ShelleyCertificateList, - ShelleyTransactionBodyList, ShelleyTransactionOutputList, ShelleyTransactionWitnessSetList, + GenesisHashList, MapStakeCredentialToCoin, MapTransactionIndexToMetadata, MultisigScriptList, + ShelleyCertificateList, ShelleyTransactionBodyList, ShelleyTransactionOutputList, + ShelleyTransactionWitnessSetList, }; use cml_chain_wasm::address::Address; use cml_chain_wasm::assets::Coin; @@ -295,7 +296,7 @@ impl ShelleyBlock { self.0.transaction_witness_sets.clone().into() } - pub fn transaction_metadata_set(&self) -> Metadata { + pub fn transaction_metadata_set(&self) -> MapTransactionIndexToMetadata { self.0.transaction_metadata_set.clone().into() } @@ -303,7 +304,7 @@ impl ShelleyBlock { header: &ShelleyHeader, transaction_bodies: &ShelleyTransactionBodyList, transaction_witness_sets: &ShelleyTransactionWitnessSetList, - transaction_metadata_set: &Metadata, + transaction_metadata_set: &MapTransactionIndexToMetadata, ) -> Self { Self(cml_multi_era::shelley::ShelleyBlock::new( header.clone().into(), diff --git a/multi-era/wasm/src/utils.rs b/multi-era/wasm/src/utils.rs index 2fc42738..060d72c1 100644 --- a/multi-era/wasm/src/utils.rs +++ b/multi-era/wasm/src/utils.rs @@ -1,7 +1,28 @@ -use wasm_bindgen::JsError; +use cml_chain::Coin; +use cml_chain_wasm::{ + address::Address, + assets::{Mint, Value}, + certs::{ + AuthCommitteeHotCert, PoolRegistration, PoolRetirement, RegCert, RegDrepCert, + ResignCommitteeColdCert, StakeDelegation, StakeDeregistration, StakeRegDelegCert, + StakeRegistration, StakeVoteDelegCert, StakeVoteRegDelegCert, UnregCert, UnregDrepCert, + UpdateDrepCert, VoteDelegCert, VoteRegDelegCert, + }, + transaction::RequiredSigners, + MapTransactionIndexToAuxiliaryData, NetworkId, TransactionInputList, TransactionWitnessSetList, + Withdrawals, +}; +use cml_core::TransactionIndex; +use cml_core_wasm::{impl_wasm_conversions, impl_wasm_json_api, impl_wasm_list}; +use cml_crypto_wasm::{AuxiliaryDataHash, ScriptDataHash, TransactionHash}; +use wasm_bindgen::{prelude::wasm_bindgen, JsError, JsValue}; -use crate::MultiEraBlock; +use crate::{ + allegra::MoveInstantaneousRewardsCert, shelley::GenesisKeyDelegation, MultiEraBlock, + MultiEraTransactionBody, +}; +#[wasm_bindgen] impl MultiEraBlock { /** * Parses a block given the network block format with explicit era tag @@ -17,4 +38,431 @@ impl MultiEraBlock { .map(Into::into) .map_err(Into::into) } + + pub fn transaction_bodies(&self) -> MultiEraTransactionBodyList { + self.0.transaction_bodies().into() + } + + pub fn transaction_witness_sets(&self) -> TransactionWitnessSetList { + self.0.transaction_witness_sets().into() + } + + pub fn auxiliary_data_set(&self) -> MapTransactionIndexToAuxiliaryData { + self.0.auxiliary_data_set().into() + } + + pub fn invalid_transactions(&self) -> Vec { + self.0.invalid_transactions() + } +} + +impl_wasm_list!( + cml_multi_era::utils::MultiEraCertificate, + MultiEraCertificate, + MultiEraCertificateList +); + +impl_wasm_list!( + cml_multi_era::MultiEraTransactionBody, + MultiEraTransactionBody, + MultiEraTransactionBodyList +); + +impl_wasm_list!( + cml_multi_era::utils::MultiEraTransactionInput, + MultiEraTransactionInput, + MultiEraTransactionInputList +); + +impl_wasm_list!( + cml_multi_era::utils::MultiEraTransactionOutput, + MultiEraTransactionOutput, + MultiEraTransactionOutputList +); + +#[derive(Clone, Debug)] +#[wasm_bindgen] +pub struct MultiEraCertificate(cml_multi_era::utils::MultiEraCertificate); + +impl_wasm_json_api!(MultiEraCertificate); + +impl_wasm_conversions!( + cml_multi_era::utils::MultiEraCertificate, + MultiEraCertificate +); + +#[wasm_bindgen] +impl MultiEraCertificate { + pub fn kind(&self) -> MultiEraCertificateKind { + match &self.0 { + cml_multi_era::utils::MultiEraCertificate::StakeRegistration(_) => { + MultiEraCertificateKind::StakeRegistration + } + cml_multi_era::utils::MultiEraCertificate::StakeDeregistration(_) => { + MultiEraCertificateKind::StakeDeregistration + } + cml_multi_era::utils::MultiEraCertificate::StakeDelegation(_) => { + MultiEraCertificateKind::StakeDelegation + } + cml_multi_era::utils::MultiEraCertificate::PoolRegistration(_) => { + MultiEraCertificateKind::PoolRegistration + } + cml_multi_era::utils::MultiEraCertificate::PoolRetirement(_) => { + MultiEraCertificateKind::PoolRetirement + } + cml_multi_era::utils::MultiEraCertificate::GenesisKeyDelegation(_) => { + MultiEraCertificateKind::GenesisKeyDelegation + } + cml_multi_era::utils::MultiEraCertificate::MoveInstantaneousRewardsCert(_) => { + MultiEraCertificateKind::MoveInstantaneousRewardsCert + } + cml_multi_era::utils::MultiEraCertificate::RegCert(_) => { + MultiEraCertificateKind::RegCert + } + cml_multi_era::utils::MultiEraCertificate::UnregCert(_) => { + MultiEraCertificateKind::UnregCert + } + cml_multi_era::utils::MultiEraCertificate::VoteDelegCert(_) => { + MultiEraCertificateKind::VoteDelegCert + } + cml_multi_era::utils::MultiEraCertificate::StakeVoteDelegCert(_) => { + MultiEraCertificateKind::StakeVoteDelegCert + } + cml_multi_era::utils::MultiEraCertificate::StakeRegDelegCert(_) => { + MultiEraCertificateKind::StakeRegDelegCert + } + cml_multi_era::utils::MultiEraCertificate::VoteRegDelegCert(_) => { + MultiEraCertificateKind::VoteRegDelegCert + } + cml_multi_era::utils::MultiEraCertificate::StakeVoteRegDelegCert(_) => { + MultiEraCertificateKind::StakeVoteRegDelegCert + } + cml_multi_era::utils::MultiEraCertificate::AuthCommitteeHotCert(_) => { + MultiEraCertificateKind::AuthCommitteeHotCert + } + cml_multi_era::utils::MultiEraCertificate::ResignCommitteeColdCert(_) => { + MultiEraCertificateKind::ResignCommitteeColdCert + } + cml_multi_era::utils::MultiEraCertificate::RegDrepCert(_) => { + MultiEraCertificateKind::RegDrepCert + } + cml_multi_era::utils::MultiEraCertificate::UnregDrepCert(_) => { + MultiEraCertificateKind::UnregDrepCert + } + cml_multi_era::utils::MultiEraCertificate::UpdateDrepCert(_) => { + MultiEraCertificateKind::UpdateDrepCert + } + } + } + + pub fn as_stake_registration(&self) -> Option { + match &self.0 { + cml_multi_era::utils::MultiEraCertificate::StakeRegistration(stake_registration) => { + Some(stake_registration.clone().into()) + } + _ => None, + } + } + + pub fn as_stake_deregistration(&self) -> Option { + match &self.0 { + cml_multi_era::utils::MultiEraCertificate::StakeDeregistration( + stake_deregistration, + ) => Some(stake_deregistration.clone().into()), + _ => None, + } + } + + pub fn as_stake_delegation(&self) -> Option { + match &self.0 { + cml_multi_era::utils::MultiEraCertificate::StakeDelegation(stake_delegation) => { + Some(stake_delegation.clone().into()) + } + _ => None, + } + } + + pub fn as_pool_registration(&self) -> Option { + match &self.0 { + cml_multi_era::utils::MultiEraCertificate::PoolRegistration(pool_registration) => { + Some(pool_registration.clone().into()) + } + _ => None, + } + } + + pub fn as_pool_retirement(&self) -> Option { + match &self.0 { + cml_multi_era::utils::MultiEraCertificate::PoolRetirement(pool_retirement) => { + Some(pool_retirement.clone().into()) + } + _ => None, + } + } + + pub fn as_genesis_key_delegation(&self) -> Option { + match &self.0 { + cml_multi_era::utils::MultiEraCertificate::GenesisKeyDelegation( + genesis_key_delegation, + ) => Some(genesis_key_delegation.clone().into()), + _ => None, + } + } + + pub fn as_move_instantaneous_rewards_cert(&self) -> Option { + match &self.0 { + cml_multi_era::utils::MultiEraCertificate::MoveInstantaneousRewardsCert( + move_instantaneous_rewards_cert, + ) => Some(move_instantaneous_rewards_cert.clone().into()), + _ => None, + } + } + + pub fn as_reg_cert(&self) -> Option { + match &self.0 { + cml_multi_era::utils::MultiEraCertificate::RegCert(reg_cert) => { + Some(reg_cert.clone().into()) + } + _ => None, + } + } + + pub fn as_unreg_cert(&self) -> Option { + match &self.0 { + cml_multi_era::utils::MultiEraCertificate::UnregCert(unreg_cert) => { + Some(unreg_cert.clone().into()) + } + _ => None, + } + } + + pub fn as_vote_deleg_cert(&self) -> Option { + match &self.0 { + cml_multi_era::utils::MultiEraCertificate::VoteDelegCert(vote_deleg_cert) => { + Some(vote_deleg_cert.clone().into()) + } + _ => None, + } + } + + pub fn as_stake_vote_deleg_cert(&self) -> Option { + match &self.0 { + cml_multi_era::utils::MultiEraCertificate::StakeVoteDelegCert( + stake_vote_deleg_cert, + ) => Some(stake_vote_deleg_cert.clone().into()), + _ => None, + } + } + + pub fn as_stake_reg_deleg_cert(&self) -> Option { + match &self.0 { + cml_multi_era::utils::MultiEraCertificate::StakeRegDelegCert(stake_reg_deleg_cert) => { + Some(stake_reg_deleg_cert.clone().into()) + } + _ => None, + } + } + + pub fn as_vote_reg_deleg_cert(&self) -> Option { + match &self.0 { + cml_multi_era::utils::MultiEraCertificate::VoteRegDelegCert(vote_reg_deleg_cert) => { + Some(vote_reg_deleg_cert.clone().into()) + } + _ => None, + } + } + + pub fn as_stake_vote_reg_deleg_cert(&self) -> Option { + match &self.0 { + cml_multi_era::utils::MultiEraCertificate::StakeVoteRegDelegCert( + stake_vote_reg_deleg_cert, + ) => Some(stake_vote_reg_deleg_cert.clone().into()), + _ => None, + } + } + + pub fn as_auth_committee_hot_cert(&self) -> Option { + match &self.0 { + cml_multi_era::utils::MultiEraCertificate::AuthCommitteeHotCert( + auth_committee_hot_cert, + ) => Some(auth_committee_hot_cert.clone().into()), + _ => None, + } + } + + pub fn as_resign_committee_cold_cert(&self) -> Option { + match &self.0 { + cml_multi_era::utils::MultiEraCertificate::ResignCommitteeColdCert( + resign_committee_cold_cert, + ) => Some(resign_committee_cold_cert.clone().into()), + _ => None, + } + } + + pub fn as_reg_drep_cert(&self) -> Option { + match &self.0 { + cml_multi_era::utils::MultiEraCertificate::RegDrepCert(reg_drep_cert) => { + Some(reg_drep_cert.clone().into()) + } + _ => None, + } + } + + pub fn as_unreg_drep_cert(&self) -> Option { + match &self.0 { + cml_multi_era::utils::MultiEraCertificate::UnregDrepCert(unreg_drep_cert) => { + Some(unreg_drep_cert.clone().into()) + } + _ => None, + } + } + + pub fn as_update_drep_cert(&self) -> Option { + match &self.0 { + cml_multi_era::utils::MultiEraCertificate::UpdateDrepCert(update_drep_cert) => { + Some(update_drep_cert.clone().into()) + } + _ => None, + } + } +} + +#[wasm_bindgen] +pub enum MultiEraCertificateKind { + StakeRegistration, + StakeDeregistration, + StakeDelegation, + PoolRegistration, + PoolRetirement, + GenesisKeyDelegation, + MoveInstantaneousRewardsCert, + RegCert, + UnregCert, + VoteDelegCert, + StakeVoteDelegCert, + StakeRegDelegCert, + VoteRegDelegCert, + StakeVoteRegDelegCert, + AuthCommitteeHotCert, + ResignCommitteeColdCert, + RegDrepCert, + UnregDrepCert, + UpdateDrepCert, +} + +#[wasm_bindgen] +impl MultiEraTransactionBody { + pub fn inputs(&self) -> MultiEraTransactionInputList { + self.0.inputs().into() + } + + pub fn outputs(&self) -> MultiEraTransactionOutputList { + self.0.outputs().into() + } + + pub fn fee(&self) -> Option { + self.0.fee() + } + + pub fn ttl(&self) -> Option { + self.0.ttl() + } + + pub fn certs(&self) -> Option { + self.0.certs().map(Into::into) + } + + pub fn withdrawals(&self) -> Option { + self.0.withdrawals().map(|wd| wd.clone().into()) + } + + pub fn auxiliary_data_hash(&self) -> Option { + self.0.auxiliary_data_hash().map(|aux| (*aux).into()) + } + + pub fn validity_interval_start(&self) -> Option { + self.0.validity_interval_start() + } + + pub fn mint(&self) -> Option { + self.0.mint().map(|m| m.clone().into()) + } + + pub fn script_data_hash(&self) -> Option { + self.0.script_data_hash().map(Into::into) + } + + pub fn collateral_inputs(&self) -> Option { + self.0 + .collateral_inputs() + .map(|inputs| inputs.clone().into()) + } + + pub fn required_signers(&self) -> Option { + self.0 + .required_signers() + .map(|signers| signers.clone().into()) + } + + pub fn network_id(&self) -> Option { + self.0.network_id().map(Into::into) + } + + pub fn collateral_return(&self) -> Option { + self.0.collateral_return().map(Into::into) + } + + pub fn total_collateral(&self) -> Option { + self.0.total_collateral() + } + + pub fn reference_inputs(&self) -> Option { + self.0 + .reference_inputs() + .map(|inputs| inputs.clone().into()) + } +} + +#[wasm_bindgen] +#[derive(Clone, Debug)] +pub struct MultiEraTransactionInput(cml_multi_era::utils::MultiEraTransactionInput); + +impl_wasm_conversions!( + cml_multi_era::utils::MultiEraTransactionInput, + MultiEraTransactionInput +); + +#[wasm_bindgen] +impl MultiEraTransactionInput { + /// Transaction hash this input was created in + /// Will return None only for Byron Genesis inputs + pub fn hash(&self) -> Option { + self.0.hash().map(|h| (*h).into()) + } + + /// Transaction index into the tx that this input was created in + /// Will return None for only Byron Genesis inputs + pub fn index(&self) -> Option { + self.0.index() + } +} + +#[wasm_bindgen] +#[derive(Clone, Debug)] +pub struct MultiEraTransactionOutput(cml_multi_era::utils::MultiEraTransactionOutput); + +impl_wasm_conversions!( + cml_multi_era::utils::MultiEraTransactionOutput, + MultiEraTransactionOutput +); + +#[wasm_bindgen] +impl MultiEraTransactionOutput { + pub fn address(&self) -> Address { + self.0.address().into() + } + + pub fn amount(&self) -> Value { + self.0.amount().into() + } } diff --git a/specs/multiera/cml_chain/byron.cddl b/specs/multiera/cml_chain/byron.cddl index df2c44af..df26b37c 100644 --- a/specs/multiera/cml_chain/byron.cddl +++ b/specs/multiera/cml_chain/byron.cddl @@ -34,4 +34,5 @@ addr_attributes = _CDDL_CODEGEN_EXTERN_TYPE_ address_content = _CDDL_CODEGEN_EXTERN_TYPE_ byron_address = _CDDL_CODEGEN_EXTERN_TYPE_ -byron_tx_out = _CDDL_CODEGEN_EXTERN_TYPE_ \ No newline at end of file +byron_tx_out = _CDDL_CODEGEN_EXTERN_TYPE_ +byron_tx = _CDDL_CODEGEN_EXTERN_TYPE_ \ No newline at end of file diff --git a/specs/multiera/cml_chain/transaction.cddl b/specs/multiera/cml_chain/transaction.cddl index 050b792e..67016b66 100644 --- a/specs/multiera/cml_chain/transaction.cddl +++ b/specs/multiera/cml_chain/transaction.cddl @@ -2,6 +2,7 @@ transaction_input = _CDDL_CODEGEN_EXTERN_TYPE_ transaction_index = uint .size 2 transaction_metadatum_label = uint transaction_metadatum = _CDDL_CODEGEN_EXTERN_TYPE_ +transaction_body = _CDDL_CODEGEN_EXTERN_TYPE_ required_signers = [* ed25519_key_hash] native_script = _CDDL_CODEGEN_EXTERN_TYPE_ alonzo_format_tx_out = _CDDL_CODEGEN_EXTERN_TYPE_ diff --git a/specs/multiera/lib.cddl b/specs/multiera/lib.cddl index 1adef27d..df62852b 100644 --- a/specs/multiera/lib.cddl +++ b/specs/multiera/lib.cddl @@ -10,4 +10,13 @@ multi_era_block = / mary_block ; @name Mary / alonzo_block ; @name Alonzo / babbage_block ; @name Babbage - / block ; @name Conway \ No newline at end of file + / block ; @name Conway + +multi_era_transaction_body = + byron_tx ; @name byron + / shelley_transaction_body ; @name Shelley + / allegra_transaction_body ; @name Allegra + / mary_transaction_body ; @name Mary + / alonzo_transaction_body ; @name Alonzo + / babbage_transaction_body ; @name Babbage + / transaction_body ; @name Conway diff --git a/specs/multiera/shelley/mod.cddl b/specs/multiera/shelley/mod.cddl index b2b20569..42cbfab0 100644 --- a/specs/multiera/shelley/mod.cddl +++ b/specs/multiera/shelley/mod.cddl @@ -2,7 +2,7 @@ shelley_block = [ header: shelley_header, transaction_bodies : [* shelley_transaction_body], transaction_witness_sets : [* shelley_transaction_witness_set], - transaction_metadata_set : metadata, + transaction_metadata_set : { * transaction_index => metadata }, ] ; Valid blocks must also satisfy the following two constraints: ; 1) the length of transaction_bodies and transaction_witness_sets From b6b28bffd6b5af4646a1d72e55b52a46d3ff2325 Mon Sep 17 00:00:00 2001 From: rooooooooob Date: Tue, 31 Oct 2023 11:00:16 -0700 Subject: [PATCH 2/3] Govnernance support --- cip25/wasm/package.json | 44 -------------------------------- multi-era/rust/src/utils.rs | 51 ++++++++++++++++++++++++++++++++++++- multi-era/wasm/src/utils.rs | 23 ++++++++++++++--- 3 files changed, 70 insertions(+), 48 deletions(-) delete mode 100644 cip25/wasm/package.json diff --git a/cip25/wasm/package.json b/cip25/wasm/package.json deleted file mode 100644 index 41d4f786..00000000 --- a/cip25/wasm/package.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "name": "cml-cip25", - "version": "1.1.0", - "description": "Cardano Multiplatform SDK for CIP25 (Cardano NFT Metadata)", - "keywords": [ - "cardano" - ], - "scripts": { - "rust:build-nodejs": "rimraf ./pkg; cross-env WASM_BINDGEN_WEAKREF=1 wasm-pack build --target=nodejs; npm run js:ts-json-gen; wasm-pack pack", - "rust:build-browser": "rimraf ./pkg; cross-env WASM_BINDGEN_WEAKREF=1 wasm-pack build --target=browser; npm run js:ts-json-gen; wasm-pack pack", - "rust:build-web": "rimraf ./pkg; cross-env WASM_BINDGEN_WEAKREF=1 wasm-pack build --target=web; npm run js:ts-json-gen; wasm-pack pack", - "rust:build-asm": "(rimraf ./rust/pkg && cd rust; wasm-pack build --target=browser -- --features wasm; cd ..; npm run js:ts-json-gen; cd rust; wasm-pack pack) && npm run asm:build && npm run js:flowgen", - "asm:build": "../../binaryen/bin/wasm2js ./rust/pkg/cardano_multiplatform_lib_bg.wasm --output ./rust/pkg/cardano_multiplatform_lib.asm.js && node ./scripts/legacy/wasm-to-asm", - "rust:publish": "cargo publish", - "rust:check-warnings": "(RUSTFLAGS=\"-D warnings\" cargo +stable build)", - "rust:test": "cargo test", - "js:prepublish": "npm run rust:test && rimraf ./publish && cp -r ./pkg ./publish && cp README.md publish/ && cp ../../LICENSE publish/", - "js:test-publish": "npm run rust:build-nodejs && npm run js:prepublish && node ../../scripts/publish-helper cip25 -nodejs && cd publish", - "js:publish-nodejs:prod": "npm run rust:build-nodejs && npm run js:prepublish && node ../../scripts/publish-helper cip25 -nodejs && cd publish && npm publish --access public", - "js:publish-nodejs:beta": "npm run rust:build-nodejs && npm run js:prepublish && node ../../scripts/publish-helper cip25 -nodejs && cd publish && npm publish --tag beta --access public", - "js:publish-browser:prod": "npm run rust:build-browser && npm run js:prepublish && node ../../scripts/publish-helper cip25 -browser && cd publish && npm publish --access public", - "js:publish-browser:beta": "npm run rust:build-browser && npm run js:prepublish && node ../../scripts/publish-helper cip25 -browser && cd publish && npm publish --tag beta --access public", - "js:publish-asm:prod": "npm run rust:build-asm && npm run js:prepublish && node ../../scripts/publish-helper cip25 -asmjs && cd publish && npm publish --access public", - "js:publish-asm:beta": "npm run rust:build-asm && npm run js:prepublish && node ../../scripts/publish-helper cip25 -asmjs && cd publish && npm publish --tag beta --access public", - "js:ts-json-gen": "cd json-gen && cargo +stable run && cd .. && node ../../scripts/run-json2ts.js && node ../../scripts/json-ts-types.js cip25" - }, - "husky": { - "hooks": { - "pre-push": "npm run rust:test && npm run rust:build-nodejs" - } - }, - "author": "dcSpark", - "license": "MIT", - "repository": { - "type": "git", - "url": "git+https://github.com/dcSpark/cardano-multiplatform-lib.git" - }, - "devDependencies": { - "husky": "4.2.5", - "json-schema-to-typescript": "^10.1.5", - "rimraf": "3.0.2", - "cross-env": "^7.0.3" - } -} diff --git a/multi-era/rust/src/utils.rs b/multi-era/rust/src/utils.rs index 32f471ea..eb8ec1b2 100644 --- a/multi-era/rust/src/utils.rs +++ b/multi-era/rust/src/utils.rs @@ -12,7 +12,7 @@ use crate::{ use crate::{MultiEraBlock, MultiEraTransactionBody}; use cbor_event::de::Deserializer; use cml_chain::address::Address; -use cml_chain::assets::Mint; +use cml_chain::assets::{Mint, PositiveCoin}; use cml_chain::auxdata::AuxiliaryData; use cml_chain::block::Block; use cml_chain::byron::ByronTxOut; @@ -22,6 +22,7 @@ use cml_chain::certs::{ StakeRegistration, StakeVoteDelegCert, StakeVoteRegDelegCert, UnregCert, UnregDrepCert, UpdateDrepCert, VoteDelegCert, VoteRegDelegCert, }; +use cml_chain::governance::{ProposalProcedure, VotingProcedures}; use cml_chain::transaction::{ AlonzoFormatTxOut, RequiredSigners, TransactionInput, TransactionOutput, TransactionWitnessSet, }; @@ -488,6 +489,54 @@ impl MultiEraTransactionBody { Self::Conway(tx) => tx.reference_inputs.as_ref(), } } + + pub fn voting_procedures(&self) -> Option<&VotingProcedures> { + match self { + Self::Byron(_tx) => None, + Self::Shelley(_tx) => None, + Self::Allegra(_tx) => None, + Self::Mary(_tx) => None, + Self::Alonzo(_tx) => None, + Self::Babbage(_tx) => None, + Self::Conway(tx) => tx.voting_procedures.as_ref(), + } + } + + pub fn proposal_procedures(&self) -> Option<&Vec> { + match self { + Self::Byron(_tx) => None, + Self::Shelley(_tx) => None, + Self::Allegra(_tx) => None, + Self::Mary(_tx) => None, + Self::Alonzo(_tx) => None, + Self::Babbage(_tx) => None, + Self::Conway(tx) => tx.proposal_procedures.as_ref(), + } + } + + pub fn current_treasury_value(&self) -> Option { + match self { + Self::Byron(_tx) => None, + Self::Shelley(_tx) => None, + Self::Allegra(_tx) => None, + Self::Mary(_tx) => None, + Self::Alonzo(_tx) => None, + Self::Babbage(_tx) => None, + Self::Conway(tx) => tx.current_treasury_value, + } + } + + pub fn donation(&self) -> Option { + match self { + Self::Byron(_tx) => None, + Self::Shelley(_tx) => None, + Self::Allegra(_tx) => None, + Self::Mary(_tx) => None, + Self::Alonzo(_tx) => None, + Self::Babbage(_tx) => None, + Self::Conway(tx) => tx.donation, + } + } } #[allow(clippy::large_enum_variant)] diff --git a/multi-era/wasm/src/utils.rs b/multi-era/wasm/src/utils.rs index 060d72c1..1a43be35 100644 --- a/multi-era/wasm/src/utils.rs +++ b/multi-era/wasm/src/utils.rs @@ -1,4 +1,4 @@ -use cml_chain::Coin; +use cml_chain::{assets::PositiveCoin, Coin}; use cml_chain_wasm::{ address::Address, assets::{Mint, Value}, @@ -8,9 +8,10 @@ use cml_chain_wasm::{ StakeRegistration, StakeVoteDelegCert, StakeVoteRegDelegCert, UnregCert, UnregDrepCert, UpdateDrepCert, VoteDelegCert, VoteRegDelegCert, }, + governance::VotingProcedures, transaction::RequiredSigners, - MapTransactionIndexToAuxiliaryData, NetworkId, TransactionInputList, TransactionWitnessSetList, - Withdrawals, + MapTransactionIndexToAuxiliaryData, NetworkId, ProposalProcedureList, TransactionInputList, + TransactionWitnessSetList, Withdrawals, }; use cml_core::TransactionIndex; use cml_core_wasm::{impl_wasm_conversions, impl_wasm_json_api, impl_wasm_list}; @@ -421,6 +422,22 @@ impl MultiEraTransactionBody { .reference_inputs() .map(|inputs| inputs.clone().into()) } + + pub fn voting_procedures(&self) -> Option { + self.0.voting_procedures().map(|vps| vps.clone().into()) + } + + pub fn proposal_procedures(&self) -> Option { + self.0.proposal_procedures().map(|pps| pps.clone().into()) + } + + pub fn current_treasury_value(&self) -> Option { + self.0.current_treasury_value() + } + + pub fn donation(&self) -> Option { + self.0.donation() + } } #[wasm_bindgen] From 334ddbfbb004309194ca08361abff32b3bf03290 Mon Sep 17 00:00:00 2001 From: rooooooooob Date: Mon, 6 Nov 2023 08:09:57 -0800 Subject: [PATCH 3/3] Multi-Era wrappers: Update + BlockHeader --- multi-era/rust/src/alonzo/cbor_encodings.rs | 4 +- multi-era/rust/src/alonzo/mod.rs | 4 +- multi-era/rust/src/alonzo/serialization.rs | 34 +- multi-era/rust/src/utils.rs | 571 +++++++++++++++++++- multi-era/wasm/src/alonzo/mod.rs | 8 +- multi-era/wasm/src/utils.rs | 266 ++++++++- specs/multiera/alonzo/mod.cddl | 2 +- 7 files changed, 850 insertions(+), 39 deletions(-) diff --git a/multi-era/rust/src/alonzo/cbor_encodings.rs b/multi-era/rust/src/alonzo/cbor_encodings.rs index d1f6ecdf..03958ad6 100644 --- a/multi-era/rust/src/alonzo/cbor_encodings.rs +++ b/multi-era/rust/src/alonzo/cbor_encodings.rs @@ -72,8 +72,8 @@ pub struct AlonzoProtocolParamUpdateEncoding { pub execution_costs_key_encoding: Option, pub max_tx_ex_units_key_encoding: Option, pub max_block_ex_units_key_encoding: Option, - pub max_encoding: Option, - pub max_key_encoding: Option, + pub max_value_size_encoding: Option, + pub max_value_size_key_encoding: Option, pub collateral_percentage_encoding: Option, pub collateral_percentage_key_encoding: Option, pub max_collateral_inputs_encoding: Option, diff --git a/multi-era/rust/src/alonzo/mod.rs b/multi-era/rust/src/alonzo/mod.rs index 596d7798..e6315069 100644 --- a/multi-era/rust/src/alonzo/mod.rs +++ b/multi-era/rust/src/alonzo/mod.rs @@ -145,7 +145,7 @@ pub struct AlonzoProtocolParamUpdate { pub execution_costs: Option, pub max_tx_ex_units: Option, pub max_block_ex_units: Option, - pub max: Option, + pub max_value_size: Option, pub collateral_percentage: Option, pub max_collateral_inputs: Option, #[serde(skip)] @@ -176,7 +176,7 @@ impl AlonzoProtocolParamUpdate { execution_costs: None, max_tx_ex_units: None, max_block_ex_units: None, - max: None, + max_value_size: None, collateral_percentage: None, max_collateral_inputs: None, encodings: None, diff --git a/multi-era/rust/src/alonzo/serialization.rs b/multi-era/rust/src/alonzo/serialization.rs index 6a1ee7eb..2e8fb2cc 100644 --- a/multi-era/rust/src/alonzo/serialization.rs +++ b/multi-era/rust/src/alonzo/serialization.rs @@ -815,7 +815,7 @@ impl Serialize for AlonzoProtocolParamUpdate { } + match &self.max_block_ex_units { Some(_) => 1, None => 0, - } + match &self.max { + } + match &self.max_value_size { Some(_) => 1, None => 0, } + match &self.collateral_percentage { @@ -897,7 +897,7 @@ impl Serialize for AlonzoProtocolParamUpdate { } + match &self.max_block_ex_units { Some(_) => 1, None => 0, - } + match &self.max { + } + match &self.max_value_size { Some(_) => 1, None => 0, } + match &self.collateral_percentage { @@ -1364,14 +1364,14 @@ impl Serialize for AlonzoProtocolParamUpdate { } } 21 => { - if let Some(field) = &self.max { + if let Some(field) = &self.max_value_size { serializer.write_unsigned_integer_sz( 22u64, fit_sz( 22u64, self.encodings .as_ref() - .map(|encs| encs.max_key_encoding) + .map(|encs| encs.max_value_size_key_encoding) .unwrap_or_default(), force_canonical, ), @@ -1382,7 +1382,7 @@ impl Serialize for AlonzoProtocolParamUpdate { *field, self.encodings .as_ref() - .map(|encs| encs.max_encoding) + .map(|encs| encs.max_value_size_encoding) .unwrap_or_default(), force_canonical, ), @@ -1512,9 +1512,9 @@ impl Deserialize for AlonzoProtocolParamUpdate { let mut max_tx_ex_units = None; let mut max_block_ex_units_key_encoding = None; let mut max_block_ex_units = None; - let mut max_encoding = None; - let mut max_key_encoding = None; - let mut max = None; + let mut max_value_size_encoding = None; + let mut max_value_size_key_encoding = None; + let mut max_value_size = None; let mut collateral_percentage_encoding = None; let mut collateral_percentage_key_encoding = None; let mut collateral_percentage = None; @@ -1849,20 +1849,20 @@ impl Deserialize for AlonzoProtocolParamUpdate { orig_deser_order.push(20); } (22, key_enc) => { - if max.is_some() { + if max_value_size.is_some() { return Err(DeserializeFailure::DuplicateKey(Key::Uint(22)).into()); } - let (tmp_max, tmp_max_encoding) = + let (tmp_max_value_size, tmp_max_value_size_encoding) = (|| -> Result<_, DeserializeError> { read_len.read_elems(1)?; raw.unsigned_integer_sz() .map(|(x, enc)| (x, Some(enc))) .map_err(Into::::into) })() - .map_err(|e| e.annotate("max"))?; - max = Some(tmp_max); - max_encoding = tmp_max_encoding; - max_key_encoding = Some(key_enc); + .map_err(|e| e.annotate("max_value_size"))?; + max_value_size = Some(tmp_max_value_size); + max_value_size_encoding = tmp_max_value_size_encoding; + max_value_size_key_encoding = Some(key_enc); orig_deser_order.push(21); } (23, key_enc) => { @@ -1946,7 +1946,7 @@ impl Deserialize for AlonzoProtocolParamUpdate { execution_costs, max_tx_ex_units, max_block_ex_units, - max, + max_value_size, collateral_percentage, max_collateral_inputs, encodings: Some(AlonzoProtocolParamUpdateEncoding { @@ -1984,8 +1984,8 @@ impl Deserialize for AlonzoProtocolParamUpdate { execution_costs_key_encoding, max_tx_ex_units_key_encoding, max_block_ex_units_key_encoding, - max_key_encoding, - max_encoding, + max_value_size_key_encoding, + max_value_size_encoding, collateral_percentage_key_encoding, collateral_percentage_encoding, max_collateral_inputs_key_encoding, diff --git a/multi-era/rust/src/utils.rs b/multi-era/rust/src/utils.rs index eb8ec1b2..4c707488 100644 --- a/multi-era/rust/src/utils.rs +++ b/multi-era/rust/src/utils.rs @@ -1,10 +1,15 @@ use crate::allegra::{ AllegraCertificate, MIRAction, MoveInstantaneousReward, MoveInstantaneousRewardsCert, }; -use crate::babbage::BabbageTransactionOutput; +use crate::alonzo::{AlonzoCostmdls, AlonzoProtocolParamUpdate}; +use crate::babbage::{BabbageCostModels, BabbageProtocolParamUpdate, BabbageTransactionOutput}; +use crate::byron::block::{ByronBlockHeader, EbbHead}; use crate::byron::transaction::ByronTxIn; use crate::mary::MaryTransactionOutput; -use crate::shelley::{GenesisKeyDelegation, ShelleyCertificate, ShelleyTransactionOutput}; +use crate::shelley::{ + GenesisKeyDelegation, ProtocolVersionStruct, ShelleyCertificate, ShelleyHeader, + ShelleyProtocolParamUpdate, ShelleyTransactionOutput, +}; use crate::{ allegra::AllegraBlock, alonzo::AlonzoBlock, babbage::BabbageBlock, byron::block::ByronBlock, mary::MaryBlock, shelley::ShelleyBlock, @@ -14,7 +19,7 @@ use cbor_event::de::Deserializer; use cml_chain::address::Address; use cml_chain::assets::{Mint, PositiveCoin}; use cml_chain::auxdata::AuxiliaryData; -use cml_chain::block::Block; +use cml_chain::block::{Block, Header, OperationalCert, ProtocolVersion}; use cml_chain::byron::ByronTxOut; use cml_chain::certs::{ AuthCommitteeHotCert, Certificate, PoolRegistration, PoolRetirement, RegCert, RegDrepCert, @@ -22,15 +27,24 @@ use cml_chain::certs::{ StakeRegistration, StakeVoteDelegCert, StakeVoteRegDelegCert, UnregCert, UnregDrepCert, UpdateDrepCert, VoteDelegCert, VoteRegDelegCert, }; +use cml_chain::crypto::{Nonce, VRFCert, Vkey}; use cml_chain::governance::{ProposalProcedure, VotingProcedures}; +use cml_chain::plutus::cbor_encodings::CostModelsEncoding; +use cml_chain::plutus::{CostModels, ExUnitPrices, ExUnits}; use cml_chain::transaction::{ AlonzoFormatTxOut, RequiredSigners, TransactionInput, TransactionOutput, TransactionWitnessSet, }; -use cml_chain::{Coin, NetworkId, OrderedHashMap, Value, Withdrawals}; +use cml_chain::{ + Coin, DRepVotingThresholds, LenEncoding, NetworkId, OrderedHashMap, PoolVotingThresholds, + ProtocolParamUpdate, Rational, UnitInterval, Value, Withdrawals, +}; use cml_core::error::{DeserializeError, DeserializeFailure}; use cml_core::serialization::{CBORReadLen, Deserialize}; -use cml_core::{Int, TransactionIndex}; -use cml_crypto::{AuxiliaryDataHash, ScriptDataHash, TransactionHash}; +use cml_core::{Epoch, Int, TransactionIndex}; +use cml_crypto::{ + AuxiliaryDataHash, BlockBodyHash, BlockHeaderHash, GenesisHash, RawBytesEncoding, + ScriptDataHash, TransactionHash, VRFVkey, +}; impl MultiEraBlock { /** @@ -85,6 +99,21 @@ impl MultiEraBlock { Ok(block) } + pub fn header(&self) -> MultiEraBlockHeader { + match self { + Self::Byron(block) => match block { + ByronBlock::EpochBoundary(ebb) => MultiEraBlockHeader::ByronEB(ebb.header.clone()), + ByronBlock::Main(mb) => MultiEraBlockHeader::Byron(mb.header.clone()), + }, + Self::Shelley(block) => MultiEraBlockHeader::Shelley(block.header.clone()), + Self::Allegra(block) => MultiEraBlockHeader::Shelley(block.header.clone()), + Self::Mary(block) => MultiEraBlockHeader::Shelley(block.header.clone()), + Self::Alonzo(block) => MultiEraBlockHeader::Shelley(block.header.clone()), + Self::Babbage(block) => MultiEraBlockHeader::Babbage(block.header.clone()), + Self::Conway(block) => MultiEraBlockHeader::Babbage(block.header.clone()), + } + } + pub fn transaction_bodies(&self) -> Vec { match self { Self::Byron(block) => match block { @@ -206,6 +235,128 @@ impl MultiEraBlock { } } +#[derive(Clone, Debug, serde::Deserialize, serde::Serialize, schemars::JsonSchema)] +pub enum MultiEraBlockHeader { + ByronEB(EbbHead), + Byron(ByronBlockHeader), + Shelley(ShelleyHeader), + Babbage(Header), +} + +impl MultiEraBlockHeader { + pub fn block_number(&self) -> Option { + match self { + Self::ByronEB(_) => None, + Self::Byron(_) => None, + Self::Shelley(header) => Some(header.body.block_number), + Self::Babbage(header) => Some(header.header_body.block_number), + } + } + + pub fn slot(&self) -> Option { + match self { + Self::ByronEB(_) => None, + Self::Byron(_) => None, + Self::Shelley(header) => Some(header.body.slot), + Self::Babbage(header) => Some(header.header_body.slot), + } + } + + pub fn prev_hash(&self) -> Option { + match self { + Self::ByronEB(ebb) => { + Some(BlockHeaderHash::from_raw_bytes(ebb.prev_block.to_raw_bytes()).unwrap()) + } + Self::Byron(mb) => { + Some(BlockHeaderHash::from_raw_bytes(mb.prev_block.to_raw_bytes()).unwrap()) + } + Self::Shelley(header) => header.body.prev_hash, + Self::Babbage(header) => header.header_body.prev_hash, + } + } + + pub fn issuer_vkey(&self) -> Option<&Vkey> { + match self { + Self::ByronEB(_) => None, + Self::Byron(_) => None, + Self::Shelley(header) => Some(&header.body.issuer_vkey), + Self::Babbage(header) => Some(&header.header_body.issuer_vkey), + } + } + + pub fn vrf_vkey(&self) -> Option<&VRFVkey> { + match self { + Self::ByronEB(_) => None, + Self::Byron(_) => None, + Self::Shelley(header) => Some(&header.body.v_r_f_vkey), + Self::Babbage(header) => Some(&header.header_body.vrf_vkey), + } + } + + pub fn nonce_vrf(&self) -> Option<&VRFCert> { + match self { + Self::ByronEB(_) => None, + Self::Byron(_) => None, + Self::Shelley(header) => Some(&header.body.nonce_vrf), + Self::Babbage(_header) => None, + } + } + + pub fn leader_vrf(&self) -> Option<&VRFCert> { + match self { + Self::ByronEB(_) => None, + Self::Byron(_) => None, + Self::Shelley(header) => Some(&header.body.leader_vrf), + Self::Babbage(_header) => None, + } + } + + pub fn vrf_result(&self) -> Option<&VRFCert> { + match self { + Self::ByronEB(_) => todo!(), + Self::Byron(_) => todo!(), + Self::Shelley(_header) => None, + Self::Babbage(header) => Some(&header.header_body.vrf_result), + } + } + + pub fn block_body_size(&self) -> Option { + match self { + Self::ByronEB(_) => None, + Self::Byron(_) => None, + Self::Shelley(header) => Some(header.body.block_body_size), + Self::Babbage(header) => Some(header.header_body.block_body_size), + } + } + + pub fn block_body_hash(&self) -> Option { + match self { + Self::ByronEB(_) => None, + Self::Byron(_) => None, + Self::Shelley(header) => Some(header.body.block_body_hash), + Self::Babbage(header) => Some(header.header_body.block_body_hash), + } + } + + pub fn operational_cert(&self) -> Option<&OperationalCert> { + match self { + Self::ByronEB(_) => None, + Self::Byron(_) => None, + Self::Shelley(header) => Some(&header.body.operational_cert), + Self::Babbage(header) => Some(&header.header_body.operational_cert), + } + } + + pub fn protocol_version(&self) -> Option<&ProtocolVersion> { + match self { + Self::ByronEB(_) => None, + Self::Byron(_) => None, + Self::Shelley(header) => Some(&header.body.protocol_version), + Self::Babbage(header) => Some(&header.header_body.protocol_version), + } + } +} + impl MultiEraTransactionBody { pub fn inputs(&self) -> Vec { match self { @@ -370,6 +521,53 @@ impl MultiEraTransactionBody { } } + pub fn update(&self) -> Option { + match self { + Self::Byron(_tx) => None, + Self::Shelley(tx) => tx.update.as_ref().map(|u| MultiEraUpdate { + epoch: u.epoch, + proposed_protocol_parameter_updates: u + .shelley_proposed_protocol_parameter_updates + .iter() + .map(|(gh, ppu)| (*gh, MultiEraProtocolParamUpdate::Shelley(ppu.clone()))) + .collect(), + }), + Self::Allegra(tx) => tx.update.as_ref().map(|u| MultiEraUpdate { + epoch: u.epoch, + proposed_protocol_parameter_updates: u + .shelley_proposed_protocol_parameter_updates + .iter() + .map(|(gh, ppu)| (*gh, MultiEraProtocolParamUpdate::Shelley(ppu.clone()))) + .collect(), + }), + Self::Mary(tx) => tx.update.as_ref().map(|u| MultiEraUpdate { + epoch: u.epoch, + proposed_protocol_parameter_updates: u + .shelley_proposed_protocol_parameter_updates + .iter() + .map(|(gh, ppu)| (*gh, MultiEraProtocolParamUpdate::Shelley(ppu.clone()))) + .collect(), + }), + Self::Alonzo(tx) => tx.update.as_ref().map(|u| MultiEraUpdate { + epoch: u.epoch, + proposed_protocol_parameter_updates: u + .proposed_protocol_parameter_updates + .iter() + .map(|(gh, ppu)| (*gh, MultiEraProtocolParamUpdate::Alonzo(ppu.clone()))) + .collect(), + }), + Self::Babbage(tx) => tx.update.as_ref().map(|u| MultiEraUpdate { + epoch: u.epoch, + proposed_protocol_parameter_updates: u + .updates + .iter() + .map(|(gh, ppu)| (*gh, MultiEraProtocolParamUpdate::Babbage(ppu.clone()))) + .collect(), + }), + Self::Conway(_tx) => None, + } + } + pub fn auxiliary_data_hash(&self) -> Option<&AuxiliaryDataHash> { match self { Self::Byron(_tx) => None, @@ -634,6 +832,320 @@ impl From for MultiEraCertificate { } } +#[allow(clippy::large_enum_variant)] +#[derive(Clone, Debug, serde::Deserialize, serde::Serialize, schemars::JsonSchema)] +pub enum MultiEraProtocolParamUpdate { + Shelley(ShelleyProtocolParamUpdate), + Alonzo(AlonzoProtocolParamUpdate), + Babbage(BabbageProtocolParamUpdate), + Conway(ProtocolParamUpdate), +} + +impl MultiEraProtocolParamUpdate { + pub fn minfee_a(&self) -> Option { + match self { + Self::Shelley(update) => update.minfee_a, + Self::Alonzo(update) => update.minfee_a, + Self::Babbage(update) => update.minfee_a, + Self::Conway(update) => update.minfee_a, + } + } + + pub fn minfee_b(&self) -> Option { + match self { + Self::Shelley(update) => update.minfee_b, + Self::Alonzo(update) => update.minfee_b, + Self::Babbage(update) => update.minfee_b, + Self::Conway(update) => update.minfee_b, + } + } + + pub fn max_block_body_size(&self) -> Option { + match self { + Self::Shelley(update) => update.max_block_body_size, + Self::Alonzo(update) => update.max_block_body_size, + Self::Babbage(update) => update.max_block_body_size, + Self::Conway(update) => update.max_block_body_size, + } + } + + pub fn max_transaction_size(&self) -> Option { + match self { + Self::Shelley(update) => update.max_transaction_size, + Self::Alonzo(update) => update.max_transaction_size, + Self::Babbage(update) => update.max_transaction_size, + Self::Conway(update) => update.max_transaction_size, + } + } + + pub fn max_block_header_size(&self) -> Option { + match self { + Self::Shelley(update) => update.max_block_header_size, + Self::Alonzo(update) => update.max_block_header_size, + Self::Babbage(update) => update.max_block_header_size, + Self::Conway(update) => update.max_block_header_size, + } + } + + pub fn key_deposit(&self) -> Option { + match self { + Self::Shelley(update) => update.key_deposit, + Self::Alonzo(update) => update.key_deposit, + Self::Babbage(update) => update.key_deposit, + Self::Conway(update) => update.key_deposit, + } + } + + pub fn pool_deposit(&self) -> Option { + match self { + Self::Shelley(update) => update.pool_deposit, + Self::Alonzo(update) => update.pool_deposit, + Self::Babbage(update) => update.pool_deposit, + Self::Conway(update) => update.pool_deposit, + } + } + + pub fn maximum_epoch(&self) -> Option { + match self { + Self::Shelley(update) => update.maximum_epoch, + Self::Alonzo(update) => update.maximum_epoch, + Self::Babbage(update) => update.maximum_epoch, + Self::Conway(update) => update.maximum_epoch, + } + } + + pub fn n_opt(&self) -> Option { + match self { + Self::Shelley(update) => update.n_opt, + Self::Alonzo(update) => update.n_opt, + Self::Babbage(update) => update.n_opt, + Self::Conway(update) => update.n_opt, + } + } + + pub fn pool_pledge_influence(&self) -> Option<&Rational> { + match self { + Self::Shelley(update) => update.pool_pledge_influence.as_ref(), + Self::Alonzo(update) => update.pool_pledge_influence.as_ref(), + Self::Babbage(update) => update.pool_pledge_influence.as_ref(), + Self::Conway(update) => update.pool_pledge_influence.as_ref(), + } + } + + pub fn expansion_rate(&self) -> Option<&UnitInterval> { + match self { + Self::Shelley(update) => update.expansion_rate.as_ref(), + Self::Alonzo(update) => update.expansion_rate.as_ref(), + Self::Babbage(update) => update.expansion_rate.as_ref(), + Self::Conway(update) => update.expansion_rate.as_ref(), + } + } + + pub fn treasury_growth_rate(&self) -> Option<&UnitInterval> { + match self { + Self::Shelley(update) => update.treasury_growth_rate.as_ref(), + Self::Alonzo(update) => update.treasury_growth_rate.as_ref(), + Self::Babbage(update) => update.treasury_growth_rate.as_ref(), + Self::Conway(update) => update.treasury_growth_rate.as_ref(), + } + } + + pub fn decentralization_constant(&self) -> Option<&UnitInterval> { + match self { + Self::Shelley(update) => update.decentralization_constant.as_ref(), + Self::Alonzo(update) => update.decentralization_constant.as_ref(), + Self::Babbage(_update) => None, + Self::Conway(_update) => None, + } + } + + pub fn extra_entropy(&self) -> Option<&Nonce> { + match self { + Self::Shelley(update) => update.extra_entropy.as_ref(), + Self::Alonzo(update) => update.extra_entropy.as_ref(), + Self::Babbage(_update) => None, + Self::Conway(_update) => None, + } + } + + pub fn protocol_version(&self) -> Option<&ProtocolVersionStruct> { + match self { + Self::Shelley(update) => update.protocol_version.as_ref(), + Self::Alonzo(update) => update.protocol_version.as_ref(), + Self::Babbage(update) => update.protocol_version.as_ref(), + Self::Conway(_update) => None, + } + } + + pub fn min_utxo_value(&self) -> Option { + match self { + Self::Shelley(update) => update.min_utxo_value, + Self::Alonzo(_update) => None, + Self::Babbage(_update) => None, + Self::Conway(_update) => None, + } + } + + pub fn min_pool_cost(&self) -> Option { + match self { + Self::Shelley(_update) => None, + Self::Alonzo(update) => update.min_pool_cost, + Self::Babbage(update) => update.min_pool_cost, + Self::Conway(update) => update.min_pool_cost, + } + } + + pub fn ada_per_utxo_byte(&self) -> Option { + match self { + Self::Shelley(_update) => None, + Self::Alonzo(update) => update.ada_per_utxo_byte, + Self::Babbage(update) => update.ada_per_utxo_byte, + Self::Conway(update) => update.ada_per_utxo_byte, + } + } + + pub fn cost_models_for_script_languages(&self) -> Option { + match self { + Self::Shelley(_update) => None, + Self::Alonzo(update) => update + .cost_models_for_script_languages + .clone() + .map(Into::into), + Self::Babbage(update) => update + .cost_models_for_script_languages + .clone() + .map(Into::into), + Self::Conway(update) => update.cost_models_for_script_languages.clone(), + } + } + + pub fn execution_costs(&self) -> Option<&ExUnitPrices> { + match self { + Self::Shelley(_update) => None, + Self::Alonzo(update) => update.execution_costs.as_ref(), + Self::Babbage(update) => update.execution_costs.as_ref(), + Self::Conway(update) => update.execution_costs.as_ref(), + } + } + + pub fn max_tx_ex_units(&self) -> Option<&ExUnits> { + match self { + Self::Shelley(_update) => None, + Self::Alonzo(update) => update.max_tx_ex_units.as_ref(), + Self::Babbage(update) => update.max_tx_ex_units.as_ref(), + Self::Conway(update) => update.max_tx_ex_units.as_ref(), + } + } + + pub fn max_block_ex_units(&self) -> Option<&ExUnits> { + match self { + Self::Shelley(_update) => None, + Self::Alonzo(update) => update.max_block_ex_units.as_ref(), + Self::Babbage(update) => update.max_block_ex_units.as_ref(), + Self::Conway(update) => update.max_block_ex_units.as_ref(), + } + } + + pub fn max_value_size(&self) -> Option { + match self { + Self::Shelley(_update) => None, + Self::Alonzo(update) => update.max_value_size, + Self::Babbage(update) => update.max_value_size, + Self::Conway(update) => update.max_value_size, + } + } + + pub fn collateral_percentage(&self) -> Option { + match self { + Self::Shelley(_update) => None, + Self::Alonzo(update) => update.collateral_percentage, + Self::Babbage(update) => update.collateral_percentage, + Self::Conway(update) => update.collateral_percentage, + } + } + + pub fn max_collateral_inputs(&self) -> Option { + match self { + Self::Shelley(_update) => None, + Self::Alonzo(update) => update.max_collateral_inputs, + Self::Babbage(update) => update.max_collateral_inputs, + Self::Conway(update) => update.max_collateral_inputs, + } + } + + pub fn pool_voting_thresholds(&self) -> Option<&PoolVotingThresholds> { + match self { + Self::Shelley(_update) => None, + Self::Alonzo(_update) => None, + Self::Babbage(_update) => None, + Self::Conway(update) => update.pool_voting_thresholds.as_ref(), + } + } + + pub fn d_rep_voting_thresholds(&self) -> Option<&DRepVotingThresholds> { + match self { + Self::Shelley(_update) => None, + Self::Alonzo(_update) => None, + Self::Babbage(_update) => None, + Self::Conway(update) => update.d_rep_voting_thresholds.as_ref(), + } + } + + pub fn min_committee_size(&self) -> Option { + match self { + Self::Shelley(_update) => None, + Self::Alonzo(_update) => None, + Self::Babbage(_update) => None, + Self::Conway(update) => update.min_committee_size, + } + } + + pub fn committee_term_limit(&self) -> Option { + match self { + Self::Shelley(_update) => None, + Self::Alonzo(_update) => None, + Self::Babbage(_update) => None, + Self::Conway(update) => update.committee_term_limit, + } + } + + pub fn governance_action_validity_period(&self) -> Option { + match self { + Self::Shelley(_update) => None, + Self::Alonzo(_update) => None, + Self::Babbage(_update) => None, + Self::Conway(update) => update.governance_action_validity_period, + } + } + + pub fn governance_action_deposit(&self) -> Option { + match self { + Self::Shelley(_update) => None, + Self::Alonzo(_update) => None, + Self::Babbage(_update) => None, + Self::Conway(update) => update.governance_action_deposit, + } + } + + pub fn d_rep_deposit(&self) -> Option { + match self { + Self::Shelley(_update) => None, + Self::Alonzo(_update) => None, + Self::Babbage(_update) => None, + Self::Conway(update) => update.d_rep_deposit, + } + } + + pub fn d_rep_inactivity_period(&self) -> Option { + match self { + Self::Shelley(_update) => None, + Self::Alonzo(_update) => None, + Self::Babbage(_update) => None, + Self::Conway(update) => update.d_rep_inactivity_period, + } + } +} + #[derive(Clone, Debug, serde::Deserialize, serde::Serialize, schemars::JsonSchema)] pub enum MultiEraTransactionInput { Byron(ByronTxIn), @@ -689,6 +1201,13 @@ impl MultiEraTransactionOutput { } } +#[derive(Debug, Clone)] +pub struct MultiEraUpdate { + pub epoch: u64, + pub proposed_protocol_parameter_updates: + OrderedHashMap, +} + impl From for MultiEraTransactionOutput { fn from(o: ShelleyTransactionOutput) -> Self { MultiEraTransactionOutput::Shelley(TransactionOutput::new( @@ -739,6 +1258,46 @@ impl From for MultiEraTransactionOutput { } } +impl From for CostModels { + fn from(cost_models: AlonzoCostmdls) -> Self { + Self { + plutus_v1: Some(cost_models.plutus_v1), + plutus_v2: None, + plutus_v3: None, + encodings: cost_models.encodings.map(|encs| CostModelsEncoding { + len_encoding: encs.len_encoding, + orig_deser_order: encs.orig_deser_order, + plutus_v1_encoding: encs.plutus_v1_encoding, + plutus_v1_key_encoding: encs.plutus_v1_key_encoding, + plutus_v2_encoding: LenEncoding::default(), + plutus_v2_key_encoding: None, + plutus_v3_encoding: LenEncoding::default(), + plutus_v3_key_encoding: None, + }), + } + } +} + +impl From for CostModels { + fn from(cost_models: BabbageCostModels) -> Self { + Self { + plutus_v1: cost_models.plutus_v1, + plutus_v2: cost_models.plutus_v2, + plutus_v3: None, + encodings: cost_models.encodings.map(|encs| CostModelsEncoding { + len_encoding: encs.len_encoding, + orig_deser_order: encs.orig_deser_order, + plutus_v1_encoding: encs.plutus_v1_encoding, + plutus_v1_key_encoding: encs.plutus_v1_key_encoding, + plutus_v2_encoding: encs.plutus_v2_encoding, + plutus_v2_key_encoding: encs.plutus_v2_key_encoding, + plutus_v3_encoding: LenEncoding::default(), + plutus_v3_key_encoding: None, + }), + } + } +} + #[cfg(test)] mod test { use super::*; diff --git a/multi-era/wasm/src/alonzo/mod.rs b/multi-era/wasm/src/alonzo/mod.rs index d854654d..6b353f91 100644 --- a/multi-era/wasm/src/alonzo/mod.rs +++ b/multi-era/wasm/src/alonzo/mod.rs @@ -458,12 +458,12 @@ impl AlonzoProtocolParamUpdate { .map(std::convert::Into::into) } - pub fn set_max(&mut self, max: u64) { - self.0.max = Some(max) + pub fn set_max_value_size(&mut self, max_value_size: u64) { + self.0.max_value_size = Some(max_value_size) } - pub fn max(&self) -> Option { - self.0.max + pub fn max_value_size(&self) -> Option { + self.0.max_value_size } pub fn set_collateral_percentage(&mut self, collateral_percentage: u64) { diff --git a/multi-era/wasm/src/utils.rs b/multi-era/wasm/src/utils.rs index 1a43be35..0bdbf21f 100644 --- a/multi-era/wasm/src/utils.rs +++ b/multi-era/wasm/src/utils.rs @@ -2,25 +2,31 @@ use cml_chain::{assets::PositiveCoin, Coin}; use cml_chain_wasm::{ address::Address, assets::{Mint, Value}, + block::{OperationalCert, ProtocolVersion}, certs::{ AuthCommitteeHotCert, PoolRegistration, PoolRetirement, RegCert, RegDrepCert, ResignCommitteeColdCert, StakeDelegation, StakeDeregistration, StakeRegDelegCert, StakeRegistration, StakeVoteDelegCert, StakeVoteRegDelegCert, UnregCert, UnregDrepCert, UpdateDrepCert, VoteDelegCert, VoteRegDelegCert, }, + crypto::{GenesisHash, Nonce, VRFCert, Vkey}, governance::VotingProcedures, + plutus::{CostModels, ExUnitPrices, ExUnits}, transaction::RequiredSigners, - MapTransactionIndexToAuxiliaryData, NetworkId, ProposalProcedureList, TransactionInputList, - TransactionWitnessSetList, Withdrawals, + DRepVotingThresholds, MapTransactionIndexToAuxiliaryData, NetworkId, PoolVotingThresholds, + ProposalProcedureList, Rational, TransactionInputList, TransactionWitnessSetList, UnitInterval, + Withdrawals, +}; +use cml_core::{Epoch, TransactionIndex}; +use cml_core_wasm::{impl_wasm_conversions, impl_wasm_json_api, impl_wasm_list, impl_wasm_map}; +use cml_crypto_wasm::{ + AuxiliaryDataHash, BlockBodyHash, BlockHeaderHash, ScriptDataHash, TransactionHash, VRFVkey, }; -use cml_core::TransactionIndex; -use cml_core_wasm::{impl_wasm_conversions, impl_wasm_json_api, impl_wasm_list}; -use cml_crypto_wasm::{AuxiliaryDataHash, ScriptDataHash, TransactionHash}; use wasm_bindgen::{prelude::wasm_bindgen, JsError, JsValue}; use crate::{ - allegra::MoveInstantaneousRewardsCert, shelley::GenesisKeyDelegation, MultiEraBlock, - MultiEraTransactionBody, + allegra::MoveInstantaneousRewardsCert, shelley::GenesisKeyDelegation, + shelley::ProtocolVersionStruct, GenesisHashList, MultiEraBlock, MultiEraTransactionBody, }; #[wasm_bindgen] @@ -81,6 +87,68 @@ impl_wasm_list!( MultiEraTransactionOutputList ); +#[derive(Clone, Debug)] +#[wasm_bindgen] +pub struct MultiEraBlockHeader(cml_multi_era::utils::MultiEraBlockHeader); + +impl_wasm_json_api!(MultiEraBlockHeader); + +impl_wasm_conversions!( + cml_multi_era::utils::MultiEraBlockHeader, + MultiEraBlockHeader +); + +#[wasm_bindgen] +impl MultiEraBlockHeader { + pub fn block_number(&self) -> Option { + self.0.block_number() + } + + pub fn slot(&self) -> Option { + self.0.slot() + } + + pub fn prev_hash(&self) -> Option { + self.0.prev_hash().map(Into::into) + } + + pub fn issuer_vkey(&self) -> Option { + self.0.issuer_vkey().map(|vkey| vkey.clone().into()) + } + + pub fn vrf_vkey(&self) -> Option { + self.0.vrf_vkey().map(|vkey| (*vkey).into()) + } + + pub fn nonce_vrf(&self) -> Option { + self.0.nonce_vrf().map(|vrf| vrf.clone().into()) + } + + pub fn leader_vrf(&self) -> Option { + self.0.leader_vrf().map(|vrf| vrf.clone().into()) + } + + pub fn vrf_result(&self) -> Option { + self.0.vrf_result().map(|res| res.clone().into()) + } + + pub fn block_body_size(&self) -> Option { + self.0.block_body_size() + } + + pub fn block_body_hash(&self) -> Option { + self.0.block_body_hash().map(Into::into) + } + + pub fn operational_cert(&self) -> Option { + self.0.operational_cert().map(|cert| cert.clone().into()) + } + + pub fn protocol_version(&self) -> Option { + self.0.protocol_version().map(|ver| ver.clone().into()) + } +} + #[derive(Clone, Debug)] #[wasm_bindgen] pub struct MultiEraCertificate(cml_multi_era::utils::MultiEraCertificate); @@ -351,6 +419,158 @@ pub enum MultiEraCertificateKind { UpdateDrepCert, } +#[derive(Clone, Debug)] +#[wasm_bindgen] +pub struct MultiEraProtocolParamUpdate(cml_multi_era::utils::MultiEraProtocolParamUpdate); + +impl_wasm_json_api!(MultiEraProtocolParamUpdate); + +impl_wasm_conversions!( + cml_multi_era::utils::MultiEraProtocolParamUpdate, + MultiEraProtocolParamUpdate +); + +#[wasm_bindgen] +impl MultiEraProtocolParamUpdate { + pub fn minfee_a(&self) -> Option { + self.0.minfee_a() + } + + pub fn minfee_b(&self) -> Option { + self.0.minfee_b() + } + + pub fn max_block_body_size(&self) -> Option { + self.0.max_block_body_size() + } + + pub fn max_transaction_size(&self) -> Option { + self.0.max_transaction_size() + } + + pub fn max_block_header_size(&self) -> Option { + self.0.max_block_header_size() + } + + pub fn key_deposit(&self) -> Option { + self.0.key_deposit() + } + + pub fn pool_deposit(&self) -> Option { + self.0.pool_deposit() + } + + pub fn maximum_epoch(&self) -> Option { + self.0.maximum_epoch() + } + + pub fn n_opt(&self) -> Option { + self.0.n_opt() + } + + pub fn pool_pledge_influence(&self) -> Option { + self.0.pool_pledge_influence().map(|ppi| ppi.clone().into()) + } + + pub fn expansion_rate(&self) -> Option { + self.0.expansion_rate().map(|er| er.clone().into()) + } + + pub fn treasury_growth_rate(&self) -> Option { + self.0.treasury_growth_rate().map(|tgr| tgr.clone().into()) + } + + pub fn decentralization_constant(&self) -> Option { + self.0 + .decentralization_constant() + .map(|dc| dc.clone().into()) + } + + pub fn extra_entropy(&self) -> Option { + self.0.extra_entropy().map(|ee| ee.clone().into()) + } + + pub fn protocol_version(&self) -> Option { + self.0.protocol_version().map(|pv| pv.clone().into()) + } + + pub fn min_utxo_value(&self) -> Option { + self.0.min_utxo_value() + } + + pub fn min_pool_cost(&self) -> Option { + self.0.min_pool_cost() + } + + pub fn ada_per_utxo_byte(&self) -> Option { + self.0.ada_per_utxo_byte() + } + + pub fn cost_models_for_script_languages(&self) -> Option { + self.0.cost_models_for_script_languages().map(Into::into) + } + + pub fn execution_costs(&self) -> Option { + self.0.execution_costs().map(|ec| ec.clone().into()) + } + + pub fn max_tx_ex_units(&self) -> Option { + self.0.max_tx_ex_units().map(|mteu| mteu.clone().into()) + } + + pub fn max_block_ex_units(&self) -> Option { + self.0.max_block_ex_units().map(|mbeu| mbeu.clone().into()) + } + + pub fn max_value_size(&self) -> Option { + self.0.max_value_size() + } + + pub fn collateral_percentage(&self) -> Option { + self.0.collateral_percentage() + } + + pub fn max_collateral_inputs(&self) -> Option { + self.0.max_collateral_inputs() + } + + pub fn pool_voting_thresholds(&self) -> Option { + self.0 + .pool_voting_thresholds() + .map(|pvt| pvt.clone().into()) + } + + pub fn d_rep_voting_thresholds(&self) -> Option { + self.0 + .d_rep_voting_thresholds() + .map(|drvt| drvt.clone().into()) + } + + pub fn min_committee_size(&self) -> Option { + self.0.min_committee_size() + } + + pub fn committee_term_limit(&self) -> Option { + self.0.committee_term_limit() + } + + pub fn governance_action_validity_period(&self) -> Option { + self.0.governance_action_validity_period() + } + + pub fn governance_action_deposit(&self) -> Option { + self.0.governance_action_deposit() + } + + pub fn d_rep_deposit(&self) -> Option { + self.0.d_rep_deposit() + } + + pub fn d_rep_inactivity_period(&self) -> Option { + self.0.d_rep_inactivity_period() + } +} + #[wasm_bindgen] impl MultiEraTransactionBody { pub fn inputs(&self) -> MultiEraTransactionInputList { @@ -377,6 +597,10 @@ impl MultiEraTransactionBody { self.0.withdrawals().map(|wd| wd.clone().into()) } + pub fn update(&self) -> Option { + self.0.update().map(Into::into) + } + pub fn auxiliary_data_hash(&self) -> Option { self.0.auxiliary_data_hash().map(|aux| (*aux).into()) } @@ -483,3 +707,31 @@ impl MultiEraTransactionOutput { self.0.amount().into() } } + +#[wasm_bindgen] +#[derive(Clone, Debug)] +pub struct MultiEraUpdate(cml_multi_era::utils::MultiEraUpdate); + +impl_wasm_conversions!(cml_multi_era::utils::MultiEraUpdate, MultiEraUpdate); + +#[wasm_bindgen] +impl MultiEraUpdate { + pub fn epoch(&self) -> u64 { + self.0.epoch + } + + pub fn proposed_protocol_parameter_updates( + &self, + ) -> MapGenesisHashToMultiEraProtocolParamUpdate { + self.0.proposed_protocol_parameter_updates.clone().into() + } +} + +impl_wasm_map!( + cml_crypto::GenesisHash, + cml_multi_era::utils::MultiEraProtocolParamUpdate, + GenesisHash, + MultiEraProtocolParamUpdate, + GenesisHashList, + MapGenesisHashToMultiEraProtocolParamUpdate +); diff --git a/specs/multiera/alonzo/mod.cddl b/specs/multiera/alonzo/mod.cddl index 72acea26..9aab2f0f 100644 --- a/specs/multiera/alonzo/mod.cddl +++ b/specs/multiera/alonzo/mod.cddl @@ -64,7 +64,7 @@ alonzo_protocol_param_update = { ? 19: ex_unit_prices, ; @name execution_costs ? 20: ex_units, ; @name max_tx_ex_units ? 21: ex_units, ; @name max_block_ex_units - ? 22: uint, ; @name max value size + ? 22: uint, ; @name max_value_size ? 23: uint, ; @name collateral_percentage ? 24: uint, ; @name max_collateral_inputs }