- }
- Event::PendingHTLCsForwardable { time_forwardable } => {
- let forwarding_channel_manager = loop_channel_manager.clone();
- tokio::spawn(async move {
- let min = time_forwardable.as_millis() as u64;
- let millis_to_sleep = thread_rng().gen_range(min, min * 5) as u64;
- tokio::time::sleep(Duration::from_millis(millis_to_sleep)).await;
- forwarding_channel_manager.process_pending_htlc_forwards();
- });
- }
- 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);
- }
+ },
+ };
+ let channel_str = |channel_id: &Option<ChannelId>| {
+ channel_id
+ .map(|channel_id| format!(" with channel {}", channel_id))
+ .unwrap_or_default()
+ };
+ let from_prev_str =
+ format!(" from {}{}", node_str(&prev_channel_id), channel_str(&prev_channel_id));
+ let to_next_str =
+ format!(" to {}{}", node_str(&next_channel_id), channel_str(&next_channel_id));
+
+ let from_onchain_str = if claim_from_onchain_tx {
+ "from onchain downstream claim"
+ } else {
+ "from HTLC fulfill message"
+ };
+ let amt_args = if let Some(v) = outbound_amount_forwarded_msat {
+ format!("{}", v)
+ } else {
+ "?".to_string()
+ };
+ if let Some(fee_earned) = fee_earned_msat {
+ println!(
+ "\nEVENT: Forwarded payment for {} msat{}{}, earning {} msat {}",
+ amt_args, from_prev_str, to_next_str, fee_earned, from_onchain_str
+ );
+ } else {
+ println!(
+ "\nEVENT: Forwarded payment for {} msat{}{}, claiming onchain {}",
+ amt_args, from_prev_str, to_next_str, from_onchain_str
+ );
+ }
+ print!("> ");
+ io::stdout().flush().unwrap();
+ }
+ Event::HTLCHandlingFailed { .. } => {}
+ Event::PendingHTLCsForwardable { time_forwardable } => {
+ let forwarding_channel_manager = channel_manager.clone();
+ let min = time_forwardable.as_millis() as u64;
+ tokio::spawn(async move {
+ let millis_to_sleep = thread_rng().gen_range(min, min * 5) as u64;
+ tokio::time::sleep(Duration::from_millis(millis_to_sleep)).await;
+ forwarding_channel_manager.process_pending_htlc_forwards();
+ });
+ }
+ Event::SpendableOutputs { outputs, channel_id: _ } => {
+ // 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.write(PENDING_SPENDABLE_OUTPUT_DIR, "", &key, &output.encode()).unwrap();