From 1ab6ecba6f509b7b76865d65c77ecebc51efd2d3 Mon Sep 17 00:00:00 2001 From: sommerfeld Date: Sun, 21 Apr 2024 16:04:38 +0100 Subject: Initial commit --- src/blockchain.rs | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 src/blockchain.rs (limited to 'src/blockchain.rs') diff --git a/src/blockchain.rs b/src/blockchain.rs new file mode 100644 index 0000000..2f5014b --- /dev/null +++ b/src/blockchain.rs @@ -0,0 +1,96 @@ +use anyhow::{Context, Result}; +use bdk::{ + bitcoin::Network, + blockchain::{ElectrumBlockchain, GetHeight}, + electrum_client::{Client, ConfigBuilder, Socks5Config}, +}; +use serde::Deserialize; + +fn get_default_electrum_server(network: Network) -> &'static str { + match network { + Network::Bitcoin => "ssl://fulcrum.sethforprivacy.com:50002", + Network::Testnet => "ssl://electrum.blockstream.info:60002", + Network::Signet => "ssl://mempool.space:60602", + _ => panic!("unsupported network"), + } +} + +#[derive(Deserialize, Default, Debug)] +pub struct ElectrumConfig { + url: Option, + + network: Option, + + socks5: Option, + + #[serde(default)] + certificate_validation: bool, +} + +impl ElectrumConfig { + pub fn url(&self) -> &str { + self.url + .as_deref() + .unwrap_or(get_default_electrum_server(self.network())) + } + + pub fn network(&self) -> Network { + self.network.unwrap_or(Network::Bitcoin) + } + + pub fn certificate_validation(&self) -> bool { + self.certificate_validation + } + + pub fn socks5(&self) -> Option { + self.socks5.as_ref().map(Socks5Config::new) + } +} + +pub fn get_blockchain(electrum_cfg: &ElectrumConfig) -> Result { + let server_cfg = ConfigBuilder::new() + .validate_domain(electrum_cfg.certificate_validation()) + .socks5(electrum_cfg.socks5()) + .build(); + let electrum_url = electrum_cfg.url(); + let client = Client::from_config(electrum_url, server_cfg) + .with_context(|| "could not configure electrum client".to_string())?; + Ok(ElectrumBlockchain::from(client)) +} + +pub struct BlockchainState { + height: Option, + url: String, + blockchain: ElectrumBlockchain, +} + +impl BlockchainState { + pub fn new(electrum_cfg: &ElectrumConfig) -> Result { + Ok(Self { + height: Default::default(), + url: String::from(electrum_cfg.url()), + blockchain: get_blockchain(electrum_cfg)?, + }) + } + + pub fn update_height(&mut self) { + match self.blockchain.get_height() { + Ok(polled_height) => { + match self.height { + Some(h) => { + if polled_height != h { + self.height = Some(polled_height); + debug!("current block height: {}", polled_height); + } + } + None => { + self.height = Some(polled_height); + info!("connected to '{}'", self.url); + info!("current block height: {}", polled_height); + } + }; + } + Err(e) => warn!("could not reach '{}': {}", self.url, e), + }; + } +} -- cgit v1.2.3-70-g09d2