From 9f2c4ed2e15e758aafe61587c17cb086b5d7904a Mon Sep 17 00:00:00 2001 From: ank Date: Thu, 20 Jun 2024 20:44:52 +0000 Subject: [PATCH] Add config file + bug fix --- .conf.model | 6 ++++ .gitignore | 1 + src/config.rs | 77 +++++++++++++++++++++++++++++++++++++++++++ src/electrumclient.rs | 7 ++-- src/main.rs | 65 ++++++++++++++---------------------- src/scan.rs | 3 +- 6 files changed, 113 insertions(+), 46 deletions(-) create mode 100644 .conf.model create mode 100644 src/config.rs diff --git a/.conf.model b/.conf.model new file mode 100644 index 0000000..6f7b470 --- /dev/null +++ b/.conf.model @@ -0,0 +1,6 @@ +core_url="" +ws_url="" +wallet_name="default" +network="signet" +electrum_url="tcp://localhost:60601" +zmq_url="" diff --git a/.gitignore b/.gitignore index ea8c4bf..143f46b 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +.conf diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..5ed91b3 --- /dev/null +++ b/src/config.rs @@ -0,0 +1,77 @@ +use std::collections::HashMap; +use std::fs::File; +use std::io::{self, BufRead}; + +use anyhow::{Error, Result}; + +use sdk_common::sp_client::bitcoin::Network; + +#[derive(Debug)] +pub struct Config { + pub core_url: String, + pub core_wallet: Option, + pub ws_url: String, + pub wallet_name: String, + pub network: Network, + pub electrum_url: String, + pub zmq_url: String, +} + +impl Config { + pub fn read_from_file(filename: &str) -> Result { + let mut file_content = HashMap::new(); + if let Ok(file) = File::open(filename) { + let reader = io::BufReader::new(file); + + // Read the file line by line + for line in reader.lines() { + if let Ok(l) = line { + // Ignore comments and empty lines + if l.starts_with('#') || l.trim().is_empty() { + continue; + } + + // Split the line into key and value + if let Some((k, v)) = l.split_once('=') { + file_content.insert(k.to_owned(), v.trim_matches('\"').to_owned()); + } + } + } + } else { + return Err(anyhow::Error::msg("Failed to find conf file")); + } + + // Now set the Config + let config = Config { + core_url: file_content + .remove("core_url") + .ok_or(Error::msg("No \"core_url\""))? + .to_owned(), + core_wallet: file_content.remove("core_wallet").map(|s| s.to_owned()), + ws_url: file_content + .remove("ws_url") + .ok_or(Error::msg("No \"ws_url\""))? + .to_owned(), + wallet_name: file_content + .remove("wallet_name") + .ok_or(Error::msg("No \"wallet_name\""))? + .to_owned(), + network: Network::from_core_arg( + &file_content + .remove("network") + .ok_or(Error::msg("no \"network\""))? + .trim_matches('\"'), + )?, + electrum_url: file_content + .remove("electrum_url") + .ok_or(Error::msg("No \"electrum_url\""))? + .to_owned(), + zmq_url: file_content + .remove("zmq_url") + .ok_or(Error::msg("No \"zmq_url\""))? + .to_owned(), + }; + + Ok(config) + } +} diff --git a/src/electrumclient.rs b/src/electrumclient.rs index 897d533..c0ff9d3 100644 --- a/src/electrumclient.rs +++ b/src/electrumclient.rs @@ -1,15 +1,14 @@ use electrum_client::{Client, ConfigBuilder}; use log::info; -const ELECTRS_URI: &str = "ssl://silentpayments.dev:51002"; const VALIDATE_DOMAIN: bool = false; // self-signed cert, so we don't validate -pub fn create_electrum_client() -> anyhow::Result { +pub fn create_electrum_client(electrum_url: String) -> anyhow::Result { let config = ConfigBuilder::new() .validate_domain(VALIDATE_DOMAIN) .build(); - let electrum_client = Client::from_config(ELECTRS_URI, config)?; - info!("ssl client {}", ELECTRS_URI); + let electrum_client = Client::from_config(&electrum_url, config)?; + info!("ssl client {}", electrum_url); Ok(electrum_client) } diff --git a/src/main.rs b/src/main.rs index 26a797c..b43ab25 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,14 +13,13 @@ use std::{ use bitcoincore_rpc::json::{self as bitcoin_json}; use futures_util::{future, pin_mut, stream::TryStreamExt, FutureExt, StreamExt}; -use log::{debug, error, info, warn}; +use log::{debug, error, warn}; use scan::compute_partial_tweak_to_transaction; use sdk_common::sp_client::bitcoin::{ - consensus::{deserialize, serialize}, + consensus::deserialize, hex::{DisplayHex, FromHex}, Amount, Network, Transaction, }; -use sdk_common::sp_client::silentpayments::utils::Network as SpNetwork; use sdk_common::sp_client::{ bitcoin::secp256k1::rand::{thread_rng, Rng}, spclient::SpWallet, @@ -42,11 +41,13 @@ use tokio_tungstenite::tungstenite::Message; use anyhow::{Error, Result}; use zeromq::{Socket, SocketRecv}; +mod config; mod daemon; mod electrumclient; mod faucet; mod scan; +use crate::config::Config; use crate::faucet::handle_faucet_request; use crate::{daemon::Daemon, scan::scan_blocks}; @@ -448,10 +449,10 @@ fn create_new_tx_message(transaction: Vec, daemon: Arc>) -> Re )) } -async fn handle_zmq(peers: PeerMap, shared_daemon: SharedDaemon) { +async fn handle_zmq(peers: PeerMap, shared_daemon: SharedDaemon, zmq_url: String) { debug!("Starting listening on Core"); let mut socket = zeromq::SubSocket::new(); - socket.connect("tcp://127.0.0.1:29100").await.unwrap(); + socket.connect(&zmq_url).await.unwrap(); socket.subscribe("rawtx").await.unwrap(); // socket.subscribe("hashblock"); loop { @@ -466,7 +467,7 @@ async fn handle_zmq(peers: PeerMap, shared_daemon: SharedDaemon) { let payload: String = if let (Some(topic), Some(data)) = (core_msg.get(0), core_msg.get(1)) { - // debug!("topic: {}", std::str::from_utf8(&topic).unwrap()); + debug!("topic: {}", std::str::from_utf8(&topic).unwrap()); match std::str::from_utf8(&topic) { Ok("rawtx") => match create_new_tx_message(data.to_vec(), shared_daemon.clone()) { Ok(m) => { @@ -502,28 +503,9 @@ async fn handle_zmq(peers: PeerMap, shared_daemon: SharedDaemon) { async fn main() -> Result<()> { env_logger::init(); - // This is rudimentary, if you change the network don't forget to change rpc_url either, we won't do that for you - let rpc_url = env::args() - .nth(1) - .unwrap_or_else(|| "127.0.0.1:38332".to_owned()); - let listening_addr = env::args() - .nth(2) - .unwrap_or_else(|| "127.0.0.1:8090".to_string()); - let wallet_name = env::args().nth(3).unwrap_or_else(|| "default".to_owned()); - let network_arg: String = env::args().nth(4).unwrap_or_else(|| "signet".to_owned()); - let core_wallet: Option = env::args().nth(5); + let config = Config::read_from_file(".conf")?; - let network: Network = match network_arg.as_str() { - "main" => Network::Bitcoin, - "test" => Network::Testnet, - "signet" => Network::Testnet, - "regtest" => Network::Regtest, - _ => return Err(Error::msg("Invalid network")), - }; - - // let network = Network::from_core_arg(&network_arg)?; - - if network == Network::Bitcoin { + if config.network == Network::Bitcoin { warn!("Running on mainnet, you're on your own"); } @@ -535,9 +517,9 @@ async fn main() -> Result<()> { // Connect the rpc daemon let shared_daemon = Arc::new(Mutex::new(Daemon::connect( - core_wallet, - rpc_url, - Network::from_core_arg(&network_arg)?, + config.core_wallet, + config.core_url, + config.network, )?)); let current_tip: u32 = shared_daemon @@ -545,11 +527,12 @@ async fn main() -> Result<()> { .get_current_height()? .try_into()?; - let mut config_dir = PathBuf::from_str(&env::var("HOME")?)?; - config_dir.push(".4nk"); - config_dir.push(&wallet_name); + let mut app_dir = PathBuf::from_str(&env::var("HOME")?)?; + app_dir.push(".4nk"); + let mut wallet_file = app_dir.clone(); + wallet_file.push(&config.wallet_name); - let wallet_file = WalletFile::new(config_dir); + let wallet_file = WalletFile::new(wallet_file); // load an existing sp_wallet, or create a new one let sp_wallet = match wallet_file.load() { @@ -557,14 +540,14 @@ async fn main() -> Result<()> { wallet_file.create()?; let mut seed = [0u8; 64]; thread_rng().fill(&mut seed); - let (scan_sk, spend_sk) = - derive_keys_from_seed(&seed, network).expect("Couldn't generate a new sp_wallet"); + let (scan_sk, spend_sk) = derive_keys_from_seed(&seed, config.network) + .expect("Couldn't generate a new sp_wallet"); let new_client = SpClient::new( - wallet_name, + config.wallet_name, scan_sk, SpendKey::Secret(spend_sk), None, - network, + config.network, ) .expect("Failed to create a new SpClient"); @@ -610,16 +593,16 @@ async fn main() -> Result<()> { shared_daemon.clone(), sp_wallet.clone(), current_tip - last_scan, + config.electrum_url, )?; } // Subscribe to Bitcoin Core - tokio::spawn(handle_zmq(peers.clone(), shared_daemon.clone())); + tokio::spawn(handle_zmq(peers.clone(), shared_daemon.clone(), config.zmq_url)); // Create the event loop and TCP listener we'll accept connections on. - let try_socket = TcpListener::bind(&listening_addr).await; + let try_socket = TcpListener::bind("127.0.0.1:9090").await; let listener = try_socket.expect("Failed to bind"); - debug!("Listening on: {}", listening_addr); tokio::spawn(MessageCache::clean_up()); diff --git a/src/scan.rs b/src/scan.rs index 56a53b1..c6a1b8f 100644 --- a/src/scan.rs +++ b/src/scan.rs @@ -220,9 +220,10 @@ pub fn scan_blocks( shared_daemon: SharedDaemon, sp_wallet: Arc, mut n_blocks_to_scan: u32, + electrum_url: String, ) -> anyhow::Result<()> { log::info!("Starting a rescan"); - let electrum_client = electrumclient::create_electrum_client()?; + let electrum_client = electrumclient::create_electrum_client(electrum_url)?; let core = shared_daemon.lock_anyhow()?;