#![deny(missing_docs)]
use std::{future::Future, ops::Range, time::Duration};
use essential_types::{
contract::{Contract, SignedContract},
predicate::Predicate,
solution::Solution,
Block, ContentAddress, Hash, Key, PredicateAddress, Word,
};
use failed_solution::{FailedSolution, SolutionFailReason, SolutionOutcomes};
pub mod failed_solution;
pub struct CommitData<'a> {
pub failed: &'a [(Hash, SolutionFailReason)],
pub solved: &'a [Hash],
pub state_updates: Box<dyn Iterator<Item = (ContentAddress, Key, Vec<Word>)> + 'a>,
}
pub trait Storage: StateStorage {
fn insert_contract(
&self,
predicate: SignedContract,
) -> impl Future<Output = anyhow::Result<()>> + Send;
fn insert_solution_into_pool(
&self,
solution: Solution,
) -> impl Future<Output = anyhow::Result<()>> + Send;
fn move_solutions_to_solved(
&self,
solutions: &[Hash],
) -> impl Future<Output = anyhow::Result<()>> + Send;
fn move_solutions_to_failed(
&self,
solutions: &[(Hash, SolutionFailReason)],
) -> impl std::future::Future<Output = anyhow::Result<()>> + Send;
fn get_predicate(
&self,
address: &PredicateAddress,
) -> impl Future<Output = anyhow::Result<Option<Predicate>>> + Send;
fn get_contract(
&self,
address: &ContentAddress,
) -> impl Future<Output = anyhow::Result<Option<SignedContract>>> + Send;
fn list_contracts(
&self,
time_range: Option<Range<Duration>>,
page: Option<usize>,
) -> impl Future<Output = anyhow::Result<Vec<Contract>>> + Send;
fn list_solutions_pool(
&self,
page: Option<usize>,
) -> impl Future<Output = anyhow::Result<Vec<Solution>>> + Send;
fn list_failed_solutions_pool(
&self,
page: Option<usize>,
) -> impl std::future::Future<Output = anyhow::Result<Vec<FailedSolution>>> + Send;
fn list_winning_blocks(
&self,
time_range: Option<Range<Duration>>,
page: Option<usize>,
) -> impl Future<Output = anyhow::Result<Vec<Block>>> + Send;
fn get_solution(
&self,
solution_hash: Hash,
) -> impl std::future::Future<Output = anyhow::Result<Option<SolutionOutcomes>>> + Send;
fn prune_failed_solutions(
&self,
older_than: Duration,
) -> impl std::future::Future<Output = anyhow::Result<()>> + Send;
fn commit_block(
&self,
data: CommitData,
) -> impl std::future::Future<Output = anyhow::Result<()>> + Send;
}
pub trait StateStorage: QueryState {
fn update_state(
&self,
address: &ContentAddress,
key: &Key,
value: Vec<Word>,
) -> impl std::future::Future<Output = anyhow::Result<Vec<Word>>> + Send;
fn update_state_batch<U>(
&self,
updates: U,
) -> impl std::future::Future<Output = anyhow::Result<Vec<Vec<Word>>>> + Send
where
U: IntoIterator<Item = (ContentAddress, Key, Vec<Word>)> + Send;
}
pub trait QueryState {
fn query_state(
&self,
address: &ContentAddress,
key: &Key,
) -> impl std::future::Future<Output = anyhow::Result<Vec<Word>>> + Send;
}
pub async fn key_range<S, E>(
storage: &S,
contract_addr: ContentAddress,
mut key: Key,
num_words: usize,
) -> Result<Vec<Vec<Word>>, E>
where
S: QueryState + Send,
E: From<anyhow::Error>,
{
let mut words = vec![];
for _ in 0..num_words {
let slot = storage.query_state(&contract_addr, &key).await?;
words.push(slot);
key = next_key(key).ok_or_else(|| anyhow::anyhow!("Failed to find next key"))?
}
Ok(words)
}
pub fn next_key(mut key: Key) -> Option<Key> {
for w in key.iter_mut().rev() {
match *w {
Word::MAX => *w = Word::MIN,
_ => {
*w += 1;
return Some(key);
}
}
}
None
}