monero_interface/
provides_decoys.rs1use core::{ops::RangeBounds, future::Future};
2use alloc::{format, vec::Vec, string::ToString};
3
4use monero_oxide::ed25519::Point;
5
6use crate::{InterfaceError, TransactionsError, ProvidesBlockchainMeta};
7
8pub enum EvaluateUnlocked {
10 Normal,
12 FingerprintableDeterministic {
16 block_number: usize,
18 },
19}
20
21pub trait ProvidesUnvalidatedDecoys: ProvidesBlockchainMeta {
25 fn ringct_output_distribution(
32 &self,
33 range: impl Send + RangeBounds<usize>,
34 ) -> impl Send + Future<Output = Result<Vec<u64>, InterfaceError>>;
35
36 fn unlocked_ringct_outputs(
41 &self,
42 indexes: &[u64],
43 evaluate_unlocked: EvaluateUnlocked,
44 ) -> impl Send + Future<Output = Result<Vec<Option<[Point; 2]>>, TransactionsError>>;
45}
46
47pub trait ProvidesDecoys: ProvidesBlockchainMeta {
51 fn ringct_output_distribution(
58 &self,
59 range: impl Send + RangeBounds<usize>,
60 ) -> impl Send + Future<Output = Result<Vec<u64>, InterfaceError>>;
61
62 fn unlocked_ringct_outputs(
64 &self,
65 indexes: &[u64],
66 evaluate_unlocked: EvaluateUnlocked,
67 ) -> impl Send + Future<Output = Result<Vec<Option<[Point; 2]>>, TransactionsError>>;
68}
69
70impl<P: ProvidesUnvalidatedDecoys> ProvidesDecoys for P {
71 fn ringct_output_distribution(
72 &self,
73 range: impl Send + RangeBounds<usize>,
74 ) -> impl Send + Future<Output = Result<Vec<u64>, InterfaceError>> {
75 async move {
76 let distribution =
77 <P as ProvidesUnvalidatedDecoys>::ringct_output_distribution(self, range).await?;
78
79 let mut monotonic = 0;
80 for d in &distribution {
81 if *d < monotonic {
82 Err(InterfaceError::InvalidInterface(
83 "received output distribution didn't increase monotonically".to_string(),
84 ))?;
85 }
86 monotonic = *d;
87 }
88
89 Ok(distribution)
90 }
91 }
92
93 fn unlocked_ringct_outputs(
94 &self,
95 indexes: &[u64],
96 evaluate_unlocked: EvaluateUnlocked,
97 ) -> impl Send + Future<Output = Result<Vec<Option<[Point; 2]>>, TransactionsError>> {
98 async move {
99 let outputs =
100 <P as ProvidesUnvalidatedDecoys>::unlocked_ringct_outputs(self, indexes, evaluate_unlocked)
101 .await?;
102 if outputs.len() != indexes.len() {
103 Err(InterfaceError::InternalError(format!(
104 "`{}` returned {} outputs, expected {}",
105 "ProvidesUnvalidatedDecoys::unlocked_ringct_outputs",
106 outputs.len(),
107 indexes.len(),
108 )))?;
109 }
110 Ok(outputs)
111 }
112 }
113}