use alloc::vec::Vec;
use miden_protocol::account::AccountId;
use miden_protocol::asset::Asset;
use miden_protocol::note::NoteType;
use miden_protocol::transaction::ExecutedTransaction;
#[doc(hidden)]
#[derive(Default, Debug, Clone)]
pub struct OutputNoteSpec {
pub note_type: Option<NoteType>,
pub sender: Option<AccountId>,
pub assets: Option<Vec<Asset>>,
}
#[doc(hidden)]
pub fn check_output_note_created(tx: &ExecutedTransaction, spec: &OutputNoteSpec) -> bool {
tx.output_notes().iter().any(|note| {
if let Some(expected) = spec.note_type
&& note.metadata().note_type() != expected
{
return false;
}
if let Some(expected) = spec.sender
&& note.metadata().sender() != expected
{
return false;
}
if let Some(expected) = spec.assets.as_ref() {
let actual = note.assets();
if actual.num_assets() != expected.len() {
return false;
}
let mut consumed = vec![false; expected.len()];
let matched = expected.iter().all(|exp| {
let slot = actual.iter().enumerate().find(|(i, a)| !consumed[*i] && *a == exp);
if let Some((i, _)) = slot {
consumed[i] = true;
true
} else {
false
}
});
if !matched {
return false;
}
}
true
})
}
#[macro_export]
macro_rules! assert_note_created {
($tx:expr $(, $key:ident : $val:expr)* $(,)?) => {{
#[allow(unused_mut)]
let mut spec = $crate::asserts::OutputNoteSpec::default();
$(
$crate::__assert_note_created_field!(spec, $key, $val);
)*
let tx: &::miden_protocol::transaction::ExecutedTransaction = &$tx;
assert!(
$crate::asserts::check_output_note_created(tx, &spec),
"no output note matches spec: {:?}\n tx produced {} output note(s)",
spec,
tx.output_notes().num_notes(),
);
}};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __assert_note_created_field {
($spec:ident,note_type, $val:expr) => {
$spec.note_type = ::core::option::Option::Some($val);
};
($spec:ident,sender, $val:expr) => {
$spec.sender = ::core::option::Option::Some($val);
};
($spec:ident,assets, $val:expr) => {
$spec.assets = ::core::option::Option::Some(
::core::iter::IntoIterator::into_iter($val)
.map(::core::convert::Into::into)
.collect::<::alloc::vec::Vec<::miden_protocol::asset::Asset>>(),
);
};
($spec:ident, $key:ident, $val:expr) => {
::core::compile_error!(concat!(
"unknown field in assert_note_created!: `",
stringify!($key),
"`. Supported fields: note_type, sender, assets",
));
};
}