diff --git a/src/db/error.rs b/src/db/error.rs index 853cd79..a3cc7a5 100644 --- a/src/db/error.rs +++ b/src/db/error.rs @@ -1,7 +1,5 @@ use std::fmt::Debug; -use crate::impl_sourceless_error; - /// Errors when initializing a SQL-based backend. #[cfg(feature = "database")] #[derive(Debug)] @@ -171,20 +169,3 @@ impl core::fmt::Display for UnitPeerStoreError { } } } - -/// Errors for the in-memory [`PeerStore`](crate) implementation. -#[derive(Debug)] -pub enum StatelessPeerStoreError { - /// There were no peers found. - NoPeers, -} - -impl core::fmt::Display for StatelessPeerStoreError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - StatelessPeerStoreError::NoPeers => write!(f, "no peers in the database."), - } - } -} - -impl_sourceless_error!(StatelessPeerStoreError); diff --git a/src/db/memory/mod.rs b/src/db/memory/mod.rs deleted file mode 100644 index 28e9727..0000000 --- a/src/db/memory/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -/// In-memory peer storage. -pub mod peers; diff --git a/src/db/memory/peers.rs b/src/db/memory/peers.rs deleted file mode 100644 index ac96a89..0000000 --- a/src/db/memory/peers.rs +++ /dev/null @@ -1,147 +0,0 @@ -use std::collections::HashMap; - -use bitcoin::{ - key::rand::{self, seq::IteratorRandom}, - p2p::address::AddrV2, -}; -use rand::{rngs::StdRng, SeedableRng}; - -use crate::{ - db::{error::StatelessPeerStoreError, traits::PeerStore, PeerStatus, PersistedPeer}, - prelude::FutureResult, -}; - -/// A simple peer store that does not save state in between sessions. -/// If DNS is not enabled, a node will require at least one peer to connect to. -/// Thereafter, the node will find peers to connect to throughout the session. -#[derive(Debug)] -pub struct StatelessPeerStore { - list: HashMap, -} - -impl StatelessPeerStore { - /// Construct a new in-memory store. - pub fn new() -> Self { - Self { - list: HashMap::new(), - } - } - - async fn update(&mut self, peer: PersistedPeer) -> Result<(), StatelessPeerStoreError> { - match peer.status { - PeerStatus::Gossiped => { - self.list - .entry(peer.clone().addr) - .and_modify(|stored| { - stored.port = peer.port; - stored.services = peer.services; - }) - .or_insert(peer); - Ok(()) - } - PeerStatus::Tried => Ok(()), - PeerStatus::Ban => { - self.list.insert(peer.clone().addr, peer); - Ok(()) - } - } - } - - async fn random(&mut self) -> Result { - let mut rng = StdRng::from_entropy(); - let random_peer = { - let iter = self - .list - .iter_mut() - .filter(|(_, peer)| peer.status != PeerStatus::Ban); - iter.choose(&mut rng).map(|(key, _)| key.clone()) - }; - match random_peer { - Some(ip) => self - .list - .remove(&ip) - .ok_or(StatelessPeerStoreError::NoPeers), - None => Err(StatelessPeerStoreError::NoPeers), - } - } - - async fn num_unbanned(&mut self) -> Result { - Ok(self - .list - .iter() - .filter(|(_, peer)| peer.status != PeerStatus::Ban) - .count() as u32) - } -} - -impl PeerStore for StatelessPeerStore { - type Error = StatelessPeerStoreError; - fn update(&mut self, peer: PersistedPeer) -> FutureResult<(), Self::Error> { - Box::pin(self.update(peer)) - } - - fn random(&mut self) -> FutureResult { - Box::pin(self.random()) - } - - fn num_unbanned(&mut self) -> FutureResult { - Box::pin(self.num_unbanned()) - } -} - -impl Default for StatelessPeerStore { - fn default() -> Self { - Self::new() - } -} - -#[cfg(test)] -mod tests { - use std::net::Ipv4Addr; - - use bitcoin::p2p::ServiceFlags; - - use super::*; - - #[tokio::test] - async fn test_stateless_store() { - let mut peer_store = StatelessPeerStore::new(); - let ip_1 = Ipv4Addr::new(1, 1, 1, 1); - let ip_2 = Ipv4Addr::new(2, 2, 2, 2); - let peer_1 = PersistedPeer::new( - AddrV2::Ipv4(ip_1), - 0, - ServiceFlags::NONE, - PeerStatus::Gossiped, - ); - let peer_2 = PersistedPeer::new( - AddrV2::Ipv4(ip_2), - 0, - ServiceFlags::NONE, - PeerStatus::Gossiped, - ); - let tor = AddrV2::TorV2([0; 10]); - let peer_3 = PersistedPeer::new(tor, 0, ServiceFlags::NONE, PeerStatus::Gossiped); - let try_peer_2 = - PersistedPeer::new(AddrV2::Ipv4(ip_2), 0, ServiceFlags::NONE, PeerStatus::Tried); - let ban_peer_1 = - PersistedPeer::new(AddrV2::Ipv4(ip_1), 0, ServiceFlags::NONE, PeerStatus::Ban); - peer_store.update(peer_1).await.unwrap(); - assert_eq!(peer_store.num_unbanned().await.unwrap(), 1); - peer_store.update(peer_2).await.unwrap(); - assert_eq!(peer_store.num_unbanned().await.unwrap(), 2); - peer_store.update(peer_3).await.unwrap(); - assert_eq!(peer_store.num_unbanned().await.unwrap(), 3); - peer_store.update(try_peer_2).await.unwrap(); - assert_eq!(peer_store.num_unbanned().await.unwrap(), 3); - peer_store.update(ban_peer_1).await.unwrap(); - assert_eq!(peer_store.num_unbanned().await.unwrap(), 2); - let _ = peer_store.random().await.unwrap(); - assert_eq!(peer_store.num_unbanned().await.unwrap(), 1); - let _ = peer_store.random().await.unwrap(); - assert_eq!(peer_store.num_unbanned().await.unwrap(), 0); - assert_eq!(peer_store.list.len(), 1); - let last_peer = peer_store.random().await; - assert!(last_peer.is_err()); - } -} diff --git a/src/db/mod.rs b/src/db/mod.rs index 4abb3f7..a08a13c 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -12,8 +12,6 @@ use bitcoin::p2p::ServiceFlags; /// Errors a database backend may produce. pub mod error; -/// In-memory persistence trait implementations for light-weight nodes running on constrained or semi-trusted setups. -pub mod memory; /// Persistence traits defined with SQL Lite to store data between sessions. #[cfg(feature = "database")] pub mod sqlite; diff --git a/src/lib.rs b/src/lib.rs index 8f81051..aea2ff9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -111,9 +111,6 @@ pub use chain::checkpoints::{ HeaderCheckpoint, MAINNET_HEADER_CP, SIGNET_HEADER_CP, TESTNET4_HEADER_CP, }; -#[doc(inline)] -pub use db::memory::peers::StatelessPeerStore; - #[cfg(feature = "database")] #[doc(inline)] pub use db::sqlite::{headers::SqliteHeaderDb, peers::SqlitePeerDb}; diff --git a/tests/core.rs b/tests/core.rs index 7117bce..f79bdb2 100644 --- a/tests/core.rs +++ b/tests/core.rs @@ -15,7 +15,6 @@ use kyoto::{ client::{Client, Receiver}, node::Node, }, - db::memory::peers::StatelessPeerStore, BlockHash, Event, Log, NodeState, ServiceFlags, SqliteHeaderDb, SqlitePeerDb, TrustedPeer, }; use tokio::sync::mpsc::UnboundedReceiver; @@ -615,9 +614,9 @@ async fn test_signet_syncs() { let host = (IpAddr::from(Ipv4Addr::new(68, 47, 229, 218)), None); let builder = kyoto::core::builder::NodeBuilder::new(bitcoin::Network::Signet); let (node, client) = builder - .add_peers(vec![host.into()]) + .add_peer(host) .add_scripts(set) - .build_with_databases(StatelessPeerStore::new(), ()); + .build_with_databases((), ()); tokio::task::spawn(async move { node.run().await }); async fn print_and_sync(mut client: Client) { loop {