sc_transaction_pool/graph/
listener.rsuse std::{collections::HashMap, fmt::Debug, hash};
use linked_hash_map::LinkedHashMap;
use log::trace;
use super::{watcher, BlockHash, ChainApi, ExtrinsicHash};
static LOG_TARGET: &str = "txpool::watcher";
pub trait EventHandler<C: ChainApi> {
fn broadcasted(&self, _hash: ExtrinsicHash<C>, _peers: Vec<String>) {}
fn ready(&self, _tx: ExtrinsicHash<C>) {}
fn future(&self, _tx: ExtrinsicHash<C>) {}
fn limits_enforced(&self, _tx: ExtrinsicHash<C>) {}
fn usurped(&self, _tx: ExtrinsicHash<C>, _by: ExtrinsicHash<C>) {}
fn dropped(&self, _tx: ExtrinsicHash<C>) {}
fn invalid(&self, _tx: ExtrinsicHash<C>) {}
fn pruned(&self, _tx: ExtrinsicHash<C>, _block_hash: BlockHash<C>, _tx_index: usize) {}
fn retracted(&self, _tx: ExtrinsicHash<C>, _block_hash: BlockHash<C>) {}
fn finality_timeout(&self, _tx: ExtrinsicHash<C>, _hash: BlockHash<C>) {}
fn finalized(&self, _tx: ExtrinsicHash<C>, _block_hash: BlockHash<C>, _tx_index: usize) {}
}
impl<C: ChainApi> EventHandler<C> for () {}
pub struct EventDispatcher<H: hash::Hash + Eq, C: ChainApi, L: EventHandler<C>> {
watchers: HashMap<H, watcher::Sender<H, BlockHash<C>>>,
finality_watchers: LinkedHashMap<ExtrinsicHash<C>, Vec<H>>,
event_handler: Option<L>,
}
const MAX_FINALITY_WATCHERS: usize = 512;
impl<H: hash::Hash + Eq + Debug, C: ChainApi, L: EventHandler<C>> Default
for EventDispatcher<H, C, L>
{
fn default() -> Self {
Self {
watchers: Default::default(),
finality_watchers: Default::default(),
event_handler: None,
}
}
}
impl<C: ChainApi, L: EventHandler<C>> EventDispatcher<ExtrinsicHash<C>, C, L> {
pub fn new_with_event_handler(event_handler: Option<L>) -> Self {
Self { event_handler, ..Default::default() }
}
fn fire<F>(&mut self, hash: &ExtrinsicHash<C>, fun: F)
where
F: FnOnce(&mut watcher::Sender<ExtrinsicHash<C>, ExtrinsicHash<C>>),
{
let clean = if let Some(h) = self.watchers.get_mut(hash) {
fun(h);
h.is_done()
} else {
false
};
if clean {
self.watchers.remove(hash);
}
}
pub fn create_watcher(
&mut self,
hash: ExtrinsicHash<C>,
) -> watcher::Watcher<ExtrinsicHash<C>, ExtrinsicHash<C>> {
let sender = self.watchers.entry(hash).or_insert_with(watcher::Sender::default);
sender.new_watcher(hash)
}
pub fn broadcasted(&mut self, hash: &ExtrinsicHash<C>, peers: Vec<String>) {
trace!(target: LOG_TARGET, "[{:?}] Broadcasted", hash);
self.fire(hash, |watcher| watcher.broadcast(peers.clone()));
self.event_handler.as_ref().map(|l| l.broadcasted(*hash, peers));
}
pub fn ready(&mut self, tx: &ExtrinsicHash<C>, old: Option<&ExtrinsicHash<C>>) {
trace!(target: LOG_TARGET, "[{:?}] Ready (replaced with {:?})", *tx, old);
self.fire(tx, |watcher| watcher.ready());
if let Some(old) = old {
self.fire(old, |watcher| watcher.usurped(*tx));
}
self.event_handler.as_ref().map(|l| l.ready(*tx));
}
pub fn future(&mut self, tx: &ExtrinsicHash<C>) {
trace!(target: LOG_TARGET, "[{:?}] Future", tx);
self.fire(tx, |watcher| watcher.future());
self.event_handler.as_ref().map(|l| l.future(*tx));
}
pub fn limits_enforced(&mut self, tx: &ExtrinsicHash<C>) {
trace!(target: LOG_TARGET, "[{:?}] Dropped (limits enforced)", tx);
self.fire(tx, |watcher| watcher.limit_enforced());
self.event_handler.as_ref().map(|l| l.limits_enforced(*tx));
}
pub fn usurped(&mut self, tx: &ExtrinsicHash<C>, by: &ExtrinsicHash<C>) {
trace!(target: LOG_TARGET, "[{:?}] Dropped (replaced with {:?})", tx, by);
self.fire(tx, |watcher| watcher.usurped(*by));
self.event_handler.as_ref().map(|l| l.usurped(*tx, *by));
}
pub fn dropped(&mut self, tx: &ExtrinsicHash<C>) {
trace!(target: LOG_TARGET, "[{:?}] Dropped", tx);
self.fire(tx, |watcher| watcher.dropped());
self.event_handler.as_ref().map(|l| l.dropped(*tx));
}
pub fn invalid(&mut self, tx: &ExtrinsicHash<C>) {
trace!(target: LOG_TARGET, "[{:?}] Extrinsic invalid", tx);
self.fire(tx, |watcher| watcher.invalid());
self.event_handler.as_ref().map(|l| l.invalid(*tx));
}
pub fn pruned(&mut self, block_hash: BlockHash<C>, tx: &ExtrinsicHash<C>) {
trace!(target: LOG_TARGET, "[{:?}] Pruned at {:?}", tx, block_hash);
let txs = self.finality_watchers.entry(block_hash).or_insert(vec![]);
txs.push(*tx);
let tx_index = txs.len() - 1;
self.fire(tx, |watcher| watcher.in_block(block_hash, tx_index));
self.event_handler.as_ref().map(|l| l.pruned(*tx, block_hash, tx_index));
while self.finality_watchers.len() > MAX_FINALITY_WATCHERS {
if let Some((hash, txs)) = self.finality_watchers.pop_front() {
for tx in txs {
self.fire(&tx, |watcher| watcher.finality_timeout(hash));
self.event_handler.as_ref().map(|l| l.finality_timeout(tx, block_hash));
}
}
}
}
pub fn retracted(&mut self, block_hash: BlockHash<C>) {
if let Some(hashes) = self.finality_watchers.remove(&block_hash) {
for hash in hashes {
self.fire(&hash, |watcher| watcher.retracted(block_hash));
self.event_handler.as_ref().map(|l| l.retracted(hash, block_hash));
}
}
}
pub fn finalized(&mut self, block_hash: BlockHash<C>) {
if let Some(hashes) = self.finality_watchers.remove(&block_hash) {
for (tx_index, hash) in hashes.into_iter().enumerate() {
log::trace!(
target: LOG_TARGET,
"[{:?}] Sent finalization event (block {:?})",
hash,
block_hash,
);
self.fire(&hash, |watcher| watcher.finalized(block_hash, tx_index));
self.event_handler.as_ref().map(|l| l.finalized(hash, block_hash, tx_index));
}
}
}
pub fn watched_transactions(&self) -> impl Iterator<Item = &ExtrinsicHash<C>> {
self.watchers.keys()
}
}