use alloc::collections::BTreeMap;
use alloc::vec::Vec;
use miden_protocol::note::{Note, NoteId};
use miden_standards::note::{FeeSponsorshipNote, NoteConsumptionStatus};
use crate::TransactionExecutorError;
pub const MAX_NUM_CHECKER_NOTES: usize = 20;
#[derive(Debug)]
pub struct SuccessfulNote {
note: Note,
num_cycles: usize,
}
impl SuccessfulNote {
pub fn new(note: Note, num_cycles: usize) -> Self {
Self { note, num_cycles }
}
pub fn note(&self) -> &Note {
&self.note
}
pub fn num_cycles(&self) -> usize {
self.num_cycles
}
}
#[derive(Debug)]
#[non_exhaustive]
pub enum NoteFailure {
Blamed {
error: TransactionExecutorError,
num_cycles: Option<usize>,
},
Collateral {
blamed_by: NoteId,
},
}
#[derive(Debug)]
pub struct FailedNote {
note: Note,
failure: NoteFailure,
}
impl FailedNote {
pub fn new(note: Note, failure: NoteFailure) -> Self {
Self { note, failure }
}
pub fn note(&self) -> &Note {
&self.note
}
pub fn failure(&self) -> &NoteFailure {
&self.failure
}
pub fn is_blamed(&self) -> bool {
matches!(self.failure, NoteFailure::Blamed { .. })
}
pub fn is_collateral(&self) -> bool {
matches!(self.failure, NoteFailure::Collateral { .. })
}
pub fn error(&self) -> Option<&TransactionExecutorError> {
match &self.failure {
NoteFailure::Blamed { error, .. } => Some(error),
NoteFailure::Collateral { .. } => None,
}
}
pub fn num_cycles(&self) -> Option<usize> {
match &self.failure {
NoteFailure::Blamed { num_cycles, .. } => *num_cycles,
NoteFailure::Collateral { .. } => None,
}
}
}
#[derive(Default, Debug)]
pub struct NoteConsumptionInfo {
successful: Vec<SuccessfulNote>,
failed: Vec<FailedNote>,
}
impl NoteConsumptionInfo {
pub fn new_successful(successful: Vec<SuccessfulNote>) -> Self {
Self { successful, ..Default::default() }
}
pub fn new(successful: Vec<SuccessfulNote>, failed: Vec<FailedNote>) -> Self {
Self { successful, failed }
}
pub fn successful(&self) -> &[SuccessfulNote] {
&self.successful
}
pub fn failed(&self) -> &[FailedNote] {
&self.failed
}
pub fn into_parts(self) -> (Vec<SuccessfulNote>, Vec<FailedNote>) {
(self.successful, self.failed)
}
}
#[derive(Debug)]
pub(super) struct NoteBundle {
notes: Vec<Note>,
}
impl NoteBundle {
pub(super) fn group(notes: Vec<Note>) -> Vec<Self> {
let note_indices: BTreeMap<NoteId, usize> =
notes.iter().enumerate().map(|(idx, note)| (note.id(), idx)).collect();
let mut bundles: BTreeMap<usize, Vec<Note>> = BTreeMap::new();
for (idx, note) in notes.into_iter().enumerate() {
match FeeSponsorshipNote::try_from(¬e)
.ok()
.and_then(|sponsorship| note_indices.get(&sponsorship.feature_note_id()).copied())
{
Some(head_idx) => bundles.entry(head_idx).or_default().push(note),
None => bundles.entry(idx).or_default().insert(0, note),
}
}
bundles.into_values().map(|notes| Self { notes }).collect()
}
pub(super) fn notes(&self) -> &[Note] {
&self.notes
}
}
pub(super) fn handle_epilogue_error(
epilogue_error: TransactionExecutorError,
) -> NoteConsumptionStatus {
match epilogue_error {
TransactionExecutorError::Unauthorized(_)
| TransactionExecutorError::MissingAuthenticator => {
NoteConsumptionStatus::ConsumableWithAuthorization
},
_ => NoteConsumptionStatus::UnconsumableConditions,
}
}