use alloc::vec::Vec;
use dusk_core::BlsScalar;
use dusk_core::transfer::phoenix::{NoteLeaf, ViewKey as PhoenixViewKey};
use crate::notes::MAX_INPUT_NOTES;
use crate::notes::owned::NoteList;
#[must_use]
pub fn notes(vk: &PhoenixViewKey, notes: NoteList, cost: u64) -> NoteList {
if notes.is_empty() {
return NoteList::default();
}
let mut notes_values_nullifier: Vec<(NoteLeaf, u64, BlsScalar)> = notes
.iter()
.filter_map(|(nullifier, leaf)| {
leaf.as_ref()
.value(Some(vk))
.ok()
.map(|value| (leaf.clone(), value, *nullifier))
})
.collect();
notes_values_nullifier.sort_by(|(_, aval, _), (_, bval, _)| aval.cmp(bval));
if notes_values_nullifier
.iter()
.rev()
.take(MAX_INPUT_NOTES)
.map(|notes_values_nullifier| notes_values_nullifier.1)
.sum::<u64>()
< cost
{
return NoteList::default();
}
if notes.len() <= MAX_INPUT_NOTES {
return notes;
}
pick_lexicographic(¬es_values_nullifier, cost)
.map(|index| notes_values_nullifier[index].clone())
.map(|(n, _, b)| (b, n))
.to_vec()
.into()
}
fn is_valid(
notes_values_nullifier: impl AsRef<[(NoteLeaf, u64, BlsScalar)]>,
cost: u64,
indices: &[usize; MAX_INPUT_NOTES],
) -> bool {
indices
.iter()
.map(|index| notes_values_nullifier.as_ref()[*index].1)
.sum::<u64>()
>= cost
}
fn pick_lexicographic(
notes_values_nullifier: &Vec<(NoteLeaf, u64, BlsScalar)>,
cost: u64,
) -> [usize; MAX_INPUT_NOTES] {
let max_len = notes_values_nullifier.len();
let mut indices = [0; MAX_INPUT_NOTES];
indices
.iter_mut()
.enumerate()
.for_each(|(i, index)| *index = i);
loop {
if is_valid(notes_values_nullifier, cost, &indices) {
return indices;
}
let mut i = MAX_INPUT_NOTES - 1;
while indices[i] == i + max_len - MAX_INPUT_NOTES {
if i > 0 {
i -= 1;
} else {
break;
}
}
indices[i] += 1;
for j in i + 1..MAX_INPUT_NOTES {
indices[j] = indices[j - 1] + 1;
}
if indices[MAX_INPUT_NOTES - 1] == max_len {
break;
}
}
indices
}