reth_dns_discovery/
sync.rsuse crate::tree::{LinkEntry, TreeRootEntry};
use enr::EnrKeyUnambiguous;
use linked_hash_set::LinkedHashSet;
use secp256k1::SecretKey;
use std::{
collections::HashMap,
time::{Duration, Instant},
};
pub(crate) struct SyncTree<K: EnrKeyUnambiguous = SecretKey> {
root: TreeRootEntry,
link: LinkEntry<K>,
root_updated: Instant,
sync_state: SyncState,
resolved_links: HashMap<String, LinkEntry<K>>,
unresolved_links: LinkedHashSet<String>,
unresolved_nodes: LinkedHashSet<String>,
}
impl<K: EnrKeyUnambiguous> SyncTree<K> {
pub(crate) fn new(root: TreeRootEntry, link: LinkEntry<K>) -> Self {
Self {
root,
link,
root_updated: Instant::now(),
sync_state: SyncState::Pending,
resolved_links: Default::default(),
unresolved_links: Default::default(),
unresolved_nodes: Default::default(),
}
}
#[cfg(test)]
pub(crate) const fn root(&self) -> &TreeRootEntry {
&self.root
}
pub(crate) const fn link(&self) -> &LinkEntry<K> {
&self.link
}
pub(crate) fn resolved_links_mut(&mut self) -> &mut HashMap<String, LinkEntry<K>> {
&mut self.resolved_links
}
pub(crate) fn extend_children(
&mut self,
kind: ResolveKind,
children: impl IntoIterator<Item = String>,
) {
match kind {
ResolveKind::Enr => {
self.unresolved_nodes.extend(children);
}
ResolveKind::Link => {
self.unresolved_links.extend(children);
}
}
}
pub(crate) fn poll(&mut self, now: Instant, update_timeout: Duration) -> Option<SyncAction> {
match self.sync_state {
SyncState::Pending => {
self.sync_state = SyncState::Enr;
return Some(SyncAction::Link(self.root.link_root.clone()))
}
SyncState::Enr => {
self.sync_state = SyncState::Active;
return Some(SyncAction::Enr(self.root.enr_root.clone()))
}
SyncState::Link => {
self.sync_state = SyncState::Active;
return Some(SyncAction::Link(self.root.link_root.clone()))
}
SyncState::Active => {
if now > self.root_updated + update_timeout {
self.sync_state = SyncState::RootUpdate;
return Some(SyncAction::UpdateRoot)
}
}
SyncState::RootUpdate => return None,
}
if let Some(link) = self.unresolved_links.pop_front() {
return Some(SyncAction::Link(link))
}
let enr = self.unresolved_nodes.pop_front()?;
Some(SyncAction::Enr(enr))
}
pub(crate) fn update_root(&mut self, root: TreeRootEntry) {
let enr = root.enr_root == self.root.enr_root;
let link = root.link_root == self.root.link_root;
self.root = root;
self.root_updated = Instant::now();
let state = match (enr, link) {
(true, true) => {
self.unresolved_nodes.clear();
self.unresolved_links.clear();
SyncState::Pending
}
(true, _) => {
self.unresolved_nodes.clear();
SyncState::Enr
}
(_, true) => {
self.unresolved_links.clear();
SyncState::Link
}
_ => {
return
}
};
self.sync_state = state;
}
}
pub(crate) enum SyncAction {
UpdateRoot,
Enr(String),
Link(String),
}
enum SyncState {
RootUpdate,
Pending,
Enr,
Link,
Active,
}
pub(crate) enum ResolveKind {
Enr,
Link,
}
impl ResolveKind {
pub(crate) const fn is_link(&self) -> bool {
matches!(self, Self::Link)
}
}