Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(rust/cardano-blockchain-types): add cardano-blockchain-types crate #107

Open
wants to merge 44 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
dba341c
feat(rust): add cardano-blockchain-types crate
stevenj Dec 17, 2024
f3871a8
fix(rust): Remove unused dependencies
stevenj Dec 17, 2024
23a5138
fix(cardano-blockchain-types): time_to_slot calculation
bkioshn Dec 17, 2024
0662020
fix(cardano-blockchain-types): remove justfile
bkioshn Dec 17, 2024
c9185b5
Merge branch 'main' into feat/cardano-blockchain-types
bkioshn Dec 17, 2024
aa6bd36
fix(cardano-blockchain-types): point new should take type Slot and Bl…
bkioshn Dec 17, 2024
e027d8b
fix(cardano-blockchain-types): Fork type
bkioshn Dec 17, 2024
7efac20
fix(cardano-blockchain-types): point and fuzzy point test
bkioshn Dec 17, 2024
8ddebf5
Merge branch 'main' into feat/cardano-blockchain-types
stevenj Dec 17, 2024
1d600bd
fix(cardano-blockchain-types): add Fork increment function
bkioshn Dec 18, 2024
bfc2e15
fix(cardano-blockchain-types): add comment on tag 259
bkioshn Dec 18, 2024
d48e32b
fix(cardano-blockchain-types): add Fork decrement function
bkioshn Dec 18, 2024
349642c
test(rust): try earthly no-cache
bkioshn Dec 18, 2024
8583611
test(rust): try earthly no-cache and fix doc artifact
bkioshn Dec 18, 2024
42f71d7
test(rust): remove no-cache
bkioshn Dec 18, 2024
c267593
fix(cardano-blockchain-types): expose Fork and Network
bkioshn Dec 18, 2024
5eb13da
Merge branch 'main' into feat/cardano-blockchain-types
bkioshn Dec 18, 2024
c80fa33
fix(cardano-blockchain-types): add partailOrd to Fork
bkioshn Dec 18, 2024
0b0152d
Update rust/cardano-blockchain-types/src/point.rs
stevenj Dec 19, 2024
347045a
fix(cardano-blockchain-types): cleanup
bkioshn Dec 19, 2024
8d04f53
fix(cardano-blockchain-types): testdoc
bkioshn Dec 19, 2024
e48399a
Update rust/cardano-blockchain-types/src/point.rs
stevenj Dec 19, 2024
d17adf7
Merge branch 'main' into feat/cardano-blockchain-types
bkioshn Dec 19, 2024
48ca937
fix(cardano-blockchain-types): cleanup
bkioshn Dec 20, 2024
60802ce
fix(cardano-blockchain-types): format
bkioshn Dec 20, 2024
ea19d3e
fix(cardano-blockchain-types): add validate PR title
bkioshn Dec 20, 2024
4e2bdc6
fix(cardano-blockchain-types): comments
bkioshn Dec 20, 2024
519c415
fix(cardano-blockchain-types): fix hash_or_default
bkioshn Dec 20, 2024
e9b8ee3
fix(cardano-blockchain-types): redundant code
bkioshn Dec 20, 2024
0d964fd
test: no cache
bkioshn Dec 20, 2024
b553132
test: revert change
bkioshn Dec 20, 2024
881f07c
test ci
bkioshn Dec 23, 2024
be14a11
test ci
bkioshn Dec 23, 2024
c68a4a5
test ci
bkioshn Dec 23, 2024
b082ccc
test ci
bkioshn Dec 23, 2024
e5a1c53
test ci
bkioshn Dec 23, 2024
02cea97
test ci
bkioshn Dec 23, 2024
87b7aa7
test ci
bkioshn Dec 23, 2024
5150b0c
test ci
bkioshn Dec 23, 2024
7b51b80
test ci
bkioshn Dec 23, 2024
1ccf814
test ci
bkioshn Dec 23, 2024
6178014
revert change
bkioshn Dec 23, 2024
4291806
test ci
bkioshn Dec 23, 2024
fe48d5a
revert change
bkioshn Dec 23, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .config/dictionaries/project.dic
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Arissara
asyncio
Attributes
auditability
auxdata
babystep
backpressure
bech
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/semantic_pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ jobs:
rust/cbork
rust/hermes-ipfs
rust/rbac-registration
rust/cardano-blockchain-types
dart
docs
general
1 change: 1 addition & 0 deletions rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
resolver = "2"
members = [
"c509-certificate",
"cardano-blockchain-types",
"cardano-chain-follower",
"hermes-ipfs",
"cbork",
Expand Down
5 changes: 3 additions & 2 deletions rust/Earthfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
Cargo.toml clippy.toml deny.toml rustfmt.toml \
.cargo .config \
c509-certificate \
cardano-blockchain-types \
cardano-chain-follower \
catalyst-voting vote-tx-v1 vote-tx-v2 \
cbork cbork-abnf-parser cbork-cddl-parser \
Expand Down Expand Up @@ -53,7 +54,7 @@

DO rust-ci+EXECUTE \
--cmd="/scripts/std_build.py" \
--args1="--libs=c509-certificate --libs=cardano-chain-follower --libs=hermes-ipfs" \
--args1="--libs=c509-certificate --libs=cardano-blockchain-types --libs=cardano-chain-follower --libs=hermes-ipfs" \
--args2="--libs=cbork-cddl-parser --libs=cbork-abnf-parser" \
--args3="--libs=catalyst-voting --libs=immutable-ledger --libs=vote-tx-v1 --libs=vote-tx-v2" \
--args4="--bins=cbork/cbork --libs=rbac-registration --libs=signed_doc" \
Expand All @@ -63,7 +64,7 @@
--coverage="cat-libs.coverage.info" \
--docs="true"

SAVE ARTIFACT target/$TARGETARCH/doc doc
SAVE ARTIFACT target/doc doc
SAVE ARTIFACT target/release/cbork cbork

# build-src-check: Check for any caching issues with the source we are building against.
Expand Down
36 changes: 36 additions & 0 deletions rust/cardano-blockchain-types/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
[package]
name = "cardano-blockchain-types"
description = "Common Cardano Blockchain data types for use in both applications and crates"
keywords = ["cardano", "catalyst",]
version = "0.0.1"
authors = [
"Steven Johnson <[email protected]>"
]
edition.workspace = true
license.workspace = true
homepage.workspace = true
repository.workspace = true

[lib]
crate-type = ["cdylib", "rlib"]

[lints]
workspace = true

[dependencies]
pallas = { version = "0.30.1", git = "https://github.com/input-output-hk/catalyst-pallas.git", rev = "9b5183c8b90b90fe2cc319d986e933e9518957b3" }
pallas-crypto = { version = "0.30.1", git = "https://github.com/input-output-hk/catalyst-pallas.git", rev = "9b5183c8b90b90fe2cc319d986e933e9518957b3" }
# pallas-hardano = { version = "0.30.1", git = "https://github.com/input-output-hk/catalyst-pallas.git", rev = "9b5183c8b90b90fe2cc319d986e933e9518957b3" }
stevenj marked this conversation as resolved.
Show resolved Hide resolved

ouroboros = "0.18.4"
tracing = "0.1.41"
anyhow = "1.0.94"
chrono = "0.4.39"
strum = { version = "0.26.3", features = ["derive"] }
dirs = "5.0.1"
hex = "0.4.3"
dashmap = "6.1.0"
blake2b_simd = "1.0.2"
minicbor = { version = "0.25.1", features = ["alloc"] }
num-traits = "0.2.19"
ed25519-dalek = "2.1.1"
6 changes: 6 additions & 0 deletions rust/cardano-blockchain-types/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Improved version of Pallas Multi Era Block

Adds features to the Pallas Multi Era Block to allow us to re-use it between the different cardano crates,
and the services that use them.

The original source was `cardano-chain-follower`.
61 changes: 61 additions & 0 deletions rust/cardano-blockchain-types/deps.tmp
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
rbac-registration = { version = "0.0.2", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "v0.0.8" }

thiserror = "1.0.64"
tokio = { version = "1.40.0", features = [
"macros",
"rt",
"net",
"rt-multi-thread",
] }
tracing = "0.1.40"
tracing-log = "0.2.0"
dashmap = "6.1.0"
url = "2.5.2"
anyhow = "1.0.89"
chrono = "0.4.38"
async-trait = "0.1.83"
dirs = "5.0.1"
futures = "0.3.31"
humantime = "2.1.0"
crossbeam-skiplist = "0.1.3"
crossbeam-channel = "0.5.13"
crossbeam-epoch = "0.9.18"
strum = "0.26.3"
ouroboros = "0.18.4"
hex = "0.4.3"
rayon = "1.10.0"
serde = "1.0.210"
serde_json = "1.0.128"
mimalloc = { version = "0.1.43", optional = true }
memx = "0.1.32"
fmmap = { version = "0.3.3", features = ["sync", "tokio-async"] }
minicbor = { version = "0.25.1", features = ["alloc", "derive", "half"] }
zstd = "0.13.2"
ed25519-dalek = "2.1.1"
blake2b_simd = "1.0.2"
num-traits = "0.2.19"
logcall = "0.1.9"
tar = "0.4.42"
ureq = { version = "2.10.1", features = ["native-certs"] }
http = "1.1.0"
hickory-resolver = { version = "0.24.1", features = ["dns-over-rustls"] }
moka = { version = "0.12.8", features = ["sync"] }

hex = "0.4.3"
anyhow = "1.0.89"
strum_macros = "0.26.4"
regex = "1.11.0"
minicbor = { version = "0.25.1", features = ["alloc", "derive", "half"] }
brotli = "7.0.0"
zstd = "0.13.2"
x509-cert = "0.2.5"
der-parser = "9.0.0"
bech32 = "0.11.0"
dashmap = "6.1.0"
blake2b_simd = "1.0.2"
tracing = "0.1.40"
ed25519-dalek = "2.1.1"
uuid = "1.11.0"

c509-certificate = { version = "0.0.3", git = "https://github.com/input-output-hk/catalyst-libs.git" , tag = "v0.0.3" }
pallas = { version = "0.30.1", git = "https://github.com/input-output-hk/catalyst-pallas.git", rev = "9b5183c8b90b90fe2cc319d986e933e9518957b3" }
172 changes: 172 additions & 0 deletions rust/cardano-blockchain-types/src/auxdata/aux_data.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
//! Auxiliary Data Decoding

use minicbor::Decode;

use super::{
metadatum::Metadata,
metadatum_label::MetadatumLabel,
metadatum_value::MetadatumValue,
scripts::{MutableTransactionScriptsMap, ScriptArray, ScriptType, TransactionScripts},
};

/// Auxiliary Data (Metadata) for a single transaction in a block
#[derive(Clone, Debug)]
#[allow(clippy::module_name_repetitions)]
pub struct TransactionAuxData {
/// Metadata attached to a transaction
metadata: Metadata,
/// Scripts attached to a transaction
#[allow(dead_code)]
scripts: TransactionScripts,
stanislav-tkach marked this conversation as resolved.
Show resolved Hide resolved
}

impl Decode<'_, ()> for TransactionAuxData {
fn decode(
d: &mut minicbor::Decoder<'_>, _ctx: &mut (),
) -> Result<Self, minicbor::decode::Error> {
// Check what kind of aux data we have to deal with
match d.datatype() {
// Shelley: https://github.com/IntersectMBO/cardano-ledger/blob/78b32d585fd4a0340fb2b184959fb0d46f32c8d2/eras/conway/impl/cddl-files/conway.cddl#L522
Ok(minicbor::data::Type::Map) => {
Ok(TransactionAuxData {
metadata: Metadata::decode(d, &mut ())?,
scripts: TransactionScripts::default(),
})
},
// Shelley-MA: https://github.com/IntersectMBO/cardano-ledger/blob/78b32d585fd4a0340fb2b184959fb0d46f32c8d2/eras/conway/impl/cddl-files/conway.cddl#L523
Ok(minicbor::data::Type::Array) => Self::decode_shelley_ma_array(d),
// Maybe Alonzo and beyond: https://github.com/IntersectMBO/cardano-ledger/blob/78b32d585fd4a0340fb2b184959fb0d46f32c8d2/eras/conway/impl/cddl-files/conway.cddl#L526
Ok(minicbor::data::Type::Tag) => Self::decode_alonzo_plus_map(d),
Ok(unexpected) => {
let msg = format!(
"Error decoding Transaction Aux Data: Unexpected datatype {unexpected}"
);
Err(minicbor::decode::Error::message(&msg))
},
Err(error) => {
let msg = format!("Error decoding Transaction Aux Data: {error}");
Err(minicbor::decode::Error::message(msg))
},
}
}
}

impl TransactionAuxData {
/// Get metadata with the given label.
#[must_use]
pub fn metadata(&self, label: MetadatumLabel) -> Option<&MetadatumValue> {
self.metadata.get(label)
}

/// Decode a Shelley-MA auxiliary data array
fn decode_shelley_ma_array(d: &mut minicbor::Decoder) -> Result<Self, minicbor::decode::Error> {
match d.array() {
Ok(Some(entries)) => {
if entries != 2 {
let msg = format!(
"Error decoding Transaction Aux Data: Script Data Array Expected 2 entries, found {entries}."
);
return Err(minicbor::decode::Error::message(&msg));
}
},
Ok(None) => {
return Err(minicbor::decode::Error::message(
"Error decoding Transaction Aux Data: Indefinite Array found decoding Metadata. Invalid."));
},
Err(error) => {
return Err(minicbor::decode::Error::message(format!(
"Error decoding Transaction Aux Data: {error}."
)));
},
};

let metadata = Metadata::decode(d, &mut ())?;
let script_array = ScriptArray::decode(d, &mut ScriptType::Native)?;

let scripts = MutableTransactionScriptsMap::default();
scripts.insert(ScriptType::Native, script_array);

Ok(Self {
metadata,
scripts: scripts.into(),
})
}

/// Decode an Alonzo Plus MAP
fn decode_alonzo_plus_map(d: &mut minicbor::Decoder) -> Result<Self, minicbor::decode::Error> {
match d.tag() {
Ok(tag) => {
// CBOR tag identifier 259 for auxiliary data in the Alonzo and beyond eras
// https://github.com/IntersectMBO/cardano-ledger/blob/78b32d585fd4a0340fb2b184959fb0d46f32c8d2/eras/conway/impl/cddl-files/conway.cddl#L526
if tag.as_u64() != 259 {
bkioshn marked this conversation as resolved.
Show resolved Hide resolved
return Err(minicbor::decode::Error::message(format!(
"Invalid tag for Alonzo+ Aux Data. Expected 259, found {tag}."
)));
}
},
Err(error) => {
return Err(minicbor::decode::Error::message(format!(
"Error decoding Transaction Alonzo+ Aux Data: {error}."
)));
},
}

let entries = match d.map() {
Ok(Some(entries)) => entries,
Ok(None) => {
return Err(minicbor::decode::Error::message(
"Indefinite Map found decoding Alonzo+ Metadata. Invalid.",
))
},
Err(error) => {
return Err(minicbor::decode::Error::message(format!(
"Error decoding Transaction Alonzo+ Aux Data: {error}."
)))
},
};

// Make the default versions of the metadata and script types
let mut metadata = Metadata::default();
let scripts = MutableTransactionScriptsMap::default();

// iterate the map
for _ in 0..entries {
let script_type = match d.u64() {
Ok(key) => {
if let Ok(script_type) = ScriptType::try_from(key) {
script_type
} else {
// Only fails if its Metadata and not a script.
if metadata.is_empty() {
metadata = Metadata::decode(d, &mut ())?;
continue;
}
return Err(minicbor::decode::Error::message(
"Multiple Alonzo+ Metadata entries found. Invalid.",
));
}
},

Err(error) => {
return Err(minicbor::decode::Error::message(format!(
"Error decoding Alonzo+ Metadata Aux Data Type Key: {error}"
)));
},
};

let mut ctx = script_type;

let script_array = ScriptArray::decode(d, &mut ctx)?;
if scripts.insert(script_type, script_array).is_some() {
return Err(minicbor::decode::Error::message(format!(
"Multiple Alonzo+ Script entries of type {script_type} found. Invalid.",
bkioshn marked this conversation as resolved.
Show resolved Hide resolved
)));
}
}

Ok(Self {
metadata,
scripts: scripts.into(),
})
}
}
68 changes: 68 additions & 0 deletions rust/cardano-blockchain-types/src/auxdata/block.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
//! Decoded Metadata for a Block

use std::sync::Arc;

use anyhow::bail;
use dashmap::DashMap;
use pallas::ledger::traverse::MultiEraBlock;

use super::aux_data::TransactionAuxData;
use crate::txn_index::TxnIndex;

/// Auxiliary data for every transaction within a block.
#[derive(Debug)]
#[allow(clippy::module_name_repetitions)]
pub struct BlockAuxData(Arc<dashmap::ReadOnlyView<TxnIndex, TransactionAuxData>>);

impl BlockAuxData {
/// Get `TransactionAuxData` for the given `TxnIndex` if any.
#[must_use]
pub fn get(&self, txn_idx: TxnIndex) -> Option<&TransactionAuxData> {
self.0.get(&txn_idx)
}
}

impl Default for BlockAuxData {
fn default() -> Self {
BlockAuxData(Arc::new(DashMap::default().into_read_only()))
}
}

impl TryFrom<&MultiEraBlock<'_>> for BlockAuxData {
type Error = anyhow::Error;

fn try_from(block: &MultiEraBlock) -> Result<Self, Self::Error> {
let aux_data = DashMap::<TxnIndex, TransactionAuxData>::new();
// Note, while this code looks redundant, it is not because all the types are not
// compatible Even though they have similar names, and ultimately the same inner
// functionality. This means we need to distinctly encode the three different
// loops with the same code.
if block.has_aux_data() {
if let Some(_metadata) = block.as_byron() {
// Nothing to do here.
} else if let Some(alonzo_block) = block.as_alonzo() {
for (txn_idx, metadata) in alonzo_block.auxiliary_data_set.iter() {
let mut d = minicbor::Decoder::new(metadata.raw_cbor());
let txn_aux_data = d.decode::<TransactionAuxData>()?;
aux_data.insert(TxnIndex::from_saturating(*txn_idx), txn_aux_data);
}
} else if let Some(babbage_block) = block.as_babbage() {
for (txn_idx, metadata) in babbage_block.auxiliary_data_set.iter() {
let mut d = minicbor::Decoder::new(metadata.raw_cbor());
let txn_aux_data = d.decode::<TransactionAuxData>()?;
aux_data.insert(TxnIndex::from_saturating(*txn_idx), txn_aux_data);
}
} else if let Some(conway_block) = block.as_conway() {
for (txn_idx, metadata) in conway_block.auxiliary_data_set.iter() {
let mut d = minicbor::Decoder::new(metadata.raw_cbor());
let txn_aux_data = d.decode::<TransactionAuxData>()?;
aux_data.insert(TxnIndex::from_saturating(*txn_idx), txn_aux_data);
}
} else {
bail!("Undecodable metadata, unknown Era");
};
}

Ok(Self(Arc::new(aux_data.into_read_only())))
}
}
Loading
Loading