2020-09-09 17:13:58 -07:00
|
|
|
use std::{
|
|
|
|
future::Future,
|
|
|
|
pin::Pin,
|
2020-09-09 23:07:47 -07:00
|
|
|
sync::Arc,
|
2020-09-09 17:13:58 -07:00
|
|
|
task::{Context, Poll},
|
|
|
|
};
|
2020-09-09 21:15:08 -07:00
|
|
|
|
|
|
|
use futures::future::{FutureExt, TryFutureExt};
|
2020-09-09 23:07:47 -07:00
|
|
|
use tokio::sync::oneshot;
|
2020-09-09 17:13:58 -07:00
|
|
|
use tower::{buffer::Buffer, util::BoxService, Service};
|
2020-09-09 23:07:47 -07:00
|
|
|
use zebra_chain::{
|
|
|
|
block::{self, Block},
|
|
|
|
parameters::Network,
|
|
|
|
};
|
2020-09-09 17:13:58 -07:00
|
|
|
|
2020-09-10 10:19:45 -07:00
|
|
|
use crate::{BoxError, Config, MemoryState, Request, Response, SledState};
|
2020-09-09 17:13:58 -07:00
|
|
|
|
2020-09-09 23:07:47 -07:00
|
|
|
// todo: put this somewhere
|
|
|
|
pub struct QueuedBlock {
|
|
|
|
pub block: Arc<Block>,
|
|
|
|
// TODO: add these parameters when we can compute anchors.
|
|
|
|
// sprout_anchor: sprout::tree::Root,
|
|
|
|
// sapling_anchor: sapling::tree::Root,
|
|
|
|
pub rsp_tx: oneshot::Sender<Result<block::Hash, BoxError>>,
|
|
|
|
}
|
|
|
|
|
2020-09-09 17:13:58 -07:00
|
|
|
struct StateService {
|
|
|
|
/// Holds data relating to finalized chain state.
|
|
|
|
sled: SledState,
|
|
|
|
/// Holds data relating to non-finalized chain state.
|
2020-09-10 10:25:39 -07:00
|
|
|
_mem: MemoryState,
|
2020-09-09 17:13:58 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
impl StateService {
|
|
|
|
pub fn new(config: Config, network: Network) -> Self {
|
|
|
|
let sled = SledState::new(&config, network);
|
2020-09-10 10:25:39 -07:00
|
|
|
let _mem = MemoryState {};
|
|
|
|
Self { sled, _mem }
|
2020-09-09 17:13:58 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Service<Request> for StateService {
|
|
|
|
type Response = Response;
|
|
|
|
type Error = BoxError;
|
|
|
|
type Future =
|
|
|
|
Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send + 'static>>;
|
|
|
|
|
|
|
|
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
|
|
|
Poll::Ready(Ok(()))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn call(&mut self, req: Request) -> Self::Future {
|
|
|
|
match req {
|
2020-09-10 10:25:39 -07:00
|
|
|
Request::CommitBlock { .. } => unimplemented!(),
|
2020-09-09 21:15:08 -07:00
|
|
|
Request::CommitFinalizedBlock { block } => {
|
2020-09-09 23:07:47 -07:00
|
|
|
let (rsp_tx, rsp_rx) = oneshot::channel();
|
|
|
|
|
|
|
|
self.sled.queue(QueuedBlock { block, rsp_tx });
|
2020-09-09 21:15:08 -07:00
|
|
|
|
2020-09-09 23:07:47 -07:00
|
|
|
async move {
|
|
|
|
rsp_rx
|
|
|
|
.await
|
|
|
|
.expect("sender oneshot is not dropped")
|
2020-09-10 10:52:51 -07:00
|
|
|
.map(Response::Committed)
|
2020-09-09 23:07:47 -07:00
|
|
|
}
|
|
|
|
.boxed()
|
2020-09-09 21:15:08 -07:00
|
|
|
}
|
|
|
|
Request::Depth(hash) => {
|
|
|
|
// todo: handle in memory and sled
|
2020-09-10 10:52:51 -07:00
|
|
|
self.sled.depth(hash).map_ok(Response::Depth).boxed()
|
2020-09-09 21:15:08 -07:00
|
|
|
}
|
|
|
|
Request::Tip => {
|
|
|
|
// todo: handle in memory and sled
|
2020-09-10 10:52:51 -07:00
|
|
|
self.sled.tip().map_ok(Response::Tip).boxed()
|
2020-09-09 21:15:08 -07:00
|
|
|
}
|
|
|
|
Request::BlockLocator => {
|
|
|
|
// todo: handle in memory and sled
|
|
|
|
self.sled
|
|
|
|
.block_locator()
|
2020-09-10 10:52:51 -07:00
|
|
|
.map_ok(Response::BlockLocator)
|
2020-09-09 21:15:08 -07:00
|
|
|
.boxed()
|
|
|
|
}
|
2020-09-10 10:25:39 -07:00
|
|
|
Request::Transaction(_) => unimplemented!(),
|
2020-09-10 10:19:45 -07:00
|
|
|
Request::Block(hash_or_height) => {
|
|
|
|
//todo: handle in memory and sled
|
|
|
|
self.sled
|
|
|
|
.block(hash_or_height)
|
2020-09-10 10:52:51 -07:00
|
|
|
.map_ok(Response::Block)
|
2020-09-10 10:19:45 -07:00
|
|
|
.boxed()
|
|
|
|
}
|
2020-09-09 17:13:58 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-09 17:51:08 -07:00
|
|
|
/// Initialize a state service from the provided [`Config`].
|
2020-09-09 17:13:58 -07:00
|
|
|
///
|
|
|
|
/// Each `network` has its own separate sled database.
|
|
|
|
///
|
|
|
|
/// The resulting service is clonable, to provide shared access to a common chain
|
|
|
|
/// state. It's possible to construct multiple state services in the same
|
|
|
|
/// application (as long as they, e.g., use different storage locations), but
|
|
|
|
/// doing so is probably not what you want.
|
|
|
|
pub fn init(
|
|
|
|
config: Config,
|
|
|
|
network: Network,
|
|
|
|
) -> Buffer<BoxService<Request, Response, BoxError>, Request> {
|
2020-09-19 23:58:41 -07:00
|
|
|
Buffer::new(BoxService::new(StateService::new(config, network)), 3)
|
2020-09-09 17:13:58 -07:00
|
|
|
}
|