mirror of
https://github.com/Cuprate/cuprate.git
synced 2024-12-23 03:59:31 +00:00
fetch block headers in parallel and support multiple rpc endpoints
this significantly speeds up initiating the hardfork struct
This commit is contained in:
parent
42548f733d
commit
a56d8ea87f
7 changed files with 217 additions and 63 deletions
|
@ -13,7 +13,7 @@ pub const CRYPTONOTE_PRUNING_LOG_STRIPES: u32 = 3;
|
||||||
pub const CRYPTONOTE_PRUNING_STRIPE_SIZE: u64 = 4096;
|
pub const CRYPTONOTE_PRUNING_STRIPE_SIZE: u64 = 4096;
|
||||||
pub const CRYPTONOTE_PRUNING_TIP_BLOCKS: u64 = 5500;
|
pub const CRYPTONOTE_PRUNING_TIP_BLOCKS: u64 = 5500;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum BlockID {
|
pub enum BlockID {
|
||||||
Hash([u8; 32]),
|
Hash([u8; 32]),
|
||||||
Height(u64),
|
Height(u64),
|
||||||
|
|
|
@ -78,7 +78,7 @@ impl PruningSeed {
|
||||||
/// and 3 for `log_stripes`.*
|
/// and 3 for `log_stripes`.*
|
||||||
///
|
///
|
||||||
pub fn new(stripe: u32, log_stripes: u32) -> Result<PruningSeed, PruningError> {
|
pub fn new(stripe: u32, log_stripes: u32) -> Result<PruningSeed, PruningError> {
|
||||||
if !(log_stripes <= PRUNING_SEED_LOG_STRIPES_MASK) {
|
if log_stripes > PRUNING_SEED_LOG_STRIPES_MASK {
|
||||||
Err(PruningError::LogStripesOutOfRange)
|
Err(PruningError::LogStripesOutOfRange)
|
||||||
} else if !(stripe > 0 && stripe <= (1 << log_stripes)) {
|
} else if !(stripe > 0 && stripe <= (1 << log_stripes)) {
|
||||||
Err(PruningError::StripeOutOfRange)
|
Err(PruningError::StripeOutOfRange)
|
||||||
|
|
|
@ -9,7 +9,7 @@ repository = "https://github.com/Cuprate/cuprate/tree/main/consensus"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["binaries"]
|
default = ["binaries"]
|
||||||
binaries = ["rpc", "dep:tokio", "dep:tracing-subscriber", "tower/retry", "tower/balance"]
|
binaries = ["rpc", "dep:tokio", "dep:tracing-subscriber", "tower/retry", "tower/balance", "tower/buffer"]
|
||||||
rpc = ["dep:futures"]
|
rpc = ["dep:futures"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|
|
@ -1,39 +1,86 @@
|
||||||
#![cfg(feature = "binaries")]
|
#![cfg(feature = "binaries")]
|
||||||
|
|
||||||
use tower::{Service, ServiceExt};
|
use futures::Stream;
|
||||||
|
use monero_serai::rpc::HttpRpc;
|
||||||
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
use std::task::{Context, Poll};
|
||||||
|
use tower::balance::p2c::Balance;
|
||||||
|
use tower::discover::Change;
|
||||||
|
use tower::util::{BoxService};
|
||||||
|
|
||||||
use tracing::level_filters::LevelFilter;
|
use tracing::level_filters::LevelFilter;
|
||||||
|
|
||||||
use monero_consensus::hardforks::{HardFork, HardForkConfig, HardForks};
|
use monero_consensus::hardforks::{HardForkConfig, HardForks};
|
||||||
use monero_consensus::rpc::Rpc;
|
use monero_consensus::rpc::Rpc;
|
||||||
use monero_consensus::DatabaseRequest;
|
|
||||||
|
|
||||||
|
struct RpcDiscoverer(Vec<String>, u64);
|
||||||
|
|
||||||
|
impl Stream for RpcDiscoverer {
|
||||||
|
type Item = Result<Change<u64, Rpc<HttpRpc>>, tower::BoxError>;
|
||||||
|
|
||||||
|
fn poll_next(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
|
let this = self.get_mut();
|
||||||
|
if let Some(url) = this.0.pop() {
|
||||||
|
this.1 += 1;
|
||||||
|
return Poll::Ready(Some(Ok(Change::Insert(this.1, Rpc::new_http(url)))));
|
||||||
|
}
|
||||||
|
Poll::Ready(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Attempts(u64);
|
||||||
|
|
||||||
|
impl<Req: Clone, Res, E> tower::retry::Policy<Req, Res, E> for Attempts {
|
||||||
|
type Future = futures::future::Ready<Self>;
|
||||||
|
fn retry(&self, _: &Req, result: Result<&Res, &E>) -> Option<Self::Future> {
|
||||||
|
if result.is_err() {
|
||||||
|
Some(futures::future::ready(Attempts(self.0 - 1)))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clone_request(&self, req: &Req) -> Option<Req> {
|
||||||
|
Some(req.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
tracing_subscriber::fmt()
|
tracing_subscriber::fmt()
|
||||||
.with_max_level(LevelFilter::INFO)
|
.with_max_level(LevelFilter::DEBUG)
|
||||||
.init();
|
.init();
|
||||||
|
|
||||||
let mut rpc = Rpc::new_http("http://xmr-node.cakewallet.com:18081".to_string());
|
let urls = vec![
|
||||||
|
"http://xmr-node.cakewallet.com:18081".to_string(),
|
||||||
|
"http://node.sethforprivacy.com".to_string(),
|
||||||
|
"http://nodex.monerujo.io:18081".to_string(),
|
||||||
|
"http://node.community.rino.io:18081".to_string(),
|
||||||
|
"http://nodes.hashvault.pro:18081".to_string(),
|
||||||
|
"http://node.moneroworld.com:18089".to_string(),
|
||||||
|
"http://node.c3pool.com:18081".to_string(),
|
||||||
|
//
|
||||||
|
"http://xmr-node.cakewallet.com:18081".to_string(),
|
||||||
|
"http://node.sethforprivacy.com".to_string(),
|
||||||
|
"http://nodex.monerujo.io:18081".to_string(),
|
||||||
|
"http://node.community.rino.io:18081".to_string(),
|
||||||
|
"http://nodes.hashvault.pro:18081".to_string(),
|
||||||
|
"http://node.moneroworld.com:18089".to_string(),
|
||||||
|
"http://node.c3pool.com:18081".to_string(),
|
||||||
|
];
|
||||||
|
|
||||||
let res = rpc
|
let rpc_discoverer = tower::discover::ServiceList::new(
|
||||||
.ready()
|
urls.into_iter()
|
||||||
.await
|
.map(|url| tower::load::Constant::new(Rpc::new_http(url), 0)),
|
||||||
.unwrap()
|
);
|
||||||
.call(DatabaseRequest::ChainHeight)
|
let rpc_balance = Balance::new(rpc_discoverer);
|
||||||
|
let rpc_buffer = tower::buffer::Buffer::new(BoxService::new(rpc_balance), 3);
|
||||||
|
let rpc = tower::retry::Retry::new(Attempts(3), rpc_buffer);
|
||||||
|
|
||||||
|
let _hfs = HardForks::init(HardForkConfig::default(), rpc.clone())
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
println!("{:?}", res);
|
|
||||||
|
|
||||||
let mut hfs = HardForks::init(HardForkConfig::default(), &mut rpc)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
println!("{:?}", hfs);
|
|
||||||
|
|
||||||
hfs.new_block(HardFork::V2, 1009827, &mut rpc).await;
|
|
||||||
println!("{:?}", hfs);
|
|
||||||
|
|
||||||
hfs.new_block(HardFork::V2, 1009828, &mut rpc).await;
|
|
||||||
println!("{:?}", hfs);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use futures::stream::FuturesUnordered;
|
||||||
|
use futures::{StreamExt, TryFutureExt};
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
use monero_serai::block::BlockHeader;
|
use monero_serai::block::BlockHeader;
|
||||||
|
@ -195,7 +197,7 @@ impl Default for HardForkConfig {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
network: Network::Mainnet,
|
network: Network::Mainnet,
|
||||||
window: 3, //DEFAULT_WINDOW_SIZE,
|
window: DEFAULT_WINDOW_SIZE,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -213,9 +215,12 @@ pub struct HardForks {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HardForks {
|
impl HardForks {
|
||||||
pub async fn init<D>(config: HardForkConfig, database: &mut D) -> Result<Self, Error>
|
pub async fn init<D: Database + Clone>(
|
||||||
|
config: HardForkConfig,
|
||||||
|
mut database: D,
|
||||||
|
) -> Result<Self, Error>
|
||||||
where
|
where
|
||||||
D: Database,
|
D::Future: Send + 'static,
|
||||||
{
|
{
|
||||||
let DatabaseResponse::ChainHeight(chain_height) = database
|
let DatabaseResponse::ChainHeight(chain_height) = database
|
||||||
.ready()
|
.ready()
|
||||||
|
@ -231,13 +236,13 @@ impl HardForks {
|
||||||
0..chain_height
|
0..chain_height
|
||||||
};
|
};
|
||||||
|
|
||||||
let votes = get_votes_in_range(database, block_heights).await?;
|
let votes = get_votes_in_range(database.clone(), block_heights).await?;
|
||||||
|
|
||||||
if chain_height > config.window {
|
if chain_height > config.window {
|
||||||
assert_eq!(votes.total_votes(), config.window)
|
debug_assert_eq!(votes.total_votes(), config.window)
|
||||||
}
|
}
|
||||||
|
|
||||||
let latest_header = get_block_header(database, chain_height - 1).await?;
|
let latest_header = get_block_header(&mut database, chain_height - 1).await?;
|
||||||
|
|
||||||
let current_hardfork = HardFork::from_version(&latest_header.major_version)
|
let current_hardfork = HardFork::from_version(&latest_header.major_version)
|
||||||
.expect("Invalid major version in stored block");
|
.expect("Invalid major version in stored block");
|
||||||
|
@ -252,40 +257,108 @@ impl HardForks {
|
||||||
last_height: chain_height - 1,
|
last_height: chain_height - 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
// chain_height = height + 1
|
hfs.resync(&mut database).await?;
|
||||||
hfs.check_set_new_hf(chain_height);
|
|
||||||
|
hfs.check_set_new_hf();
|
||||||
|
|
||||||
|
tracing::info!("HardFork state: {:?}", hfs);
|
||||||
|
|
||||||
Ok(hfs)
|
Ok(hfs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(skip(self, database))]
|
||||||
|
async fn resync<D: Database>(&mut self, mut database: D) -> Result<(), Error> {
|
||||||
|
let DatabaseResponse::ChainHeight(mut chain_height) = database
|
||||||
|
.ready()
|
||||||
|
.await?
|
||||||
|
.call(DatabaseRequest::ChainHeight)
|
||||||
|
.await? else {
|
||||||
|
panic!("Database sent incorrect response")
|
||||||
|
};
|
||||||
|
|
||||||
|
tracing::debug!(
|
||||||
|
"chain-tip: {}, last height: {}",
|
||||||
|
chain_height - 1,
|
||||||
|
self.last_height
|
||||||
|
);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
while chain_height > self.last_height + 1 {
|
||||||
|
self.get_and_account_new_block(self.last_height + 1, &mut database)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
|
let DatabaseResponse::ChainHeight(c_h) = database
|
||||||
|
.ready()
|
||||||
|
.await?
|
||||||
|
.call(DatabaseRequest::ChainHeight)
|
||||||
|
.await? else {
|
||||||
|
panic!("Database sent incorrect response")
|
||||||
|
};
|
||||||
|
chain_height = c_h;
|
||||||
|
|
||||||
|
if chain_height == self.last_height + 1 {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
tracing::debug!(
|
||||||
|
"chain-tip: {}, last height: {}",
|
||||||
|
chain_height - 1,
|
||||||
|
self.last_height
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_and_account_new_block<D: Database>(&mut self, height: u64, mut database: D) {
|
||||||
|
let header = get_block_header(&mut database, height)
|
||||||
|
.await
|
||||||
|
.expect("Error retrieving block we should have in database");
|
||||||
|
|
||||||
|
self.new_block(HardFork::from_vote(&header.minor_version), height, database)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
pub fn check_block_version_vote(&self, version: &HardFork, vote: &HardFork) -> bool {
|
pub fn check_block_version_vote(&self, version: &HardFork, vote: &HardFork) -> bool {
|
||||||
&self.current_hardfork == version && vote >= &self.current_hardfork
|
&self.current_hardfork == version && vote >= &self.current_hardfork
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn new_block<D: Database>(&mut self, vote: HardFork, height: u64, database: &mut D) {
|
pub async fn new_block<D: Database>(&mut self, vote: HardFork, height: u64, mut database: D) {
|
||||||
assert_eq!(self.last_height + 1, height);
|
debug_assert_eq!(self.last_height + 1, height);
|
||||||
self.last_height += 1;
|
self.last_height += 1;
|
||||||
|
|
||||||
|
tracing::debug!(
|
||||||
|
"Accounting for new blocks vote, height: {}, vote: {:?}",
|
||||||
|
self.last_height,
|
||||||
|
vote
|
||||||
|
);
|
||||||
|
|
||||||
self.votes.add_vote_for_hf(&vote);
|
self.votes.add_vote_for_hf(&vote);
|
||||||
|
|
||||||
for offset in self.config.window..self.votes.total_votes() {
|
for offset in self.config.window..self.votes.total_votes() {
|
||||||
let header = get_block_header(database, height - offset)
|
let header = get_block_header(&mut database, height - offset)
|
||||||
.await
|
.await
|
||||||
.expect("Error retrieving block we should have in database");
|
.expect("Error retrieving block we should have in database");
|
||||||
self.votes
|
|
||||||
.remove_vote_for_hf(&HardFork::from_vote(&header.minor_version));
|
let vote = HardFork::from_vote(&header.minor_version);
|
||||||
|
tracing::debug!(
|
||||||
|
"Removing block {} vote ({:?}) as they have left the window",
|
||||||
|
height - offset,
|
||||||
|
vote
|
||||||
|
);
|
||||||
|
|
||||||
|
self.votes.remove_vote_for_hf(&vote);
|
||||||
}
|
}
|
||||||
|
|
||||||
if height > self.config.window {
|
if height > self.config.window {
|
||||||
assert_eq!(self.votes.total_votes(), self.config.window);
|
debug_assert_eq!(self.votes.total_votes(), self.config.window);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.check_set_new_hf(height + 1)
|
self.check_set_new_hf()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_set_new_hf(&mut self, height: u64) {
|
fn check_set_new_hf(&mut self) {
|
||||||
while let Some(new_hf) = self.next_hardfork {
|
while let Some(new_hf) = self.next_hardfork {
|
||||||
if height >= new_hf.fork_height(&self.config.network)
|
if self.last_height + 1 >= new_hf.fork_height(&self.config.network)
|
||||||
&& self.votes.get_votes_for_hf(&new_hf)
|
&& self.votes.get_votes_for_hf(&new_hf)
|
||||||
>= new_hf.votes_needed(&self.config.network, self.config.window)
|
>= new_hf.votes_needed(&self.config.network, self.config.window)
|
||||||
{
|
{
|
||||||
|
@ -303,18 +376,25 @@ impl HardForks {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(skip(database))]
|
#[instrument(skip(database))]
|
||||||
async fn get_votes_in_range<D: Database>(
|
async fn get_votes_in_range<D: Database + Clone>(
|
||||||
database: &mut D,
|
database: D,
|
||||||
block_heights: Range<u64>,
|
block_heights: Range<u64>,
|
||||||
) -> Result<HFVotes, Error> {
|
) -> Result<HFVotes, Error>
|
||||||
|
where
|
||||||
|
D::Future: Send + 'static,
|
||||||
|
{
|
||||||
let mut votes = HFVotes::default();
|
let mut votes = HFVotes::default();
|
||||||
|
|
||||||
for height in block_heights {
|
let mut fut =
|
||||||
let header = get_block_header(database, height).await?;
|
FuturesUnordered::from_iter(block_heights.map(|height| {
|
||||||
|
get_block_header(database.clone(), height).map_ok(move |res| (height, res))
|
||||||
|
}));
|
||||||
|
|
||||||
|
while let Some(res) = fut.next().await {
|
||||||
|
let (height, header): (u64, BlockHeader) = res?;
|
||||||
let vote = HardFork::from_vote(&header.minor_version);
|
let vote = HardFork::from_vote(&header.minor_version);
|
||||||
|
|
||||||
tracing::info!("Block vote for height: {} = {:?}", height, vote);
|
tracing::debug!("Block vote for height: {} = {:?}", height, vote);
|
||||||
|
|
||||||
votes.add_vote_for_hf(&HardFork::from_vote(&header.minor_version));
|
votes.add_vote_for_hf(&HardFork::from_vote(&header.minor_version));
|
||||||
}
|
}
|
||||||
|
@ -323,7 +403,7 @@ async fn get_votes_in_range<D: Database>(
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_block_header<D: Database>(
|
async fn get_block_header<D: Database>(
|
||||||
database: &mut D,
|
database: D,
|
||||||
block_id: impl Into<BlockID>,
|
block_id: impl Into<BlockID>,
|
||||||
) -> Result<BlockHeader, Error> {
|
) -> Result<BlockHeader, Error> {
|
||||||
let DatabaseResponse::BlockHeader(header) = database
|
let DatabaseResponse::BlockHeader(header) = database
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
use tower::ServiceExt;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
pub mod genesis;
|
pub mod genesis;
|
||||||
pub mod hardforks;
|
pub mod hardforks;
|
||||||
|
@ -23,7 +25,7 @@ impl<T: tower::Service<DatabaseRequest, Response = DatabaseResponse, Error = tow
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum DatabaseRequest {
|
pub enum DatabaseRequest {
|
||||||
BlockHeader(cuprate_common::BlockID),
|
BlockHeader(cuprate_common::BlockID),
|
||||||
ChainHeight,
|
ChainHeight,
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
use futures::lock::{OwnedMutexGuard, OwnedMutexLockFuture};
|
use futures::lock::{OwnedMutexGuard, OwnedMutexLockFuture};
|
||||||
use futures::{FutureExt, TryFutureExt};
|
use futures::{FutureExt, TryFutureExt};
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
|
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::sync::Arc;
|
use std::sync::{Arc, Mutex};
|
||||||
use std::task::{Context, Poll};
|
use std::task::{Context, Poll};
|
||||||
|
|
||||||
use monero_serai::rpc::{HttpRpc, RpcConnection};
|
use monero_serai::rpc::{HttpRpc, RpcConnection};
|
||||||
|
use tower::BoxError;
|
||||||
|
|
||||||
use cuprate_common::BlockID;
|
use cuprate_common::BlockID;
|
||||||
|
|
||||||
|
@ -19,6 +21,7 @@ enum RpcState<R: RpcConnection> {
|
||||||
pub struct Rpc<R: RpcConnection>(
|
pub struct Rpc<R: RpcConnection>(
|
||||||
Arc<futures::lock::Mutex<monero_serai::rpc::Rpc<R>>>,
|
Arc<futures::lock::Mutex<monero_serai::rpc::Rpc<R>>>,
|
||||||
RpcState<R>,
|
RpcState<R>,
|
||||||
|
Arc<Mutex<bool>>,
|
||||||
);
|
);
|
||||||
|
|
||||||
impl Rpc<HttpRpc> {
|
impl Rpc<HttpRpc> {
|
||||||
|
@ -27,22 +30,27 @@ impl Rpc<HttpRpc> {
|
||||||
Rpc(
|
Rpc(
|
||||||
Arc::new(futures::lock::Mutex::new(http_rpc)),
|
Arc::new(futures::lock::Mutex::new(http_rpc)),
|
||||||
RpcState::Locked,
|
RpcState::Locked,
|
||||||
|
Arc::new(Mutex::new(false)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: RpcConnection> Clone for Rpc<R> {
|
impl<R: RpcConnection> Clone for Rpc<R> {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Rpc(Arc::clone(&self.0), RpcState::Locked)
|
Rpc(Arc::clone(&self.0), RpcState::Locked, Arc::clone(&self.2))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: RpcConnection + Send + Sync + 'static> tower::Service<DatabaseRequest> for Rpc<R> {
|
impl<R: RpcConnection + Send + Sync + 'static> tower::Service<DatabaseRequest> for Rpc<R> {
|
||||||
type Response = DatabaseResponse;
|
type Response = DatabaseResponse;
|
||||||
type Error = tower::BoxError;
|
type Error = tower::BoxError;
|
||||||
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + 'static>>;
|
type Future =
|
||||||
|
Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send + 'static>>;
|
||||||
|
|
||||||
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||||
|
if *self.2.lock().unwrap() {
|
||||||
|
return Poll::Ready(Err("Rpc has errored".into()));
|
||||||
|
}
|
||||||
loop {
|
loop {
|
||||||
match &mut self.1 {
|
match &mut self.1 {
|
||||||
RpcState::Locked => self.1 = RpcState::Acquiring(self.0.clone().lock_owned()),
|
RpcState::Locked => self.1 = RpcState::Acquiring(self.0.clone().lock_owned()),
|
||||||
|
@ -59,28 +67,45 @@ impl<R: RpcConnection + Send + Sync + 'static> tower::Service<DatabaseRequest> f
|
||||||
panic!("poll_ready was not called first!");
|
panic!("poll_ready was not called first!");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let err = self.2.clone();
|
||||||
|
|
||||||
match req {
|
match req {
|
||||||
DatabaseRequest::ChainHeight => async move {
|
DatabaseRequest::ChainHeight => async move {
|
||||||
rpc.get_height()
|
let res = rpc
|
||||||
|
.get_height()
|
||||||
.map_ok(|height| DatabaseResponse::ChainHeight(height.try_into().unwrap()))
|
.map_ok(|height| DatabaseResponse::ChainHeight(height.try_into().unwrap()))
|
||||||
.map_err(Into::into)
|
.map_err(Into::into)
|
||||||
.await
|
.await;
|
||||||
|
if res.is_err() {
|
||||||
|
*err.lock().unwrap() = true;
|
||||||
|
}
|
||||||
|
res
|
||||||
}
|
}
|
||||||
.boxed(),
|
.boxed(),
|
||||||
|
|
||||||
DatabaseRequest::BlockHeader(id) => match id {
|
DatabaseRequest::BlockHeader(id) => match id {
|
||||||
BlockID::Hash(hash) => async move {
|
BlockID::Hash(hash) => async move {
|
||||||
rpc.get_block(hash)
|
let res = rpc
|
||||||
|
.get_block(hash)
|
||||||
.map_ok(|block| DatabaseResponse::BlockHeader(block.header))
|
.map_ok(|block| DatabaseResponse::BlockHeader(block.header))
|
||||||
.map_err(Into::into)
|
.map_err(Into::<BoxError>::into)
|
||||||
.await
|
.await;
|
||||||
|
if res.is_err() {
|
||||||
|
*err.lock().unwrap() = true;
|
||||||
|
}
|
||||||
|
res
|
||||||
}
|
}
|
||||||
.boxed(),
|
.boxed(),
|
||||||
BlockID::Height(height) => async move {
|
BlockID::Height(height) => async move {
|
||||||
rpc.get_block_by_number(height.try_into().unwrap())
|
let res = rpc
|
||||||
|
.get_block_by_number(height.try_into().unwrap())
|
||||||
.map_ok(|block| DatabaseResponse::BlockHeader(block.header))
|
.map_ok(|block| DatabaseResponse::BlockHeader(block.header))
|
||||||
.map_err(Into::into)
|
.map_err(Into::into)
|
||||||
.await
|
.await;
|
||||||
|
if res.is_err() {
|
||||||
|
*err.lock().unwrap() = true;
|
||||||
|
}
|
||||||
|
res
|
||||||
}
|
}
|
||||||
.boxed(),
|
.boxed(),
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in a new issue