use std::sync::{Arc, RwLock, Mutex, MutexGuard};
use std::marker::PhantomData;
use super::Error;
use crate::traits::{Operation, ImportOperation, Block, BlockExecutor, Backend, AsExternalities, Auxiliary};
pub struct SharedBackend<B: Block, A: Auxiliary<B>, Ba: Backend<B, A>> {
backend: Arc<RwLock<Ba>>,
import_lock: Arc<Mutex<()>>,
_marker: PhantomData<(B, A)>,
}
impl<B: Block, A: Auxiliary<B>, Ba> SharedBackend<B, A, Ba> where
Ba: Backend<B, A>
{
pub fn new(backend: Ba) -> Self {
Self {
backend: Arc::new(RwLock::new(backend)),
import_lock: Arc::new(Mutex::new(())),
_marker: PhantomData,
}
}
pub fn genesis(&self) -> B::Identifier {
self.backend.read().expect("backend lock is poisoned")
.genesis()
}
pub fn head(&self) -> B::Identifier {
self.backend.read().expect("backend lock is poisoned")
.head()
}
pub fn contains(
&self,
hash: &B::Identifier,
) -> Result<bool, Ba::Error> {
self.backend.read().expect("backend lock is poisoned")
.contains(hash)
}
pub fn is_canon(
&self,
hash: &B::Identifier
) -> Result<bool, Ba::Error> {
self.backend.read().expect("backend lock is poisoned")
.is_canon(hash)
}
pub fn lookup_canon_depth(
&self,
depth: usize,
) -> Result<Option<B::Identifier>, Ba::Error> {
self.backend.read().expect("backend lock is poisoned")
.lookup_canon_depth(depth)
}
pub fn auxiliary(
&self,
key: &A::Key
) -> Result<Option<A>, Ba::Error> {
self.backend.read().expect("backend lock is poisoned")
.auxiliary(key)
}
pub fn depth_at(
&self,
hash: &B::Identifier,
) -> Result<usize, Ba::Error> {
self.backend.read().expect("backend lock is poisoned")
.depth_at(hash)
}
pub fn children_at(
&self,
hash: &B::Identifier,
) -> Result<Vec<B::Identifier>, Ba::Error> {
self.backend.read().expect("backend lock is poisoned")
.children_at(hash)
}
pub fn state_at(
&self,
hash: &B::Identifier,
) -> Result<Ba::State, Ba::Error> {
self.backend.read().expect("backend lock is poisoned")
.state_at(hash)
}
pub fn block_at(
&self,
hash: &B::Identifier,
) -> Result<B, Ba::Error> {
self.backend.read().expect("backend lock is poisoned")
.block_at(hash)
}
pub fn begin_import<'a, 'executor, E: BlockExecutor<Block=B>>(
&'a self,
executor: &'executor E
) -> Importer<'a, 'executor, E, A, Ba> where
Ba::State: AsExternalities<E::Externalities>
{
Importer {
executor,
backend: self,
pending: Default::default(),
_guard: self.import_lock.lock().expect("Import mutex is poisoned"),
}
}
}
impl<B: Block, A: Auxiliary<B>, Ba: Backend<B, A>> Clone for SharedBackend<B, A, Ba> {
fn clone(&self) -> Self {
SharedBackend {
backend: self.backend.clone(),
import_lock: self.import_lock.clone(),
_marker: PhantomData,
}
}
}
pub struct Importer<'a, 'executor, E: BlockExecutor, A: Auxiliary<E::Block>, Ba: Backend<E::Block, A>> {
executor: &'executor E,
backend: &'a SharedBackend<E::Block, A, Ba>,
pending: Operation<E::Block, Ba::State, A>,
_guard: MutexGuard<'a, ()>,
}
impl<'a, 'executor, E: BlockExecutor, A: Auxiliary<E::Block>, Ba: Backend<E::Block, A>> Importer<'a, 'executor, E, A, Ba> where
Ba::State: AsExternalities<E::Externalities>,
{
pub fn backend(&self) -> &'a SharedBackend<E::Block, A, Ba> {
self.backend
}
pub fn import_block(&mut self, block: E::Block) -> Result<(), Error> {
let mut state = self.backend
.state_at(&block.parent_id().ok_or(Error::IsGenesis)?)
.map_err(|e| Error::Backend(Box::new(e)))?;
self.executor.execute_block(&block, state.as_externalities())
.map_err(|e| Error::Executor(Box::new(e)))?;
let operation = ImportOperation { block, state };
self.import_raw(operation);
Ok(())
}
pub fn import_raw(&mut self, operation: ImportOperation<E::Block, Ba::State>) {
self.pending.import_block.push(operation);
}
pub fn set_head(&mut self, head: <E::Block as Block>::Identifier) {
self.pending.set_head = Some(head);
}
pub fn insert_auxiliary(&mut self, aux: A) {
self.pending.insert_auxiliaries.push(aux);
}
pub fn remove_auxiliary(&mut self, aux_key: A::Key) {
self.pending.remove_auxiliaries.push(aux_key);
}
pub fn commit(self) -> Result<(), Ba::Error> {
self.backend.backend.write().expect("backend lock is poisoned")
.commit(self.pending)
}
}