mod convert;
mod disk;
mod hex_utils;
+mod sweep;
use crate::bitcoind_client::BitcoindClient;
use crate::disk::FilesystemLogger;
use bitcoin::blockdata::transaction::Transaction;
use bitcoin::consensus::encode;
use bitcoin::network::constants::Network;
-use bitcoin::secp256k1::Secp256k1;
use bitcoin::BlockHash;
use bitcoin_bech32::WitnessProgram;
use lightning::chain;
-use lightning::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator};
-use lightning::chain::keysinterface::{EntropySource, InMemorySigner, KeysManager};
+use lightning::chain::keysinterface::{
+ EntropySource, InMemorySigner, KeysManager, SpendableOutputDescriptor,
+};
use lightning::chain::{chainmonitor, ChannelMonitorUpdateStatus};
use lightning::chain::{Filter, Watch};
use lightning::events::{Event, PaymentFailureReason, PaymentPurpose};
use lightning::routing::gossip::{NodeId, P2PGossipSync};
use lightning::routing::router::DefaultRouter;
use lightning::util::config::UserConfig;
+use lightning::util::persist::KVStorePersister;
use lightning::util::ser::ReadableArgs;
use lightning_background_processor::{process_events_async, GossipSync};
use lightning_block_sync::init;
use std::sync::{Arc, Mutex};
use std::time::{Duration, SystemTime};
+pub(crate) const PENDING_SPENDABLE_OUTPUT_DIR: &'static str = "pending_spendable_outputs";
+
pub(crate) enum HTLCStatus {
Pending,
Succeeded,
channel_manager: &Arc<ChannelManager>, bitcoind_client: &BitcoindClient,
network_graph: &NetworkGraph, keys_manager: &KeysManager,
inbound_payments: &PaymentInfoStorage, outbound_payments: &PaymentInfoStorage,
- network: Network, event: Event,
+ persister: &Arc<FilesystemPersister>, network: Network, event: Event,
) {
match event {
Event::FundingGenerationReady {
});
}
Event::SpendableOutputs { outputs } => {
- 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);
- let spending_tx = keys_manager
- .spend_spendable_outputs(
- output_descriptors,
- Vec::new(),
- destination_address.script_pubkey(),
- tx_feerate,
- &Secp256k1::new(),
- )
- .unwrap();
- bitcoind_client.broadcast_transaction(&spending_tx);
+ // SpendableOutputDescriptors, of which outputs is a vec of, are critical to keep track
+ // of! While a `StaticOutput` descriptor is just an output to a static, well-known key,
+ // other descriptors are not currently ever regenerated for you by LDK. Once we return
+ // from this method, the descriptor will be gone, and you may lose track of some funds.
+ //
+ // Here we simply persist them to disk, with a background task running which will try
+ // to spend them regularly (possibly duplicatively/RBF'ing them). These can just be
+ // treated as normal funds where possible - they are only spendable by us and there is
+ // no rush to claim them.
+ for output in outputs {
+ let key = hex_utils::hex_str(&keys_manager.get_secure_random_bytes());
+ // Note that if the type here changes our read code needs to change as well.
+ let output: SpendableOutputDescriptor = output;
+ persister
+ .persist(&format!("{}/{}", PENDING_SPENDABLE_OUTPUT_DIR, key), &output)
+ .unwrap();
+ }
}
Event::ChannelPending { channel_id, counterparty_node_id, .. } => {
println!(
let keys_manager_event_listener = Arc::clone(&keys_manager);
let inbound_payments_event_listener = Arc::clone(&inbound_payments);
let outbound_payments_event_listener = Arc::clone(&outbound_payments);
+ let persister_event_listener = Arc::clone(&persister);
let network = args.network;
let event_handler = move |event: Event| {
let channel_manager_event_listener = Arc::clone(&channel_manager_event_listener);
let keys_manager_event_listener = Arc::clone(&keys_manager_event_listener);
let inbound_payments_event_listener = Arc::clone(&inbound_payments_event_listener);
let outbound_payments_event_listener = Arc::clone(&outbound_payments_event_listener);
+ let persister_event_listener = Arc::clone(&persister_event_listener);
async move {
handle_ldk_events(
&channel_manager_event_listener,
&keys_manager_event_listener,
&inbound_payments_event_listener,
&outbound_payments_event_listener,
+ &persister_event_listener,
network,
event,
)
// Step 20: Background Processing
let (bp_exit, bp_exit_check) = tokio::sync::watch::channel(());
let background_processor = tokio::spawn(process_events_async(
- persister,
+ Arc::clone(&persister),
event_handler,
chain_monitor.clone(),
channel_manager.clone(),
});
// Regularly broadcast our node_announcement. This is only required (or possible) if we have
- // some public channels, and is only useful if we have public listen address(es) to announce.
- // In a production environment, this should occur only after the announcement of new channels
- // to avoid churn in the global network graph.
+ // some public channels.
let peer_man = Arc::clone(&peer_manager);
+ let chan_man = Arc::clone(&channel_manager);
let network = args.network;
- if !args.ldk_announced_listen_addr.is_empty() {
- tokio::spawn(async move {
- let mut interval = tokio::time::interval(Duration::from_secs(60));
- loop {
- interval.tick().await;
+ tokio::spawn(async move {
+ // First wait a minute until we have some peers and maybe have opened a channel.
+ tokio::time::sleep(Duration::from_secs(60)).await;
+ // Then, update our announcement once an hour to keep it fresh but avoid unnecessary churn
+ // in the global gossip network.
+ let mut interval = tokio::time::interval(Duration::from_secs(3600));
+ loop {
+ interval.tick().await;
+ // Don't bother trying to announce if we don't have any public channls, though our
+ // peers should drop such an announcement anyway. Note that announcement may not
+ // propagate until we have a channel with 6+ confirmations.
+ if chan_man.list_channels().iter().any(|chan| chan.is_public) {
peer_man.broadcast_node_announcement(
[0; 3],
args.ldk_announced_node_name,
args.ldk_announced_listen_addr.clone(),
);
}
- });
- }
+ }
+ });
+
+ tokio::spawn(sweep::periodic_sweep(
+ ldk_data_dir.clone(),
+ Arc::clone(&keys_manager),
+ Arc::clone(&logger),
+ Arc::clone(&persister),
+ Arc::clone(&bitcoind_client),
+ ));
// Start the CLI.
cli::poll_for_user_input(
Arc::clone(&onion_messenger),
inbound_payments,
outbound_payments,
- ldk_data_dir.clone(),
+ ldk_data_dir,
network,
Arc::clone(&logger),
)