),
@@ -186,7 +186,7 @@ where
/// transform key-value structures into an orderer vec of `properties`, where
/// each entry represents a a cbor-encodable variant of an attribute of the
/// struct.
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Clone)]
pub struct OrderPreservingProperties(Vec
);
impl
Deref for OrderPreservingProperties
{
@@ -229,7 +229,7 @@ where
}
/// Wraps a struct so that it is encoded/decoded as a cbor bytes
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub struct CborWrap(pub T);
impl<'b, C, T> minicbor::Decode<'b, C> for CborWrap
@@ -312,7 +312,7 @@ where
/// An empty map
///
/// don't ask me why, that's what the CDDL asks for.
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub struct EmptyMap;
impl<'b, C> minicbor::decode::Decode<'b, C> for EmptyMap {
@@ -518,7 +518,7 @@ impl From<&AnyUInt> for u64 {
/// let confirm: (u16, u16) = minicbor::decode(keeper.raw_cbor()).unwrap();
/// assert_eq!(confirm, (456u16, 789u16));
/// ```
-#[derive(Debug, PartialEq, PartialOrd)]
+#[derive(Debug, PartialEq, PartialOrd, Clone)]
pub struct KeepRaw<'b, T> {
raw: &'b [u8],
inner: T,
diff --git a/pallas-primitives/src/alonzo/model.rs b/pallas-primitives/src/alonzo/model.rs
index 49cb017..8bc36f0 100644
--- a/pallas-primitives/src/alonzo/model.rs
+++ b/pallas-primitives/src/alonzo/model.rs
@@ -74,7 +74,7 @@ pub struct Header {
pub body_signature: ByteVec,
}
-#[derive(Encode, Decode, Debug, PartialEq)]
+#[derive(Encode, Decode, Debug, PartialEq, Clone)]
pub struct TransactionInput {
#[n(0)]
pub transaction_id: Hash<32>,
@@ -85,7 +85,7 @@ pub struct TransactionInput {
// $nonce /= [ 0 // 1, bytes .size 32 ]
-#[derive(Encode, Decode, Debug, PartialEq)]
+#[derive(Encode, Decode, Debug, PartialEq, Clone)]
#[cbor(index_only)]
pub enum NonceVariant {
#[n(0)]
@@ -95,7 +95,7 @@ pub enum NonceVariant {
Nonce,
}
-#[derive(Encode, Decode, Debug, PartialEq)]
+#[derive(Encode, Decode, Debug, PartialEq, Clone)]
pub struct Nonce {
#[n(0)]
pub variant: NonceVariant,
@@ -162,7 +162,7 @@ impl minicbor::encode::Encode for Value {
}
}
-#[derive(Encode, Decode, Debug, PartialEq)]
+#[derive(Encode, Decode, Debug, PartialEq, Clone)]
pub struct TransactionOutput {
#[n(0)]
pub address: ByteVec,
@@ -187,7 +187,7 @@ pub type VrfKeyhash = Hash<32>;
; otherwise the funds are given to the other accounting pot.
*/
-#[derive(Debug, PartialEq, PartialOrd)]
+#[derive(Debug, PartialEq, PartialOrd, Clone)]
pub enum InstantaneousRewardSource {
Reserves,
Treasury,
@@ -225,7 +225,7 @@ impl minicbor::encode::Encode for InstantaneousRewardSource {
}
}
-#[derive(Debug, PartialEq, PartialOrd)]
+#[derive(Debug, PartialEq, PartialOrd, Clone)]
pub enum InstantaneousRewardTarget {
StakeCredentials(KeyValuePairs),
OtherAccountingPot(Coin),
@@ -267,7 +267,7 @@ impl minicbor::encode::Encode for InstantaneousRewardTarget {
}
}
-#[derive(Encode, Decode, Debug, PartialEq, PartialOrd)]
+#[derive(Encode, Decode, Debug, PartialEq, PartialOrd, Clone)]
#[cbor]
pub struct MoveInstantaneousReward {
#[n(0)]
@@ -284,7 +284,7 @@ pub type IPv4 = ByteVec;
pub type IPv6 = ByteVec;
pub type DnsName = String;
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Clone)]
pub enum Relay {
SingleHostAddr(Option, Option, Option),
SingleHostName(Option, DnsName),
@@ -351,7 +351,7 @@ impl minicbor::encode::Encode for Relay {
pub type PoolMetadataHash = Hash<32>;
-#[derive(Encode, Decode, Debug, PartialEq)]
+#[derive(Encode, Decode, Debug, PartialEq, Clone)]
pub struct PoolMetadata {
#[n(0)]
pub url: String,
@@ -363,7 +363,7 @@ pub struct PoolMetadata {
pub type AddrKeyhash = Hash<28>;
pub type Scripthash = Hash<28>;
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Clone)]
pub struct RationalNumber {
pub numerator: i64,
pub denominator: u64,
@@ -401,7 +401,7 @@ pub type UnitInterval = RationalNumber;
pub type PositiveInterval = RationalNumber;
-#[derive(Debug, PartialEq, PartialOrd, Eq, Ord)]
+#[derive(Debug, PartialEq, PartialOrd, Eq, Ord, Clone)]
pub enum StakeCredential {
AddrKeyhash(AddrKeyhash),
Scripthash(Scripthash),
@@ -447,7 +447,7 @@ impl minicbor::encode::Encode for StakeCredential {
}
}
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Clone)]
pub enum Certificate {
StakeRegistration(StakeCredential),
StakeDeregistration(StakeCredential),
@@ -615,7 +615,7 @@ impl minicbor::encode::Encode for Certificate {
}
}
-#[derive(Encode, Decode, Debug, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(Encode, Decode, Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
#[cbor(index_only)]
pub enum NetworkId {
#[n(0)]
@@ -624,7 +624,7 @@ pub enum NetworkId {
Two,
}
-#[derive(Encode, Decode, Debug, PartialEq)]
+#[derive(Encode, Decode, Debug, PartialEq, Clone)]
#[cbor(index_only)]
pub enum Language {
#[n(0)]
@@ -637,7 +637,7 @@ pub type CostMdls = KeyValuePairs;
pub type ProtocolVersion = (u32, u32);
-#[derive(Encode, Decode, Debug, PartialEq)]
+#[derive(Encode, Decode, Debug, PartialEq, Clone)]
#[cbor(map)]
pub struct ProtocolParamUpdate {
#[n(0)]
@@ -690,7 +690,7 @@ pub struct ProtocolParamUpdate {
pub max_collateral_inputs: Option,
}
-#[derive(Encode, Decode, Debug, PartialEq)]
+#[derive(Encode, Decode, Debug, PartialEq, Clone)]
pub struct Update {
#[n(0)]
pub proposed_protocol_parameter_updates: KeyValuePairs,
@@ -699,7 +699,7 @@ pub struct Update {
pub epoch: Epoch,
}
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Clone)]
pub enum TransactionBodyComponent {
Inputs(MaybeIndefArray),
Outputs(MaybeIndefArray),
@@ -814,7 +814,7 @@ impl minicbor::encode::Encode for TransactionBodyComponent {
// Can't derive encode for TransactionBody because it seems to require a very
// particular order for each key in the map
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Clone)]
pub struct TransactionBody(Vec);
impl Deref for TransactionBody {
@@ -850,7 +850,7 @@ impl minicbor::encode::Encode for TransactionBody {
}
}
-#[derive(Encode, Decode, Debug, PartialEq)]
+#[derive(Encode, Decode, Debug, PartialEq, Clone)]
pub struct VKeyWitness {
#[n(0)]
pub vkey: ByteVec,
@@ -859,7 +859,7 @@ pub struct VKeyWitness {
pub signature: ByteVec,
}
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Clone)]
pub enum NativeScript {
ScriptPubkey(AddrKeyhash),
ScriptAll(MaybeIndefArray),
@@ -931,7 +931,7 @@ impl minicbor::encode::Encode for NativeScript {
}
}
-#[derive(Encode, Decode, Debug, PartialEq)]
+#[derive(Encode, Decode, Debug, PartialEq, Clone)]
#[cbor(transparent)]
pub struct PlutusScript(#[n(0)] pub ByteVec);
@@ -947,7 +947,7 @@ big_uint = #6.2(bounded_bytes) ; New
big_nint = #6.3(bounded_bytes) ; New
*/
-#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub enum BigInt {
Int(Int),
BigUInt(ByteVec),
@@ -1009,7 +1009,7 @@ impl minicbor::encode::Encode for BigInt {
}
}
-#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub enum PlutusData {
Constr(Constr),
Map(KeyValuePairs),
@@ -1090,7 +1090,7 @@ impl minicbor::encode::Encode for PlutusData {
}
}
-#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct Constr {
pub tag: u64,
pub any_constructor: Option,
@@ -1159,7 +1159,7 @@ where
}
}
-#[derive(Encode, Decode, Debug, PartialEq)]
+#[derive(Encode, Decode, Debug, PartialEq, Clone)]
pub struct ExUnits {
#[n(0)]
pub mem: u32,
@@ -1167,7 +1167,7 @@ pub struct ExUnits {
pub steps: u64,
}
-#[derive(Encode, Decode, Debug, PartialEq)]
+#[derive(Encode, Decode, Debug, PartialEq, Clone)]
pub struct ExUnitPrices {
#[n(0)]
mem_price: PositiveInterval,
@@ -1176,7 +1176,7 @@ pub struct ExUnitPrices {
step_price: PositiveInterval,
}
-#[derive(Encode, Decode, Debug, PartialEq)]
+#[derive(Encode, Decode, Debug, PartialEq, Clone)]
#[cbor(index_only)]
pub enum RedeemerTag {
#[n(0)]
@@ -1189,7 +1189,7 @@ pub enum RedeemerTag {
Reward,
}
-#[derive(Encode, Decode, Debug, PartialEq)]
+#[derive(Encode, Decode, Debug, PartialEq, Clone)]
pub struct Redeemer {
#[n(0)]
pub tag: RedeemerTag,
@@ -1211,7 +1211,7 @@ pub struct Redeemer {
, attributes : bytes
] */
-#[derive(Encode, Decode, Debug, PartialEq)]
+#[derive(Encode, Decode, Debug, PartialEq, Clone)]
pub struct BootstrapWitness {
#[n(0)]
pub public_key: ByteVec,
@@ -1226,7 +1226,7 @@ pub struct BootstrapWitness {
pub attributes: ByteVec,
}
-#[derive(Encode, Decode, Debug, PartialEq)]
+#[derive(Encode, Decode, Debug, PartialEq, Clone)]
#[cbor(map)]
pub struct TransactionWitnessSet {
#[n(0)]
@@ -1248,7 +1248,7 @@ pub struct TransactionWitnessSet {
pub redeemer: Option>,
}
-#[derive(Encode, Decode, Debug, PartialEq)]
+#[derive(Encode, Decode, Debug, PartialEq, Clone)]
#[cbor(map)]
pub struct AlonzoAuxiliaryData {
#[n(0)]
@@ -1259,7 +1259,7 @@ pub struct AlonzoAuxiliaryData {
pub plutus_scripts: Option>,
}
-#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub enum Metadatum {
Int(Int),
Bytes(ByteVec),
@@ -1350,7 +1350,7 @@ pub type MetadatumLabel = AnyUInt;
pub type Metadata = KeyValuePairs;
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Clone)]
pub enum AuxiliaryData {
Shelley(Metadata),
ShelleyMa {
@@ -1417,7 +1417,7 @@ impl minicbor::Encode for AuxiliaryData {
pub type TransactionIndex = u32;
-#[derive(Encode, Decode, Debug, PartialEq)]
+#[derive(Encode, Decode, Debug, PartialEq, Clone)]
pub struct Block {
#[n(0)]
pub header: Header,
@@ -1459,18 +1459,33 @@ pub struct MintedBlock<'b> {
}
#[derive(Encode, Decode, Debug)]
-pub struct Transaction {
+pub struct Tx {
#[n(0)]
- transaction_body: TransactionBody,
+ pub transaction_body: TransactionBody,
#[n(1)]
- transaction_witness_set: TransactionWitnessSet,
+ pub transaction_witness_set: TransactionWitnessSet,
#[n(2)]
- success: bool,
+ pub success: bool,
#[n(3)]
- auxiliary_data: Option,
+ pub auxiliary_data: Option,
+}
+
+#[derive(Encode, Decode, Debug)]
+pub struct MintedTx<'b> {
+ #[b(0)]
+ pub transaction_body: KeepRaw<'b, TransactionBody>,
+
+ #[n(1)]
+ pub transaction_witness_set: TransactionWitnessSet,
+
+ #[n(2)]
+ pub success: bool,
+
+ #[n(3)]
+ pub auxiliary_data: Option>,
}
#[cfg(test)]
diff --git a/pallas-primitives/src/byron/address.rs b/pallas-primitives/src/byron/address.rs
index 73974a0..0d08ab6 100644
--- a/pallas-primitives/src/byron/address.rs
+++ b/pallas-primitives/src/byron/address.rs
@@ -13,9 +13,9 @@ impl Address {
#[cfg(test)]
mod tests {
- use crate::byron::MintedMainBlock;
+ use crate::byron::MintedBlock;
- type BlockWrapper<'b> = (u16, MintedMainBlock<'b>);
+ type BlockWrapper<'b> = (u16, MintedBlock<'b>);
const KNOWN_ADDRESSES: &[&str] = &[
"DdzFFzCqrht8QHTQXbWy2qoyPaqTN8BjyfKygGmpy9dtot1tvkBfCaVTnR22XCaaDVn3M1U6aiMShoCLzw6VWSwzQKhhJrM3YjYp3wyy",
diff --git a/pallas-primitives/src/byron/crypto.rs b/pallas-primitives/src/byron/crypto.rs
index 84881f1..d57bfb6 100644
--- a/pallas-primitives/src/byron/crypto.rs
+++ b/pallas-primitives/src/byron/crypto.rs
@@ -48,9 +48,9 @@ impl ToHash<32> for KeepRaw<'_, Tx> {
mod tests {
use pallas_codec::minicbor;
- use crate::{byron::MintedMainBlock, ToHash};
+ use crate::{byron::MintedBlock, ToHash};
- type BlockWrapper<'b> = (u16, MintedMainBlock<'b>);
+ type BlockWrapper<'b> = (u16, MintedBlock<'b>);
const KNOWN_HASH: &'static str =
"5c196e7394ace0449ba5a51c919369699b13896e97432894b4f0354dce8670b6";
diff --git a/pallas-primitives/src/byron/fees.rs b/pallas-primitives/src/byron/fees.rs
index e9d0f1b..586b1d3 100644
--- a/pallas-primitives/src/byron/fees.rs
+++ b/pallas-primitives/src/byron/fees.rs
@@ -48,9 +48,9 @@ impl TxPayload {
mod tests {
use pallas_codec::minicbor;
- use crate::{byron::MainBlock, ToHash};
+ use crate::{byron::Block, ToHash};
- type BlockWrapper = (u16, MainBlock);
+ type BlockWrapper = (u16, Block);
#[test]
fn known_fee_matches() {
diff --git a/pallas-primitives/src/byron/model.rs b/pallas-primitives/src/byron/model.rs
index ab29554..d99ddf1 100644
--- a/pallas-primitives/src/byron/model.rs
+++ b/pallas-primitives/src/byron/model.rs
@@ -51,7 +51,7 @@ pub type Attributes = EmptyMap;
// Addresses
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub enum AddrDistr {
Variant0(StakeholderId),
Variant1,
@@ -96,7 +96,7 @@ impl minicbor::Encode<()> for AddrDistr {
}
}
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub enum AddrType {
PubKey,
Script,
@@ -137,7 +137,7 @@ impl minicbor::Encode for AddrType {
}
}
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub enum AddrAttrProperty {
AddrDistr(AddrDistr),
Bytes(ByteVec),
@@ -187,7 +187,7 @@ impl minicbor::Encode for AddrAttrProperty {
pub type AddrAttr = OrderPreservingProperties;
-#[derive(Debug, Encode, Decode)]
+#[derive(Debug, Encode, Decode, Clone)]
pub struct AddressPayload {
#[n(0)]
pub root: AddressId,
@@ -200,7 +200,7 @@ pub struct AddressPayload {
}
// address = [ #6.24(bytes .cbor ([addressid, addrattr, addrtype])), u64 ]
-#[derive(Debug, Encode, Decode)]
+#[derive(Debug, Encode, Decode, Clone)]
pub struct Address {
#[n(0)]
pub payload: CborWrap,
@@ -212,7 +212,7 @@ pub struct Address {
// Transactions
// txout = [address, u64]
-#[derive(Debug, Encode, Decode)]
+#[derive(Debug, Encode, Decode, Clone)]
pub struct TxOut {
#[n(0)]
pub address: Address,
@@ -221,7 +221,7 @@ pub struct TxOut {
pub amount: u64,
}
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub enum TxIn {
// [0, #6.24(bytes .cbor ([txid, u32]))]
Variant0(CborWrap<(TxId, u32)>),
@@ -269,7 +269,7 @@ impl minicbor::Encode for TxIn {
}
// tx = [[+ txin], [+ txout], attributes]
-#[derive(Debug, Encode, Decode)]
+#[derive(Debug, Encode, Decode, Clone)]
pub struct Tx {
#[n(0)]
pub inputs: MaybeIndefArray,
@@ -287,7 +287,7 @@ pub type TxProof = (u32, ByronHash, ByronHash);
pub type ValidatorScript = (u16, ByteVec);
pub type RedeemerScript = (u16, ByteVec);
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub enum Twit {
// [0, #6.24(bytes .cbor ([pubkey, signature]))]
PkWitness(CborWrap<(PubKey, Signature)>),
@@ -841,7 +841,6 @@ pub struct BlockHead {
pub extra_data: BlockHeadEx,
}
-// [tx, [* twit]]
#[derive(Debug, Encode, Decode)]
pub struct TxPayload {
#[n(0)]
@@ -851,6 +850,15 @@ pub struct TxPayload {
pub witness: MaybeIndefArray,
}
+#[derive(Debug, Encode, Decode, Clone)]
+pub struct MintedTxPayload<'b> {
+ #[b(0)]
+ pub transaction: KeepRaw<'b, Tx>,
+
+ #[n(1)]
+ pub witness: MaybeIndefArray,
+}
+
#[derive(Encode, Decode, Debug)]
pub struct BlockBody {
#[n(0)]
@@ -866,6 +874,21 @@ pub struct BlockBody {
pub upd_payload: Up,
}
+#[derive(Encode, Decode, Debug)]
+pub struct MintedBlockBody<'b> {
+ #[b(0)]
+ pub tx_payload: MaybeIndefArray>,
+
+ #[b(1)]
+ pub ssc_payload: Ssc,
+
+ #[b(2)]
+ pub dlg_payload: MaybeIndefArray,
+
+ #[b(3)]
+ pub upd_payload: Up,
+}
+
// Epoch Boundary Blocks
#[derive(Encode, Decode, Debug)]
@@ -896,7 +919,7 @@ pub struct EbbHead {
}
#[derive(Encode, Decode, Debug)]
-pub struct MainBlock {
+pub struct Block {
#[n(0)]
pub header: BlockHead,
@@ -908,12 +931,12 @@ pub struct MainBlock {
}
#[derive(Encode, Decode, Debug)]
-pub struct MintedMainBlock<'b> {
+pub struct MintedBlock<'b> {
#[b(0)]
pub header: KeepRaw<'b, BlockHead>,
- #[n(1)]
- pub body: BlockBody,
+ #[b(1)]
+ pub body: MintedBlockBody<'b>,
#[n(2)]
pub extra: MaybeIndefArray,
@@ -933,7 +956,7 @@ pub struct EbBlock {
#[cfg(test)]
mod tests {
- use super::{BlockHead, EbBlock, MintedMainBlock};
+ use super::{BlockHead, EbBlock, MintedBlock};
use pallas_codec::minicbor::{self, to_vec};
#[test]
@@ -958,7 +981,7 @@ mod tests {
#[test]
fn main_block_isomorphic_decoding_encoding() {
- type BlockWrapper<'b> = (u16, MintedMainBlock<'b>);
+ type BlockWrapper<'b> = (u16, MintedBlock<'b>);
let test_blocks = vec![
//include_str!("../../../test_data/genesis.block"),
diff --git a/pallas-primitives/src/byron/time.rs b/pallas-primitives/src/byron/time.rs
index 3d1d389..1f1f21b 100644
--- a/pallas-primitives/src/byron/time.rs
+++ b/pallas-primitives/src/byron/time.rs
@@ -24,9 +24,9 @@ impl EbbHead {
mod tests {
use pallas_codec::minicbor;
- use crate::byron::MainBlock;
+ use crate::byron::Block;
- type BlockWrapper = (u16, MainBlock);
+ type BlockWrapper = (u16, Block);
#[test]
fn knwon_slot_matches() {
diff --git a/pallas-primitives/src/framework.rs b/pallas-primitives/src/framework.rs
index b4ce4a0..813a17e 100644
--- a/pallas-primitives/src/framework.rs
+++ b/pallas-primitives/src/framework.rs
@@ -23,15 +23,6 @@ where
}
}
-#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
-pub enum Era {
- Byron,
- Shelley,
- Allegra, // time-locks
- Mary, // multi-assets
- Alonzo, // smart-contracts
-}
-
#[cfg(feature = "json")]
pub trait ToCanonicalJson {
fn to_json(&self) -> serde_json::Value;
diff --git a/pallas-primitives/src/lib.rs b/pallas-primitives/src/lib.rs
index a623304..39fdb6a 100644
--- a/pallas-primitives/src/lib.rs
+++ b/pallas-primitives/src/lib.rs
@@ -4,6 +4,5 @@ mod framework;
pub mod alonzo;
pub mod byron;
-pub mod probing;
pub use framework::*;
diff --git a/pallas-traverse/Cargo.toml b/pallas-traverse/Cargo.toml
new file mode 100644
index 0000000..0621377
--- /dev/null
+++ b/pallas-traverse/Cargo.toml
@@ -0,0 +1,20 @@
+[package]
+name = "pallas-traverse"
+description = "Utilities to traverse over multi-era block data"
+version = "0.11.0-alpha.0"
+edition = "2021"
+repository = "https://github.com/txpipe/pallas"
+homepage = "https://github.com/txpipe/pallas"
+documentation = "https://docs.rs/pallas-traverse"
+license = "Apache-2.0"
+readme = "README.md"
+authors = [
+ "Santiago Carmuega ",
+]
+
+[dependencies]
+pallas-primitives = { version = "0.11.0-alpha.0", path = "../pallas-primitives" }
+pallas-crypto = { version = "0.11.0-alpha.0", path = "../pallas-crypto" }
+pallas-codec = { version = "0.11.0-alpha.0", path = "../pallas-codec" }
+hex = "0.4.3"
+thiserror = "1.0.31"
diff --git a/pallas-traverse/src/block.rs b/pallas-traverse/src/block.rs
new file mode 100644
index 0000000..c8b7cd3
--- /dev/null
+++ b/pallas-traverse/src/block.rs
@@ -0,0 +1,63 @@
+use pallas_codec::minicbor;
+use pallas_crypto::hash::Hash;
+use pallas_primitives::{alonzo, byron, ToHash};
+
+use crate::{probe, Era, Error, MultiEraBlock};
+
+type BlockWrapper = (u16, T);
+
+impl<'b> MultiEraBlock<'b> {
+ pub fn from_epoch_boundary(block: byron::EbBlock) -> Self {
+ Self::EpochBoundary(Box::new(block))
+ }
+
+ pub fn from_byron(block: byron::MintedBlock<'b>) -> Self {
+ Self::Byron(Box::new(block))
+ }
+
+ pub fn from_alonzo_compatible(block: alonzo::MintedBlock<'b>) -> Self {
+ Self::AlonzoCompatible(Box::new(block))
+ }
+
+ pub fn decode(cbor: &'b [u8]) -> Result, Error> {
+ match probe::block_era(cbor) {
+ probe::Outcome::EpochBoundary => {
+ let (_, block): BlockWrapper =
+ minicbor::decode(cbor).map_err(Error::invalid_cbor)?;
+
+ Ok(MultiEraBlock::from_epoch_boundary(block))
+ }
+ probe::Outcome::Matched(era) => match era {
+ Era::Byron => {
+ let (_, block): BlockWrapper =
+ minicbor::decode(cbor).map_err(Error::invalid_cbor)?;
+
+ Ok(Self::from_byron(block))
+ }
+ Era::Shelley | Era::Allegra | Era::Mary | Era::Alonzo => {
+ let (_, block): BlockWrapper =
+ minicbor::decode(cbor).map_err(Error::invalid_cbor)?;
+
+ Ok(Self::from_alonzo_compatible(block))
+ }
+ },
+ probe::Outcome::Inconclusive => Err(Error::unknown_cbor(cbor)),
+ }
+ }
+
+ pub fn hash(&self) -> Hash<32> {
+ match self {
+ MultiEraBlock::EpochBoundary(x) => x.header.to_hash(),
+ MultiEraBlock::AlonzoCompatible(x) => x.header.to_hash(),
+ MultiEraBlock::Byron(x) => x.header.to_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::Byron(x) => x.header.consensus_data.0.to_abs_slot(),
+ }
+ }
+}
diff --git a/pallas-traverse/src/iter.rs b/pallas-traverse/src/iter.rs
new file mode 100644
index 0000000..ef602a6
--- /dev/null
+++ b/pallas-traverse/src/iter.rs
@@ -0,0 +1,96 @@
+//! Iterate over block data
+
+use pallas_primitives::{alonzo, byron};
+
+use crate::{MultiEraBlock, MultiEraTx};
+
+fn clone_alonzo_tx_at<'b>(
+ block: &'b alonzo::MintedBlock,
+ index: usize,
+) -> Option> {
+ let transaction_body = block.transaction_bodies.get(index).cloned()?;
+ let transaction_witness_set = block.transaction_witness_sets.get(index).cloned()?;
+ let success = block
+ .invalid_transactions
+ .as_ref()?
+ .contains(&(index as u32));
+
+ let auxiliary_data = block
+ .auxiliary_data_set
+ .iter()
+ .find_map(|(idx, val)| {
+ if idx.eq(&(index as u32)) {
+ Some(val)
+ } else {
+ None
+ }
+ })
+ .cloned();
+
+ Some(alonzo::MintedTx {
+ transaction_body,
+ transaction_witness_set,
+ success,
+ auxiliary_data,
+ })
+}
+
+fn clone_byron_tx_at<'b>(
+ block: &'b byron::MintedBlock,
+ index: usize,
+) -> Option> {
+ block.body.tx_payload.get(index).cloned()
+}
+
+pub struct TxIter<'b> {
+ block: &'b MultiEraBlock<'b>,
+ index: usize,
+}
+
+impl<'b> Iterator for TxIter<'b> {
+ type Item = MultiEraTx<'b>;
+
+ fn next(&mut self) -> Option {
+ let tx = match self.block {
+ MultiEraBlock::EpochBoundary(_) => None,
+ MultiEraBlock::AlonzoCompatible(x) => {
+ clone_alonzo_tx_at(x, self.index).map(MultiEraTx::from_alonzo_compatible)
+ }
+ MultiEraBlock::Byron(x) => clone_byron_tx_at(x, self.index).map(MultiEraTx::from_byron),
+ }?;
+
+ self.index += 1;
+ Some(tx)
+ }
+}
+
+impl<'b> MultiEraBlock<'b> {
+ pub fn tx_iter(&'b self) -> TxIter<'b> {
+ TxIter {
+ index: 0,
+ block: self,
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_iteration() {
+ let blocks = vec![
+ (include_str!("../../test_data/byron2.block"), 2usize),
+ (include_str!("../../test_data/shelley1.block"), 0),
+ (include_str!("../../test_data/mary1.block"), 0),
+ (include_str!("../../test_data/allegra1.block"), 0),
+ (include_str!("../../test_data/alonzo1.block"), 5),
+ ];
+
+ for (block_str, tx_count) in blocks.into_iter() {
+ let cbor = hex::decode(block_str).expect("invalid hex");
+ let block = MultiEraBlock::decode(&cbor).expect("invalid cbor");
+ assert_eq!(block.tx_iter().count(), tx_count);
+ }
+ }
+}
diff --git a/pallas-traverse/src/lib.rs b/pallas-traverse/src/lib.rs
new file mode 100644
index 0000000..65b9a2f
--- /dev/null
+++ b/pallas-traverse/src/lib.rs
@@ -0,0 +1,54 @@
+//! Utilities to traverse over multi-era block data
+use std::fmt::Display;
+
+use pallas_primitives::{alonzo, byron};
+use thiserror::Error;
+
+pub mod block;
+pub mod iter;
+pub mod probe;
+pub mod tx;
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
+#[non_exhaustive]
+pub enum Era {
+ Byron,
+ Shelley,
+ Allegra, // time-locks
+ Mary, // multi-assets
+ Alonzo, // smart-contracts
+}
+
+#[derive(Debug)]
+#[non_exhaustive]
+pub enum MultiEraTx<'b> {
+ AlonzoCompatible(Box>),
+ Byron(Box>),
+}
+
+#[derive(Debug)]
+#[non_exhaustive]
+pub enum MultiEraBlock<'b> {
+ EpochBoundary(Box),
+ AlonzoCompatible(Box>),
+ Byron(Box>),
+}
+
+#[derive(Debug, Error)]
+pub enum Error {
+ #[error("Invalid CBOR structure: {0}")]
+ InvalidCbor(String),
+
+ #[error("Unknown CBOR structure: {0}")]
+ UnknownCbor(String),
+}
+
+impl Error {
+ pub fn invalid_cbor(error: impl Display) -> Self {
+ Error::InvalidCbor(format!("{}", error))
+ }
+
+ pub fn unknown_cbor(bytes: &[u8]) -> Self {
+ Error::UnknownCbor(hex::encode(bytes))
+ }
+}
diff --git a/pallas-primitives/src/probing.rs b/pallas-traverse/src/probe.rs
similarity index 79%
rename from pallas-primitives/src/probing.rs
rename to pallas-traverse/src/probe.rs
index 73fcbb6..91ac19c 100644
--- a/pallas-primitives/src/probing.rs
+++ b/pallas-traverse/src/probe.rs
@@ -1,4 +1,4 @@
-//! Heuristics for detecting cbor content without decoding
+//! Lightweight inspection of block data without full CBOR decoding
use pallas_codec::minicbor::decode::{Token, Tokenizer};
@@ -12,9 +12,9 @@ pub enum Outcome {
}
// Executes a very lightweight inspection of the initial tokens of the CBOR
-// payload and infers with a certain degree of confidence the type of Cardano
-// structure within.
-pub fn probe_block_cbor_era(cbor: &[u8]) -> Outcome {
+// block payload to extract the tag of the block wrapper which defines the era
+// of the contained bytes.
+pub fn block_era(cbor: &[u8]) -> Outcome {
let mut tokenizer = Tokenizer::new(cbor);
if !matches!(tokenizer.next(), Some(Ok(Token::Array(2)))) {
@@ -44,7 +44,7 @@ mod tests {
let block_str = include_str!("../../test_data/genesis.block");
let bytes = hex::decode(block_str).unwrap();
- let inference = probe_block_cbor_era(bytes.as_slice());
+ let inference = block_era(bytes.as_slice());
assert!(matches!(inference, Outcome::EpochBoundary));
}
@@ -54,7 +54,7 @@ mod tests {
let block_str = include_str!("../../test_data/byron1.block");
let bytes = hex::decode(block_str).unwrap();
- let inference = probe_block_cbor_era(bytes.as_slice());
+ let inference = block_era(bytes.as_slice());
assert!(matches!(inference, Outcome::Matched(Era::Byron)));
}
@@ -64,7 +64,7 @@ mod tests {
let block_str = include_str!("../../test_data/shelley1.block");
let bytes = hex::decode(block_str).unwrap();
- let inference = probe_block_cbor_era(bytes.as_slice());
+ let inference = block_era(bytes.as_slice());
assert!(matches!(inference, Outcome::Matched(Era::Shelley)));
}
@@ -74,7 +74,7 @@ mod tests {
let block_str = include_str!("../../test_data/allegra1.block");
let bytes = hex::decode(block_str).unwrap();
- let inference = probe_block_cbor_era(bytes.as_slice());
+ let inference = block_era(bytes.as_slice());
assert!(matches!(inference, Outcome::Matched(Era::Allegra)));
}
@@ -84,7 +84,7 @@ mod tests {
let block_str = include_str!("../../test_data/mary1.block");
let bytes = hex::decode(block_str).unwrap();
- let inference = probe_block_cbor_era(bytes.as_slice());
+ let inference = block_era(bytes.as_slice());
assert!(matches!(inference, Outcome::Matched(Era::Mary)));
}
@@ -94,7 +94,7 @@ mod tests {
let block_str = include_str!("../../test_data/alonzo1.block");
let bytes = hex::decode(block_str).unwrap();
- let inference = probe_block_cbor_era(bytes.as_slice());
+ let inference = block_era(bytes.as_slice());
assert!(matches!(inference, Outcome::Matched(Era::Alonzo)));
}
diff --git a/pallas-traverse/src/tx.rs b/pallas-traverse/src/tx.rs
new file mode 100644
index 0000000..15b6336
--- /dev/null
+++ b/pallas-traverse/src/tx.rs
@@ -0,0 +1,13 @@
+use pallas_primitives::{alonzo, byron};
+
+use crate::MultiEraTx;
+
+impl<'b> MultiEraTx<'b> {
+ pub fn from_byron(tx: byron::MintedTxPayload<'b>) -> Self {
+ Self::Byron(Box::new(tx))
+ }
+
+ pub fn from_alonzo_compatible(tx: alonzo::MintedTx<'b>) -> Self {
+ Self::AlonzoCompatible(Box::new(tx))
+ }
+}
diff --git a/pallas/Cargo.toml b/pallas/Cargo.toml
index 2a00532..3ad0813 100644
--- a/pallas/Cargo.toml
+++ b/pallas/Cargo.toml
@@ -16,5 +16,6 @@ authors = [
pallas-multiplexer = { version = "0.11.0-alpha.0", path = "../pallas-multiplexer/" }
pallas-miniprotocols = { version = "0.11.0-alpha.0", path = "../pallas-miniprotocols/" }
pallas-primitives = { version = "0.11.0-alpha.0", path = "../pallas-primitives/" }
+pallas-traverse = { version = "0.11.0-alpha.0", path = "../pallas-traverse/" }
pallas-crypto = { version = "0.11.0-alpha.0", path = "../pallas-crypto/" }
pallas-codec = { version = "0.11.0-alpha.0", path = "../pallas-codec/" }
diff --git a/pallas/src/ledger.rs b/pallas/src/ledger.rs
index 81be084..70fa942 100644
--- a/pallas/src/ledger.rs
+++ b/pallas/src/ledger.rs
@@ -2,3 +2,6 @@
#[doc(inline)]
pub use pallas_primitives as primitives;
+
+#[doc(inline)]
+pub use pallas_traverse as traverse;