mod lifecycle;
use std::sync::Arc;
use std::time::Duration;
use crate::tip_cache::{AbortOnDrop, TipCache, TipRead, spawn_tip_refresh};
use crate::{ChainPlane, RpcRequestContext, RpcServerConfig};
#[derive(Debug)]
pub struct NativeTransactionService<S, C, R> {
submit: S,
chain: Arc<C>,
read: R,
config: RpcServerConfig,
tip_cache: TipCache,
_tip_refresh: Option<AbortOnDrop>,
}
impl<S, C, R> NativeTransactionService<S, C, R> {
fn request_context(&self) -> RpcRequestContext {
RpcRequestContext::new(self.config.request_timeout_ms.map(Duration::from_millis))
}
}
impl<S, C, R> NativeTransactionService<S, C, R>
where
C: ChainPlane,
{
pub fn new(submit: S, chain: C, read: R, config: RpcServerConfig) -> Self {
let chain = Arc::new(chain);
let tip_cache = TipCache::default();
let tip_refresh = spawn_tip_refresh(chain.clone(), tip_cache.clone(), &config);
Self {
submit,
chain,
read,
config,
tip_cache,
_tip_refresh: tip_refresh,
}
}
async fn cached_tip_state(&self, context: RpcRequestContext) -> TipRead {
self.tip_state_within(self.tip_reuse_window(), context)
.await
}
fn tip_reuse_window(&self) -> Duration {
if self.config.tip_refresh_interval_ms == 0 {
return Duration::ZERO;
}
Duration::from_millis(
self.config
.tip_refresh_interval_ms
.saturating_add(self.config.tip_probe_timeout_ms),
)
}
async fn fresh_tip_state(&self, context: RpcRequestContext) -> TipRead {
self.tip_state_within(Duration::ZERO, context).await
}
async fn tip_state_within(&self, window: Duration, context: RpcRequestContext) -> TipRead {
self.tip_cache
.reading(
window,
Duration::from_millis(self.config.tip_probe_timeout_ms),
context,
|probe_context| self.chain.chain_tip(probe_context),
)
.await
}
}
#[cfg(test)]
mod tests;