monero_interface/
provides_decoys.rs1use core::{ops::RangeBounds, future::Future};
2use alloc::{borrow::ToOwned as _, format, vec::Vec};
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(
40 &self,
41 indexes: &[u64],
42 evaluate_unlocked: EvaluateUnlocked,
43 ) -> impl Send + Future<Output = Result<Vec<Option<[Point; 2]>>, TransactionsError>>;
44}
45
46pub trait ProvidesDecoys: ProvidesBlockchainMeta {
50 fn ringct_output_distribution(
57 &self,
58 range: impl Send + RangeBounds<usize>,
59 ) -> impl Send + Future<Output = Result<Vec<u64>, InterfaceError>>;
60
61 fn unlocked_ringct_outputs(
66 &self,
67 indexes: &[u64],
68 evaluate_unlocked: EvaluateUnlocked,
69 ) -> impl Send + Future<Output = Result<Vec<Option<[Point; 2]>>, TransactionsError>>;
70}
71
72impl<P: ProvidesUnvalidatedDecoys> ProvidesDecoys for P {
73 fn ringct_output_distribution(
74 &self,
75 range: impl Send + RangeBounds<usize>,
76 ) -> impl Send + Future<Output = Result<Vec<u64>, InterfaceError>> {
77 async move {
78 let distribution =
79 <P as ProvidesUnvalidatedDecoys>::ringct_output_distribution(self, range).await?;
80
81 let mut monotonic = 0;
82 for d in &distribution {
83 if *d < monotonic {
84 Err(InterfaceError::InvalidInterface(
85 "received output distribution didn't increase monotonically".to_owned(),
86 ))?;
87 }
88 monotonic = *d;
89 }
90
91 Ok(distribution)
92 }
93 }
94
95 fn unlocked_ringct_outputs(
96 &self,
97 indexes: &[u64],
98 evaluate_unlocked: EvaluateUnlocked,
99 ) -> impl Send + Future<Output = Result<Vec<Option<[Point; 2]>>, TransactionsError>> {
100 async move {
101 let outputs =
102 <P as ProvidesUnvalidatedDecoys>::unlocked_ringct_outputs(self, indexes, evaluate_unlocked)
103 .await?;
104 if outputs.len() != indexes.len() {
105 Err(InterfaceError::InternalError(format!(
106 "`{}` returned {} outputs, expected {}",
107 "ProvidesUnvalidatedDecoys::unlocked_ringct_outputs",
108 outputs.len(),
109 indexes.len(),
110 )))?;
111 }
112 Ok(outputs)
113 }
114 }
115}