Merge pull request #131 from tnull/2024-02-align-rustfmt
[ldk-sample] / src / sweep.rs
index ad1e9ef4d8698993c2615fd7e0fccfd46114a6bb..fbfa62c97c41c1b6ab5d69bed5e83c6cc7e5ac22 100644 (file)
@@ -7,17 +7,19 @@ use std::{fs, io};
 use lightning::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator};
 use lightning::sign::{EntropySource, KeysManager, SpendableOutputDescriptor};
 use lightning::util::logger::Logger;
-use lightning::util::persist::KVStorePersister;
-use lightning::util::ser::{Readable, WithoutLength};
+use lightning::util::persist::KVStore;
+use lightning::util::ser::{Readable, WithoutLength, Writeable};
 
+use lightning_persister::fs_store::FilesystemStore;
+
+use bitcoin::blockdata::locktime::absolute::LockTime;
 use bitcoin::secp256k1::Secp256k1;
-use bitcoin::{LockTime, PackedLockTime};
+use rand::{thread_rng, Rng};
 
 use crate::hex_utils;
 use crate::BitcoindClient;
 use crate::ChannelManager;
 use crate::FilesystemLogger;
-use crate::FilesystemPersister;
 
 /// If we have any pending claimable outputs, we should slowly sweep them to our Bitcoin Core
 /// wallet. We technically don't need to do this - they're ours to spend when we want and can just
@@ -29,7 +31,7 @@ use crate::FilesystemPersister;
 /// we don't do that here either.
 pub(crate) async fn periodic_sweep(
        ldk_data_dir: String, keys_manager: Arc<KeysManager>, logger: Arc<FilesystemLogger>,
-       persister: Arc<FilesystemPersister>, bitcoind_client: Arc<BitcoindClient>,
+       persister: Arc<FilesystemStore>, bitcoind_client: Arc<BitcoindClient>,
        channel_manager: Arc<ChannelManager>,
 ) {
        // Regularly claim outputs which are exclusively spendable by us and send them to Bitcoin Core.
@@ -78,7 +80,7 @@ pub(crate) async fn periodic_sweep(
                        if !outputs.is_empty() {
                                let key = hex_utils::hex_str(&keys_manager.get_secure_random_bytes());
                                persister
-                                       .persist(&format!("spendable_outputs/{}", key), &WithoutLength(&outputs))
+                                       .write("spendable_outputs", "", &key, &WithoutLength(&outputs).encode())
                                        .unwrap();
                                fs::remove_dir_all(&processing_spendables_dir).unwrap();
                        }
@@ -99,7 +101,7 @@ pub(crate) async fn periodic_sweep(
                                        match file.read_exact(&mut [0; 1]) {
                                                Ok(_) => {
                                                        file.seek(SeekFrom::Current(-1)).unwrap();
-                                               }
+                                               },
                                                Err(e) if e.kind() == io::ErrorKind::UnexpectedEof => break,
                                                Err(e) => Err(e).unwrap(),
                                        }
@@ -107,13 +109,25 @@ pub(crate) async fn periodic_sweep(
                                }
                                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::Background);
+                               let tx_feerate = bitcoind_client
+                                       .get_est_sat_per_1000_weight(ConfirmationTarget::ChannelCloseMinimum);
 
                                // We set nLockTime to the current height to discourage fee sniping.
-                               let cur_height = channel_manager.current_best_block().height();
-                               let locktime: PackedLockTime =
-                                       LockTime::from_height(cur_height).map_or(PackedLockTime::ZERO, |l| l.into());
+                               // Occasionally randomly pick a nLockTime even further back, so
+                               // that transactions that are delayed after signing for whatever reason,
+                               // e.g. high-latency mix networks and some CoinJoin implementations, have
+                               // better privacy.
+                               // Logic copied from core: https://github.com/bitcoin/bitcoin/blob/1d4846a8443be901b8a5deb0e357481af22838d0/src/wallet/spend.cpp#L936
+                               let mut cur_height = channel_manager.current_best_block().height();
+
+                               // 10% of the time
+                               if thread_rng().gen_range(0, 10) == 0 {
+                                       // subtract random number between 0 and 100
+                                       cur_height = cur_height.saturating_sub(thread_rng().gen_range(0, 100));
+                               }
+
+                               let locktime =
+                                       LockTime::from_height(cur_height).map_or(LockTime::ZERO, |l| l.into());
 
                                if let Ok(spending_tx) = keys_manager.spend_spendable_outputs(
                                        output_descriptors,