Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,3 +159,5 @@ pub(crate) mod num256;

#[cfg(feature = "alloc")]
pub(crate) mod num128;

pub mod transaction_meta;
Comment on lines 160 to +164
62 changes: 62 additions & 0 deletions src/transaction_meta.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use crate::{
LedgerEntryChange, OperationMeta, OperationMetaV2, TransactionMeta, TransactionResultMeta, VecM,
};
pub enum OperationsMetaRef<'a> {
V0toV3(&'a VecM<OperationMeta>),
V4(&'a VecM<OperationMetaV2>),
}

impl<'a> TransactionResultMeta {
pub fn operations(&'a self) -> OperationsMetaRef<'a> {
match &self.tx_apply_processing {
TransactionMeta::V0(value) => OperationsMetaRef::V0toV3(&value),
TransactionMeta::V1(value) => OperationsMetaRef::V0toV3(&value.operations),
TransactionMeta::V2(value) => OperationsMetaRef::V0toV3(&value.operations),
TransactionMeta::V3(value) => OperationsMetaRef::V0toV3(&value.operations),
TransactionMeta::V4(value) => OperationsMetaRef::V4(&value.operations),
}
}

pub fn changes(&self) -> impl Iterator<Item = &LedgerEntryChange> {
let tx_apply_processing_ledgers: Box<dyn Iterator<Item = &LedgerEntryChange>> =

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Avoid std-prelude Box in no_std builds

In non-std feature sets this module is still compiled, but Box is only available from the std prelude here; the crate advertises supported no_std profiles with alloc or even without alloc, so cargo check --no-default-features --features alloc / --no-default-features will fail to resolve this Box (and the no-alloc profile cannot allocate a boxed iterator at all). Please either gate this API on alloc and import alloc::boxed::Box, or return a non-allocating concrete iterator/enumeration so the supported no_std configurations keep compiling.

Useful? React with 👍 / 👎.

match &self.tx_apply_processing {
TransactionMeta::V0(operation_meta) => {
let res = operation_meta.iter().flat_map(|op| op.changes.0.iter());
Box::new(res)
}

TransactionMeta::V1(operation_meta) => {
let iter = operation_meta
.operations
.iter()
.flat_map(|op| op.changes.0.iter());
Box::new(iter)
}

TransactionMeta::V2(operation_meta) => {
let iter = operation_meta
.operations
.iter()
.flat_map(|op| op.changes.0.iter());
Box::new(iter)
}

TransactionMeta::V3(operation_meta) => {
let iter = operation_meta
.operations
.iter()
.flat_map(|op| op.changes.0.iter());
Box::new(iter)
}

TransactionMeta::V4(operation_meta) => {
let iter = operation_meta
.operations
.iter()
.flat_map(|op| op.changes.0.iter());
Box::new(iter)
}
};
tx_apply_processing_ledgers
}
}
256 changes: 256 additions & 0 deletions tests/transaction_meta.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,256 @@
#![cfg(feature = "alloc")]

use std::vec;

use stellar_xdr::transaction_meta::OperationsMetaRef;
use stellar_xdr::LedgerEntryChange;
use stellar_xdr::{
ContractEvent, DiagnosticEvent, ExtensionPoint, LedgerEntry, LedgerEntryChanges,
LedgerEntryData, LedgerEntryExt, OperationMeta, OperationMetaV2, SorobanTransactionMeta,
SorobanTransactionMetaV2, TransactionEvent, TransactionMeta, TransactionMetaV1,
TransactionMetaV2, TransactionMetaV3, TransactionMetaV4, TransactionResultMeta,
TransactionResultPair, VecM,
};

fn create_ledger_entry(seq: u32) -> LedgerEntry {
LedgerEntry {
last_modified_ledger_seq: seq,
data: LedgerEntryData::default(),
ext: LedgerEntryExt::V0,
}
}

fn create_ledger_entry_change_created(ledger_entry: LedgerEntry) -> LedgerEntryChange {
LedgerEntryChange::Created(ledger_entry)
}

fn create_ledger_entry_change_updated(ledger_entry: LedgerEntry) -> LedgerEntryChange {
LedgerEntryChange::Updated(ledger_entry)
}

fn create_ledger_entry_change_restored(ledger_entry: LedgerEntry) -> LedgerEntryChange {
LedgerEntryChange::Restored(ledger_entry)
}

fn create_ledger_entry_changes(ledger_entry_change: Vec<LedgerEntryChange>) -> LedgerEntryChanges {
LedgerEntryChanges(VecM::try_from(ledger_entry_change).unwrap())
}

fn create_operation_meta(ledger_entry_changes: LedgerEntryChanges) -> OperationMeta {
OperationMeta {
changes: ledger_entry_changes,
}
}

fn create_operation_meta_v2(ledger_entry_changes: LedgerEntryChanges) -> OperationMetaV2 {
OperationMetaV2 {
ext: ExtensionPoint::default(),
changes: ledger_entry_changes,
events: VecM::try_from(vec![ContractEvent::default()]).unwrap(),
}
}

fn create_transaction_meta_v1(
tx_changes: LedgerEntryChanges,
operations: Vec<OperationMeta>,
) -> TransactionMetaV1 {
TransactionMetaV1 {
tx_changes,
operations: VecM::try_from(operations).unwrap(),
}
}

fn create_transaction_meta_v2(
tx_changes_before: LedgerEntryChanges,
operations: Vec<OperationMeta>,
tx_changes_after: LedgerEntryChanges,
) -> TransactionMetaV2 {
TransactionMetaV2 {
tx_changes_before,
operations: VecM::try_from(operations).unwrap(),
tx_changes_after,
}
}

fn create_transaction_meta_v3(
tx_changes_before: LedgerEntryChanges,
operations: Vec<OperationMeta>,
tx_changes_after: LedgerEntryChanges,
) -> TransactionMetaV3 {
TransactionMetaV3 {
ext: ExtensionPoint::default(),
tx_changes_before,
operations: VecM::try_from(operations).unwrap(),
tx_changes_after,
soroban_meta: Some(SorobanTransactionMeta::default()),
}
}

fn create_transaction_meta_v4(
tx_changes_before: LedgerEntryChanges,
operations: Vec<OperationMetaV2>,
tx_changes_after: LedgerEntryChanges,
) -> TransactionMetaV4 {
TransactionMetaV4 {
ext: ExtensionPoint::default(),
tx_changes_before,
operations: VecM::try_from(operations).unwrap(),
tx_changes_after,
soroban_meta: Some(SorobanTransactionMetaV2::default()),
events: VecM::try_from(vec![TransactionEvent::default()]).unwrap(),
diagnostic_events: VecM::try_from(vec![DiagnosticEvent::default()]).unwrap(),
}
}

fn create_transaction_result_meta(
result: TransactionResultPair,
fee_processing: LedgerEntryChanges,
tx_apply_processing: TransactionMeta,
) -> TransactionResultMeta {
TransactionResultMeta {
result,
fee_processing,
tx_apply_processing,
}
}

#[test]
fn test_transaction_meta_v0_default_operations() {
let transaction_result_meta = TransactionResultMeta {
result: TransactionResultPair::default(),
fee_processing: LedgerEntryChanges::default(),
tx_apply_processing: TransactionMeta::default(),
};

match transaction_result_meta.operations() {
OperationsMetaRef::V0toV3(ops) => {
assert_eq!(ops.len(), 0);
}
OperationsMetaRef::V4(_) => panic!("unexpected V4 in test"),
}
}

#[test]
fn test_transaction_meta_v1_operations() {
let entry1 = create_ledger_entry(1);
let entry2 = create_ledger_entry(2);
let ledger_entry_created = create_ledger_entry_change_created(entry1);
let ledger_entry_updated = create_ledger_entry_change_updated(entry2);
let ledger_entry_changes =
create_ledger_entry_changes(vec![ledger_entry_created, ledger_entry_updated]);
let operation_meta = create_operation_meta(ledger_entry_changes.clone());
let transaction_meta =
create_transaction_meta_v1(ledger_entry_changes.clone(), vec![operation_meta]);
let transaction_result_meta_v1 = create_transaction_result_meta(
TransactionResultPair::default(),
ledger_entry_changes,
TransactionMeta::V1(transaction_meta),
);
match transaction_result_meta_v1.operations() {
OperationsMetaRef::V0toV3(ops) => {
assert_eq!(ops.len(), 1);

let ledger_changes = &ops.get(0).unwrap().changes;
let first_ledger_name = ledger_changes.get(0).unwrap().name();
assert_eq!(first_ledger_name, "Created");

let second_ledger_name = ledger_changes.get(1).unwrap().name();
assert_eq!(second_ledger_name, "Updated");
}
OperationsMetaRef::V4(_) => panic!("unexpected V4 in test"),
}
}

#[test]
fn test_transaction_meta_v4_operations() {
let ledger_entry_created = create_ledger_entry_change_created(create_ledger_entry(1));
let ledger_entry_updated = create_ledger_entry_change_updated(create_ledger_entry(2));
let ledger_entry_restored = create_ledger_entry_change_restored(create_ledger_entry(3));
let ledger_entry_fee_processing = create_ledger_entry_change_restored(create_ledger_entry(4));
let tx_changes_before = create_ledger_entry_changes(vec![ledger_entry_created]);
let tx_changes_after = create_ledger_entry_changes(vec![ledger_entry_updated]);
let tx_restored = create_ledger_entry_changes(vec![ledger_entry_restored]);
let fee_processing = create_ledger_entry_changes(vec![ledger_entry_fee_processing]);
let operation1 = create_operation_meta_v2(tx_restored.clone());
let operation2 = create_operation_meta_v2(tx_changes_before.clone());
let operation3 = create_operation_meta_v2(tx_changes_after.clone());
let transaction_meta_v4 = create_transaction_meta_v4(
tx_changes_before,
vec![operation1, operation2, operation3],
tx_changes_after,
);

let transaction_result_meta_v4 = create_transaction_result_meta(
TransactionResultPair::default(),
fee_processing,
TransactionMeta::V4(transaction_meta_v4),
);
match transaction_result_meta_v4.operations() {
OperationsMetaRef::V0toV3(_) => panic!("unexpected V0-V3 in test"),

OperationsMetaRef::V4(ops) => {
assert_eq!(ops.len(), 3);

let first_ledger_name = &ops.get(0).unwrap().changes.get(0).unwrap().name();
assert_eq!(*first_ledger_name, "Restored");

let second_ledger_name = &ops.get(1).unwrap().changes.get(0).unwrap().name();
assert_eq!(*second_ledger_name, "Created");

let thrid_ledger_name = &ops.get(2).unwrap().changes.get(0).unwrap().name();
assert_eq!(*thrid_ledger_name, "Updated");
}
}
}

#[test]
fn test_transaction_meta_v1_changes() {
let entry1 = create_ledger_entry(1);
let entry2 = create_ledger_entry(2);
let ledger_entry_created = create_ledger_entry_change_created(entry1);
let ledger_entry_updated = create_ledger_entry_change_updated(entry2);
let ledger_entry_fee_processing = create_ledger_entry_change_restored(create_ledger_entry(3));
let ledger_entry_changes =
create_ledger_entry_changes(vec![ledger_entry_created, ledger_entry_updated]);
let operation_meta = create_operation_meta(ledger_entry_changes.clone()); //2
let fee_processing = create_ledger_entry_changes(vec![ledger_entry_fee_processing]); //1
let transaction_meta =
create_transaction_meta_v1(ledger_entry_changes.clone(), vec![operation_meta]); //4
let transaction_result_meta_v1 = create_transaction_result_meta(
TransactionResultPair::default(),
fee_processing,
TransactionMeta::V1(transaction_meta),
);

let changes: Vec<&LedgerEntryChange> = transaction_result_meta_v1.changes().collect();
assert_eq!(changes.len(), 2);
}

#[test]
fn test_transaction_meta_v4_changes() {
let ledger_entry_created = create_ledger_entry_change_created(create_ledger_entry(1));
let ledger_entry_updated = create_ledger_entry_change_updated(create_ledger_entry(2));
let ledger_entry_restored = create_ledger_entry_change_restored(create_ledger_entry(3));
let ledger_entry_fee_processing = create_ledger_entry_change_restored(create_ledger_entry(4));
let tx_changes_before = create_ledger_entry_changes(vec![ledger_entry_created]);
let tx_changes_after = create_ledger_entry_changes(vec![ledger_entry_updated]);
let tx_restored = create_ledger_entry_changes(vec![ledger_entry_restored]);
let fee_processing = create_ledger_entry_changes(vec![ledger_entry_fee_processing]); // 1
let operation1 = create_operation_meta_v2(tx_restored.clone());
let operation2 = create_operation_meta_v2(tx_changes_before.clone());
let operation3 = create_operation_meta_v2(tx_changes_after.clone());
let transaction_meta_v4 = create_transaction_meta_v4(
tx_changes_before,
vec![operation1, operation2, operation3], // 3
tx_changes_after,
);

let transaction_result_meta_v4 = create_transaction_result_meta(
TransactionResultPair::default(),
fee_processing,
TransactionMeta::V4(transaction_meta_v4),
);

let changes: Vec<&LedgerEntryChange> = transaction_result_meta_v4.changes().collect();
assert_eq!(changes.len(), 3);
}