Persist channel scores
authorJeffrey Czyz <jkczyz@gmail.com>
Tue, 2 Nov 2021 21:06:05 +0000 (16:06 -0500)
committerJeffrey Czyz <jkczyz@gmail.com>
Wed, 3 Nov 2021 04:10:19 +0000 (23:10 -0500)
src/disk.rs
src/main.rs

index b641ebb053167b01c6f397c1ef40d0decd98ad61..7be070c962f4d73e3c9445c8a5a8730fedd71fe3 100644 (file)
@@ -3,6 +3,7 @@ use bitcoin::secp256k1::key::PublicKey;
 use bitcoin::BlockHash;
 use chrono::Utc;
 use lightning::routing::network_graph::NetworkGraph;
+use lightning::routing::scorer::Scorer;
 use lightning::util::logger::{Logger, Record};
 use lightning::util::ser::{Readable, Writeable, Writer};
 use std::collections::HashMap;
@@ -92,3 +93,25 @@ pub(crate) fn read_network(path: &Path, genesis_hash: BlockHash) -> NetworkGraph
        }
        NetworkGraph::new(genesis_hash)
 }
+
+pub(crate) fn persist_scorer(path: &Path, scorer: &Scorer) -> std::io::Result<()> {
+       let mut tmp_path = path.to_path_buf().into_os_string();
+       tmp_path.push(".tmp");
+       let file = fs::OpenOptions::new().write(true).create(true).open(&tmp_path)?;
+       let write_res = scorer.write(&mut BufWriter::new(file));
+       if let Err(e) = write_res.and_then(|_| fs::rename(&tmp_path, path)) {
+               let _ = fs::remove_file(&tmp_path);
+               Err(e)
+       } else {
+               Ok(())
+       }
+}
+
+pub(crate) fn read_scorer(path: &Path) -> Scorer {
+       if let Ok(file) = File::open(path) {
+               if let Ok(scorer) = Scorer::read(&mut BufReader::new(file)) {
+                       return scorer;
+               }
+       }
+       Scorer::default()
+}
index b85fb4baad293aec773cf9abcad5dd636c0abd8f..421069b804ed2aae75ebecc35389a4a4705203f0 100644 (file)
@@ -596,9 +596,26 @@ async fn start_ldk() {
                ));
        };
 
-       // Step 16: Create InvoicePayer
+       // Step 16: Initialize routing Scorer
+       let scorer_path = format!("{}/scorer", ldk_data_dir.clone());
+       let scorer = Arc::new(Mutex::new(disk::read_scorer(Path::new(&scorer_path))));
+       let scorer_persist = Arc::clone(&scorer);
+       tokio::spawn(async move {
+               let mut interval = tokio::time::interval(Duration::from_secs(600));
+               loop {
+                       interval.tick().await;
+                       if disk::persist_scorer(Path::new(&scorer_path), &scorer_persist.lock().unwrap())
+                               .is_err()
+                       {
+                               // Persistence errors here are non-fatal as channels will be re-scored as payments
+                               // fail, but they may indicate a disk error which could be fatal elsewhere.
+                               eprintln!("Warning: Failed to persist scorer, check your disk and permissions");
+                       }
+               }
+       });
+
+       // Step 17: Create InvoicePayer
        let router = DefaultRouter::new(network_graph.clone(), logger.clone());
-       let scorer = Arc::new(Mutex::new(Scorer::default()));
        let invoice_payer = Arc::new(InvoicePayer::new(
                channel_manager.clone(),
                router,
@@ -608,12 +625,12 @@ async fn start_ldk() {
                payment::RetryAttempts(5),
        ));
 
-       // Step 17: Persist ChannelManager
+       // Step 18: Persist ChannelManager
        let data_dir = ldk_data_dir.clone();
        let persist_channel_manager_callback =
                move |node: &ChannelManager| FilesystemPersister::persist_manager(data_dir.clone(), &*node);
 
-       // Step 18: Background Processing
+       // Step 19: Background Processing
        let background_processor = BackgroundProcessor::start(
                persist_channel_manager_callback,
                invoice_payer.clone(),