snarkvm_ledger_puzzle/solutions/
mod.rs1mod bytes;
17mod serialize;
18mod string;
19
20use crate::{Solution, SolutionID};
21use console::{network::prelude::*, prelude::DeserializeExt, types::Field};
22use indexmap::IndexMap;
23
24#[derive(Clone, Eq, PartialEq)]
26pub struct PuzzleSolutions<N: Network> {
27 solutions: IndexMap<SolutionID<N>, Solution<N>>,
29}
30
31impl<N: Network> PuzzleSolutions<N> {
32 pub fn new(solutions: Vec<Solution<N>>) -> Result<Self> {
34 ensure!(!solutions.is_empty(), "There are no solutions to verify for the puzzle");
36 if solutions.len() > N::MAX_SOLUTIONS {
38 bail!("Exceeded the maximum number of solutions ({} > {})", solutions.len(), N::MAX_SOLUTIONS);
39 }
40 if has_duplicates(solutions.iter().map(Solution::id)) {
42 bail!("The solutions contain duplicate solution IDs");
43 }
44 Ok(Self { solutions: solutions.into_iter().map(|solution| (solution.id(), solution)).collect() })
46 }
47
48 pub fn solution_ids(&self) -> impl '_ + Iterator<Item = &SolutionID<N>> {
50 self.solutions.keys()
51 }
52
53 pub fn len(&self) -> usize {
55 self.solutions.len()
56 }
57
58 pub fn is_empty(&self) -> bool {
60 self.solutions.is_empty()
61 }
62
63 pub fn get_solution(&self, solution_id: &SolutionID<N>) -> Option<&Solution<N>> {
65 self.solutions.get(solution_id)
66 }
67
68 pub fn to_accumulator_point(&self) -> Result<Field<N>> {
70 let mut preimage = self.solution_ids().map(|id| Field::from_u64(**id)).collect::<Vec<_>>();
72 preimage.resize(N::MAX_SOLUTIONS, Field::zero());
74 N::hash_psd8(&preimage)
76 }
77}
78
79impl<N: Network> Deref for PuzzleSolutions<N> {
80 type Target = IndexMap<SolutionID<N>, Solution<N>>;
81
82 fn deref(&self) -> &Self::Target {
83 &self.solutions
84 }
85}
86
87#[cfg(test)]
88mod tests {
89 use super::*;
90 use crate::PartialSolution;
91 use console::account::{Address, PrivateKey};
92
93 use std::collections::HashSet;
94
95 type CurrentNetwork = console::network::MainnetV0;
96
97 pub(crate) fn sample_solutions_with_count(
99 num_solutions: usize,
100 rng: &mut TestRng,
101 ) -> PuzzleSolutions<CurrentNetwork> {
102 let mut solutions = vec![];
104 for _ in 0..num_solutions {
105 let private_key = PrivateKey::<CurrentNetwork>::new(rng).unwrap();
106 let address = Address::try_from(private_key).unwrap();
107
108 let partial_solution = PartialSolution::new(rng.r#gen(), address, u64::rand(rng)).unwrap();
109 let solution = Solution::new(partial_solution, u64::rand(rng));
110 solutions.push(solution);
111 }
112 PuzzleSolutions::new(solutions).unwrap()
113 }
114
115 #[test]
116 fn test_new_is_not_empty() {
117 assert!(PuzzleSolutions::<CurrentNetwork>::new(vec![]).is_err());
119 }
120
121 #[test]
122 fn test_len() {
123 let mut rng = TestRng::default();
124
125 for num_solutions in 1..<CurrentNetwork as Network>::MAX_SOLUTIONS {
126 let solutions = sample_solutions_with_count(num_solutions, &mut rng);
128 assert_eq!(num_solutions, solutions.len());
130 }
131 }
132
133 #[test]
134 fn test_is_empty() {
135 let mut rng = TestRng::default();
136
137 for num_solutions in 1..<CurrentNetwork as Network>::MAX_SOLUTIONS {
138 let solutions = sample_solutions_with_count(num_solutions, &mut rng);
140 assert!(!solutions.is_empty());
142 }
143 }
144
145 #[test]
146 fn test_solution_ids() {
147 let mut rng = TestRng::default();
148
149 for num_solutions in 1..<CurrentNetwork as Network>::MAX_SOLUTIONS {
150 let solutions = sample_solutions_with_count(num_solutions, &mut rng);
152 assert_eq!(num_solutions, solutions.solution_ids().collect::<HashSet<_>>().len());
154 }
155 }
156
157 #[test]
158 fn test_get_solution() {
159 let mut rng = TestRng::default();
160
161 for num_solutions in 1..<CurrentNetwork as Network>::MAX_SOLUTIONS {
162 let solutions = sample_solutions_with_count(num_solutions, &mut rng);
164 for solution_id in solutions.solution_ids() {
166 assert_eq!(solutions.get_solution(solution_id).unwrap().id(), *solution_id);
167 }
168 }
169 }
170
171 #[test]
172 fn test_to_accumulator_point() {
173 let mut rng = TestRng::default();
174
175 for num_solutions in 1..<CurrentNetwork as Network>::MAX_SOLUTIONS {
176 let solutions = crate::solutions::tests::sample_solutions_with_count(num_solutions, &mut rng);
178 let candidate = solutions.to_accumulator_point().unwrap();
180 let mut preimage = vec![Field::zero(); <CurrentNetwork as Network>::MAX_SOLUTIONS];
182 for (i, id) in solutions.keys().enumerate() {
183 preimage[i] = Field::from_u64(**id);
184 }
185 let expected = <CurrentNetwork as Network>::hash_psd8(&preimage).unwrap();
186 assert_eq!(expected, candidate);
187 }
188 }
189}