use super::{Mutations, SolutionSetIx};
use crate::{
error::{QueryPredicateError, QueryProgramError, StateReadError},
BlockNum,
};
use essential_check::vm::StateRead;
use essential_node as node;
use essential_node_types::{contract_registry, program_registry};
use essential_types::{
convert::bytes_from_word, predicate::Predicate, ContentAddress, Key, PredicateAddress, Program,
Value, Word,
};
use futures::FutureExt;
use std::{future::Future, pin::Pin, sync::Arc};
#[derive(Clone)]
pub(crate) struct View {
conn_pool: node::db::ConnectionPool,
proposed_mutations: Arc<Mutations>,
block_num: BlockNum,
solution_set_ix: SolutionSetIx,
}
impl View {
async fn query(
&self,
contract: ContentAddress,
key: Key,
) -> Result<Option<Value>, node::db::pool::AcquireThenQueryError> {
if let Some((_ix, v)) =
self.proposed_mutations
.query_excl(contract.clone(), key.clone(), self.solution_set_ix)
{
return Ok(Some(v.clone()));
}
let block_num = self.block_num;
self.conn_pool
.acquire_then(move |conn| {
use essential_node_db::finalized::query_state_exclusive_block;
let value = query_state_exclusive_block(conn, &contract, &key, block_num)?;
Ok(value)
})
.await
}
async fn query_range(
&self,
contract_ca: ContentAddress,
mut key: Key,
mut num_values: usize,
) -> Result<Vec<Value>, StateReadError> {
let mut values = vec![];
while num_values > 0 {
let value = self
.query(contract_ca.clone(), key.clone())
.await?
.unwrap_or(vec![]);
values.push(value);
key = next_key(key).map_err(|key| StateReadError::OutOfRange { key, num_values })?;
num_values -= 1;
}
Ok(values)
}
pub(crate) async fn get_predicate(
self,
contract_registry: ContentAddress,
pred_addr: &PredicateAddress,
) -> Result<Option<Predicate>, QueryPredicateError> {
let contract_predicate_key = contract_registry::contract_predicate_key(pred_addr);
if self
.query(contract_registry.clone(), contract_predicate_key)
.await?
.is_none()
{
return Ok(None);
}
let predicate_key = contract_registry::predicate_key(&pred_addr.predicate);
let Some(pred_words) = self.query(contract_registry, predicate_key).await? else {
return Ok(None);
};
let Some(&pred_len_bytes) = pred_words.first() else {
return Err(QueryPredicateError::MissingLenBytes);
};
let pred_len_bytes: usize = pred_len_bytes
.try_into()
.map_err(|_| QueryPredicateError::InvalidLenBytes)?;
let pred_words = &pred_words[1..];
let pred_bytes: Vec<u8> = pred_words
.iter()
.copied()
.flat_map(bytes_from_word)
.take(pred_len_bytes)
.collect();
let predicate = Predicate::decode(&pred_bytes)?;
Ok(Some(predicate))
}
pub(crate) async fn get_program(
self,
program_registry: ContentAddress,
prog_addr: &ContentAddress,
) -> Result<Option<Program>, QueryProgramError> {
let program_key = program_registry::program_key(prog_addr);
let Some(prog_words) = self.query(program_registry, program_key).await? else {
return Ok(None);
};
let Some(&prog_len_bytes) = prog_words.first() else {
return Err(QueryProgramError::MissingLenBytes);
};
let prog_len_bytes: usize = prog_len_bytes
.try_into()
.map_err(|_| QueryProgramError::InvalidLenBytes)?;
let prog_words = &prog_words[1..];
let prog_bytes: Vec<u8> = prog_words
.iter()
.copied()
.flat_map(bytes_from_word)
.take(prog_len_bytes)
.collect();
let program = Program(prog_bytes);
Ok(Some(program))
}
}
impl StateRead for View {
type Error = StateReadError;
type Future = Pin<Box<dyn Future<Output = Result<Vec<Value>, Self::Error>> + Send>>;
fn key_range(&self, contract: ContentAddress, key: Key, num_values: usize) -> Self::Future {
let tx = self.clone();
async move { tx.query_range(contract, key, num_values).await }.boxed()
}
}
pub(crate) fn pre_and_post_view(
conn_pool: node::db::ConnectionPool,
proposed_mutations: Arc<Mutations>,
block_num: BlockNum,
solution_set_ix: SolutionSetIx,
) -> (View, View) {
let pre = View {
conn_pool: conn_pool.clone(),
proposed_mutations: proposed_mutations.clone(),
block_num,
solution_set_ix,
};
let post = View {
conn_pool,
proposed_mutations,
block_num,
solution_set_ix: solution_set_ix
.checked_add(1)
.expect("solution set max out of range"),
};
(pre, post)
}
fn next_key(mut key: Key) -> Result<Key, Key> {
for w in key.iter_mut().rev() {
match *w {
Word::MAX => *w = Word::MIN,
_ => {
*w += 1;
return Ok(key);
}
}
}
Err(key)
}