Skip to content

Commit 5f31d75

Browse files
fix(rust/cardano-blockchain-types): Introduce 'TxnOutputOffset' type (#206)
* Introduce 'TxnOutputOffset' type * Fix Clippy
1 parent c441fb6 commit 5f31d75

File tree

7 files changed

+110
-16
lines changed

7 files changed

+110
-16
lines changed

rust/cardano-blockchain-types/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ workspace = true
2020
[dependencies]
2121
pallas = { version = "0.30.1", git = "https://github.com/input-output-hk/catalyst-pallas.git", rev = "9b5183c8b90b90fe2cc319d986e933e9518957b3" }
2222
# pallas-hardano = { version = "0.30.1", git = "https://github.com/input-output-hk/catalyst-pallas.git", rev = "9b5183c8b90b90fe2cc319d986e933e9518957b3" }
23-
cbork-utils = { version = "0.0.1", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "r20250128-01" }
24-
catalyst-types = { version = "0.0.1", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "r20250128-01" }
23+
cbork-utils = { version = "0.0.1", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "r20250212-00" }
24+
catalyst-types = { version = "0.0.1", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "r20250212-00" }
2525

2626
ouroboros = "0.18.4"
2727
tracing = "0.1.41"

rust/cardano-blockchain-types/src/hashes.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@ define_hashes!(
99
/// A transaction hash - Blake2b-256 hash of a transaction.
1010
(TransactionHash, Blake2b256Hash),
1111
/// A public key hash - raw Blake2b-224 hash of an Ed25519 public key (has no discriminator, just the hash).
12-
(PubKeyHash, Blake2b224Hash)
12+
(PubKeyHash, Blake2b224Hash),
1313
);

rust/cardano-blockchain-types/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ mod network;
1010
mod point;
1111
mod slot;
1212
mod txn_index;
13+
mod txn_output_offset;
1314
mod txn_witness;
1415

1516
pub use auxdata::{
@@ -29,4 +30,5 @@ pub use network::Network;
2930
pub use point::Point;
3031
pub use slot::Slot;
3132
pub use txn_index::TxnIndex;
33+
pub use txn_output_offset::TxnOutputOffset;
3234
pub use txn_witness::{TxnWitness, VKeyHash};

rust/cardano-blockchain-types/src/multi_era_block_data.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ use crate::{
2424
point::Point,
2525
txn_index::TxnIndex,
2626
txn_witness::{TxnWitness, VKeyHash},
27+
Slot,
2728
};
2829

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

282+
/// Returns an iterator over `(TxnIndex, MultiEraTx)` pair.
283+
pub fn enumerate_txs(&self) -> impl Iterator<Item = (TxnIndex, MultiEraTx)> {
284+
self.txs()
285+
.into_iter()
286+
.enumerate()
287+
.map(|(i, t)| (i.into(), t))
288+
}
289+
281290
/// Get the auxiliary data of the block.
282291
#[must_use]
283292
pub fn aux_data(&self) -> &BlockAuxData {
284293
&self.inner.aux_data
285294
}
295+
296+
/// Returns a slot of the block.
297+
#[must_use]
298+
pub fn slot(&self) -> Slot {
299+
self.decode().slot().into()
300+
}
286301
}
287302

288303
impl Display for MultiEraBlock {

rust/cardano-blockchain-types/src/slot.rs

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,14 @@
11
//! Block Slot
22
3-
use std::{
4-
cmp::Ordering,
5-
ops::{MulAssign, Sub},
6-
};
3+
use std::ops::{MulAssign, Sub};
74

85
use catalyst_types::conversion::from_saturating;
96
use num_bigint::{BigInt, Sign};
107
use serde::Serialize;
118

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

1814
impl Slot {
@@ -45,12 +41,6 @@ impl MulAssign<u64> for Slot {
4541
}
4642
}
4743

48-
impl PartialOrd for Slot {
49-
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
50-
self.0.partial_cmp(&other.0)
51-
}
52-
}
53-
5444
impl Sub for Slot {
5545
type Output = Slot;
5646

rust/cardano-blockchain-types/src/txn_index.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use catalyst_types::conversion::from_saturating;
33

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

99
impl<
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
//! A transaction output offset inside the transaction.
2+
use catalyst_types::conversion::from_saturating;
3+
4+
/// A transaction output offset inside the transaction.
5+
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
6+
pub struct TxnOutputOffset(u16);
7+
8+
impl<
9+
T: Copy
10+
+ TryInto<u16>
11+
+ std::ops::Sub<Output = T>
12+
+ PartialOrd<T>
13+
+ num_traits::identities::Zero,
14+
> From<T> for TxnOutputOffset
15+
{
16+
fn from(value: T) -> Self {
17+
Self(from_saturating(value))
18+
}
19+
}
20+
21+
impl From<TxnOutputOffset> for i16 {
22+
fn from(val: TxnOutputOffset) -> Self {
23+
i16::try_from(val.0).unwrap_or(i16::MAX)
24+
}
25+
}
26+
27+
impl From<TxnOutputOffset> for usize {
28+
fn from(value: TxnOutputOffset) -> Self {
29+
value.0.into()
30+
}
31+
}
32+
33+
#[cfg(test)]
34+
mod tests {
35+
use super::*;
36+
37+
#[test]
38+
fn test_from_u8_to_txn_index() {
39+
let txn_index: TxnOutputOffset = 100u8.into(); // u8 is a valid type for conversion
40+
assert_eq!(txn_index.0, 100);
41+
}
42+
43+
#[test]
44+
fn test_from_u16_to_txn_index() {
45+
let txn_index: TxnOutputOffset = 500u16.into(); // u16 is valid and within range for `TxnOutputOffset`
46+
assert_eq!(txn_index.0, 500);
47+
}
48+
49+
#[test]
50+
fn test_from_i32_to_txn_index() {
51+
let txn_index: TxnOutputOffset = 1234i32.into(); // i32 can be converted into `TxnOutputOffset`
52+
assert_eq!(txn_index.0, 1234);
53+
}
54+
55+
#[test]
56+
fn test_from_u32_to_txn_index() {
57+
let txn_index: TxnOutputOffset = 500_000u32.into(); // u32 is larger but should be saturated to `u16::MAX`
58+
assert_eq!(txn_index.0, u16::MAX);
59+
}
60+
61+
#[test]
62+
fn test_from_large_i32_to_txn_index() {
63+
let txn_index: TxnOutputOffset = 70000i32.into(); // i32 too large for u16, should saturate to `u16::MAX`
64+
assert_eq!(txn_index.0, u16::MAX);
65+
}
66+
67+
#[test]
68+
fn test_txn_index_to_i16_within_range() {
69+
let txn_index = TxnOutputOffset(100);
70+
let result: i16 = txn_index.into(); // Should successfully convert to i16
71+
assert_eq!(result, 100);
72+
}
73+
74+
#[test]
75+
fn test_txn_index_to_i16_with_saturation() {
76+
let txn_index = TxnOutputOffset(u16::MAX); // u16::MAX = 65535, which is too large for i16
77+
let result: i16 = txn_index.into(); // Should saturate to i16::MAX
78+
assert_eq!(result, i16::MAX);
79+
}
80+
81+
#[test]
82+
fn test_txn_index_to_i16_with_zero() {
83+
let txn_index = TxnOutputOffset(0); // Should be able to convert to i16 without issue
84+
let result: i16 = txn_index.into();
85+
assert_eq!(result, 0);
86+
}
87+
}

0 commit comments

Comments
 (0)