//! Utilities that handle persisting Rust-Lightning data to disk via standard filesystem APIs.
+// Prefix these with `rustdoc::` when we update our MSRV to be >= 1.52 to remove warnings.
#![deny(broken_intra_doc_links)]
+#![deny(private_intra_doc_links)]
+
#![deny(missing_docs)]
-#![cfg_attr(all(test, feature = "unstable"), feature(test))]
-#[cfg(all(test, feature = "unstable"))] extern crate test;
+#![cfg_attr(docsrs, feature(doc_auto_cfg))]
+
+#![cfg_attr(all(test, feature = "_bench_unstable"), feature(test))]
+#[cfg(all(test, feature = "_bench_unstable"))] extern crate test;
mod util;
extern crate libc;
use bitcoin::hash_types::{BlockHash, Txid};
-use bitcoin::hashes::hex::{FromHex, ToHex};
-use crate::util::DiskWriteable;
-use lightning::chain;
-use lightning::chain::chaininterface::{BroadcasterInterface, FeeEstimator};
-use lightning::chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate};
-use lightning::chain::chainmonitor;
-use lightning::chain::keysinterface::{Sign, KeysInterface};
-use lightning::chain::transaction::OutPoint;
-use lightning::ln::channelmanager::ChannelManager;
-use lightning::util::logger::Logger;
+use bitcoin::hashes::hex::FromHex;
+use lightning::chain::channelmonitor::ChannelMonitor;
+use lightning::chain::keysinterface::KeysInterface;
use lightning::util::ser::{ReadableArgs, Writeable};
+use lightning::util::persist::KVStorePersister;
use std::fs;
-use std::io::{Cursor, Error};
+use std::io::Cursor;
use std::ops::Deref;
use std::path::{Path, PathBuf};
path_to_channel_data: String,
}
-impl<Signer: Sign> DiskWriteable for ChannelMonitor<Signer> {
- fn write_to_file(&self, writer: &mut fs::File) -> Result<(), Error> {
- self.write(writer)
- }
-}
-
-impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> DiskWriteable for ChannelManager<Signer, M, T, K, F, L>
-where
- M::Target: chain::Watch<Signer>,
- T::Target: BroadcasterInterface,
- K::Target: KeysInterface<Signer=Signer>,
- F::Target: FeeEstimator,
- L::Target: Logger,
-{
- fn write_to_file(&self, writer: &mut fs::File) -> Result<(), std::io::Error> {
- self.write(writer)
- }
-}
-
impl FilesystemPersister {
/// Initialize a new FilesystemPersister and set the path to the individual channels'
/// files.
self.path_to_channel_data.clone()
}
- pub(crate) fn path_to_monitor_data(&self) -> PathBuf {
- let mut path = PathBuf::from(self.path_to_channel_data.clone());
- path.push("monitors");
- path
- }
-
- /// Writes the provided `ChannelManager` to the path provided at `FilesystemPersister`
- /// initialization, within a file called "manager".
- pub fn persist_manager<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>(
- data_dir: String,
- manager: &ChannelManager<Signer, M, T, K, F, L>
- ) -> Result<(), std::io::Error>
- where
- M::Target: chain::Watch<Signer>,
- T::Target: BroadcasterInterface,
- K::Target: KeysInterface<Signer=Signer>,
- F::Target: FeeEstimator,
- L::Target: Logger,
- {
- let path = PathBuf::from(data_dir);
- util::write_to_file(path, "manager".to_string(), manager)
- }
-
/// Read `ChannelMonitor`s from disk.
- pub fn read_channelmonitors<Signer: Sign, K: Deref> (
+ pub fn read_channelmonitors<K: Deref> (
&self, keys_manager: K
- ) -> Result<Vec<(BlockHash, ChannelMonitor<Signer>)>, std::io::Error>
- where K::Target: KeysInterface<Signer=Signer> + Sized,
+ ) -> Result<Vec<(BlockHash, ChannelMonitor<<K::Target as KeysInterface>::Signer>)>, std::io::Error>
+ where K::Target: KeysInterface + Sized,
{
- let path = self.path_to_monitor_data();
+ let mut path = PathBuf::from(&self.path_to_channel_data);
+ path.push("monitors");
if !Path::new(&path).exists() {
return Ok(Vec::new());
}
"Invalid ChannelMonitor file name",
));
}
+ if filename.unwrap().ends_with(".tmp") {
+ // If we were in the middle of committing an new update and crashed, it should be
+ // safe to ignore the update - we should never have returned to the caller and
+ // irrevocably committed to the new state in any way.
+ continue;
+ }
let txid = Txid::from_hex(filename.unwrap().split_at(64).0);
if txid.is_err() {
let contents = fs::read(&file.path())?;
let mut buffer = Cursor::new(&contents);
- match <(BlockHash, ChannelMonitor<Signer>)>::read(&mut buffer, &*keys_manager) {
+ match <(BlockHash, ChannelMonitor<<K::Target as KeysInterface>::Signer>)>::read(&mut buffer, &*keys_manager) {
Ok((blockhash, channel_monitor)) => {
if channel_monitor.get_funding_txo().0.txid != txid.unwrap() || channel_monitor.get_funding_txo().0.index != index.unwrap() {
return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "ChannelMonitor was stored in the wrong file"));
}
}
-impl<ChannelSigner: Sign> chainmonitor::Persist<ChannelSigner> for FilesystemPersister {
- fn persist_new_channel(&self, funding_txo: OutPoint, monitor: &ChannelMonitor<ChannelSigner>, _update_id: chainmonitor::MonitorUpdateId) -> Result<(), chain::ChannelMonitorUpdateErr> {
- let filename = format!("{}_{}", funding_txo.txid.to_hex(), funding_txo.index);
- util::write_to_file(self.path_to_monitor_data(), filename, monitor)
- .map_err(|_| chain::ChannelMonitorUpdateErr::PermanentFailure)
- }
-
- fn update_persisted_channel(&self, funding_txo: OutPoint, _update: &ChannelMonitorUpdate, monitor: &ChannelMonitor<ChannelSigner>, _update_id: chainmonitor::MonitorUpdateId) -> Result<(), chain::ChannelMonitorUpdateErr> {
- let filename = format!("{}_{}", funding_txo.txid.to_hex(), funding_txo.index);
- util::write_to_file(self.path_to_monitor_data(), filename, monitor)
- .map_err(|_| chain::ChannelMonitorUpdateErr::PermanentFailure)
+impl KVStorePersister for FilesystemPersister {
+ fn persist<W: Writeable>(&self, key: &str, object: &W) -> std::io::Result<()> {
+ let mut dest_file = PathBuf::from(self.path_to_channel_data.clone());
+ dest_file.push(key);
+ util::write_to_file(dest_file, object)
}
}
use crate::FilesystemPersister;
use bitcoin::blockdata::block::{Block, BlockHeader};
use bitcoin::hashes::hex::FromHex;
- use bitcoin::Txid;
- use lightning::chain::ChannelMonitorUpdateErr;
+ use bitcoin::{Txid, TxMerkleNode};
+ use lightning::chain::ChannelMonitorUpdateStatus;
use lightning::chain::chainmonitor::Persist;
use lightning::chain::transaction::OutPoint;
use lightning::{check_closed_broadcast, check_closed_event, check_added_monitors};
- use lightning::ln::features::InitFeatures;
+ use lightning::ln::channelmanager;
use lightning::ln::functional_test_utils::*;
- use lightning::ln::msgs::ErrorAction;
- use lightning::util::events::{ClosureReason, Event, MessageSendEventsProvider, MessageSendEvent};
+ use lightning::util::events::{ClosureReason, MessageSendEventsProvider};
use lightning::util::test_utils;
use std::fs;
+ use bitcoin::hashes::Hash;
#[cfg(target_os = "windows")]
use {
lightning::get_event_msg,
}
// Create some initial channel and check that a channel was persisted.
- let _ = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let _ = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
check_persisted_data!(0);
// Send a few payments and make sure the monitors are updated to the latest.
// Force close because cooperative close doesn't result in any persisted
// updates.
- nodes[0].node.force_close_channel(&nodes[0].node.list_channels()[0].channel_id).unwrap();
+ nodes[0].node.force_close_broadcasting_latest_txn(&nodes[0].node.list_channels()[0].channel_id, &nodes[1].node.get_our_node_id()).unwrap();
check_closed_event!(nodes[0], 1, ClosureReason::HolderForceClosed);
check_closed_broadcast!(nodes[0], true);
check_added_monitors!(nodes[0], 1);
let node_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap();
assert_eq!(node_txn.len(), 1);
- let header = BlockHeader { version: 0x20000000, prev_blockhash: nodes[0].best_block_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
+ let header = BlockHeader { version: 0x20000000, prev_blockhash: nodes[0].best_block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 };
connect_block(&nodes[1], &Block { header, txdata: vec![node_txn[0].clone(), node_txn[0].clone()]});
check_closed_broadcast!(nodes[1], true);
check_closed_event!(nodes[1], 1, ClosureReason::CommitmentTxConfirmed);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let chan = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
- nodes[1].node.force_close_channel(&chan.2).unwrap();
+ let chan = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ nodes[1].node.force_close_broadcasting_latest_txn(&chan.2, &nodes[0].node.get_our_node_id()).unwrap();
check_closed_event!(nodes[1], 1, ClosureReason::HolderForceClosed);
let mut added_monitors = nodes[1].chain_monitor.added_monitors.lock().unwrap();
let update_map = nodes[1].chain_monitor.latest_monitor_update_id.lock().unwrap();
index: 0
};
match persister.persist_new_channel(test_txo, &added_monitors[0].1, update_id.2) {
- Err(ChannelMonitorUpdateErr::PermanentFailure) => {},
+ ChannelMonitorUpdateStatus::PermanentFailure => {},
_ => panic!("unexpected result from persisting new channel")
}
let mut node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let chan = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
- nodes[1].node.force_close_channel(&chan.2).unwrap();
+ let chan = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ nodes[1].node.force_close_broadcasting_latest_txn(&chan.2, &nodes[0].node.get_our_node_id()).unwrap();
check_closed_event!(nodes[1], 1, ClosureReason::HolderForceClosed);
let mut added_monitors = nodes[1].chain_monitor.added_monitors.lock().unwrap();
let update_map = nodes[1].chain_monitor.latest_monitor_update_id.lock().unwrap();
index: 0
};
match persister.persist_new_channel(test_txo, &added_monitors[0].1, update_id.2) {
- Err(ChannelMonitorUpdateErr::PermanentFailure) => {},
+ ChannelMonitorUpdateStatus::PermanentFailure => {},
_ => panic!("unexpected result from persisting new channel")
}
}
}
-#[cfg(all(test, feature = "unstable"))]
+#[cfg(all(test, feature = "_bench_unstable"))]
pub mod bench {
use test::Bencher;