use crate::{
error::{MemoryError, OpError, OpResult, StackError, StateReadArgError},
Memory, Stack,
};
use essential_types::{convert::u8_32_from_word_4, ContentAddress, Key, Value, Word};
#[cfg(test)]
mod tests;
pub trait StateRead: Send + Sync {
type Error: core::fmt::Debug + core::fmt::Display;
fn key_range(
&self,
contract_addr: ContentAddress,
key: Key,
num_values: usize,
) -> Result<Vec<Vec<Word>>, Self::Error>;
}
pub trait StateReads: Send + Sync {
type Error: core::fmt::Debug + core::fmt::Display + Send;
type Pre: StateRead<Error = Self::Error>;
type Post: StateRead<Error = Self::Error>;
fn pre(&self) -> &Self::Pre;
fn post(&self) -> &Self::Post;
}
impl<S, P> StateReads for (S, P)
where
S: StateRead,
P: StateRead<Error = S::Error>,
S::Error: Send,
{
type Error = S::Error;
type Pre = S;
type Post = P;
fn pre(&self) -> &Self::Pre {
&self.0
}
fn post(&self) -> &Self::Post {
&self.1
}
}
pub fn key_range<S>(
state_read: &S,
contract_addr: &ContentAddress,
stack: &mut Stack,
memory: &mut Memory,
) -> OpResult<(), S::Error>
where
S: StateRead,
{
let mem_addr = pop_memory_address(stack)?;
let values = read_key_range(state_read, contract_addr, stack)?;
write_values_to_memory(mem_addr, values, memory)?;
Ok(())
}
pub fn key_range_ext<S>(
state_read: &S,
stack: &mut Stack,
memory: &mut Memory,
) -> OpResult<(), S::Error>
where
S: StateRead,
{
let mem_addr = pop_memory_address(stack)?;
let values = read_key_range_ext(state_read, stack)?;
write_values_to_memory(mem_addr, values, memory)?;
Ok(())
}
fn read_key_range<S>(
state_read: &S,
contract_addr: &ContentAddress,
stack: &mut Stack,
) -> OpResult<Vec<Value>, S::Error>
where
S: StateRead,
{
let (key, num_keys) = pop_key_range_args(stack)?;
state_read
.key_range(contract_addr.clone(), key, num_keys)
.map_err(OpError::StateRead)
}
fn read_key_range_ext<S>(state_read: &S, stack: &mut Stack) -> OpResult<Vec<Value>, S::Error>
where
S: StateRead,
{
let (key, num_keys) = pop_key_range_args(stack)?;
let contract_addr = ContentAddress(u8_32_from_word_4(stack.pop4()?));
state_read
.key_range(contract_addr, key, num_keys)
.map_err(OpError::StateRead)
}
fn pop_memory_address(stack: &mut Stack) -> Result<usize, StateReadArgError> {
let mem_addr = stack.pop()?;
let mem_addr = usize::try_from(mem_addr).map_err(|_| MemoryError::IndexOutOfBounds)?;
Ok(mem_addr)
}
fn pop_key_range_args(stack: &mut Stack) -> Result<(Key, usize), StackError> {
let num_keys = stack.pop()?;
let num_keys = usize::try_from(num_keys).map_err(|_| StackError::IndexOutOfBounds)?;
let key = stack.pop_len_words::<_, _, StackError>(|words| Ok(words.to_vec()))?;
Ok((key, num_keys))
}
fn write_values_to_memory(
mem_addr: usize,
values: Vec<Vec<Word>>,
memory: &mut Memory,
) -> Result<(), MemoryError> {
let values_len = Word::try_from(values.len()).map_err(|_| MemoryError::Overflow)?;
let index_len_pairs_len = values_len.checked_mul(2).ok_or(MemoryError::Overflow)?;
let mut mem_addr = Word::try_from(mem_addr).map_err(|_| MemoryError::IndexOutOfBounds)?;
let mut value_addr = mem_addr
.checked_add(index_len_pairs_len)
.ok_or(MemoryError::Overflow)?;
for value in values {
let value_len = Word::try_from(value.len()).map_err(|_| MemoryError::Overflow)?;
memory.store_range(mem_addr, &[value_addr, value_len])?;
memory.store_range(value_addr, &value)?;
value_addr += value_len;
mem_addr += 2;
}
Ok(())
}