pub use crate::runtime_api::StatementSource;
use crate::{Hash, Statement, Topic, MAX_ANY_TOPICS, MAX_TOPICS};
use sp_core::{bounded_vec::BoundedVec, Bytes, ConstU32};
use std::collections::HashSet;
#[derive(Debug, Clone, Eq, PartialEq, thiserror::Error)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Error {
#[error("Database error: {0:?}")]
Db(String),
#[error("Decoding error: {0:?}")]
Decode(String),
#[error("Storage error: {0:?}")]
Storage(String),
#[error("Invalid configuration: {0}")]
InvalidConfig(String),
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
pub enum TopicFilter {
Any,
MatchAll(BoundedVec<Topic, ConstU32<{ MAX_TOPICS as u32 }>>),
MatchAny(BoundedVec<Topic, ConstU32<{ MAX_ANY_TOPICS as u32 }>>),
}
#[derive(Clone, Debug)]
pub enum OptimizedTopicFilter {
Any,
MatchAll(HashSet<Topic>),
MatchAny(HashSet<Topic>),
}
impl OptimizedTopicFilter {
pub fn matches(&self, statement: &Statement) -> bool {
match self {
OptimizedTopicFilter::Any => true,
OptimizedTopicFilter::MatchAll(topics) => {
statement.topics().iter().filter(|topic| topics.contains(*topic)).count() ==
topics.len()
},
OptimizedTopicFilter::MatchAny(topics) => {
statement.topics().iter().any(|topic| topics.contains(topic))
},
}
}
}
impl From<TopicFilter> for OptimizedTopicFilter {
fn from(filter: TopicFilter) -> Self {
match filter {
TopicFilter::Any => OptimizedTopicFilter::Any,
TopicFilter::MatchAll(topics) => {
let mut parsed_topics = HashSet::with_capacity(topics.len());
for topic in topics {
parsed_topics.insert(topic);
}
OptimizedTopicFilter::MatchAll(parsed_topics)
},
TopicFilter::MatchAny(topics) => {
let mut parsed_topics = HashSet::with_capacity(topics.len());
for topic in topics {
parsed_topics.insert(topic);
}
OptimizedTopicFilter::MatchAny(parsed_topics)
},
}
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "reason", rename_all = "camelCase"))]
pub enum RejectionReason {
DataTooLarge {
submitted_size: usize,
available_size: usize,
},
ChannelPriorityTooLow {
submitted_expiry: u64,
min_expiry: u64,
},
AccountFull {
submitted_expiry: u64,
min_expiry: u64,
},
StoreFull,
NoAllowance,
}
impl RejectionReason {
pub fn label(&self) -> &'static str {
match self {
RejectionReason::DataTooLarge { .. } => "data_too_large",
RejectionReason::ChannelPriorityTooLow { .. } => "channel_priority_too_low",
RejectionReason::AccountFull { .. } => "account_full",
RejectionReason::StoreFull => "store_full",
RejectionReason::NoAllowance => "no_allowance",
}
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "reason", rename_all = "camelCase"))]
pub enum InvalidReason {
NoProof,
BadProof,
EncodingTooLarge {
submitted_size: usize,
max_size: usize,
},
AlreadyExpired,
}
impl InvalidReason {
pub fn label(&self) -> &'static str {
match self {
InvalidReason::NoProof => "no_proof",
InvalidReason::BadProof => "bad_proof",
InvalidReason::EncodingTooLarge { .. } => "encoding_too_large",
InvalidReason::AlreadyExpired => "already_expired",
}
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "status", rename_all = "camelCase"))]
pub enum SubmitResult {
New,
Known,
KnownExpired,
Rejected(RejectionReason),
Invalid(InvalidReason),
InternalError(Error),
}
#[derive(Debug, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "event", content = "data", rename_all = "camelCase"))]
pub enum StatementEvent {
NewStatements {
statements: Vec<Bytes>,
#[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
remaining: Option<u32>,
},
}
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FilterDecision {
Skip,
Take,
Abort,
}
pub trait StatementStore: Send + Sync {
fn statements(&self) -> Result<Vec<(Hash, Statement)>>;
fn take_recent_statements(&self) -> Result<Vec<(Hash, Statement)>>;
fn statement(&self, hash: &Hash) -> Result<Option<Statement>>;
fn has_statement(&self, hash: &Hash) -> bool;
fn statement_hashes(&self) -> Vec<Hash>;
fn statements_by_hashes(
&self,
hashes: &[Hash],
filter: &mut dyn FnMut(&Hash, &[u8], &Statement) -> FilterDecision,
) -> Result<(Vec<(Hash, Statement)>, usize)>;
fn broadcasts(&self, match_all_topics: &[Topic]) -> Result<Vec<Vec<u8>>>;
fn posted(&self, match_all_topics: &[Topic], dest: [u8; 32]) -> Result<Vec<Vec<u8>>>;
fn posted_clear(&self, match_all_topics: &[Topic], dest: [u8; 32]) -> Result<Vec<Vec<u8>>>;
fn broadcasts_stmt(&self, match_all_topics: &[Topic]) -> Result<Vec<Vec<u8>>>;
fn posted_stmt(&self, match_all_topics: &[Topic], dest: [u8; 32]) -> Result<Vec<Vec<u8>>>;
fn posted_clear_stmt(&self, match_all_topics: &[Topic], dest: [u8; 32])
-> Result<Vec<Vec<u8>>>;
fn submit(&self, statement: Statement, source: StatementSource) -> SubmitResult;
fn remove(&self, hash: &Hash) -> Result<()>;
fn remove_by(&self, who: [u8; 32]) -> Result<()>;
}