use crate::cidomap::FromStrErrDisplay;
use crate::graphql::GraphqlMetaExtension;
use chrono::{DateTime, Utc};
use core::fmt::{Debug, Display};
use core::hash::Hash;
use core::ops::Range;
use serde::Deserialize;
use serde::{Serialize, de::DeserializeOwned};
use sqlx::PgPool;
use std::sync::Arc;
pub(crate) mod sealed {
pub trait Sealed {}
}
pub trait BlockNumber:
Send
+ Sync
+ Unpin
+ Copy
+ Ord
+ Display
+ Debug
+ Hash
+ Sized
+ async_graphql::InputType
+ async_graphql::OutputType
+ sqlx::Type<sqlx::Postgres>
+ for<'a> sqlx::Decode<'a, sqlx::Postgres>
+ for<'a> sqlx::Encode<'a, sqlx::Postgres>
+ sqlx::postgres::PgHasArrayType
+ core::ops::Add<u16, Output = Self>
+ core::ops::Sub<u16, Output = Self>
+ FromStrErrDisplay
+ Serialize
+ DeserializeOwned
+ 'static
+ Into<u64>
{
const ZERO: Self;
const MAX: Self;
type EventOrder: EventOrder<BlockNumber = Self>;
type Range: BlockNumberRange<BlockNumber = Self>;
fn event_order(self) -> Self::EventOrder;
}
pub trait BlockNumberRange:
Send
+ Sync
+ Sized
+ Unpin
+ Copy
+ Debug
+ Eq
+ Default
+ 'static
+ sqlx::Type<sqlx::Postgres>
+ for<'a> sqlx::Encode<'a, sqlx::Postgres>
+ for<'a> sqlx::Decode<'a, sqlx::Postgres>
+ sqlx::postgres::PgHasArrayType
{
type BlockNumber: BlockNumber<Range = Self>;
fn bounds(self) -> (Self::BlockNumber, Option<Self::BlockNumber>);
fn new(lower: Self::BlockNumber, upper: Option<Self::BlockNumber>) -> Self;
}
pub trait BlockId:
Send
+ Sync
+ Unpin
+ Display
+ Debug
+ Default
+ Ord
+ Hash
+ Sized
+ async_graphql::InputType
+ 'static
{
type Network: Network;
fn latest() -> impl Future<Output = Result<Self, <Self::Network as Network>::Error>> + Send;
fn to_block_number(
self,
network: &Self::Network,
) -> impl Future<
Output = Result<<Self::Network as Network>::BlockNumber, <Self::Network as Network>::Error>,
> + Send;
}
pub trait AsBlockNumber {
type BlockNumber: BlockNumber;
fn as_block_number(&self) -> Self::BlockNumber;
}
pub trait AsEventOrder {
type EventOrder: EventOrder;
fn as_event_order(&self) -> Self::EventOrder;
}
pub trait EventOrder:
Copy
+ Ord
+ Display
+ Debug
+ Hash
+ From<Self::BlockNumber>
+ sqlx::Type<sqlx::Postgres>
+ for<'a> sqlx::Decode<'a, sqlx::Postgres>
+ for<'a> sqlx::Encode<'a, sqlx::Postgres>
+ Sized
+ Unpin
+ Send
+ Sync
+ 'static
{
type BlockNumber: BlockNumber;
fn block_number(self) -> Self::BlockNumber;
}
pub trait Block: Debug + Sized + Send + Sync + 'static {
type BlockNumber: BlockNumber;
fn to_timestamp(&self) -> DateTime<Utc>;
fn block_number(&self) -> Self::BlockNumber;
}
pub trait BlockGenerator: Sized + Send + 'static {
type Network: Network;
fn new(
network: Arc<Self::Network>,
) -> impl Future<Output = Result<Self, <Self::Network as Network>::Error>> + Send;
fn get_blocks(
&mut self,
request: BlockRequest<<Self::Network as Network>::BlockNumber>,
) -> impl Future<
Output = Result<
Vec<Arc<<Self::Network as Network>::FullBlock>>,
<Self::Network as Network>::Error,
>,
> + Send;
fn clear_cache(
&mut self,
before: <Self::Network as Network>::BlockNumber,
) -> impl Future<Output = Result<(), <Self::Network as Network>::Error>> + Send;
fn rollback_to_block(
&mut self,
block_number: <Self::Network as Network>::BlockNumber,
) -> impl Future<Output = Result<(), <Self::Network as Network>::Error>> + Send;
}
pub trait TriggerFilterStorage<N: Network>: Send + Sync + 'static + sealed::Sealed + Debug {
fn id(&self) -> uuid::Uuid;
fn block_number(&self) -> N::BlockNumber;
fn filter(&self) -> &N::TriggerFilter;
}
pub trait TriggerGenerator<S: TriggerFilterStorage<Self::Network>>:
Send + 'static + Sized + Debug
{
type Network: Network;
fn new(
network: Arc<Self::Network>,
) -> impl Future<Output = Result<Self, <Self::Network as Network>::Error>> + Send;
fn new_trigger_filter(&mut self, filter: Arc<S>)
-> Result<(), <Self::Network as Network>::Error>;
fn remove_trigger_filter(&mut self, filter: &S) -> Result<(), <Self::Network as Network>::Error>;
fn get_triggers(
&mut self,
range: BlockRange<<Self::Network as Network>::BlockNumber>,
) -> impl Future<
Output = Result<
Vec<(<Self::Network as Network>::Trigger, Arc<S>)>,
<Self::Network as Network>::Error,
>,
> + Send;
}
pub trait Network: Send + Sync + 'static {
type Error: Send + Sync + std::error::Error + 'static;
type InitConfig: Send + Sync + 'static;
type FullBlock: Block<BlockNumber = Self::BlockNumber>;
type BlockId: BlockId<Network = Self>;
type BlockNumber: BlockNumber<Range = Self::BlockNumberRange, EventOrder = Self::EventOrder>;
type BlockNumberRange: BlockNumberRange<BlockNumber = Self::BlockNumber>;
type BlockGenerator: BlockGenerator<Network = Self>;
type TriggerGenerator<S: TriggerFilterStorage<Self>>: TriggerGenerator<S, Network = Self>;
type TriggerFilter: Send + Sync + Clone + Debug + Serialize + DeserializeOwned + 'static;
type Trigger: Send
+ Sync
+ Debug
+ AsEventOrder<EventOrder = Self::EventOrder>
+ AsBlockNumber<BlockNumber = Self::BlockNumber>
+ 'static;
type EventOrder: EventOrder<BlockNumber = Self::BlockNumber>;
type GraphqlMetaExtension: GraphqlMetaExtension<Self>;
fn network_identifier() -> &'static str;
fn network_concurrency(&self) -> usize;
fn create(
config: Self::InitConfig,
db_pool: PgPool,
) -> impl Future<Output = Result<Arc<Self>, Self::Error>> + Send;
fn init(
&self,
transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
) -> impl Future<Output = Result<(), Self::Error>>;
fn chain_head_block(&self)
-> impl Future<Output = Result<Self::BlockNumber, Self::Error>> + Send;
fn wait_for_latest_block(
&self,
current_block: Self::BlockNumber,
) -> impl Future<Output = Result<LatestBlock<Self::BlockNumber>, Self::Error>> + Send;
fn persist_to_block(
&self,
block: Self::BlockNumber,
) -> impl Future<Output = Result<(), Self::Error>> + Send;
fn rollback_to_block(
&self,
block: Self::BlockNumber,
) -> impl Future<Output = Result<(), Self::Error>> + Send;
}
#[derive(Debug, Clone)]
pub struct LatestBlock<B: BlockNumber> {
rollback_to: Option<B>,
advance_to: B,
}
impl<B: BlockNumber> LatestBlock<B> {
pub fn new(advance_to: B) -> Self {
Self {
advance_to,
rollback_to: None,
}
}
pub fn with_rollback(mut self, rollback_to: B) -> Self {
assert!(
rollback_to <= self.advance_to,
"rollback_to {rollback_to} is <= advance_to {}",
self.advance_to
);
self.rollback_to = Some(rollback_to);
self
}
pub fn advance_to(&self) -> B {
self.advance_to
}
pub fn rollback_to(&self) -> Option<B> {
self.rollback_to
}
}
#[derive(Debug, Clone)]
pub enum BlockRequest<B: BlockNumber> {
Range(BlockRange<B>),
Sparse(Vec<B>),
}
impl<B: BlockNumber> From<Range<B>> for BlockRequest<B> {
fn from(r: Range<B>) -> Self {
Self::Range(r.into())
}
}
impl<B: BlockNumber> From<BlockRange<B>> for BlockRequest<B> {
fn from(r: BlockRange<B>) -> Self {
Self::Range(r)
}
}
impl<B: BlockNumber> From<Vec<B>> for BlockRequest<B> {
fn from(s: Vec<B>) -> Self {
Self::Sparse(s)
}
}
#[derive(Clone, PartialEq, Eq)]
pub struct BlockRange<B: BlockNumber>(pub Range<B>);
impl<B: BlockNumber> BlockRange<B> {
pub fn to_block_number_range(&self) -> B::Range {
<B::Range as BlockNumberRange>::new(self.start, Some(self.end))
}
}
impl<B: BlockNumber> From<Range<B>> for BlockRange<B> {
fn from(r: Range<B>) -> Self {
Self(r)
}
}
impl<B: BlockNumber> core::fmt::Debug for BlockRange<B> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.0.fmt(f)
}
}
impl<B: BlockNumber> core::fmt::Display for BlockRange<B> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.0.fmt(f)
}
}
impl<B: BlockNumber> core::ops::Deref for BlockRange<B> {
type Target = Range<B>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[derive(Deserialize, Serialize, Debug)]
pub struct ChainTrackerResponse<T: Block> {
pub last_block_stored: T,
pub last_block_in_chain: T::BlockNumber,
}