[[package]]
name = "lightning"
version = "0.0.13"
-source = "git+https://github.com/rust-bitcoin/rust-lightning?rev=32f6205848806a3b2876a2ae36b1db7d5fa22f7d#32f6205848806a3b2876a2ae36b1db7d5fa22f7d"
dependencies = [
"bitcoin",
]
[[package]]
name = "lightning-background-processor"
version = "0.0.13"
-source = "git+https://github.com/rust-bitcoin/rust-lightning?rev=32f6205848806a3b2876a2ae36b1db7d5fa22f7d#32f6205848806a3b2876a2ae36b1db7d5fa22f7d"
dependencies = [
"bitcoin",
"lightning",
[[package]]
name = "lightning-block-sync"
version = "0.0.13"
-source = "git+https://github.com/rust-bitcoin/rust-lightning?rev=32f6205848806a3b2876a2ae36b1db7d5fa22f7d#32f6205848806a3b2876a2ae36b1db7d5fa22f7d"
dependencies = [
"bitcoin",
"chunked_transfer",
[[package]]
name = "lightning-net-tokio"
version = "0.0.13"
-source = "git+https://github.com/rust-bitcoin/rust-lightning?rev=32f6205848806a3b2876a2ae36b1db7d5fa22f7d#32f6205848806a3b2876a2ae36b1db7d5fa22f7d"
dependencies = [
"bitcoin",
"lightning",
[[package]]
name = "lightning-persister"
version = "0.0.13"
-source = "git+https://github.com/rust-bitcoin/rust-lightning?rev=32f6205848806a3b2876a2ae36b1db7d5fa22f7d#32f6205848806a3b2876a2ae36b1db7d5fa22f7d"
dependencies = [
"bitcoin",
"libc",
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-lightning-background-processor = { git = "https://github.com/rust-bitcoin/rust-lightning", rev = "32f6205848806a3b2876a2ae36b1db7d5fa22f7d" }
+# lightning-background-processor = { git = "https://github.com/rust-bitcoin/rust-lightning", rev = "32f6205848806a3b2876a2ae36b1db7d5fa22f7d" }
+lightning-background-processor = { path = "../rust-lightning/background-processor" }
base64 = "0.13.0"
bitcoin = "0.26"
bitcoin-bech32 = "0.7"
bech32 = "0.7"
hex = "0.3"
-lightning = { git = "https://github.com/rust-bitcoin/rust-lightning", rev = "32f6205848806a3b2876a2ae36b1db7d5fa22f7d" }
-lightning-block-sync = { git = "https://github.com/rust-bitcoin/rust-lightning", features = ["rpc-client"], rev = "32f6205848806a3b2876a2ae36b1db7d5fa22f7d" }
+# lightning = { git = "https://github.com/rust-bitcoin/rust-lightning", rev = "32f6205848806a3b2876a2ae36b1db7d5fa22f7d" }
+lightning = { path = "../rust-lightning/lightning" }
+# lightning-block-sync = { git = "https://github.com/rust-bitcoin/rust-lightning", features = ["rpc-client"], rev = "32f6205848806a3b2876a2ae36b1db7d5fa22f7d" }
+lightning-block-sync = { path = "../rust-lightning/lightning-block-sync", features = ["rpc-client"] }
lightning-invoice = { git = "https://github.com/rust-bitcoin/rust-lightning-invoice", rev = "aa3a57b9dca5205fa25fa333a2db165d7e77b3b0" }
-lightning-net-tokio = { git = "https://github.com/rust-bitcoin/rust-lightning", rev = "32f6205848806a3b2876a2ae36b1db7d5fa22f7d" }
-lightning-persister = { git = "https://github.com/rust-bitcoin/rust-lightning", rev = "32f6205848806a3b2876a2ae36b1db7d5fa22f7d" }
+# lightning-net-tokio = { git = "https://github.com/rust-bitcoin/rust-lightning", rev = "32f6205848806a3b2876a2ae36b1db7d5fa22f7d" }
+lightning-net-tokio = { path = "../rust-lightning/lightning-net-tokio" }
+# lightning-persister = { git = "https://github.com/rust-bitcoin/rust-lightning", rev = "32f6205848806a3b2876a2ae36b1db7d5fa22f7d" }
+lightning-persister = { path = "../rust-lightning/lightning-persister" }
time = "0.2"
rand = "0.4"
serde_json = { version = "1.0" }
use crate::convert::{BlockchainInfo, FeeResponse, FundedTx, NewAddress, RawTx, SignedTx};
use base64;
+use bitcoin::blockdata::block::Block;
use bitcoin::blockdata::transaction::Transaction;
use bitcoin::consensus::encode;
+use bitcoin::hash_types::BlockHash;
use bitcoin::util::address::Address;
use lightning::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator};
use lightning_block_sync::http::HttpEndpoint;
use lightning_block_sync::rpc::RpcClient;
+use lightning_block_sync::{AsyncBlockSourceResult, BlockHeaderData, BlockSource};
use serde_json;
use std::collections::HashMap;
use std::str::FromStr;
-use std::sync::Mutex;
-use tokio::runtime::{Handle, Runtime};
+use std::sync::atomic::{AtomicU32, Ordering};
+use std::sync::Arc;
+use std::time::Duration;
+use tokio::sync::Mutex;
pub struct BitcoindClient {
- bitcoind_rpc_client: Mutex<RpcClient>,
+ bitcoind_rpc_client: Arc<Mutex<RpcClient>>,
host: String,
port: u16,
rpc_user: String,
rpc_password: String,
- runtime: Mutex<Runtime>,
+ fees: Arc<HashMap<Target, AtomicU32>>,
+}
+
+#[derive(Clone, Eq, Hash, PartialEq)]
+pub enum Target {
+ Background,
+ Normal,
+ HighPriority,
+}
+
+impl BlockSource for &BitcoindClient {
+ fn get_header<'a>(
+ &'a mut self, header_hash: &'a BlockHash, height_hint: Option<u32>,
+ ) -> AsyncBlockSourceResult<'a, BlockHeaderData> {
+ Box::pin(async move {
+ let mut rpc = self.bitcoind_rpc_client.lock().await;
+ rpc.get_header(header_hash, height_hint).await
+ })
+ }
+
+ fn get_block<'a>(
+ &'a mut self, header_hash: &'a BlockHash,
+ ) -> AsyncBlockSourceResult<'a, Block> {
+ Box::pin(async move {
+ let mut rpc = self.bitcoind_rpc_client.lock().await;
+ rpc.get_block(header_hash).await
+ })
+ }
+
+ fn get_best_block<'a>(&'a mut self) -> AsyncBlockSourceResult<(BlockHash, Option<u32>)> {
+ Box::pin(async move {
+ let mut rpc = self.bitcoind_rpc_client.lock().await;
+ rpc.get_best_block().await
+ })
+ }
}
impl BitcoindClient {
- pub fn new(
+ pub async fn new(
host: String, port: u16, rpc_user: String, rpc_password: String,
) -> std::io::Result<Self> {
let http_endpoint = HttpEndpoint::for_host(host.clone()).with_port(port);
let rpc_credentials =
base64::encode(format!("{}:{}", rpc_user.clone(), rpc_password.clone()));
let bitcoind_rpc_client = RpcClient::new(&rpc_credentials, http_endpoint)?;
+ let mut fees: HashMap<Target, AtomicU32> = HashMap::new();
+ fees.insert(Target::Background, AtomicU32::new(253));
+ fees.insert(Target::Normal, AtomicU32::new(2000));
+ fees.insert(Target::HighPriority, AtomicU32::new(5000));
let client = Self {
- bitcoind_rpc_client: Mutex::new(bitcoind_rpc_client),
+ bitcoind_rpc_client: Arc::new(Mutex::new(bitcoind_rpc_client)),
host,
port,
rpc_user,
rpc_password,
- runtime: Mutex::new(Runtime::new().unwrap()),
+ fees: Arc::new(fees),
};
+ BitcoindClient::poll_for_fee_estimates(
+ client.fees.clone(),
+ client.bitcoind_rpc_client.clone(),
+ )
+ .await;
Ok(client)
}
+ async fn poll_for_fee_estimates(
+ fees: Arc<HashMap<Target, AtomicU32>>, rpc_client: Arc<Mutex<RpcClient>>,
+ ) {
+ tokio::spawn(async move {
+ loop {
+ let background_estimate = {
+ let mut rpc = rpc_client.lock().await;
+ let background_conf_target = serde_json::json!(144);
+ let background_estimate_mode = serde_json::json!("ECONOMICAL");
+ let resp = rpc
+ .call_method::<FeeResponse>(
+ "estimatesmartfee",
+ &vec![background_conf_target, background_estimate_mode],
+ )
+ .await
+ .unwrap();
+ match resp.feerate {
+ Some(fee) => fee,
+ None => 253,
+ }
+ };
+ // if background_estimate.
+
+ let normal_estimate = {
+ let mut rpc = rpc_client.lock().await;
+ let normal_conf_target = serde_json::json!(18);
+ let normal_estimate_mode = serde_json::json!("ECONOMICAL");
+ let resp = rpc
+ .call_method::<FeeResponse>(
+ "estimatesmartfee",
+ &vec![normal_conf_target, normal_estimate_mode],
+ )
+ .await
+ .unwrap();
+ match resp.feerate {
+ Some(fee) => fee,
+ None => 2000,
+ }
+ };
+
+ let high_prio_estimate = {
+ let mut rpc = rpc_client.lock().await;
+ let high_prio_conf_target = serde_json::json!(6);
+ let high_prio_estimate_mode = serde_json::json!("CONSERVATIVE");
+ let resp = rpc
+ .call_method::<FeeResponse>(
+ "estimatesmartfee",
+ &vec![high_prio_conf_target, high_prio_estimate_mode],
+ )
+ .await
+ .unwrap();
+
+ match resp.feerate {
+ Some(fee) => fee,
+ None => 5000,
+ }
+ };
+
+ fees.get(&Target::Background)
+ .unwrap()
+ .store(background_estimate, Ordering::Release);
+ fees.get(&Target::Normal).unwrap().store(normal_estimate, Ordering::Release);
+ fees.get(&Target::HighPriority)
+ .unwrap()
+ .store(high_prio_estimate, Ordering::Release);
+ // match fees.get(Target::Background) {
+ // Some(fee) => fee.store(background_estimate, Ordering::Release),
+ // None =>
+ // }
+ // if let Some(fee) = background_estimate.feerate {
+ // fees.get("background").unwrap().store(fee, Ordering::Release);
+ // }
+ // if let Some(fee) = normal_estimate.feerate {
+ // fees.get("normal").unwrap().store(fee, Ordering::Release);
+ // }
+ // if let Some(fee) = high_prio_estimate.feerate {
+ // fees.get("high_prio").unwrap().store(fee, Ordering::Release);
+ // }
+ tokio::time::sleep(Duration::from_secs(60)).await;
+ }
+ });
+ }
+
pub fn get_new_rpc_client(&self) -> std::io::Result<RpcClient> {
let http_endpoint = HttpEndpoint::for_host(self.host.clone()).with_port(self.port);
let rpc_credentials =
RpcClient::new(&rpc_credentials, http_endpoint)
}
- pub fn create_raw_transaction(&self, outputs: Vec<HashMap<String, f64>>) -> RawTx {
- let runtime = self.runtime.lock().unwrap();
- let mut rpc = self.bitcoind_rpc_client.lock().unwrap();
+ pub async fn create_raw_transaction(&self, outputs: Vec<HashMap<String, f64>>) -> RawTx {
+ let mut rpc = self.bitcoind_rpc_client.lock().await;
let outputs_json = serde_json::json!(outputs);
- runtime
- .block_on(rpc.call_method::<RawTx>(
- "createrawtransaction",
- &vec![serde_json::json!([]), outputs_json],
- ))
+ rpc.call_method::<RawTx>("createrawtransaction", &vec![serde_json::json!([]), outputs_json])
+ .await
.unwrap()
}
- pub fn fund_raw_transaction(&self, raw_tx: RawTx) -> FundedTx {
- let runtime = self.runtime.lock().unwrap();
- let mut rpc = self.bitcoind_rpc_client.lock().unwrap();
+ pub async fn fund_raw_transaction(&self, raw_tx: RawTx) -> FundedTx {
+ let mut rpc = self.bitcoind_rpc_client.lock().await;
+
+ let raw_tx_json = serde_json::json!(raw_tx.0);
+ rpc.call_method("fundrawtransaction", &[raw_tx_json]).await.unwrap()
+ }
+
+ pub async fn send_raw_transaction(&self, raw_tx: RawTx) {
+ let mut rpc = self.bitcoind_rpc_client.lock().await;
let raw_tx_json = serde_json::json!(raw_tx.0);
- runtime.block_on(rpc.call_method("fundrawtransaction", &[raw_tx_json])).unwrap()
+ rpc.call_method::<RawTx>("sendrawtransaction", &[raw_tx_json]).await.unwrap();
}
- pub fn sign_raw_transaction_with_wallet(&self, tx_hex: String) -> SignedTx {
- let runtime = self.runtime.lock().unwrap();
- let mut rpc = self.bitcoind_rpc_client.lock().unwrap();
+ pub async fn sign_raw_transaction_with_wallet(&self, tx_hex: String) -> SignedTx {
+ let mut rpc = self.bitcoind_rpc_client.lock().await;
let tx_hex_json = serde_json::json!(tx_hex);
- runtime
- .block_on(rpc.call_method("signrawtransactionwithwallet", &vec![tx_hex_json]))
- .unwrap()
+ rpc.call_method("signrawtransactionwithwallet", &vec![tx_hex_json]).await.unwrap()
}
- pub fn get_new_address(&self) -> Address {
- let runtime = self.runtime.lock().unwrap();
- let mut rpc = self.bitcoind_rpc_client.lock().unwrap();
+ pub async fn get_new_address(&self) -> Address {
+ let mut rpc = self.bitcoind_rpc_client.lock().await;
let addr_args = vec![serde_json::json!("LDK output address")];
- let addr =
- runtime.block_on(rpc.call_method::<NewAddress>("getnewaddress", &addr_args)).unwrap();
+ let addr = rpc.call_method::<NewAddress>("getnewaddress", &addr_args).await.unwrap();
Address::from_str(addr.0.as_str()).unwrap()
}
- pub fn get_blockchain_info(&self) -> BlockchainInfo {
- let runtime = self.runtime.lock().unwrap();
- let mut rpc = self.bitcoind_rpc_client.lock().unwrap();
-
- runtime.block_on(rpc.call_method::<BlockchainInfo>("getblockchaininfo", &vec![])).unwrap()
+ pub async fn get_blockchain_info(&self) -> BlockchainInfo {
+ let mut rpc = self.bitcoind_rpc_client.lock().await;
+ rpc.call_method::<BlockchainInfo>("getblockchaininfo", &vec![]).await.unwrap()
}
}
impl FeeEstimator for BitcoindClient {
fn get_est_sat_per_1000_weight(&self, confirmation_target: ConfirmationTarget) -> u32 {
- let runtime = self.runtime.lock().unwrap();
- let mut rpc = self.bitcoind_rpc_client.lock().unwrap();
+ match confirmation_target {
+ ConfirmationTarget::Background => {
+ self.fees.get(&Target::Background).unwrap().load(Ordering::Acquire)
+ }
+ ConfirmationTarget::Normal => {
+ self.fees.get(&Target::Normal).unwrap().load(Ordering::Acquire)
+ }
+ ConfirmationTarget::HighPriority => {
+ self.fees.get(&Target::HighPriority).unwrap().load(Ordering::Acquire)
+ }
+ }
+ // self.fees.g
+ // 253
+ // match confirmation_target {
+ // ConfirmationTarget::Background =>
+ // }
+ // let mut rpc = self.bitcoind_rpc_client.lock().unwrap();
- let (conf_target, estimate_mode, default) = match confirmation_target {
- ConfirmationTarget::Background => (144, "ECONOMICAL", 253),
- ConfirmationTarget::Normal => (18, "ECONOMICAL", 20000),
- ConfirmationTarget::HighPriority => (6, "ECONOMICAL", 50000),
- };
+ // let (conf_target, estimate_mode, default) = match confirmation_target {
+ // ConfirmationTarget::Background => (144, "ECONOMICAL", 253),
+ // ConfirmationTarget::Normal => (18, "ECONOMICAL", 20000),
+ // ConfirmationTarget::HighPriority => (6, "CONSERVATIVE", 50000),
+ // };
- // This function may be called from a tokio runtime, or not. So we need to check before
- // making the call to avoid the error "cannot run a tokio runtime from within a tokio runtime".
- let conf_target_json = serde_json::json!(conf_target);
- let estimate_mode_json = serde_json::json!(estimate_mode);
- let resp = match Handle::try_current() {
- Ok(_) => tokio::task::block_in_place(|| {
- runtime
- .block_on(rpc.call_method::<FeeResponse>(
- "estimatesmartfee",
- &vec![conf_target_json, estimate_mode_json],
- ))
- .unwrap()
- }),
- _ => runtime
- .block_on(rpc.call_method::<FeeResponse>(
- "estimatesmartfee",
- &vec![conf_target_json, estimate_mode_json],
- ))
- .unwrap(),
- };
- if resp.errored {
- return default;
- }
- resp.feerate.unwrap()
+ // // This function may be called from a tokio runtime, or not. So we need to check before
+ // // making the call to avoid the error "cannot run a tokio runtime from within a tokio runtime".
+ // let conf_target_json = serde_json::json!(conf_target);
+ // let estimate_mode_json = serde_json::json!(estimate_mode);
+ // let resp = match Handle::try_current() {
+ // Ok(_) => tokio::task::block_in_place(|| {
+ // runtime
+ // .block_on(rpc.call_method::<FeeResponse>(
+ // "estimatesmartfee",
+ // &vec![conf_target_json, estimate_mode_json],
+ // ))
+ // .unwrap()
+ // }),
+ // _ => runtime
+ // .block_on(rpc.call_method::<FeeResponse>(
+ // "estimatesmartfee",
+ // &vec![conf_target_json, estimate_mode_json],
+ // ))
+ // .unwrap(),
+ // };
+ // if resp.errored {
+ // return default;
+ // }
+ // resp.feerate.unwrap()
}
}
impl BroadcasterInterface for BitcoindClient {
fn broadcast_transaction(&self, tx: &Transaction) {
- let mut rpc = self.bitcoind_rpc_client.lock().unwrap();
- let runtime = self.runtime.lock().unwrap();
-
+ let bitcoind_rpc_client = self.bitcoind_rpc_client.clone();
let tx_serialized = serde_json::json!(encode::serialize_hex(tx));
- // This function may be called from a tokio runtime, or not. So we need to check before
- // making the call to avoid the error "cannot run a tokio runtime from within a tokio runtime".
- match Handle::try_current() {
- Ok(_) => {
- tokio::task::block_in_place(|| {
- runtime
- .block_on(
- rpc.call_method::<RawTx>("sendrawtransaction", &vec![tx_serialized]),
- )
- .unwrap();
- });
- }
- _ => {
- runtime
- .block_on(rpc.call_method::<RawTx>("sendrawtransaction", &vec![tx_serialized]))
- .unwrap();
- }
- }
+ tokio::spawn(async move {
+ let mut rpc = bitcoind_rpc_client.lock().await;
+ rpc.call_method::<RawTx>("sendrawtransaction", &vec![tx_serialized]).await.unwrap();
+ });
+ // let bitcoind_rpc_client = self.bitcoind_rpc_client.clone();
+ // tokio::spawn(async move {
+ // let rpc = bitcoind_rpc_client.lock().await;
+ // rpc.call_method::<R>
+ // });
+ // let mut rpc = self.bitcoind_rpc_client.lock().unwrap();
+ // let runtime = self.runtime.lock().unwrap();
+
+ // let tx_serialized = serde_json::json!(encode::serialize_hex(tx));
+ // // This function may be called from a tokio runtime, or not. So we need to check before
+ // // making the call to avoid the error "cannot run a tokio runtime from within a tokio runtime".
+ // match Handle::try_current() {
+ // Ok(_) => {
+ // tokio::task::block_in_place(|| {
+ // runtime
+ // .block_on(
+ // rpc.call_method::<RawTx>("sendrawtransaction", &vec![tx_serialized]),
+ // )
+ // .unwrap();
+ // });
+ // }
+ // _ => {
+ // runtime
+ // .block_on(rpc.call_method::<RawTx>("sendrawtransaction", &vec![tx_serialized]))
+ // .unwrap();
+ // }
+ // }
}
}
use std::str::FromStr;
use std::sync::Arc;
use std::time::Duration;
-use tokio::runtime::Handle;
use tokio::sync::mpsc;
pub(crate) struct LdkUserInfo {
})
}
-pub(crate) fn poll_for_user_input(
+pub(crate) async fn poll_for_user_input(
peer_manager: Arc<PeerManager>, channel_manager: Arc<ChannelManager>,
router: Arc<NetGraphMsgHandler<Arc<dyn chain::Access>, Arc<FilesystemLogger>>>,
payment_storage: PaymentInfoStorage, node_privkey: SecretKey, event_notifier: mpsc::Sender<()>,
- ldk_data_dir: String, logger: Arc<FilesystemLogger>, runtime_handle: Handle, network: Network,
+ ldk_data_dir: String, logger: Arc<FilesystemLogger>, network: Network,
) {
println!("LDK startup successful. To view available commands: \"help\".\nLDK logs are available at <your-supplied-ldk-data-dir-path>/.ldk/logs");
let stdin = io::stdin();
peer_addr,
peer_manager.clone(),
event_notifier.clone(),
- runtime_handle.clone(),
)
.is_err()
{
peer_addr,
peer_manager.clone(),
event_notifier.clone(),
- runtime_handle.clone(),
)
.is_ok()
{
pub(crate) fn connect_peer_if_necessary(
pubkey: PublicKey, peer_addr: SocketAddr, peer_manager: Arc<PeerManager>,
- event_notifier: mpsc::Sender<()>, runtime: Handle,
+ event_notifier: mpsc::Sender<()>,
) -> Result<(), ()> {
for node_pubkey in peer_manager.get_peer_node_ids() {
if node_pubkey == pubkey {
Ok(stream) => {
let peer_mgr = peer_manager.clone();
let event_ntfns = event_notifier.clone();
- runtime.spawn(async move {
+ tokio::spawn(async move {
lightning_net_tokio::setup_outbound(peer_mgr, event_ntfns, pubkey, stream).await;
});
let mut peer_connected = false;
pub struct FeeResponse {
pub feerate: Option<u32>,
+ // pub errors: Array<String>,
pub errored: bool,
}
let errored = !self.0["errors"].is_null();
Ok(FeeResponse {
errored,
- feerate: match errored {
- true => None,
- // The feerate from bitcoind is in BTC/kb, and we want satoshis/kb.
- false => Some((self.0["feerate"].as_f64().unwrap() * 100_000_000.0).round() as u32),
- },
+ feerate: match self.0["feerate"].as_f64() {
+ Some(fee) => Some((fee * 100_000_000.0).round() as u32),
+ None => None
+ }
+ // true => None,
+ // // The feerate from bitcoind is in BTC/kb, and we want satoshis/kb.
+ // false => Some((self.0["feerate"].as_f64().unwrap() * 100_000_000.0).round() as u32),
})
}
}
-mod bitcoind_client;
+pub mod bitcoind_client;
mod cli;
mod convert;
mod disk;
use bitcoin_bech32::WitnessProgram;
use lightning::chain;
use lightning::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator};
-use lightning::chain::chainmonitor::ChainMonitor;
+use lightning::chain::chainmonitor;
use lightning::chain::keysinterface::{InMemorySigner, KeysInterface, KeysManager};
use lightning::chain::transaction::OutPoint;
use lightning::chain::Filter;
use std::fs::File;
use std::io;
use std::io::Write;
+use std::ops::Deref;
use std::path::Path;
use std::sync::{Arc, Mutex};
-use std::thread;
use std::time::{Duration, SystemTime};
-use tokio::runtime::Runtime;
use tokio::sync::mpsc;
#[derive(PartialEq)]
>,
>;
-type ArcChainMonitor = ChainMonitor<
+type ChainMonitor = chainmonitor::ChainMonitor<
InMemorySigner,
Arc<dyn Filter>,
Arc<BitcoindClient>,
pub(crate) type PeerManager = SimpleArcPeerManager<
SocketDescriptor,
- ArcChainMonitor,
+ ChainMonitor,
BitcoindClient,
BitcoindClient,
dyn chain::Access,
>;
pub(crate) type ChannelManager =
- SimpleArcChannelManager<ArcChainMonitor, BitcoindClient, BitcoindClient, FilesystemLogger>;
+ SimpleArcChannelManager<ChainMonitor, BitcoindClient, BitcoindClient, FilesystemLogger>;
-fn handle_ldk_events(
+async fn handle_ldk_events(
peer_manager: Arc<PeerManager>, channel_manager: Arc<ChannelManager>,
- chain_monitor: Arc<ArcChainMonitor>, bitcoind_client: Arc<BitcoindClient>,
+ chain_monitor: Arc<ChainMonitor>, bitcoind_client: Arc<BitcoindClient>,
keys_manager: Arc<KeysManager>, payment_storage: PaymentInfoStorage, network: Network,
) {
let mut pending_txs: HashMap<OutPoint, Transaction> = HashMap::new();
.to_address();
let mut outputs = vec![HashMap::with_capacity(1)];
outputs[0].insert(addr, channel_value_satoshis as f64 / 100_000_000.0);
- let raw_tx = bitcoind_client.create_raw_transaction(outputs);
+ let raw_tx = bitcoind_client.create_raw_transaction(outputs).await;
// Have your wallet put the inputs into the transaction such that the output is
// satisfied.
- let funded_tx = bitcoind_client.fund_raw_transaction(raw_tx);
+ let funded_tx = bitcoind_client.fund_raw_transaction(raw_tx).await;
let change_output_position = funded_tx.changepos;
assert!(change_output_position == 0 || change_output_position == 1);
// Sign the final funding transaction and broadcast it.
- let signed_tx = bitcoind_client.sign_raw_transaction_with_wallet(funded_tx.hex);
+ let signed_tx =
+ bitcoind_client.sign_raw_transaction_with_wallet(funded_tx.hex).await;
assert_eq!(signed_tx.complete, true);
let final_tx: Transaction =
encode::deserialize(&hex_utils::to_vec(&signed_tx.hex).unwrap()).unwrap();
}
Event::PendingHTLCsForwardable { time_forwardable } => {
let forwarding_channel_manager = loop_channel_manager.clone();
- thread::spawn(move || {
+ tokio::spawn(async move {
let min = time_forwardable.as_secs();
let seconds_to_sleep = thread_rng().gen_range(min, min * 5);
- thread::sleep(Duration::new(seconds_to_sleep, 0));
+ // thread::sleep(Duration::new(seconds_to_sleep, 0));
+ tokio::time::sleep(Duration::from_secs(seconds_to_sleep)).await;
forwarding_channel_manager.process_pending_htlc_forwards();
});
}
Event::SpendableOutputs { outputs } => {
- let destination_address = bitcoind_client.get_new_address();
+ let destination_address = bitcoind_client.get_new_address().await;
let output_descriptors = &outputs.iter().map(|a| a).collect::<Vec<_>>();
let tx_feerate =
bitcoind_client.get_est_sat_per_1000_weight(ConfirmationTarget::Normal);
}
}
}
- thread::sleep(Duration::new(1, 0));
+ tokio::time::sleep(Duration::from_secs(1)).await;
}
}
-fn main() {
+#[tokio::main]
+pub async fn main() {
let args = match cli::parse_startup_args() {
Ok(user_args) => user_args,
Err(()) => return,
fs::create_dir_all(ldk_data_dir.clone()).unwrap();
// Initialize our bitcoind client.
- let bitcoind_client = match BitcoindClient::new(
+ let mut bitcoind_client = match BitcoindClient::new(
args.bitcoind_rpc_host.clone(),
args.bitcoind_rpc_port,
args.bitcoind_rpc_username.clone(),
args.bitcoind_rpc_password.clone(),
- ) {
+ )
+ .await
+ {
Ok(client) => Arc::new(client),
Err(e) => {
println!("Failed to connect to bitcoind client: {}", e);
return;
}
};
- let mut bitcoind_rpc_client = bitcoind_client.get_new_rpc_client().unwrap();
+ // let mut bitcoind_rpc_client = bitcoind_client.get_new_rpc_client().unwrap();
// ## Setup
// Step 1: Initialize the FeeEstimator
let persister = Arc::new(FilesystemPersister::new(ldk_data_dir.clone()));
// Step 5: Initialize the ChainMonitor
- let chain_monitor: Arc<ArcChainMonitor> = Arc::new(ChainMonitor::new(
+ let chain_monitor: Arc<ChainMonitor> = Arc::new(chainmonitor::ChainMonitor::new(
None,
broadcaster.clone(),
logger.clone(),
} else {
let mut key = [0; 32];
thread_rng().fill_bytes(&mut key);
- let mut f = File::create(keys_seed_path).unwrap();
- f.write_all(&key).expect("Failed to write node keys seed to disk");
- f.sync_all().expect("Failed to sync node keys seed to disk");
+ match File::create(keys_seed_path.clone()) {
+ Ok(mut f) => {
+ f.write_all(&key).expect("Failed to write node keys seed to disk");
+ f.sync_all().expect("Failed to sync node keys seed to disk");
+ }
+ Err(e) => {
+ println!("ERROR: Unable to create keys seed file {}: {}", keys_seed_path, e);
+ return;
+ }
+ }
key
};
let cur = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap();
// Step 9: Initialize the ChannelManager
let user_config = UserConfig::default();
- let runtime = Runtime::new().unwrap();
let mut restarting_node = true;
let (channel_manager_blockhash, mut channel_manager) = {
if let Ok(mut f) = fs::File::open(format!("{}/manager", ldk_data_dir.clone())) {
} else {
// We're starting a fresh node.
restarting_node = false;
- let getinfo_resp = bitcoind_client.get_blockchain_info();
+ let getinfo_resp = bitcoind_client.get_blockchain_info().await;
+
let chain_params = ChainParameters {
network: args.network,
latest_hash: getinfo_resp.latest_blockhash,
));
}
chain_tip = Some(
- runtime
- .block_on(init::synchronize_listeners(
- &mut bitcoind_rpc_client,
- args.network,
- &mut cache,
- chain_listeners,
- ))
- .unwrap(),
+ init::synchronize_listeners(
+ // &mut bitcoind_rpc_client,
+ &mut bitcoind_client.deref(),
+ args.network,
+ &mut cache,
+ chain_listeners,
+ )
+ .await
+ .unwrap(),
);
}
// We poll for events in handle_ldk_events(..) rather than waiting for them over the
// mpsc::channel, so we can leave the event receiver as unused.
- let (event_ntfn_sender, mut _event_ntfn_receiver) = mpsc::channel(2);
+ let (event_ntfn_sender, _event_ntfn_receiver) = mpsc::channel(2);
let peer_manager_connection_handler = peer_manager.clone();
let event_notifier = event_ntfn_sender.clone();
let listening_port = args.ldk_peer_listening_port;
- runtime.spawn(async move {
+ tokio::spawn(async move {
let listener = std::net::TcpListener::bind(format!("0.0.0.0:{}", listening_port)).unwrap();
loop {
let tcp_stream = listener.accept().unwrap().0;
// Step 17: Connect and Disconnect Blocks
if chain_tip.is_none() {
- chain_tip = Some(
- runtime.block_on(init::validate_best_block_header(&mut bitcoind_rpc_client)).unwrap(),
- );
+ // chain_tip = Some(init::validate_best_block_header(&mut bitcoind_client).await.unwrap());
+ chain_tip =
+ Some(init::validate_best_block_header(&mut bitcoind_client.deref()).await.unwrap());
+ // chain_tip = Some(init::validate_best_block_header(&mut bitcoind_rpc_client).await.unwrap());
}
let channel_manager_listener = channel_manager.clone();
let chain_monitor_listener = chain_monitor.clone();
+ let bitcoind_block_source = bitcoind_client.clone();
let network = args.network;
- runtime.spawn(async move {
- let chain_poller = poll::ChainPoller::new(&mut bitcoind_rpc_client, network);
+ tokio::spawn(async move {
+ // let chain_poller = poll::ChainPoller::new(&mut bitcoind_client, network);
+ let mut derefed = bitcoind_block_source.deref();
+ // let chain_poller = poll::ChainPoller::new(&mut bitcoind_block_source.deref(), network);
+ let chain_poller = poll::ChainPoller::new(&mut derefed, network);
+ // let chain_poller = poll::ChainPoller::new(&mut bitcoind_rpc_client, network);
let chain_listener = (chain_monitor_listener, channel_manager_listener);
let mut spv_client =
SpvClient::new(chain_tip.unwrap(), chain_poller, &mut cache, &chain_listener);
// Step 17 & 18: Initialize ChannelManager persistence & Once Per Minute: ChannelManager's
// timer_chan_freshness_every_min() and PeerManager's timer_tick_occurred
- let runtime_handle = runtime.handle();
let data_dir = ldk_data_dir.clone();
let persist_channel_manager_callback =
move |node: &ChannelManager| FilesystemPersister::persist_manager(data_dir.clone(), &*node);
);
let peer_manager_processor = peer_manager.clone();
- thread::spawn(move || loop {
- peer_manager_processor.timer_tick_occurred();
- thread::sleep(Duration::new(60, 0));
+ tokio::spawn(async move {
+ loop {
+ peer_manager_processor.timer_tick_occurred();
+ tokio::time::sleep(Duration::from_secs(60)).await;
+ }
});
// Step 15: Initialize LDK Event Handling
let payment_info: PaymentInfoStorage = Arc::new(Mutex::new(HashMap::new()));
let payment_info_for_events = payment_info.clone();
let network = args.network;
- thread::spawn(move || {
+ // let bitcoind = BitcoindClient::new(
+ // args.bitcoind_rpc_host.clone(),
+ // args.bitcoind_rpc_port,
+ // args.bitcoind_rpc_username.clone(),
+ // args.bitcoind_rpc_password.clone(),
+ // ).await.unwrap();
+ let bitcoind_rpc = bitcoind_client.clone();
+ tokio::spawn(async move {
handle_ldk_events(
peer_manager_event_listener,
channel_manager_event_listener,
chain_monitor_event_listener,
- bitcoind_client.clone(),
+ // bitcoind_client.clone(),
+ bitcoind_rpc,
+ // bitcoind,
keys_manager_listener,
payment_info_for_events,
network,
- );
+ )
+ .await;
});
// Reconnect to channel peers if possible.
- let handle = runtime_handle.clone();
let peer_data_path = format!("{}/channel_peer_data", ldk_data_dir.clone());
match disk::read_channel_peer_data(Path::new(&peer_data_path)) {
Ok(mut info) => {
peer_addr,
peer_manager.clone(),
event_ntfn_sender.clone(),
- handle.clone(),
);
}
}
event_ntfn_sender,
ldk_data_dir.clone(),
logger.clone(),
- handle,
args.network,
- );
+ )
+ .await;
}