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

fix(rust/cardano-blockchain-types): Introduce 'TxnOutputOffset' type #206

Merged
merged 2 commits into from
Feb 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions rust/cardano-blockchain-types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ workspace = true
[dependencies]
pallas = { 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" }
cbork-utils = { version = "0.0.1", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "r20250128-01" }
catalyst-types = { version = "0.0.1", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "r20250128-01" }
cbork-utils = { version = "0.0.1", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "r20250212-00" }
catalyst-types = { version = "0.0.1", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "r20250212-00" }

ouroboros = "0.18.4"
tracing = "0.1.41"
Expand Down
2 changes: 1 addition & 1 deletion rust/cardano-blockchain-types/src/hashes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ define_hashes!(
/// A transaction hash - Blake2b-256 hash of a transaction.
(TransactionHash, Blake2b256Hash),
/// A public key hash - raw Blake2b-224 hash of an Ed25519 public key (has no discriminator, just the hash).
(PubKeyHash, Blake2b224Hash)
(PubKeyHash, Blake2b224Hash),
);
2 changes: 2 additions & 0 deletions rust/cardano-blockchain-types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ mod network;
mod point;
mod slot;
mod txn_index;
mod txn_output_offset;
mod txn_witness;

pub use auxdata::{
Expand All @@ -29,4 +30,5 @@ pub use network::Network;
pub use point::Point;
pub use slot::Slot;
pub use txn_index::TxnIndex;
pub use txn_output_offset::TxnOutputOffset;
pub use txn_witness::{TxnWitness, VKeyHash};
15 changes: 15 additions & 0 deletions rust/cardano-blockchain-types/src/multi_era_block_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use crate::{
point::Point,
txn_index::TxnIndex,
txn_witness::{TxnWitness, VKeyHash},
Slot,
};

/// Self-referencing CBOR encoded data of a multi-era block.
Expand Down Expand Up @@ -278,11 +279,25 @@ impl MultiEraBlock {
self.decode().txs()
}

/// Returns an iterator over `(TxnIndex, MultiEraTx)` pair.
pub fn enumerate_txs(&self) -> impl Iterator<Item = (TxnIndex, MultiEraTx)> {
self.txs()
.into_iter()
.enumerate()
.map(|(i, t)| (i.into(), t))
}

/// Get the auxiliary data of the block.
#[must_use]
pub fn aux_data(&self) -> &BlockAuxData {
&self.inner.aux_data
}

/// Returns a slot of the block.
#[must_use]
pub fn slot(&self) -> Slot {
self.decode().slot().into()
}
}

impl Display for MultiEraBlock {
Expand Down
14 changes: 2 additions & 12 deletions rust/cardano-blockchain-types/src/slot.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
//! Block Slot

use std::{
cmp::Ordering,
ops::{MulAssign, Sub},
};
use std::ops::{MulAssign, Sub};

use catalyst_types::conversion::from_saturating;
use num_bigint::{BigInt, Sign};
use serde::Serialize;

#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Default, Serialize)]

/// Slot on the blockchain, typically one slot equals one second. However chain
/// parameters can alter how long a slot is.
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Serialize)]
pub struct Slot(u64);

impl Slot {
Expand Down Expand Up @@ -45,12 +41,6 @@ impl MulAssign<u64> for Slot {
}
}

impl PartialOrd for Slot {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.0.partial_cmp(&other.0)
}
}

impl Sub for Slot {
type Output = Slot;

Expand Down
2 changes: 1 addition & 1 deletion rust/cardano-blockchain-types/src/txn_index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use catalyst_types::conversion::from_saturating;

/// Transaction index within a block
/// See: <https://github.com/IntersectMBO/cardano-ledger/blob/78b32d585fd4a0340fb2b184959fb0d46f32c8d2/eras/conway/impl/cddl-files/conway.cddl#L20C1-L20C33>
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct TxnIndex(u16);

impl<
Expand Down
87 changes: 87 additions & 0 deletions rust/cardano-blockchain-types/src/txn_output_offset.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
//! A transaction output offset inside the transaction.
use catalyst_types::conversion::from_saturating;

/// A transaction output offset inside the transaction.
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct TxnOutputOffset(u16);

impl<
T: Copy
+ TryInto<u16>
+ std::ops::Sub<Output = T>
+ PartialOrd<T>
+ num_traits::identities::Zero,
> From<T> for TxnOutputOffset
{
fn from(value: T) -> Self {
Self(from_saturating(value))
}
}

impl From<TxnOutputOffset> for i16 {
fn from(val: TxnOutputOffset) -> Self {
i16::try_from(val.0).unwrap_or(i16::MAX)
}
}

impl From<TxnOutputOffset> for usize {
fn from(value: TxnOutputOffset) -> Self {
value.0.into()
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_from_u8_to_txn_index() {
let txn_index: TxnOutputOffset = 100u8.into(); // u8 is a valid type for conversion
assert_eq!(txn_index.0, 100);
}

#[test]
fn test_from_u16_to_txn_index() {
let txn_index: TxnOutputOffset = 500u16.into(); // u16 is valid and within range for `TxnOutputOffset`
assert_eq!(txn_index.0, 500);
}

#[test]
fn test_from_i32_to_txn_index() {
let txn_index: TxnOutputOffset = 1234i32.into(); // i32 can be converted into `TxnOutputOffset`
assert_eq!(txn_index.0, 1234);
}

#[test]
fn test_from_u32_to_txn_index() {
let txn_index: TxnOutputOffset = 500_000u32.into(); // u32 is larger but should be saturated to `u16::MAX`
assert_eq!(txn_index.0, u16::MAX);
}

#[test]
fn test_from_large_i32_to_txn_index() {
let txn_index: TxnOutputOffset = 70000i32.into(); // i32 too large for u16, should saturate to `u16::MAX`
assert_eq!(txn_index.0, u16::MAX);
}

#[test]
fn test_txn_index_to_i16_within_range() {
let txn_index = TxnOutputOffset(100);
let result: i16 = txn_index.into(); // Should successfully convert to i16
assert_eq!(result, 100);
}

#[test]
fn test_txn_index_to_i16_with_saturation() {
let txn_index = TxnOutputOffset(u16::MAX); // u16::MAX = 65535, which is too large for i16
let result: i16 = txn_index.into(); // Should saturate to i16::MAX
assert_eq!(result, i16::MAX);
}

#[test]
fn test_txn_index_to_i16_with_zero() {
let txn_index = TxnOutputOffset(0); // Should be able to convert to i16 without issue
let result: i16 = txn_index.into();
assert_eq!(result, 0);
}
}