1use crate::{
4 cached::LazyCache,
5 error::{AccessError, MissingAccessArgError, OpResult},
6 repeat::Repeat,
7 types::{
8 convert::{bytes_from_word, u8_32_from_word_4, word_4_from_u8_32},
9 solution::{Solution, SolutionIndex},
10 Value, Word,
11 },
12 Stack,
13};
14use std::sync::Arc;
15
16#[cfg(test)]
17mod dec_vars;
18#[cfg(test)]
19mod predicate_exists;
20#[cfg(test)]
21mod test_utils;
22#[cfg(test)]
23mod tests;
24
25#[derive(Clone, Debug)]
27pub struct Access {
28 pub solutions: Arc<Vec<Solution>>,
32 pub index: usize,
35}
36
37impl Access {
38 pub fn new(solutions: Arc<Vec<Solution>>, solution_index: SolutionIndex) -> Self {
44 Self {
45 solutions,
46 index: solution_index.into(),
47 }
48 }
49
50 pub fn this_solution(&self) -> &Solution {
54 self.solutions
55 .get(self.index)
56 .expect("solution index out of range of solutions slice")
57 }
58}
59
60pub(crate) fn predicate_data(this_predicate_data: &[Value], stack: &mut Stack) -> OpResult<()> {
62 let len = stack
63 .pop()
64 .map_err(|_| AccessError::MissingArg(MissingAccessArgError::PredDataLen))?;
65 let value_ix = stack
66 .pop()
67 .map_err(|_| AccessError::MissingArg(MissingAccessArgError::PredDataValueIx))?;
68 let slot_ix = stack
69 .pop()
70 .map_err(|_| AccessError::MissingArg(MissingAccessArgError::PredDataSlotIx))?;
71 let slot_ix = usize::try_from(slot_ix)
72 .map_err(|_| AccessError::PredicateDataSlotIxOutOfBounds(slot_ix))?;
73 let range = range_from_start_len(value_ix, len).ok_or(AccessError::InvalidAccessRange)?;
74 let words = resolve_predicate_data_range(this_predicate_data, slot_ix, range)?;
75 stack.extend(words.iter().copied())?;
76 Ok(())
77}
78
79pub(crate) fn predicate_data_len(
81 this_predicate_data: &[Value],
82 stack: &mut Stack,
83) -> Result<(), AccessError> {
84 let slot_ix = stack
85 .pop()
86 .map_err(|_| MissingAccessArgError::PredDataSlotIx)?;
87 let slot_ix = usize::try_from(slot_ix)
88 .map_err(|_| AccessError::PredicateDataSlotIxOutOfBounds(slot_ix))?;
89 let len = resolve_predicate_data_len(this_predicate_data, slot_ix)?;
90 let w = Word::try_from(len).map_err(|_| AccessError::PredicateDataValueTooLarge(len))?;
91 stack
92 .push(w)
93 .expect("Can't fail because 1 is popped and 1 is pushed");
94 Ok(())
95}
96
97pub(crate) fn this_address(solution: &Solution, stack: &mut Stack) -> OpResult<()> {
99 let words = word_4_from_u8_32(solution.predicate_to_solve.predicate.0);
100 stack.extend(words)?;
101 Ok(())
102}
103
104pub(crate) fn this_contract_address(solution: &Solution, stack: &mut Stack) -> OpResult<()> {
106 let words = word_4_from_u8_32(solution.predicate_to_solve.contract.0);
107 stack.extend(words)?;
108 Ok(())
109}
110
111pub(crate) fn repeat_counter(stack: &mut Stack, repeat: &Repeat) -> OpResult<()> {
112 let counter = repeat.counter()?;
113 Ok(stack.push(counter)?)
114}
115
116pub(crate) fn predicate_data_slots(stack: &mut Stack, predicate_data: &[Value]) -> OpResult<()> {
118 let num_slots = Word::try_from(predicate_data.len())
119 .map_err(|_| AccessError::SlotsLengthTooLarge(predicate_data.len()))?;
120 stack.push(num_slots)?;
121 Ok(())
122}
123
124pub(crate) fn resolve_predicate_data_range(
128 predicate_data: &[Value],
129 slot_ix: usize,
130 value_range_ix: core::ops::Range<usize>,
131) -> Result<&[Word], AccessError> {
132 predicate_data
133 .get(slot_ix)
134 .ok_or(AccessError::PredicateDataSlotIxOutOfBounds(slot_ix as Word))?
135 .get(value_range_ix.clone())
136 .ok_or(AccessError::PredicateDataValueRangeOutOfBounds(
137 value_range_ix.start as Word,
138 value_range_ix.end as Word,
139 ))
140}
141
142pub(crate) fn resolve_predicate_data_len(
146 predicate_data: &[Value],
147 slot_ix: usize,
148) -> Result<usize, AccessError> {
149 predicate_data
150 .get(slot_ix)
151 .map(|slot| slot.len())
152 .ok_or(AccessError::PredicateDataSlotIxOutOfBounds(slot_ix as Word))
153}
154
155pub(crate) fn predicate_exists(
156 stack: &mut Stack,
157 solutions: Arc<Vec<Solution>>,
158 cache: &LazyCache,
159) -> OpResult<()> {
160 let hash = u8_32_from_word_4(stack.pop4()?);
161 let found = cache.get_pred_data_hashes(solutions).contains(&hash);
162 stack.push(found as Word)?;
163 Ok(())
164}
165
166pub(crate) fn init_predicate_exists(solutions: Arc<Vec<Solution>>) -> Vec<essential_types::Hash> {
167 solutions
168 .iter()
169 .map(|d| {
170 let data = d
171 .predicate_data
172 .iter()
173 .flat_map(|slot| {
174 Some(slot.len() as Word)
175 .into_iter()
176 .chain(slot.iter().cloned())
177 })
178 .chain(word_4_from_u8_32(d.predicate_to_solve.contract.0))
179 .chain(word_4_from_u8_32(d.predicate_to_solve.predicate.0))
180 .flat_map(bytes_from_word)
181 .collect::<Vec<_>>();
182 sha256(&data)
183 })
184 .collect()
185}
186
187fn sha256(bytes: &[u8]) -> [u8; 32] {
188 use sha2::{Digest, Sha256};
189 let mut hasher = Sha256::new();
190 hasher.update(bytes);
191 let result: [u8; 32] = hasher.finalize().into();
192 result
193}
194
195fn range_from_start_len(start: Word, len: Word) -> Option<std::ops::Range<usize>> {
196 let start = usize::try_from(start).ok()?;
197 let len = usize::try_from(len).ok()?;
198 let end = start.checked_add(len)?;
199 Some(start..end)
200}