lite-rpc/blockstore/src/block_stores/multiple_strategy_block_sto...

155 lines
5.4 KiB
Rust

use crate::block_stores::faithful_history::faithful_block_store::FaithfulBlockStore;
use crate::block_stores::postgres::postgres_block_store_query::PostgresQueryBlockStore;
use anyhow::{bail, Context, Result};
use log::{debug, trace};
use solana_lite_rpc_core::structures::produced_block::ProducedBlock;
use solana_rpc_client::nonblocking::rpc_client::RpcClient;
use solana_sdk::slot_history::Slot;
use std::ops::{Deref, RangeInclusive};
use std::sync::Arc;
#[derive(Debug, Clone)]
pub enum BlockSource {
// serve two epochs from postgres
RecentEpochDatabase,
// serve epochs older than two from faithful_history service
FaithfulArchive,
}
#[derive(Debug, Clone)]
pub struct BlockStorageData {
// note: commitment_config is the actual commitment level
pub block: ProducedBlock,
// meta data
pub result_source: BlockSource,
}
impl Deref for BlockStorageData {
type Target = ProducedBlock;
fn deref(&self) -> &Self::Target {
&self.block
}
}
// you might need to add a read-cache instead
pub struct MultipleStrategyBlockStorage {
block_storage_query: PostgresQueryBlockStore,
// note supported ATM
faithful_block_storage: Option<FaithfulBlockStore>, // to fetch legacy blocks from faithful_history
// last_confirmed_slot: Arc<AtomicU64>,
}
impl MultipleStrategyBlockStorage {
pub fn new(
block_storage_query: PostgresQueryBlockStore,
_faithful_rpc_client: Option<Arc<RpcClient>>,
) -> Self {
Self {
block_storage_query,
// faithful_history not used ATM
faithful_block_storage: None,
// faithful_block_storage: faithful_rpc_client.map(|rpc| FaithfulBlockStore::new(rpc)),
}
}
// we need to build the slots from right to left
pub async fn get_slot_range(&self) -> RangeInclusive<Slot> {
// merge them
let persistent_storage_range = self.block_storage_query.get_slot_range().await;
trace!("Persistent storage range: {:?}", persistent_storage_range);
let mut lower = *persistent_storage_range.start();
if let Some(faithful_block_storage) = &self.faithful_block_storage {
let faithful_storage_range = faithful_block_storage.get_slot_range();
trace!("Faithful storage range: {:?}", faithful_storage_range);
if lower.saturating_sub(*faithful_storage_range.end()) <= 1 {
// move the lower bound to the left
lower = lower.min(*faithful_storage_range.start());
}
}
let merged = RangeInclusive::new(lower, *persistent_storage_range.end());
trace!(
"Merged range from database + faithful_history: {:?}",
merged
);
merged
}
// lookup confirmed or finalized block from either our blockstore or faithful_history
// TODO find better method name
pub async fn query_block(
&self,
slot: solana_sdk::slot_history::Slot,
) -> Result<BlockStorageData> {
// TODO this check is optional and might be moved to the caller
// if slot > last_confirmed_slot {
// bail!(format!(
// "Block {} not found (last_confirmed_slot={})",
// slot, last_confirmed_slot
// ));
// }
// TODO: use a smarter strategy to decide about the cutoff
// current strategy:
// 1. check if requested slot is in min-max range served from Postgres
// 2.1. if yes; fetch from Postgres
// 2.2. if not: try to fetch from faithful_history
match self.block_storage_query.is_block_in_range(slot).await {
true => {
debug!(
"Assume block {} to be available in persistent block-storage",
slot,
);
let lookup = self
.block_storage_query
.query_block(slot)
.await
.context(format!("block {} not found although it was in range", slot));
return lookup.map(|b| BlockStorageData {
block: b,
result_source: BlockSource::RecentEpochDatabase,
});
}
false => {
debug!(
"Block {} not found in persistent block-storage - continue",
slot
);
}
}
if let Some(faithful_block_storage) = &self.faithful_block_storage {
match faithful_block_storage.get_block(slot).await {
Ok(block) => {
debug!(
"Lookup for block {} successful in faithful_history block-storage",
slot
);
Ok(BlockStorageData {
block,
result_source: BlockSource::FaithfulArchive,
})
}
Err(_) => {
debug!(
"Block {} not found in faithful_history storage - giving up",
slot
);
bail!(format!("Block {} not found in faithful_history", slot));
}
}
} else {
bail!(format!(
"Block {} not found - faithful_history not available",
slot
));
}
}
}