use crate::{
BlockData, ColdReceipt, ColdResult, ColdStorageBackend, ColdStorageRead, ColdStorageWrite,
Confirmed, Filter, HeaderSpecifier, ReceiptSpecifier, RpcLog, SignetEventsSpecifier,
StreamParams, TransactionSpecifier, ZenithHeaderSpecifier,
};
use alloy::primitives::BlockNumber;
use signet_storage_types::{DbSignetEvent, DbZenithHeader, RecoveredTx, SealedHeader};
use std::{future::Future, pin::Pin, sync::Arc, time::Duration};
pub type StorageFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
pub struct ErasedBackend(Arc<dyn DynColdStorageBackend>);
impl ErasedBackend {
pub fn new<B: ColdStorageBackend>(backend: B) -> Self {
Self(Arc::new(backend))
}
pub const fn from_arc(arc: Arc<dyn DynColdStorageBackend>) -> Self {
Self(arc)
}
pub fn as_dyn(&self) -> &(dyn DynColdStorageBackend + 'static) {
&*self.0
}
pub fn into_arc(self) -> Arc<dyn DynColdStorageBackend> {
self.0
}
}
impl Clone for ErasedBackend {
fn clone(&self) -> Self {
Self(Arc::clone(&self.0))
}
}
impl std::fmt::Debug for ErasedBackend {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("ErasedBackend").finish()
}
}
pub trait DynColdStorageBackend: Send + Sync + 'static {
fn dyn_get_header<'a>(
&'a self,
spec: HeaderSpecifier,
) -> StorageFuture<'a, ColdResult<Option<SealedHeader>>>;
fn dyn_get_headers<'a>(
&'a self,
specs: Vec<HeaderSpecifier>,
) -> StorageFuture<'a, ColdResult<Vec<Option<SealedHeader>>>>;
fn dyn_get_transaction<'a>(
&'a self,
spec: TransactionSpecifier,
) -> StorageFuture<'a, ColdResult<Option<Confirmed<RecoveredTx>>>>;
fn dyn_get_transactions_in_block<'a>(
&'a self,
block: BlockNumber,
) -> StorageFuture<'a, ColdResult<Vec<RecoveredTx>>>;
fn dyn_get_transaction_count<'a>(
&'a self,
block: BlockNumber,
) -> StorageFuture<'a, ColdResult<u64>>;
fn dyn_get_receipt<'a>(
&'a self,
spec: ReceiptSpecifier,
) -> StorageFuture<'a, ColdResult<Option<ColdReceipt>>>;
fn dyn_get_receipts_in_block<'a>(
&'a self,
block: BlockNumber,
) -> StorageFuture<'a, ColdResult<Vec<ColdReceipt>>>;
fn dyn_get_signet_events<'a>(
&'a self,
spec: SignetEventsSpecifier,
) -> StorageFuture<'a, ColdResult<Vec<DbSignetEvent>>>;
fn dyn_get_zenith_header<'a>(
&'a self,
spec: ZenithHeaderSpecifier,
) -> StorageFuture<'a, ColdResult<Option<DbZenithHeader>>>;
fn dyn_get_zenith_headers<'a>(
&'a self,
spec: ZenithHeaderSpecifier,
) -> StorageFuture<'a, ColdResult<Vec<DbZenithHeader>>>;
fn dyn_get_latest_block<'a>(&'a self) -> StorageFuture<'a, ColdResult<Option<BlockNumber>>>;
fn dyn_get_logs<'a>(
&'a self,
filter: &'a Filter,
max_logs: usize,
) -> StorageFuture<'a, ColdResult<Vec<RpcLog>>>;
fn dyn_produce_log_stream<'a>(
&'a self,
filter: &'a Filter,
params: StreamParams,
) -> StorageFuture<'a, ()>;
fn dyn_append_block<'a>(&'a self, data: BlockData) -> StorageFuture<'a, ColdResult<()>>;
fn dyn_append_blocks<'a>(&'a self, data: Vec<BlockData>) -> StorageFuture<'a, ColdResult<()>>;
fn dyn_truncate_above<'a>(&'a self, block: BlockNumber) -> StorageFuture<'a, ColdResult<()>>;
fn dyn_drain_above<'a>(
&'a self,
block: BlockNumber,
) -> StorageFuture<'a, ColdResult<Vec<Vec<ColdReceipt>>>>;
fn dyn_read_timeout(&self) -> Option<Duration>;
fn dyn_write_timeout(&self) -> Option<Duration>;
}
impl<B: ColdStorageBackend> DynColdStorageBackend for B {
fn dyn_get_header<'a>(
&'a self,
spec: HeaderSpecifier,
) -> StorageFuture<'a, ColdResult<Option<SealedHeader>>> {
Box::pin(<B as ColdStorageRead>::get_header(self, spec))
}
fn dyn_get_headers<'a>(
&'a self,
specs: Vec<HeaderSpecifier>,
) -> StorageFuture<'a, ColdResult<Vec<Option<SealedHeader>>>> {
Box::pin(<B as ColdStorageRead>::get_headers(self, specs))
}
fn dyn_get_transaction<'a>(
&'a self,
spec: TransactionSpecifier,
) -> StorageFuture<'a, ColdResult<Option<Confirmed<RecoveredTx>>>> {
Box::pin(<B as ColdStorageRead>::get_transaction(self, spec))
}
fn dyn_get_transactions_in_block<'a>(
&'a self,
block: BlockNumber,
) -> StorageFuture<'a, ColdResult<Vec<RecoveredTx>>> {
Box::pin(<B as ColdStorageRead>::get_transactions_in_block(self, block))
}
fn dyn_get_transaction_count<'a>(
&'a self,
block: BlockNumber,
) -> StorageFuture<'a, ColdResult<u64>> {
Box::pin(<B as ColdStorageRead>::get_transaction_count(self, block))
}
fn dyn_get_receipt<'a>(
&'a self,
spec: ReceiptSpecifier,
) -> StorageFuture<'a, ColdResult<Option<ColdReceipt>>> {
Box::pin(<B as ColdStorageRead>::get_receipt(self, spec))
}
fn dyn_get_receipts_in_block<'a>(
&'a self,
block: BlockNumber,
) -> StorageFuture<'a, ColdResult<Vec<ColdReceipt>>> {
Box::pin(<B as ColdStorageRead>::get_receipts_in_block(self, block))
}
fn dyn_get_signet_events<'a>(
&'a self,
spec: SignetEventsSpecifier,
) -> StorageFuture<'a, ColdResult<Vec<DbSignetEvent>>> {
Box::pin(<B as ColdStorageRead>::get_signet_events(self, spec))
}
fn dyn_get_zenith_header<'a>(
&'a self,
spec: ZenithHeaderSpecifier,
) -> StorageFuture<'a, ColdResult<Option<DbZenithHeader>>> {
Box::pin(<B as ColdStorageRead>::get_zenith_header(self, spec))
}
fn dyn_get_zenith_headers<'a>(
&'a self,
spec: ZenithHeaderSpecifier,
) -> StorageFuture<'a, ColdResult<Vec<DbZenithHeader>>> {
Box::pin(<B as ColdStorageRead>::get_zenith_headers(self, spec))
}
fn dyn_get_latest_block<'a>(&'a self) -> StorageFuture<'a, ColdResult<Option<BlockNumber>>> {
Box::pin(<B as ColdStorageRead>::get_latest_block(self))
}
fn dyn_get_logs<'a>(
&'a self,
filter: &'a Filter,
max_logs: usize,
) -> StorageFuture<'a, ColdResult<Vec<RpcLog>>> {
Box::pin(<B as ColdStorageRead>::get_logs(self, filter, max_logs))
}
fn dyn_produce_log_stream<'a>(
&'a self,
filter: &'a Filter,
params: StreamParams,
) -> StorageFuture<'a, ()> {
Box::pin(<B as ColdStorageRead>::produce_log_stream(self, filter, params))
}
fn dyn_append_block<'a>(&'a self, data: BlockData) -> StorageFuture<'a, ColdResult<()>> {
Box::pin(<B as ColdStorageWrite>::append_block(self, data))
}
fn dyn_append_blocks<'a>(&'a self, data: Vec<BlockData>) -> StorageFuture<'a, ColdResult<()>> {
Box::pin(<B as ColdStorageWrite>::append_blocks(self, data))
}
fn dyn_truncate_above<'a>(&'a self, block: BlockNumber) -> StorageFuture<'a, ColdResult<()>> {
Box::pin(<B as ColdStorageWrite>::truncate_above(self, block))
}
fn dyn_drain_above<'a>(
&'a self,
block: BlockNumber,
) -> StorageFuture<'a, ColdResult<Vec<Vec<ColdReceipt>>>> {
Box::pin(<B as ColdStorageBackend>::drain_above(self, block))
}
fn dyn_read_timeout(&self) -> Option<Duration> {
<B as ColdStorageBackend>::read_timeout(self)
}
fn dyn_write_timeout(&self) -> Option<Duration> {
<B as ColdStorageBackend>::write_timeout(self)
}
}
const _: fn() = || {
fn _assert_object_safe(_: &dyn DynColdStorageBackend) {}
};
impl ColdStorageRead for ErasedBackend {
fn get_header(
&self,
spec: HeaderSpecifier,
) -> impl Future<Output = ColdResult<Option<SealedHeader>>> + Send {
self.0.dyn_get_header(spec)
}
fn get_headers(
&self,
specs: Vec<HeaderSpecifier>,
) -> impl Future<Output = ColdResult<Vec<Option<SealedHeader>>>> + Send {
self.0.dyn_get_headers(specs)
}
fn get_transaction(
&self,
spec: TransactionSpecifier,
) -> impl Future<Output = ColdResult<Option<Confirmed<RecoveredTx>>>> + Send {
self.0.dyn_get_transaction(spec)
}
fn get_transactions_in_block(
&self,
block: BlockNumber,
) -> impl Future<Output = ColdResult<Vec<RecoveredTx>>> + Send {
self.0.dyn_get_transactions_in_block(block)
}
fn get_transaction_count(
&self,
block: BlockNumber,
) -> impl Future<Output = ColdResult<u64>> + Send {
self.0.dyn_get_transaction_count(block)
}
fn get_receipt(
&self,
spec: ReceiptSpecifier,
) -> impl Future<Output = ColdResult<Option<ColdReceipt>>> + Send {
self.0.dyn_get_receipt(spec)
}
fn get_receipts_in_block(
&self,
block: BlockNumber,
) -> impl Future<Output = ColdResult<Vec<ColdReceipt>>> + Send {
self.0.dyn_get_receipts_in_block(block)
}
fn get_signet_events(
&self,
spec: SignetEventsSpecifier,
) -> impl Future<Output = ColdResult<Vec<DbSignetEvent>>> + Send {
self.0.dyn_get_signet_events(spec)
}
fn get_zenith_header(
&self,
spec: ZenithHeaderSpecifier,
) -> impl Future<Output = ColdResult<Option<DbZenithHeader>>> + Send {
self.0.dyn_get_zenith_header(spec)
}
fn get_zenith_headers(
&self,
spec: ZenithHeaderSpecifier,
) -> impl Future<Output = ColdResult<Vec<DbZenithHeader>>> + Send {
self.0.dyn_get_zenith_headers(spec)
}
fn get_latest_block(&self) -> impl Future<Output = ColdResult<Option<BlockNumber>>> + Send {
self.0.dyn_get_latest_block()
}
fn get_logs(
&self,
filter: &Filter,
max_logs: usize,
) -> impl Future<Output = ColdResult<Vec<RpcLog>>> + Send {
let this = self.clone();
let filter = filter.clone();
async move { DynColdStorageBackend::dyn_get_logs(this.0.as_ref(), &filter, max_logs).await }
}
fn produce_log_stream(
&self,
filter: &Filter,
params: StreamParams,
) -> impl Future<Output = ()> + Send {
let this = self.clone();
let filter = filter.clone();
async move {
DynColdStorageBackend::dyn_produce_log_stream(this.0.as_ref(), &filter, params).await
}
}
}
impl ColdStorageWrite for ErasedBackend {
fn append_block(&self, data: BlockData) -> impl Future<Output = ColdResult<()>> + Send {
self.0.dyn_append_block(data)
}
fn append_blocks(&self, data: Vec<BlockData>) -> impl Future<Output = ColdResult<()>> + Send {
self.0.dyn_append_blocks(data)
}
fn truncate_above(&self, block: BlockNumber) -> impl Future<Output = ColdResult<()>> + Send {
self.0.dyn_truncate_above(block)
}
}
impl ColdStorageBackend for ErasedBackend {
fn read_timeout(&self) -> Option<Duration> {
self.0.dyn_read_timeout()
}
fn write_timeout(&self) -> Option<Duration> {
self.0.dyn_write_timeout()
}
fn drain_above(
&self,
block: BlockNumber,
) -> impl Future<Output = ColdResult<Vec<Vec<ColdReceipt>>>> + Send {
self.0.dyn_drain_above(block)
}
}
const _: fn() = || {
const fn _assert_bound<B: ColdStorageBackend>() {}
_assert_bound::<ErasedBackend>();
};