feat(traverse): Introduce new accessor methods (#152)

This commit is contained in:
Santiago Carmuega 2022-07-16 19:31:27 -03:00 committed by GitHub
parent 3b685e8b7f
commit 3ac707e486
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 507 additions and 238 deletions

View file

@ -16,7 +16,6 @@ authors = [
hex = "0.4.3"
pallas-crypto = { version = "0.11.0", path = "../pallas-crypto" }
pallas-codec = { version = "0.11.0", path = "../pallas-codec" }
pallas-primitives = { version = "0.11.0", path = "../pallas-primitives" }
base58 = "0.2.0"
bech32 = "0.8.1"
thiserror = "1.0.31"

View file

@ -0,0 +1,159 @@
use pallas_codec::{
minicbor::{self, bytes::ByteVec, Decode, Encode},
utils::OrderPreservingProperties,
};
use pallas_crypto::hash::Hash;
pub type Blake2b224 = Hash<28>;
pub type AddressId = Blake2b224;
pub type StakeholderId = Blake2b224;
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub enum AddrDistr {
Variant0(StakeholderId),
Variant1,
}
impl<'b, C> minicbor::Decode<'b, C> for AddrDistr {
fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result<Self, minicbor::decode::Error> {
d.array()?;
let variant = d.u32()?;
match variant {
0 => Ok(AddrDistr::Variant0(d.decode_with(ctx)?)),
1 => Ok(AddrDistr::Variant1),
_ => Err(minicbor::decode::Error::message(
"invalid variant for addrdstr",
)),
}
}
}
impl minicbor::Encode<()> for AddrDistr {
fn encode<W: minicbor::encode::Write>(
&self,
e: &mut minicbor::Encoder<W>,
_ctx: &mut (),
) -> Result<(), minicbor::encode::Error<W::Error>> {
match self {
AddrDistr::Variant0(x) => {
e.array(2)?;
e.u32(0)?;
e.encode(x)?;
Ok(())
}
AddrDistr::Variant1 => {
e.array(1)?;
e.u32(1)?;
Ok(())
}
}
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub enum AddrType {
PubKey,
Script,
Redeem,
Other(u64),
}
impl<'b, C> minicbor::Decode<'b, C> for AddrType {
fn decode(
d: &mut minicbor::Decoder<'b>,
_ctx: &mut C,
) -> Result<Self, minicbor::decode::Error> {
let variant = d.u64()?;
match variant {
0 => Ok(AddrType::PubKey),
1 => Ok(AddrType::Script),
2 => Ok(AddrType::Redeem),
x => Ok(AddrType::Other(x)),
}
}
}
impl<C> minicbor::Encode<C> for AddrType {
fn encode<W: minicbor::encode::Write>(
&self,
e: &mut minicbor::Encoder<W>,
_ctx: &mut C,
) -> Result<(), minicbor::encode::Error<W::Error>> {
match self {
AddrType::PubKey => e.u64(0)?,
AddrType::Script => e.u64(1)?,
AddrType::Redeem => e.u64(2)?,
AddrType::Other(x) => e.u64(*x)?,
};
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub enum AddrAttrProperty {
AddrDistr(AddrDistr),
Bytes(ByteVec),
Unparsed(u8, ByteVec),
}
impl<'b, C> minicbor::Decode<'b, C> for AddrAttrProperty {
fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result<Self, minicbor::decode::Error> {
let key = d.u8()?;
match key {
0 => Ok(AddrAttrProperty::AddrDistr(d.decode_with(ctx)?)),
1 => Ok(AddrAttrProperty::Bytes(d.decode_with(ctx)?)),
x => Ok(AddrAttrProperty::Unparsed(x, d.decode_with(ctx)?)),
}
}
}
impl<C> minicbor::Encode<C> for AddrAttrProperty {
fn encode<W: minicbor::encode::Write>(
&self,
e: &mut minicbor::Encoder<W>,
_ctx: &mut C,
) -> Result<(), minicbor::encode::Error<W::Error>> {
match self {
AddrAttrProperty::AddrDistr(x) => {
e.u32(0)?;
e.encode(x)?;
Ok(())
}
AddrAttrProperty::Bytes(x) => {
e.u32(1)?;
e.encode(x)?;
Ok(())
}
AddrAttrProperty::Unparsed(a, b) => {
e.encode(a)?;
e.encode(b)?;
Ok(())
}
}
}
}
pub type AddrAttr = OrderPreservingProperties<AddrAttrProperty>;
#[derive(Debug, Encode, Decode, Clone, PartialEq, PartialOrd)]
pub struct AddressPayload {
#[n(0)]
pub root: AddressId,
#[n(1)]
pub attributes: AddrAttr,
#[n(2)]
pub addrtype: AddrType,
}

View file

@ -7,6 +7,7 @@
//!
//! For more information regarding Cardano addresses and their formats, please refer to [CIP-19](https://cips.cardano.org/cips/cip19/).
pub mod byron;
pub mod varuint;
use std::io::Cursor;
@ -236,10 +237,10 @@ pub struct StakeAddress(Network, StakePayload);
/// New type wrapping a Byron address primitive
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct ByronAddress(pallas_primitives::byron::Address);
pub struct ByronAddress(byron::AddressPayload);
impl ByronAddress {
pub fn new(primitive: pallas_primitives::byron::Address) -> Self {
pub fn new(primitive: byron::AddressPayload) -> Self {
Self(primitive)
}
}

View file

@ -273,7 +273,7 @@ impl<T> Deref for CborWrap<T> {
}
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct TagWrap<I, const T: u64>(I);
impl<I, const T: u64> TagWrap<I, T> {
@ -309,6 +309,14 @@ where
}
}
impl<I, const T: u64> Deref for TagWrap<I, T> {
type Target = I;
fn deref(&self) -> &Self::Target {
&self.0
}
}
/// An empty map
///
/// don't ask me why, that's what the CDDL asks for.

View file

@ -4,12 +4,7 @@ use std::{
};
use log::info;
use pallas_codec::minicbor;
use pallas_multiplexer::{
agents::{Channel, ChannelBuffer},
bearers::Bearer,
Payload, StdPlexer,
};
use pallas_multiplexer::{agents::Channel, bearers::Bearer, StdPlexer};
use rand::{distributions::Uniform, Rng};
fn setup_passive_muxer<const P: u16>() -> JoinHandle<StdPlexer> {

View file

@ -280,6 +280,8 @@ pub struct MoveInstantaneousReward {
pub type RewardAccount = ByteVec;
pub type Withdrawals = KeyValuePairs<RewardAccount, Coin>;
pub type Port = u32;
pub type IPv4 = ByteVec;
pub type IPv6 = ByteVec;
@ -719,7 +721,7 @@ pub struct TransactionBody {
pub certificates: Option<MaybeIndefArray<Certificate>>,
#[n(5)]
pub withdrawals: Option<KeyValuePairs<RewardAccount, Coin>>,
pub withdrawals: Option<Withdrawals>,
#[n(6)]
pub update: Option<Update>,

View file

@ -6,8 +6,7 @@ use pallas_codec::minicbor::{bytes::ByteVec, Decode, Encode};
use pallas_crypto::hash::Hash;
use pallas_codec::utils::{
CborWrap, EmptyMap, KeepRaw, KeyValuePairs, MaybeIndefArray, OrderPreservingProperties,
TagWrap, ZeroOrOneArray,
CborWrap, EmptyMap, KeepRaw, KeyValuePairs, MaybeIndefArray, TagWrap, ZeroOrOneArray,
};
// required for derive attrs to work
@ -49,161 +48,14 @@ pub type Signature = ByteVec;
// attributes = {* any => any}
pub type Attributes = EmptyMap;
// Addresses
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub enum AddrDistr {
Variant0(StakeholderId),
Variant1,
}
impl<'b, C> minicbor::Decode<'b, C> for AddrDistr {
fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result<Self, minicbor::decode::Error> {
d.array()?;
let variant = d.u32()?;
match variant {
0 => Ok(AddrDistr::Variant0(d.decode_with(ctx)?)),
1 => Ok(AddrDistr::Variant1),
_ => Err(minicbor::decode::Error::message(
"invalid variant for addrdstr",
)),
}
}
}
impl minicbor::Encode<()> for AddrDistr {
fn encode<W: minicbor::encode::Write>(
&self,
e: &mut minicbor::Encoder<W>,
_ctx: &mut (),
) -> Result<(), minicbor::encode::Error<W::Error>> {
match self {
AddrDistr::Variant0(x) => {
e.array(2)?;
e.u32(0)?;
e.encode(x)?;
Ok(())
}
AddrDistr::Variant1 => {
e.array(1)?;
e.u32(1)?;
Ok(())
}
}
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub enum AddrType {
PubKey,
Script,
Redeem,
Other(u64),
}
impl<'b, C> minicbor::Decode<'b, C> for AddrType {
fn decode(
d: &mut minicbor::Decoder<'b>,
_ctx: &mut C,
) -> Result<Self, minicbor::decode::Error> {
let variant = d.u64()?;
match variant {
0 => Ok(AddrType::PubKey),
1 => Ok(AddrType::Script),
2 => Ok(AddrType::Redeem),
x => Ok(AddrType::Other(x)),
}
}
}
impl<C> minicbor::Encode<C> for AddrType {
fn encode<W: minicbor::encode::Write>(
&self,
e: &mut minicbor::Encoder<W>,
_ctx: &mut C,
) -> Result<(), minicbor::encode::Error<W::Error>> {
match self {
AddrType::PubKey => e.u64(0)?,
AddrType::Script => e.u64(1)?,
AddrType::Redeem => e.u64(2)?,
AddrType::Other(x) => e.u64(*x)?,
};
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub enum AddrAttrProperty {
AddrDistr(AddrDistr),
Bytes(ByteVec),
Unparsed(u8, ByteVec),
}
impl<'b, C> minicbor::Decode<'b, C> for AddrAttrProperty {
fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result<Self, minicbor::decode::Error> {
let key = d.u8()?;
match key {
0 => Ok(AddrAttrProperty::AddrDistr(d.decode_with(ctx)?)),
1 => Ok(AddrAttrProperty::Bytes(d.decode_with(ctx)?)),
x => Ok(AddrAttrProperty::Unparsed(x, d.decode_with(ctx)?)),
}
}
}
impl<C> minicbor::Encode<C> for AddrAttrProperty {
fn encode<W: minicbor::encode::Write>(
&self,
e: &mut minicbor::Encoder<W>,
_ctx: &mut C,
) -> Result<(), minicbor::encode::Error<W::Error>> {
match self {
AddrAttrProperty::AddrDistr(x) => {
e.u32(0)?;
e.encode(x)?;
Ok(())
}
AddrAttrProperty::Bytes(x) => {
e.u32(1)?;
e.encode(x)?;
Ok(())
}
AddrAttrProperty::Unparsed(a, b) => {
e.encode(a)?;
e.encode(b)?;
Ok(())
}
}
}
}
pub type AddrAttr = OrderPreservingProperties<AddrAttrProperty>;
#[derive(Debug, Encode, Decode, Clone, PartialEq, PartialOrd)]
pub struct AddressPayload {
#[n(0)]
pub root: AddressId,
#[n(1)]
pub attributes: AddrAttr,
#[n(2)]
pub addrtype: AddrType,
}
// The cbor struct of the address payload is now defined in pallas-addresses.
// The primitives crate will treat addresses as a black-box vec of bytes.
// address = [ #6.24(bytes .cbor ([addressid, addrattr, addrtype])), u64 ]
#[derive(Debug, Encode, Decode, Clone, PartialEq, PartialOrd)]
pub struct Address {
#[n(0)]
pub payload: CborWrap<AddressPayload>,
pub payload: TagWrap<ByteVec, 24>,
#[n(1)]
pub crc: u64,
@ -954,6 +806,18 @@ pub struct EbBlock {
pub extra: MaybeIndefArray<Attributes>,
}
#[derive(Encode, Decode, Debug, Clone)]
pub struct MintedEbBlock<'b> {
#[b(0)]
pub header: KeepRaw<'b, EbbHead>,
#[n(1)]
pub body: MaybeIndefArray<StakeholderId>,
#[n(2)]
pub extra: MaybeIndefArray<Attributes>,
}
#[cfg(test)]
mod tests {
use super::{BlockHead, EbBlock, MintedBlock};

View file

@ -2,15 +2,15 @@ use std::borrow::Cow;
use pallas_codec::minicbor;
use pallas_crypto::hash::Hash;
use pallas_primitives::{alonzo, babbage, byron, ToHash};
use pallas_primitives::{alonzo, babbage, byron};
use crate::{probe, support, Era, Error, MultiEraBlock, MultiEraTx};
use crate::{probe, support, Era, Error, MultiEraBlock, MultiEraHeader, MultiEraTx};
type BlockWrapper<T> = (u16, T);
impl<'b> MultiEraBlock<'b> {
pub fn decode_epoch_boundary(cbor: &'b [u8]) -> Result<Self, Error> {
let (_, block): BlockWrapper<byron::EbBlock> =
let (_, block): BlockWrapper<byron::MintedEbBlock> =
minicbor::decode(cbor).map_err(Error::invalid_cbor)?;
Ok(Self::EpochBoundary(Box::new(Cow::Owned(block))))
@ -85,27 +85,24 @@ impl<'b> MultiEraBlock<'b> {
}
}
pub fn number(&self) -> u64 {
pub fn header(&self) -> MultiEraHeader<'_> {
match self {
MultiEraBlock::EpochBoundary(x) => x
.header
.consensus_data
.difficulty
.first()
.cloned()
.unwrap_or_default(),
MultiEraBlock::AlonzoCompatible(x, _) => x.header.header_body.block_number,
MultiEraBlock::Babbage(x) => x.header.header_body.block_number,
MultiEraBlock::Byron(x) => x
.header
.consensus_data
.2
.first()
.cloned()
.unwrap_or_default(),
MultiEraBlock::EpochBoundary(x) => {
MultiEraHeader::EpochBoundary(Cow::Borrowed(&x.header))
}
MultiEraBlock::Byron(x) => MultiEraHeader::Byron(Cow::Borrowed(&x.header)),
MultiEraBlock::AlonzoCompatible(x, _) => {
MultiEraHeader::AlonzoCompatible(Cow::Borrowed(&x.header))
}
MultiEraBlock::Babbage(x) => MultiEraHeader::Babbage(Cow::Borrowed(&x.header)),
}
}
/// Returns the block number (aka: height)
pub fn number(&self) -> u64 {
self.header().number()
}
pub fn era(&self) -> Era {
match self {
MultiEraBlock::EpochBoundary(_) => Era::Byron,
@ -116,23 +113,14 @@ impl<'b> MultiEraBlock<'b> {
}
pub fn hash(&self) -> Hash<32> {
match self {
MultiEraBlock::EpochBoundary(x) => x.header.to_hash(),
MultiEraBlock::AlonzoCompatible(x, _) => x.header.to_hash(),
MultiEraBlock::Babbage(x) => x.header.to_hash(),
MultiEraBlock::Byron(x) => x.header.to_hash(),
}
self.header().hash()
}
pub fn slot(&self) -> u64 {
match self {
MultiEraBlock::EpochBoundary(x) => x.header.to_abs_slot(),
MultiEraBlock::AlonzoCompatible(x, _) => x.header.header_body.slot,
MultiEraBlock::Babbage(x) => x.header.header_body.slot,
MultiEraBlock::Byron(x) => x.header.consensus_data.0.to_abs_slot(),
}
self.header().slot()
}
/// Builds a vec with the Txs of the block
pub fn txs(&self) -> Vec<MultiEraTx> {
match self {
MultiEraBlock::AlonzoCompatible(x, era) => support::clone_alonzo_txs(x)
@ -151,6 +139,36 @@ impl<'b> MultiEraBlock<'b> {
}
}
/// Returns true if the there're no tx in the block
pub fn is_empty(&self) -> bool {
match self {
MultiEraBlock::EpochBoundary(_) => true,
MultiEraBlock::AlonzoCompatible(x, _) => x.transaction_bodies.is_empty(),
MultiEraBlock::Babbage(x) => x.transaction_bodies.is_empty(),
MultiEraBlock::Byron(x) => x.body.tx_payload.is_empty(),
}
}
/// Returns the count of txs in the block
pub fn tx_count(&self) -> usize {
match self {
MultiEraBlock::EpochBoundary(_) => 0,
MultiEraBlock::AlonzoCompatible(x, _) => x.transaction_bodies.len(),
MultiEraBlock::Babbage(x) => x.transaction_bodies.len(),
MultiEraBlock::Byron(x) => x.body.tx_payload.len(),
}
}
/// Returns true if the block has any auxiliary data
pub fn has_aux_data(&self) -> bool {
match self {
MultiEraBlock::EpochBoundary(_) => false,
MultiEraBlock::AlonzoCompatible(x, _) => !x.auxiliary_data_set.is_empty(),
MultiEraBlock::Babbage(x) => !x.auxiliary_data_set.is_empty(),
MultiEraBlock::Byron(_) => false,
}
}
pub fn as_alonzo(&self) -> Option<&alonzo::MintedBlock> {
match self {
MultiEraBlock::EpochBoundary(_) => None,

View file

@ -5,8 +5,8 @@ use crate::MultiEraCert;
impl<'b> MultiEraCert<'b> {
pub fn as_alonzo(&self) -> Option<&alonzo::Certificate> {
match self {
MultiEraCert::NotApplicable => None,
MultiEraCert::AlonzoCompatible(x) => Some(x),
_ => None,
}
}
}

View file

@ -1,3 +1,5 @@
use std::borrow::Cow;
use pallas_codec::minicbor;
use pallas_crypto::hash::{Hash, Hasher};
use pallas_primitives::ToHash;
@ -11,24 +13,33 @@ impl<'b> MultiEraHeader<'b> {
0 => match subtag {
Some(0) => {
let header = minicbor::decode(cbor).map_err(Error::invalid_cbor)?;
Ok(MultiEraHeader::EpochBoundary(header))
Ok(MultiEraHeader::EpochBoundary(Cow::Owned(header)))
}
_ => {
let header = minicbor::decode(cbor).map_err(Error::invalid_cbor)?;
Ok(MultiEraHeader::Byron(header))
Ok(MultiEraHeader::Byron(Cow::Owned(header)))
}
},
5 => {
let header = minicbor::decode(cbor).map_err(Error::invalid_cbor)?;
Ok(MultiEraHeader::Babbage(header))
Ok(MultiEraHeader::Babbage(Cow::Owned(header)))
}
_ => {
let header = minicbor::decode(cbor).map_err(Error::invalid_cbor)?;
Ok(MultiEraHeader::AlonzoCompatible(header))
Ok(MultiEraHeader::AlonzoCompatible(Cow::Owned(header)))
}
}
}
pub fn cbor(&self) -> &'b [u8] {
match self {
MultiEraHeader::EpochBoundary(x) => x.raw_cbor(),
MultiEraHeader::AlonzoCompatible(x) => x.raw_cbor(),
MultiEraHeader::Babbage(x) => x.raw_cbor(),
MultiEraHeader::Byron(x) => x.raw_cbor(),
}
}
pub fn number(&self) -> u64 {
match self {
MultiEraHeader::EpochBoundary(x) => x

View file

@ -11,18 +11,18 @@ impl OutputRef {
Self(hash, index)
}
pub fn tx_id(&self) -> &Hash<32> {
pub fn hash(&self) -> &Hash<32> {
&self.0
}
pub fn tx_index(&self) -> u64 {
pub fn index(&self) -> u64 {
self.1
}
}
impl Display for OutputRef {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}#{}", self.tx_id(), self.tx_index())
write!(f, "{}#{}", self.hash(), self.index())
}
}
@ -52,13 +52,33 @@ impl<'b> MultiEraInput<'b> {
Self::AlonzoCompatible(Box::new(Cow::Borrowed(input)))
}
pub fn output_ref(&self) -> Option<OutputRef> {
pub fn output_ref(&self) -> OutputRef {
match self {
MultiEraInput::Byron(x) => match x.deref().deref() {
byron::TxIn::Variant0(CborWrap((tx, idx))) => Some(OutputRef(*tx, *idx as u64)),
byron::TxIn::Other(_, _) => None,
byron::TxIn::Variant0(CborWrap((tx, idx))) => OutputRef(*tx, *idx as u64),
byron::TxIn::Other(_, _) => unreachable!(),
},
MultiEraInput::AlonzoCompatible(x) => Some(OutputRef(x.transaction_id, x.index)),
MultiEraInput::AlonzoCompatible(x) => OutputRef(x.transaction_id, x.index),
}
}
pub fn hash(&self) -> &Hash<32> {
match self {
MultiEraInput::Byron(x) => match x.deref().deref() {
byron::TxIn::Variant0(CborWrap((x, _))) => x,
byron::TxIn::Other(_, _) => unreachable!(),
},
MultiEraInput::AlonzoCompatible(x) => &x.transaction_id,
}
}
pub fn index(&self) -> u64 {
match self {
MultiEraInput::Byron(x) => match x.deref().deref() {
byron::TxIn::Variant0(CborWrap((_, x))) => *x as u64,
byron::TxIn::Other(_, _) => unreachable!(),
},
MultiEraInput::AlonzoCompatible(x) => x.index,
}
}
@ -110,10 +130,9 @@ mod tests {
let block = MultiEraBlock::decode(&cbor).expect("invalid cbor");
for tx in block.txs() {
for input in tx.inputs() {
if let Some(out) = input.output_ref() {
let right = expected.remove(0);
assert_eq!(out.to_string(), right);
}
let ref_ = input.output_ref();
let right = expected.remove(0);
assert_eq!(ref_.to_string(), right);
}
}
}
@ -130,10 +149,10 @@ mod tests {
let sample = OutputRef::from_str(vector).unwrap();
assert_eq!(
sample.tx_id().to_string(),
sample.hash().to_string(),
"da832fb5ef57df5b91817e9a7448d26e92552afb34f8ee5adb491b24bbe990d5"
);
assert_eq!(sample.tx_index(), 14);
assert_eq!(sample.index(), 14);
}
}
}

View file

@ -15,10 +15,12 @@ pub mod era;
pub mod header;
pub mod input;
pub mod meta;
pub mod mint;
pub mod output;
pub mod probe;
mod support;
pub mod tx;
pub mod withdrawals;
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
#[non_exhaustive]
@ -45,16 +47,16 @@ pub enum Feature {
#[derive(Debug)]
pub enum MultiEraHeader<'b> {
EpochBoundary(KeepRaw<'b, byron::EbbHead>),
AlonzoCompatible(KeepRaw<'b, alonzo::Header>),
Babbage(KeepRaw<'b, babbage::Header>),
Byron(KeepRaw<'b, byron::BlockHead>),
EpochBoundary(Cow<'b, KeepRaw<'b, byron::EbbHead>>),
AlonzoCompatible(Cow<'b, KeepRaw<'b, alonzo::Header>>),
Babbage(Cow<'b, KeepRaw<'b, babbage::Header>>),
Byron(Cow<'b, KeepRaw<'b, byron::BlockHead>>),
}
#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum MultiEraBlock<'b> {
EpochBoundary(Box<Cow<'b, byron::EbBlock>>),
EpochBoundary(Box<Cow<'b, byron::MintedEbBlock<'b>>>),
AlonzoCompatible(Box<Cow<'b, alonzo::MintedBlock<'b>>>, Era),
Babbage(Box<Cow<'b, babbage::MintedBlock<'b>>>),
Byron(Box<Cow<'b, byron::MintedBlock<'b>>>),
@ -83,12 +85,36 @@ pub enum MultiEraInput<'b> {
AlonzoCompatible(Box<Cow<'b, alonzo::TransactionInput>>),
}
#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum MultiEraCert<'b> {
NotApplicable,
AlonzoCompatible(Box<Cow<'b, alonzo::Certificate>>),
}
pub struct MultiEraMeta<'b>(Cow<'b, alonzo::Metadata>);
#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum MultiEraMeta<'b> {
NotApplicable,
Empty,
AlonzoCompatible(Cow<'b, alonzo::Metadata>),
}
#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum MultiEraMint<'b> {
NotApplicable,
Empty,
AlonzoCompatible(Cow<'b, alonzo::Mint>),
}
#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum MultiEraWithdrawals<'b> {
NotApplicable,
Empty,
AlonzoCompatible(Cow<'b, alonzo::Withdrawals>),
}
#[derive(Debug, Clone)]
pub struct OutputRef(Hash<32>, u64);

View file

@ -2,14 +2,44 @@ use pallas_primitives::alonzo;
use crate::MultiEraMeta;
impl Default for MultiEraMeta<'_> {
fn default() -> Self {
MultiEraMeta::Empty
}
}
impl<'b> MultiEraMeta<'b> {
pub fn entries(&self) -> &alonzo::Metadata {
&self.0
pub fn as_alonzo(&self) -> Option<&alonzo::Metadata> {
match self {
Self::AlonzoCompatible(x) => Some(x),
_ => None,
}
}
pub fn is_empty(&self) -> bool {
match self {
MultiEraMeta::AlonzoCompatible(x) => x.is_empty(),
_ => true,
}
}
pub fn find(&self, label: alonzo::MetadatumLabel) -> Option<&alonzo::Metadatum> {
self.entries()
self.as_alonzo()?
.iter()
.find_map(|(key, value)| if key.eq(&label) { Some(value) } else { None })
}
pub fn collect<'a, T>(&'a self) -> T
where
T: FromIterator<(&'a alonzo::MetadatumLabel, &'a alonzo::Metadatum)>,
{
match self {
MultiEraMeta::NotApplicable => T::from_iter(std::iter::empty()),
MultiEraMeta::Empty => T::from_iter(std::iter::empty()),
MultiEraMeta::AlonzoCompatible(x) => {
let iter = x.iter().map(|(k, v)| (k, v));
T::from_iter(iter)
}
}
}
}

View file

@ -0,0 +1,32 @@
use pallas_primitives::alonzo;
use crate::MultiEraMint;
impl Default for MultiEraMint<'_> {
fn default() -> Self {
MultiEraMint::Empty
}
}
impl<'b> MultiEraMint<'b> {
pub fn len(&self) -> usize {
match self {
MultiEraMint::AlonzoCompatible(x) => x.len(),
_ => 0,
}
}
pub fn is_empty(&self) -> bool {
match self {
MultiEraMint::AlonzoCompatible(x) => x.is_empty(),
_ => true,
}
}
pub fn as_alonzo(&self) -> Option<&alonzo::Mint> {
match self {
Self::AlonzoCompatible(x) => Some(x),
_ => None,
}
}
}

View file

@ -1,6 +1,6 @@
use std::{borrow::Cow, ops::Deref};
use pallas_addresses::{Address, ByronAddress, Error as AddressError};
use pallas_addresses::{Address, Error as AddressError};
use pallas_codec::minicbor;
use pallas_primitives::{alonzo, babbage, byron};
@ -19,17 +19,21 @@ impl<'b> MultiEraOutput<'b> {
Self::Babbage(Box::new(Cow::Borrowed(output)))
}
pub fn to_address(&self) -> Result<Address, AddressError> {
pub fn address_raw(&self) -> &[u8] {
match self {
MultiEraOutput::AlonzoCompatible(x) => Address::from_bytes(&x.address),
MultiEraOutput::AlonzoCompatible(x) => &x.address,
MultiEraOutput::Babbage(x) => match x.deref().deref() {
babbage::TransactionOutput::Legacy(x) => Address::from_bytes(&x.address),
babbage::TransactionOutput::PostAlonzo(x) => Address::from_bytes(&x.address),
babbage::TransactionOutput::Legacy(x) => &x.address,
babbage::TransactionOutput::PostAlonzo(x) => &x.address,
},
MultiEraOutput::Byron(x) => Ok(ByronAddress::new(x.address.clone()).into()),
MultiEraOutput::Byron(x) => x.address.payload.deref(),
}
}
pub fn address(&self) -> Result<Address, AddressError> {
Address::from_bytes(self.address_raw())
}
pub fn ada_amount(&self) -> u64 {
match self {
MultiEraOutput::Byron(x) => x.amount,

View file

@ -6,7 +6,10 @@ use pallas_primitives::{
};
use std::{borrow::Cow, ops::Deref};
use crate::{Era, MultiEraCert, MultiEraInput, MultiEraMeta, MultiEraOutput, MultiEraTx};
use crate::{
Era, MultiEraCert, MultiEraInput, MultiEraMeta, MultiEraMint, MultiEraOutput, MultiEraTx,
MultiEraWithdrawals,
};
impl<'b> MultiEraTx<'b> {
pub fn from_byron(tx: &'b byron::MintedTxPayload<'b>) -> Self {
@ -151,6 +154,58 @@ impl<'b> MultiEraTx<'b> {
}
}
pub fn mint(&self) -> MultiEraMint {
match self {
MultiEraTx::AlonzoCompatible(x, _) => x
.transaction_body
.mint
.as_ref()
.map(|c| MultiEraMint::AlonzoCompatible(Cow::Borrowed(c)))
.unwrap_or_default(),
MultiEraTx::Babbage(x) => x
.transaction_body
.mint
.as_ref()
.map(|c| MultiEraMint::AlonzoCompatible(Cow::Borrowed(c)))
.unwrap_or_default(),
MultiEraTx::Byron(_) => MultiEraMint::NotApplicable,
}
}
pub fn collateral(&self) -> Vec<MultiEraInput> {
match self {
MultiEraTx::AlonzoCompatible(x, _) => x
.transaction_body
.collateral
.iter()
.flat_map(|x| x.iter())
.map(MultiEraInput::from_alonzo_compatible)
.collect(),
MultiEraTx::Babbage(x) => x
.transaction_body
.collateral
.iter()
.flat_map(|x| x.iter())
.map(MultiEraInput::from_alonzo_compatible)
.collect(),
MultiEraTx::Byron(_) => vec![],
}
}
pub fn withdrawals(&'b self) -> MultiEraWithdrawals<'b> {
match self {
MultiEraTx::AlonzoCompatible(x, _) => match &x.transaction_body.withdrawals {
Some(x) => MultiEraWithdrawals::AlonzoCompatible(Cow::Borrowed(x)),
None => MultiEraWithdrawals::Empty,
},
MultiEraTx::Babbage(x) => match &x.transaction_body.withdrawals {
Some(x) => MultiEraWithdrawals::AlonzoCompatible(Cow::Borrowed(x)),
None => MultiEraWithdrawals::Empty,
},
MultiEraTx::Byron(_) => MultiEraWithdrawals::NotApplicable,
}
}
fn aux_data(&self) -> Option<&KeepRaw<'_, AuxiliaryData>> {
match self {
MultiEraTx::AlonzoCompatible(x, _) => x.auxiliary_data.as_ref(),
@ -159,15 +214,28 @@ impl<'b> MultiEraTx<'b> {
}
}
pub fn metadata(&self) -> Option<MultiEraMeta> {
match self.aux_data()?.deref() {
AuxiliaryData::Shelley(x) => MultiEraMeta(Cow::Borrowed(x)).into(),
AuxiliaryData::ShelleyMa(x) => {
MultiEraMeta(Cow::Borrowed(&x.transaction_metadata)).into()
}
AuxiliaryData::PostAlonzo(x) => {
x.metadata.as_ref().map(|x| MultiEraMeta(Cow::Borrowed(x)))
}
pub fn metadata(&'b self) -> MultiEraMeta<'b> {
match self.aux_data() {
Some(x) => match x.deref() {
AuxiliaryData::Shelley(x) => MultiEraMeta::AlonzoCompatible(Cow::Borrowed(x)),
AuxiliaryData::ShelleyMa(x) => {
MultiEraMeta::AlonzoCompatible(Cow::Borrowed(&x.transaction_metadata))
}
AuxiliaryData::PostAlonzo(x) => x
.metadata
.as_ref()
.map(|x| MultiEraMeta::AlonzoCompatible(Cow::Borrowed(x)))
.unwrap_or_default(),
},
None => MultiEraMeta::Empty,
}
}
pub fn is_valid(&self) -> bool {
match self {
MultiEraTx::AlonzoCompatible(x, _) => x.success,
MultiEraTx::Babbage(x) => x.success,
MultiEraTx::Byron(_) => true,
}
}

View file

@ -0,0 +1,33 @@
use pallas_primitives::alonzo;
use crate::MultiEraWithdrawals;
impl<'b> MultiEraWithdrawals<'b> {
pub fn as_alonzo(&self) -> Option<&alonzo::Withdrawals> {
match self {
Self::AlonzoCompatible(x) => Some(x),
_ => None,
}
}
pub fn is_empty(&self) -> bool {
match self {
MultiEraWithdrawals::AlonzoCompatible(x) => x.is_empty(),
_ => true,
}
}
pub fn collect<'a, T>(&'a self) -> T
where
T: FromIterator<(&'a [u8], u64)>,
{
match self {
MultiEraWithdrawals::NotApplicable => T::from_iter(std::iter::empty()),
MultiEraWithdrawals::Empty => T::from_iter(std::iter::empty()),
MultiEraWithdrawals::AlonzoCompatible(x) => {
let iter = x.iter().map(|(k, v)| (k.as_slice(), v.into()));
T::from_iter(iter)
}
}
}
}