essential_vm/
state_read.rs

1//! State read operation implementations.
2
3use crate::{
4    error::{MemoryError, OpError, OpResult, StackError, StateReadArgError},
5    Memory, Stack,
6};
7use essential_types::{convert::u8_32_from_word_4, ContentAddress, Key, Value, Word};
8
9#[cfg(test)]
10mod tests;
11
12/// Read-only access to state required by the VM.
13pub trait StateRead: Send + Sync {
14    /// An error type describing any cases that might occur during state reading.
15    type Error: core::fmt::Debug + core::fmt::Display;
16
17    /// Read the given number of values from state at the given key associated
18    /// with the given contract address.
19    fn key_range(
20        &self,
21        contract_addr: ContentAddress,
22        key: Key,
23        num_values: usize,
24    ) -> Result<Vec<Vec<Word>>, Self::Error>;
25}
26
27/// Pre and post sync state reads.
28pub trait StateReads: Send + Sync {
29    /// Common error type
30    type Error: core::fmt::Debug + core::fmt::Display + Send;
31
32    /// Pre state read
33    type Pre: StateRead<Error = Self::Error>;
34
35    /// Post state read
36    type Post: StateRead<Error = Self::Error>;
37
38    /// Get the pre state read
39    fn pre(&self) -> &Self::Pre;
40
41    /// Get the post state read
42    fn post(&self) -> &Self::Post;
43}
44
45impl<S, P> StateReads for (S, P)
46where
47    S: StateRead,
48    P: StateRead<Error = S::Error>,
49    S::Error: Send,
50{
51    type Error = S::Error;
52
53    type Pre = S;
54
55    type Post = P;
56
57    fn pre(&self) -> &Self::Pre {
58        &self.0
59    }
60
61    fn post(&self) -> &Self::Post {
62        &self.1
63    }
64}
65/// `StateRead::KeyRange` operation.
66/// Uses a synchronous state read.
67pub fn key_range<S>(
68    state_read: &S,
69    contract_addr: &ContentAddress,
70    stack: &mut Stack,
71    memory: &mut Memory,
72) -> OpResult<(), S::Error>
73where
74    S: StateRead,
75{
76    let mem_addr = pop_memory_address(stack)?;
77    let values = read_key_range(state_read, contract_addr, stack)?;
78    write_values_to_memory(mem_addr, values, memory)?;
79    Ok(())
80}
81
82/// `StateRead::KeyRangeExtern` operation.
83/// Uses a synchronous state read.
84pub fn key_range_ext<S>(
85    state_read: &S,
86    stack: &mut Stack,
87    memory: &mut Memory,
88) -> OpResult<(), S::Error>
89where
90    S: StateRead,
91{
92    let mem_addr = pop_memory_address(stack)?;
93    let values = read_key_range_ext(state_read, stack)?;
94    write_values_to_memory(mem_addr, values, memory)?;
95    Ok(())
96}
97
98/// Read the length and key from the top of the stack and read the associated words from state.
99/// Uses a synchronous state read.
100fn read_key_range<S>(
101    state_read: &S,
102    contract_addr: &ContentAddress,
103    stack: &mut Stack,
104) -> OpResult<Vec<Value>, S::Error>
105where
106    S: StateRead,
107{
108    let (key, num_keys) = pop_key_range_args(stack)?;
109    state_read
110        .key_range(contract_addr.clone(), key, num_keys)
111        .map_err(OpError::StateRead)
112}
113
114/// Read the length, key and external contract address from the top of the stack and
115/// read the associated words from state.
116/// Uses a synchronous state read.
117fn read_key_range_ext<S>(state_read: &S, stack: &mut Stack) -> OpResult<Vec<Value>, S::Error>
118where
119    S: StateRead,
120{
121    let (key, num_keys) = pop_key_range_args(stack)?;
122    let contract_addr = ContentAddress(u8_32_from_word_4(stack.pop4()?));
123    state_read
124        .key_range(contract_addr, key, num_keys)
125        .map_err(OpError::StateRead)
126}
127
128/// Pop the memory address that the state read will write to from the stack.
129fn pop_memory_address(stack: &mut Stack) -> Result<usize, StateReadArgError> {
130    let mem_addr = stack.pop()?;
131    let mem_addr = usize::try_from(mem_addr).map_err(|_| MemoryError::IndexOutOfBounds)?;
132    Ok(mem_addr)
133}
134
135/// Pop the key and number of keys from the stack.
136fn pop_key_range_args(stack: &mut Stack) -> Result<(Key, usize), StackError> {
137    let num_keys = stack.pop()?;
138    let num_keys = usize::try_from(num_keys).map_err(|_| StackError::IndexOutOfBounds)?;
139    let key = stack.pop_len_words::<_, _, StackError>(|words| Ok(words.to_vec()))?;
140    Ok((key, num_keys))
141}
142
143/// Write the given values to memory.
144fn write_values_to_memory(
145    mem_addr: usize,
146    values: Vec<Vec<Word>>,
147    memory: &mut Memory,
148) -> Result<(), MemoryError> {
149    let values_len = Word::try_from(values.len()).map_err(|_| MemoryError::Overflow)?;
150    let index_len_pairs_len = values_len.checked_mul(2).ok_or(MemoryError::Overflow)?;
151    let mut mem_addr = Word::try_from(mem_addr).map_err(|_| MemoryError::IndexOutOfBounds)?;
152    let mut value_addr = mem_addr
153        .checked_add(index_len_pairs_len)
154        .ok_or(MemoryError::Overflow)?;
155    for value in values {
156        let value_len = Word::try_from(value.len()).map_err(|_| MemoryError::Overflow)?;
157        // Write the [index, len] pair.
158        memory.store_range(mem_addr, &[value_addr, value_len])?;
159        // Write the value.
160        memory.store_range(value_addr, &value)?;
161        // No need to check addition here as `store_range` would have failed.
162        value_addr += value_len;
163        mem_addr += 2;
164    }
165    Ok(())
166}