1use crate::{
4 cached::LazyCache,
5 error::{AccessError, MissingAccessArgError, OpSyncResult},
6 repeat::Repeat,
7 sets::encode_set,
8 types::{
9 convert::{bytes_from_word, u8_32_from_word_4, word_4_from_u8_32},
10 solution::{Solution, SolutionIndex, SolutionSet},
11 Key, Value, Word,
12 },
13 Stack,
14};
15use std::collections::HashSet;
16
17#[cfg(test)]
18mod dec_vars;
19#[cfg(test)]
20mod predicate_exists;
21#[cfg(test)]
22mod test_utils;
23#[cfg(test)]
24mod tests;
25
26#[derive(Clone, Copy, Debug)]
28pub struct Access<'a> {
29 pub solutions: &'a [Solution],
33 pub index: usize,
36 pub mutable_keys: &'a HashSet<&'a [Word]>,
38}
39
40impl<'a> Access<'a> {
41 pub fn new(
47 set: &'a SolutionSet,
48 solution_index: SolutionIndex,
49 mutable_keys: &'a HashSet<&[Word]>,
50 ) -> Self {
51 Self {
52 solutions: &set.solutions,
53 index: solution_index.into(),
54 mutable_keys,
55 }
56 }
57
58 pub fn this_solution(&self) -> &Solution {
62 self.solutions
63 .get(self.index)
64 .expect("solution index out of range of solutions slice")
65 }
66}
67
68pub fn mut_keys(set: &SolutionSet, solution_index: SolutionIndex) -> impl Iterator<Item = &Key> {
77 set.solutions[solution_index as usize]
78 .state_mutations
79 .iter()
80 .map(|m| &m.key)
81}
82
83pub fn mut_keys_slices(
85 set: &SolutionSet,
86 solution_index: SolutionIndex,
87) -> impl Iterator<Item = &[Word]> {
88 set.solutions[solution_index as usize]
89 .state_mutations
90 .iter()
91 .map(|m| m.key.as_ref())
92}
93
94pub fn mut_keys_set(solution_set: &SolutionSet, solution_index: SolutionIndex) -> HashSet<&[Word]> {
96 mut_keys_slices(solution_set, solution_index).collect()
97}
98
99pub(crate) fn predicate_data(this_predicate_data: &[Value], stack: &mut Stack) -> OpSyncResult<()> {
101 let len = stack
102 .pop()
103 .map_err(|_| AccessError::MissingArg(MissingAccessArgError::PredDataLen))?;
104 let value_ix = stack
105 .pop()
106 .map_err(|_| AccessError::MissingArg(MissingAccessArgError::PredDataValueIx))?;
107 let slot_ix = stack
108 .pop()
109 .map_err(|_| AccessError::MissingArg(MissingAccessArgError::PredDataSlotIx))?;
110 let slot_ix = usize::try_from(slot_ix)
111 .map_err(|_| AccessError::PredicateDataSlotIxOutOfBounds(slot_ix))?;
112 let range = range_from_start_len(value_ix, len).ok_or(AccessError::InvalidAccessRange)?;
113 let words = resolve_predicate_data_range(this_predicate_data, slot_ix, range)?;
114 stack.extend(words.iter().copied())?;
115 Ok(())
116}
117
118pub(crate) fn predicate_data_len(
120 this_predicate_data: &[Value],
121 stack: &mut Stack,
122) -> Result<(), AccessError> {
123 let slot_ix = stack
124 .pop()
125 .map_err(|_| MissingAccessArgError::PredDataSlotIx)?;
126 let slot_ix = usize::try_from(slot_ix)
127 .map_err(|_| AccessError::PredicateDataSlotIxOutOfBounds(slot_ix))?;
128 let len = resolve_predicate_data_len(this_predicate_data, slot_ix)?;
129 let w = Word::try_from(len).map_err(|_| AccessError::PredicateDataValueTooLarge(len))?;
130 stack
131 .push(w)
132 .expect("Can't fail because 1 is popped and 1 is pushed");
133 Ok(())
134}
135
136pub(crate) fn push_mut_keys(access: Access, stack: &mut Stack) -> OpSyncResult<()> {
138 encode_set(access.mutable_keys.iter().map(|k| k.iter().copied()), stack)
139}
140
141pub(crate) fn this_address(solution: &Solution, stack: &mut Stack) -> OpSyncResult<()> {
143 let words = word_4_from_u8_32(solution.predicate_to_solve.predicate.0);
144 stack.extend(words)?;
145 Ok(())
146}
147
148pub(crate) fn this_contract_address(solution: &Solution, stack: &mut Stack) -> OpSyncResult<()> {
150 let words = word_4_from_u8_32(solution.predicate_to_solve.contract.0);
151 stack.extend(words)?;
152 Ok(())
153}
154
155pub(crate) fn repeat_counter(stack: &mut Stack, repeat: &Repeat) -> OpSyncResult<()> {
156 let counter = repeat.counter()?;
157 Ok(stack.push(counter)?)
158}
159
160pub(crate) fn predicate_data_slots(
162 stack: &mut Stack,
163 predicate_data: &[Value],
164) -> OpSyncResult<()> {
165 let num_slots = Word::try_from(predicate_data.len())
166 .map_err(|_| AccessError::SlotsLengthTooLarge(predicate_data.len()))?;
167 stack.push(num_slots)?;
168 Ok(())
169}
170
171pub(crate) fn resolve_predicate_data_range(
175 predicate_data: &[Value],
176 slot_ix: usize,
177 value_range_ix: core::ops::Range<usize>,
178) -> Result<&[Word], AccessError> {
179 predicate_data
180 .get(slot_ix)
181 .ok_or(AccessError::PredicateDataSlotIxOutOfBounds(slot_ix as Word))?
182 .get(value_range_ix.clone())
183 .ok_or(AccessError::PredicateDataValueRangeOutOfBounds(
184 value_range_ix.start as Word,
185 value_range_ix.end as Word,
186 ))
187}
188
189pub(crate) fn resolve_predicate_data_len(
193 predicate_data: &[Value],
194 slot_ix: usize,
195) -> Result<usize, AccessError> {
196 predicate_data
197 .get(slot_ix)
198 .map(|slot| slot.len())
199 .ok_or(AccessError::PredicateDataSlotIxOutOfBounds(slot_ix as Word))
200}
201
202pub(crate) fn predicate_exists(
203 stack: &mut Stack,
204 solutions: &[Solution],
205 cache: &LazyCache,
206) -> OpSyncResult<()> {
207 let hash = u8_32_from_word_4(stack.pop4()?);
208 let found = cache.get_pred_data_hashes(solutions).contains(&hash);
209 stack.push(found as Word)?;
210 Ok(())
211}
212
213pub(crate) fn init_predicate_exists(
214 solutions: &[Solution],
215) -> impl Iterator<Item = essential_types::Hash> + '_ {
216 solutions.iter().map(|d| {
217 let data = d
218 .predicate_data
219 .iter()
220 .flat_map(|slot| {
221 Some(slot.len() as Word)
222 .into_iter()
223 .chain(slot.iter().cloned())
224 })
225 .chain(word_4_from_u8_32(d.predicate_to_solve.contract.0))
226 .chain(word_4_from_u8_32(d.predicate_to_solve.predicate.0))
227 .flat_map(bytes_from_word)
228 .collect::<Vec<_>>();
229 sha256(&data)
230 })
231}
232
233fn sha256(bytes: &[u8]) -> [u8; 32] {
234 use sha2::{Digest, Sha256};
235 let mut hasher = Sha256::new();
236 hasher.update(bytes);
237 let result: [u8; 32] = hasher.finalize().into();
238 result
239}
240
241fn range_from_start_len(start: Word, len: Word) -> Option<std::ops::Range<usize>> {
242 let start = usize::try_from(start).ok()?;
243 let len = usize::try_from(len).ok()?;
244 let end = start.checked_add(len)?;
245 Some(start..end)
246}