Skip to content

Commit 6fa6a98

Browse files
implement Persist and Persister with generic KVStorePersister trait
1 parent 711bcef commit 6fa6a98

File tree

3 files changed

+104
-119
lines changed

3 files changed

+104
-119
lines changed

lightning-background-processor/src/lib.rs

+18-29
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use lightning::ln::peer_handler::{CustomMessageHandler, PeerManager, SocketDescr
2020
use lightning::routing::network_graph::{NetworkGraph, NetGraphMsgHandler};
2121
use lightning::util::events::{Event, EventHandler, EventsProvider};
2222
use lightning::util::logger::Logger;
23+
use lightning_persister::Persister;
2324
use std::sync::Arc;
2425
use std::sync::atomic::{AtomicBool, Ordering};
2526
use std::thread;
@@ -80,22 +81,7 @@ const FIRST_NETWORK_PRUNE_TIMER: u64 = 60;
8081
#[cfg(test)]
8182
const FIRST_NETWORK_PRUNE_TIMER: u64 = 1;
8283

83-
/// Trait that handles persisting a [`ChannelManager`] and [`NetworkGraph`] to disk.
84-
pub trait Persister<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
85-
where
86-
M::Target: 'static + chain::Watch<Signer>,
87-
T::Target: 'static + BroadcasterInterface,
88-
K::Target: 'static + KeysInterface<Signer = Signer>,
89-
F::Target: 'static + FeeEstimator,
90-
L::Target: 'static + Logger,
91-
{
92-
/// Persist the given [`ChannelManager`] to disk, returning an error if persistence failed
93-
/// (which will cause the [`BackgroundProcessor`] which called this method to exit).
94-
fn persist_manager(&self, channel_manager: &ChannelManager<Signer, M, T, K, F, L>) -> Result<(), std::io::Error>;
95-
96-
/// Persist the given [`NetworkGraph`] to disk, returning an error if persistence failed.
97-
fn persist_graph(&self, network_graph: &NetworkGraph) -> Result<(), std::io::Error>;
98-
}
84+
9985

10086
/// Decorates an [`EventHandler`] with common functionality provided by standard [`EventHandler`]s.
10187
struct DecoratingEventHandler<
@@ -142,7 +128,7 @@ impl BackgroundProcessor {
142128
/// provided implementation.
143129
///
144130
/// [`Persister::persist_graph`] is responsible for writing out the [`NetworkGraph`] to disk. See
145-
/// [`NetworkGraph::write`] for writing out a [`NetworkGraph`]. See [`FilesystemPersister::persist_network_graph`]
131+
/// [`NetworkGraph::write`] for writing out a [`NetworkGraph`]. See [`FilesystemPersister::persist_graph`]
146132
/// for Rust-Lightning's provided implementation.
147133
///
148134
/// Typically, users should either implement [`Persister::persist_manager`] to never return an
@@ -161,8 +147,8 @@ impl BackgroundProcessor {
161147
/// [`stop`]: Self::stop
162148
/// [`ChannelManager`]: lightning::ln::channelmanager::ChannelManager
163149
/// [`ChannelManager::write`]: lightning::ln::channelmanager::ChannelManager#impl-Writeable
164-
/// [`FilesystemPersister::persist_manager`]: lightning_persister::FilesystemPersister::persist_manager
165-
/// [`FilesystemPersister::persist_network_graph`]: lightning_persister::FilesystemPersister::persist_network_graph
150+
/// [`FilesystemPersister::persist_manager`]: lightning_persister::FilesystemPersister#impl-Persister
151+
/// [`FilesystemPersister::persist_graph`]: lightning_persister::FilesystemPersister#impl-Persister
166152
/// [`NetworkGraph`]: lightning::routing::network_graph::NetworkGraph
167153
/// [`NetworkGraph::write`]: lightning::routing::network_graph::NetworkGraph#impl-Writeable
168154
pub fn start<
@@ -180,7 +166,7 @@ impl BackgroundProcessor {
180166
CMH: 'static + Deref + Send + Sync,
181167
RMH: 'static + Deref + Send + Sync,
182168
EH: 'static + EventHandler + Send,
183-
PS: 'static + Send + Persister<Signer, CW, T, K, F, L>,
169+
PS: 'static + Send + Persister,
184170
M: 'static + Deref<Target = ChainMonitor<Signer, CF, T, F, L, P>> + Send + Sync,
185171
CM: 'static + Deref<Target = ChannelManager<Signer, CW, T, K, F, L>> + Send + Sync,
186172
NG: 'static + Deref<Target = NetGraphMsgHandler<G, CA, L>> + Send + Sync,
@@ -367,8 +353,8 @@ mod tests {
367353
use lightning::util::test_utils;
368354
use lightning_invoice::payment::{InvoicePayer, RetryAttempts};
369355
use lightning_invoice::utils::DefaultRouter;
370-
use lightning_persister::FilesystemPersister;
371-
use std::fs;
356+
use lightning_persister::{FilesystemPersister, Persister as LPPersister};
357+
use std::fs::{self, File};
372358
use std::ops::Deref;
373359
use std::path::PathBuf;
374360
use std::sync::{Arc, Mutex};
@@ -414,12 +400,14 @@ mod tests {
414400
struct Persister {
415401
data_dir: String,
416402
graph_error: Option<(std::io::ErrorKind, &'static str)>,
417-
manager_error: Option<(std::io::ErrorKind, &'static str)>
403+
manager_error: Option<(std::io::ErrorKind, &'static str)>,
404+
filesystem_persister: FilesystemPersister
418405
}
419406

420407
impl Persister {
421408
fn new(data_dir: String) -> Self {
422-
Self { data_dir, graph_error: None, manager_error: None }
409+
let filesystem_persister = FilesystemPersister::new(data_dir.clone());
410+
Self { data_dir, graph_error: None, manager_error: None, filesystem_persister }
423411
}
424412

425413
fn with_graph_error(self, error: std::io::ErrorKind, message: &'static str) -> Self {
@@ -431,23 +419,24 @@ mod tests {
431419
}
432420
}
433421

434-
impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L:Deref> super::Persister<Signer, M, T, K, F, L> for Persister where
422+
impl LPPersister for Persister
423+
{
424+
fn persist_manager<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>(&self, channel_manager: &ChannelManager<Signer, M, T, K, F, L>) -> Result<(), std::io::Error> where
435425
M::Target: 'static + chain::Watch<Signer>,
436426
T::Target: 'static + BroadcasterInterface,
437427
K::Target: 'static + KeysInterface<Signer = Signer>,
438428
F::Target: 'static + FeeEstimator,
439429
L::Target: 'static + Logger,
440-
{
441-
fn persist_manager(&self, channel_manager: &ChannelManager<Signer, M, T, K, F, L>) -> Result<(), std::io::Error> {
430+
{
442431
match self.manager_error {
443-
None => FilesystemPersister::persist_manager(self.data_dir.clone(), channel_manager),
432+
None => self.filesystem_persister.persist_manager(channel_manager),
444433
Some((error, message)) => Err(std::io::Error::new(error, message)),
445434
}
446435
}
447436

448437
fn persist_graph(&self, network_graph: &NetworkGraph) -> Result<(), std::io::Error> {
449438
match self.graph_error {
450-
None => FilesystemPersister::persist_network_graph(self.data_dir.clone(), network_graph),
439+
None => self.filesystem_persister.persist_graph(network_graph),
451440
Some((error, message)) => Err(std::io::Error::new(error, message)),
452441
}
453442
}

lightning-persister/src/lib.rs

+59-61
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ extern crate libc;
1717
use bitcoin::hash_types::{BlockHash, Txid};
1818
use bitcoin::hashes::hex::{FromHex, ToHex};
1919
use lightning::routing::network_graph::NetworkGraph;
20-
use crate::util::DiskWriteable;
2120
use lightning::chain;
2221
use lightning::chain::chaininterface::{BroadcasterInterface, FeeEstimator};
2322
use lightning::chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate};
@@ -28,9 +27,38 @@ use lightning::ln::channelmanager::ChannelManager;
2827
use lightning::util::logger::Logger;
2928
use lightning::util::ser::{ReadableArgs, Writeable};
3029
use std::fs;
31-
use std::io::{Cursor, Error};
30+
use std::io::{Cursor, Error, Write};
3231
use std::ops::Deref;
33-
use std::path::{Path, PathBuf};
32+
use std::path::{Path, PathBuf, MAIN_SEPARATOR};
33+
34+
35+
/// Trait that handles persisting a [`ChannelManager`] and [`NetworkGraph`] to disk.
36+
pub trait Persister
37+
{
38+
/// Persist the given [`ChannelManager`] to disk, returning an error if persistence failed
39+
/// (which will cause the BackgroundProcessor which called this method to exit).
40+
fn persist_manager<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>(&self, channel_manager: &ChannelManager<Signer, M, T, K, F, L>) -> Result<(), std::io::Error> where
41+
M::Target: 'static + chain::Watch<Signer>,
42+
T::Target: 'static + BroadcasterInterface,
43+
K::Target: 'static + KeysInterface<Signer = Signer>,
44+
F::Target: 'static + FeeEstimator,
45+
L::Target: 'static + Logger;
46+
47+
/// Persist the given [`NetworkGraph`] to disk, returning an error if persistence failed.
48+
fn persist_graph(&self, network_graph: &NetworkGraph) -> Result<(), std::io::Error>;
49+
}
50+
51+
/// Trait for a key-value store for persisting some writeable object at some key
52+
pub trait KVStorePersister<W: Writeable> {
53+
/// Persist the given writeable using the provided key
54+
fn persist(&self, key: String, object: &W) -> std::io::Result<()>;
55+
}
56+
57+
impl<W: Writeable> KVStorePersister<W> for FilesystemPersister {
58+
fn persist(&self, key: String, object: &W) -> std::io::Result<()> {
59+
util::write_to_file(format!("{}{}{}", self.path_to_channel_data, MAIN_SEPARATOR, key), object)
60+
}
61+
}
3462

3563
/// FilesystemPersister persists channel data on disk, where each channel's
3664
/// data is stored in a file named after its funding outpoint.
@@ -48,31 +76,6 @@ pub struct FilesystemPersister {
4876
path_to_channel_data: String,
4977
}
5078

51-
impl<Signer: Sign> DiskWriteable for ChannelMonitor<Signer> {
52-
fn write_to_file(&self, writer: &mut fs::File) -> Result<(), Error> {
53-
self.write(writer)
54-
}
55-
}
56-
57-
impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> DiskWriteable for ChannelManager<Signer, M, T, K, F, L>
58-
where
59-
M::Target: chain::Watch<Signer>,
60-
T::Target: BroadcasterInterface,
61-
K::Target: KeysInterface<Signer=Signer>,
62-
F::Target: FeeEstimator,
63-
L::Target: Logger,
64-
{
65-
fn write_to_file(&self, writer: &mut fs::File) -> Result<(), std::io::Error> {
66-
self.write(writer)
67-
}
68-
}
69-
70-
impl DiskWriteable for NetworkGraph {
71-
fn write_to_file(&self, writer: &mut fs::File) -> Result<(), std::io::Error> {
72-
self.write(writer)
73-
}
74-
}
75-
7679
impl FilesystemPersister {
7780
/// Initialize a new FilesystemPersister and set the path to the individual channels'
7881
/// files.
@@ -87,34 +90,8 @@ impl FilesystemPersister {
8790
self.path_to_channel_data.clone()
8891
}
8992

90-
pub(crate) fn path_to_monitor_data(&self) -> PathBuf {
91-
let mut path = PathBuf::from(self.path_to_channel_data.clone());
92-
path.push("monitors");
93-
path
94-
}
95-
96-
/// Writes the provided `ChannelManager` to the path provided at `FilesystemPersister`
97-
/// initialization, within a file called "manager".
98-
pub fn persist_manager<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>(
99-
data_dir: String,
100-
manager: &ChannelManager<Signer, M, T, K, F, L>
101-
) -> Result<(), std::io::Error>
102-
where
103-
M::Target: chain::Watch<Signer>,
104-
T::Target: BroadcasterInterface,
105-
K::Target: KeysInterface<Signer=Signer>,
106-
F::Target: FeeEstimator,
107-
L::Target: Logger,
108-
{
109-
let path = PathBuf::from(data_dir);
110-
util::write_to_file(path, "manager".to_string(), manager)
111-
}
112-
113-
/// Write the provided `NetworkGraph` to the path provided at `FilesystemPersister`
114-
/// initialization, within a file called "network_graph"
115-
pub fn persist_network_graph(data_dir: String, network_graph: &NetworkGraph) -> Result<(), std::io::Error> {
116-
let path = PathBuf::from(data_dir);
117-
util::write_to_file(path, "network_graph".to_string(), network_graph)
93+
pub(crate) fn path_to_monitor_data(&self) -> String {
94+
format!("{}{}monitors", self.path_to_channel_data, MAIN_SEPARATOR)
11895
}
11996

12097
/// Read `ChannelMonitor`s from disk.
@@ -124,7 +101,7 @@ impl FilesystemPersister {
124101
where K::Target: KeysInterface<Signer=Signer> + Sized,
125102
{
126103
let path = self.path_to_monitor_data();
127-
if !Path::new(&path).exists() {
104+
if !Path::new(&PathBuf::from(&path)).exists() {
128105
return Ok(Vec::new());
129106
}
130107
let mut res = Vec::new();
@@ -187,18 +164,39 @@ impl<ChannelSigner: Sign> chainmonitor::Persist<ChannelSigner> for FilesystemPer
187164
// even broadcasting!
188165

189166
fn persist_new_channel(&self, funding_txo: OutPoint, monitor: &ChannelMonitor<ChannelSigner>, _update_id: chainmonitor::MonitorUpdateId) -> Result<(), chain::ChannelMonitorUpdateErr> {
190-
let filename = format!("{}_{}", funding_txo.txid.to_hex(), funding_txo.index);
191-
util::write_to_file(self.path_to_monitor_data(), filename, monitor)
167+
let key = format!("monitors{}{}_{}", MAIN_SEPARATOR, funding_txo.txid.to_hex(), funding_txo.index);
168+
self.persist(key, monitor)
192169
.map_err(|_| chain::ChannelMonitorUpdateErr::PermanentFailure)
193170
}
194171

195172
fn update_persisted_channel(&self, funding_txo: OutPoint, _update: &Option<ChannelMonitorUpdate>, monitor: &ChannelMonitor<ChannelSigner>, _update_id: chainmonitor::MonitorUpdateId) -> Result<(), chain::ChannelMonitorUpdateErr> {
196-
let filename = format!("{}_{}", funding_txo.txid.to_hex(), funding_txo.index);
197-
util::write_to_file(self.path_to_monitor_data(), filename, monitor)
173+
let key = format!("monitors{}{}_{}", MAIN_SEPARATOR, funding_txo.txid.to_hex(), funding_txo.index);
174+
self.persist(key, monitor)
198175
.map_err(|_| chain::ChannelMonitorUpdateErr::PermanentFailure)
199176
}
200177
}
201178

179+
impl Persister for FilesystemPersister {
180+
fn persist_manager<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>(&self, channel_manager: &ChannelManager<Signer, M, T, K, F, L>) -> Result<(), std::io::Error> where
181+
M::Target: 'static + chain::Watch<Signer>,
182+
T::Target: 'static + BroadcasterInterface,
183+
K::Target: 'static + KeysInterface<Signer=Signer>,
184+
F::Target: 'static + FeeEstimator,
185+
L::Target: 'static + Logger {
186+
self.persist("manager".to_string(), channel_manager)
187+
}
188+
189+
fn persist_graph(&self, network_graph: &NetworkGraph) -> Result<(), std::io::Error> {
190+
if self.persist("network_graph".to_string(), network_graph).is_err()
191+
{
192+
// Persistence errors here are non-fatal as we can just fetch the routing graph
193+
// again later, but they may indicate a disk error which could be fatal elsewhere.
194+
eprintln!("Warning: Failed to persist network graph, check your disk and permissions");
195+
}
196+
Ok(())
197+
}
198+
}
199+
202200
#[cfg(test)]
203201
mod tests {
204202
extern crate lightning;

0 commit comments

Comments
 (0)