#![warn(missing_docs)]
pub mod chain;
pub mod db;
mod network;
mod prelude;
use network::dns::CBF_SERVICE_BIT_PREFIX;
use network::dns::CBF_V2T_SERVICE_BIT_PREFIX;
pub(crate) use prelude::impl_sourceless_error;
mod broadcaster;
pub mod builder;
pub(crate) mod channel_messages;
pub mod client;
pub(crate) mod config;
pub(crate) mod dialog;
pub mod error;
pub mod messages;
pub mod node;
use chain::Filter;
use network::dns::DnsQuery;
use network::dns::DNS_RESOLVER_PORT;
use std::net::{IpAddr, SocketAddr};
#[doc(inline)]
pub use chain::checkpoints::HeaderCheckpoint;
#[doc(inline)]
#[cfg(feature = "rusqlite")]
pub use db::sqlite::{headers::SqliteHeaderDb, peers::SqlitePeerDb};
#[doc(inline)]
pub use db::traits::{HeaderStore, PeerStore};
#[doc(inline)]
pub use tokio::sync::mpsc::Receiver;
#[doc(inline)]
pub use tokio::sync::mpsc::UnboundedReceiver;
#[doc(inline)]
pub use {
crate::builder::Builder,
crate::client::{Client, Requester},
crate::error::{ClientError, NodeError},
crate::messages::{Event, Info, Progress, RejectPayload, SyncUpdate, Warning},
crate::network::PeerTimeoutConfig,
crate::node::Node,
};
#[doc(inline)]
pub use bitcoin::bip158::BlockFilter;
#[doc(inline)]
pub use bitcoin::{
block::Header, p2p::address::AddrV2, p2p::message_network::RejectReason, p2p::ServiceFlags,
Address, Block, BlockHash, FeeRate, Network, ScriptBuf, Transaction, Txid,
};
pub extern crate tokio;
#[derive(Debug, Clone)]
pub struct IndexedBlock {
pub height: u32,
pub block: Block,
}
impl IndexedBlock {
pub(crate) fn new(height: u32, block: Block) -> Self {
Self { height, block }
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct IndexedFilter {
height: u32,
filter: Filter,
}
impl IndexedFilter {
fn new(height: u32, filter: Filter) -> Self {
Self { height, filter }
}
pub fn height(&self) -> u32 {
self.height
}
pub fn block_hash(&self) -> BlockHash {
*self.filter.block_hash()
}
pub fn contains_any<'a>(&'a self, scripts: impl Iterator<Item = &'a ScriptBuf>) -> bool {
self.filter
.contains_any(scripts)
.expect("vec reader is infallible")
}
pub fn block_filter(self) -> BlockFilter {
self.filter.into_filter()
}
pub fn into_contents(self) -> Vec<u8> {
self.filter.contents()
}
}
impl std::cmp::PartialOrd for IndexedFilter {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl std::cmp::Ord for IndexedFilter {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.height.cmp(&other.height)
}
}
#[derive(Debug, Clone)]
pub struct TxBroadcast {
pub tx: Transaction,
pub broadcast_policy: TxBroadcastPolicy,
}
impl TxBroadcast {
pub fn new(tx: Transaction, broadcast_policy: TxBroadcastPolicy) -> Self {
Self {
tx,
broadcast_policy,
}
}
pub fn random_broadcast(tx: Transaction) -> Self {
Self {
tx,
broadcast_policy: TxBroadcastPolicy::RandomPeer,
}
}
}
#[derive(Debug, Default, Clone)]
pub enum TxBroadcastPolicy {
AllPeers,
#[default]
RandomPeer,
}
#[derive(Debug, Clone)]
pub struct TrustedPeer {
pub address: AddrV2,
pub port: Option<u16>,
pub known_services: ServiceFlags,
}
impl TrustedPeer {
pub fn new(address: AddrV2, port: Option<u16>, services: ServiceFlags) -> Self {
Self {
address,
port,
known_services: services,
}
}
pub fn from_ip(ip_addr: impl Into<IpAddr>) -> Self {
let address = match ip_addr.into() {
IpAddr::V4(ip) => AddrV2::Ipv4(ip),
IpAddr::V6(ip) => AddrV2::Ipv6(ip),
};
Self {
address,
port: None,
known_services: ServiceFlags::NONE,
}
}
pub fn from_socket_addr(socket_addr: impl Into<SocketAddr>) -> Self {
let socket_addr: SocketAddr = socket_addr.into();
let address = match socket_addr {
SocketAddr::V4(ip) => AddrV2::Ipv4(*ip.ip()),
SocketAddr::V6(ip) => AddrV2::Ipv6(*ip.ip()),
};
Self {
address,
port: Some(socket_addr.port()),
known_services: ServiceFlags::NONE,
}
}
pub fn address(&self) -> AddrV2 {
self.address.clone()
}
pub fn port(&self) -> Option<u16> {
self.port
}
pub fn services(&self) -> ServiceFlags {
self.known_services
}
pub fn set_services(&mut self, services: ServiceFlags) {
self.known_services = services;
}
}
impl From<(IpAddr, Option<u16>)> for TrustedPeer {
fn from(value: (IpAddr, Option<u16>)) -> Self {
let address = match value.0 {
IpAddr::V4(ip) => AddrV2::Ipv4(ip),
IpAddr::V6(ip) => AddrV2::Ipv6(ip),
};
TrustedPeer::new(address, value.1, ServiceFlags::NONE)
}
}
impl From<TrustedPeer> for (AddrV2, Option<u16>) {
fn from(value: TrustedPeer) -> Self {
(value.address(), value.port())
}
}
impl From<IpAddr> for TrustedPeer {
fn from(value: IpAddr) -> Self {
TrustedPeer::from_ip(value)
}
}
impl From<SocketAddr> for TrustedPeer {
fn from(value: SocketAddr) -> Self {
TrustedPeer::from_socket_addr(value)
}
}
#[derive(Debug, Default, Clone)]
pub enum PeerStoreSizeConfig {
#[default]
Unbounded,
Limit(u32),
}
#[derive(Debug, Clone, Copy)]
enum NodeState {
Behind,
HeadersSynced,
FilterHeadersSynced,
FiltersSynced,
}
impl core::fmt::Display for NodeState {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
NodeState::Behind => {
write!(f, "Requesting block headers.")
}
NodeState::HeadersSynced => {
write!(f, "Requesting compact filter headers.")
}
NodeState::FilterHeadersSynced => {
write!(f, "Requesting compact block filters.")
}
NodeState::FiltersSynced => write!(f, "Downloading blocks with relevant transactions."),
}
}
}
pub async fn lookup_host<S: AsRef<str>>(hostname: S, resolver: impl Into<IpAddr>) -> Vec<IpAddr> {
let ip_addr = resolver.into();
let socket_addr = SocketAddr::new(ip_addr, DNS_RESOLVER_PORT);
let mut responses = Vec::new();
let dns_query = DnsQuery::new(hostname.as_ref(), None);
let no_filter = dns_query.lookup(socket_addr).await.unwrap_or(Vec::new());
responses.extend(no_filter);
let dns_query = DnsQuery::new(hostname.as_ref(), Some(CBF_V2T_SERVICE_BIT_PREFIX));
let no_filter = dns_query.lookup(socket_addr).await.unwrap_or(Vec::new());
responses.extend(no_filter);
let dns_query = DnsQuery::new(hostname.as_ref(), Some(CBF_SERVICE_BIT_PREFIX));
let no_filter = dns_query.lookup(socket_addr).await.unwrap_or(Vec::new());
responses.extend(no_filter);
responses
}
macro_rules! debug {
($expr:expr) => {
#[cfg(debug_assertions)]
println!("{}", $expr)
};
}
pub(crate) use debug;