From cd5af40c3489ef2d6e7c915ae69df4bf9df95239 Mon Sep 17 00:00:00 2001 From: decentclock Date: Fri, 15 Jul 2022 19:38:46 -0600 Subject: [PATCH] FsPersister successfully restores channels on an ubuntu machine --- persister/src/lib.rs | 15 +- persister/src/persist_fs.rs | 286 ++++++++++++++++++++++++++++++++++++ signer/Cargo.toml | 1 + signer/src/lib.rs | 4 +- sphinx-key/Cargo.toml | 1 - 5 files changed, 291 insertions(+), 16 deletions(-) create mode 100644 persister/src/persist_fs.rs diff --git a/persister/src/lib.rs b/persister/src/lib.rs index 7d12d9a..f485c10 100644 --- a/persister/src/lib.rs +++ b/persister/src/lib.rs @@ -1,14 +1 @@ -pub fn add(left: usize, right: usize) -> usize { - left + right -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); - } -} +pub mod persist_fs; diff --git a/persister/src/persist_fs.rs b/persister/src/persist_fs.rs new file mode 100644 index 0000000..e61550f --- /dev/null +++ b/persister/src/persist_fs.rs @@ -0,0 +1,286 @@ +use lightning_signer::persist::Persist; +use lightning_signer_server::persist::model::{ChannelEntry, NodeEntry}; +use std::fs; +use std::io::BufReader; +use std::io::BufWriter; +use std::io::Read; +use std::io::Write; +use std::path::Path; +use std::ptr; +use std::string::String; + +use lightning_signer::bitcoin::secp256k1::PublicKey; +use lightning_signer::chain::tracker::ChainTracker; +use lightning_signer::channel::Channel; +use lightning_signer::channel::ChannelId; +use lightning_signer::channel::ChannelStub; +use lightning_signer::monitor::ChainMonitor; +use lightning_signer::node::NodeConfig; +use lightning_signer::policy::validator::EnforcementState; +use lightning_signer_server::persist::model::AllowlistItemEntry; +use lightning_signer_server::persist::model::ChainTrackerEntry; +use lightning_signer_server::persist::model::NodeChannelId; +use serde::Deserialize; +use serde::Serialize; + +use lightning_signer::persist::model::{ + ChannelEntry as CoreChannelEntry, NodeEntry as CoreNodeEntry, +}; + +const FAT32_MAXFILENAMESIZE: usize = 8; + +const NODE: &str = "/home/ubuntu/sdcard/nodes"; +const CHAN: &str = "/home/ubuntu/sdcard/channel"; +const ALLO: &str = "/home/ubuntu/sdcard/allowlis"; +const CHAI: &str = "/home/ubuntu/sdcard/chaintra"; +const PUBS: &str = "/home/ubuntu/sdcard/pubkey"; + +pub struct FsPersister { + node_path: String, + channel_path: String, + allowlist_path: String, + chaintracker_path: String, + pubkey_path: String, +} + +impl FsPersister { + pub fn new() -> Self { + let _ = fs::create_dir(NODE); + let _ = fs::create_dir(CHAN); + let _ = fs::create_dir(ALLO); + let _ = fs::create_dir(CHAI); + let _ = fs::create_dir(PUBS); + + let mut node_path = String::with_capacity(NODE.len() + 1 + FAT32_MAXFILENAMESIZE); + node_path.push_str(NODE); + node_path.push_str("/"); + let mut channel_path = String::with_capacity(CHAN.len() + 2 + 2 * FAT32_MAXFILENAMESIZE); + channel_path.push_str(CHAN); + channel_path.push_str("/"); + let mut allowlist_path = String::with_capacity(ALLO.len() + 1 + FAT32_MAXFILENAMESIZE); + allowlist_path.push_str(ALLO); + allowlist_path.push_str("/"); + let mut chaintracker_path = String::with_capacity(CHAI.len() + 1 + FAT32_MAXFILENAMESIZE); + chaintracker_path.push_str(CHAI); + chaintracker_path.push_str("/"); + let mut pubkey_path = String::with_capacity(PUBS.len() + 1 + FAT32_MAXFILENAMESIZE); + pubkey_path.push_str(PUBS); + pubkey_path.push_str("/"); + + Self { + node_path, + channel_path, + allowlist_path, + chaintracker_path, + pubkey_path, + } + } +} + +fn write(path: String, entry: T) -> anyhow::Result<()> { + let mut buf = [0u8; 10000]; + let used = postcard::to_slice(&entry, &mut buf)?; + println!("WROTE: {:?} BYTES", used.len()); + let file = fs::File::create(path)?; + let mut writer = BufWriter::new(file); + writer.write_all(used)?; + writer.flush()?; + drop(writer); + Ok(()) +} + +fn read<'a, T: Deserialize<'a>>(path: String, buf: &'a mut Vec) -> T { + let file = fs::File::open(path).expect("Cannot open file"); + let mut reader = BufReader::new(file); + reader.read_to_end(buf).expect("Could not read"); + println!("READ: {:?} BYTES", buf.len()); + postcard::from_bytes(buf).unwrap() +} + +impl Persist for FsPersister { + fn new_node(&self, node_id: &PublicKey, config: &NodeConfig, seed: &[u8]) { + let mut node_path = self.node_path.clone(); + let mut pubkey_path = self.pubkey_path.clone(); + let filename = &hex::encode(node_id.serialize())[..FAT32_MAXFILENAMESIZE]; + node_path.push_str(filename); + pubkey_path.push_str(filename); + let entry = NodeEntry { + seed: seed.to_vec(), + key_derivation_style: config.key_derivation_style as u8, + network: config.network.to_string(), + }; + if let Err(e) = write(node_path, entry) { + println!("Write error: {:?}", e); + } + if let Err(e) = write(pubkey_path, node_id) { + println!("Write error: {:?}", e); + } + } + fn delete_node(&self, node_id: &PublicKey) { + let mut channel_path = self.channel_path.clone(); + let key_a = &hex::encode(node_id.serialize())[..FAT32_MAXFILENAMESIZE]; + channel_path.push_str(key_a); + fs::remove_dir_all(channel_path).unwrap(); + let mut node_path = self.node_path.clone(); + let mut pubkey_path = self.pubkey_path.clone(); + let filename = &hex::encode(node_id.serialize())[..FAT32_MAXFILENAMESIZE]; + node_path.push_str(filename); + pubkey_path.push_str(filename); + fs::remove_file(node_path).unwrap(); + fs::remove_file(pubkey_path).unwrap(); + } + fn new_channel(&self, node_id: &PublicKey, stub: &ChannelStub) -> Result<(), ()> { + let mut channel_path = self.channel_path.clone(); + let key_a = &hex::encode(node_id.serialize())[..FAT32_MAXFILENAMESIZE]; + channel_path.push_str(&key_a); + fs::create_dir(channel_path.clone()).expect("Problem creating a directory"); + channel_path.push_str("/"); + + let id = NodeChannelId::new(node_id, &stub.id0); + channel_path.push_str(&hex::encode( + &id.channel_id().as_slice()[..FAT32_MAXFILENAMESIZE], + )); + let channel_value_satoshis = 0; + let entry = ChannelEntry { + channel_value_satoshis, + channel_setup: None, + id: Some(id.channel_id()), + enforcement_state: EnforcementState::new(0), + }; + if let Err(e) = write(channel_path, entry) { + println!("Write error: {:?}", e); + } + Ok(()) + } + fn new_chain_tracker(&self, node_id: &PublicKey, tracker: &ChainTracker) { + let mut chaintracker_path = self.chaintracker_path.clone(); + chaintracker_path.push_str(&hex::encode(node_id.serialize())[..FAT32_MAXFILENAMESIZE]); + let entry: ChainTrackerEntry = tracker.into(); + if let Err(e) = write(chaintracker_path, entry) { + println!("Write error: {:?}", e); + } + } + fn update_tracker( + &self, + node_id: &PublicKey, + tracker: &ChainTracker, + ) -> Result<(), ()> { + let mut chaintracker_path = self.chaintracker_path.clone(); + chaintracker_path.push_str(&hex::encode(node_id.serialize())[..FAT32_MAXFILENAMESIZE]); + let entry: ChainTrackerEntry = tracker.into(); + if let Err(e) = write(chaintracker_path, entry) { + println!("Write error: {:?}", e); + } + Ok(()) + } + fn get_tracker(&self, node_id: &PublicKey) -> Result, ()> { + let mut chaintracker_path = self.chaintracker_path.clone(); + chaintracker_path.push_str(&hex::encode(node_id.serialize())[..FAT32_MAXFILENAMESIZE]); + let mut buf = Vec::new(); + let ret: ChainTrackerEntry = read(chaintracker_path, &mut buf); + Ok(ret.into()) + } + fn update_channel(&self, node_id: &PublicKey, channel: &Channel) -> Result<(), ()> { + println!("UPDATING CHANNEL: {:?}", channel.id); + let channel_value_satoshis = channel.setup.channel_value_sat; + let mut channel_path = self.channel_path.clone(); + let key_a = &hex::encode(node_id.serialize())[..FAT32_MAXFILENAMESIZE]; + channel_path.push_str(&key_a); + channel_path.push_str("/"); + + let id = NodeChannelId::new(node_id, &channel.id0); + channel_path.push_str(&hex::encode( + &id.channel_id().as_slice()[..FAT32_MAXFILENAMESIZE], + )); + let entry = ChannelEntry { + channel_value_satoshis, + channel_setup: Some(channel.setup.clone()), + //id: channel.id.clone(), + id: if channel.id.is_none() { + Some(id.channel_id()) + } else { + channel.id.clone() + }, + enforcement_state: channel.enforcement_state.clone(), + }; + if let Err(e) = write(channel_path, entry) { + println!("Write error: {:?}", e); + } + Ok(()) + } + fn get_channel( + &self, + node_id: &PublicKey, + channel_id: &ChannelId, + ) -> Result { + let mut channel_path = self.channel_path.clone(); + let key_a = &hex::encode(node_id.serialize())[..FAT32_MAXFILENAMESIZE]; + channel_path.push_str(&key_a); + channel_path.push_str("/"); + let id = NodeChannelId::new(node_id, channel_id); + channel_path.push_str(&hex::encode( + &id.channel_id().as_slice()[..FAT32_MAXFILENAMESIZE], + )); + let mut buf = Vec::new(); + let ret: ChannelEntry = read(channel_path, &mut buf); + Ok(ret.into()) + } + fn get_node_channels(&self, node_id: &PublicKey) -> Vec<(ChannelId, CoreChannelEntry)> { + let mut res = Vec::new(); + let mut channel_path = self.channel_path.clone(); + let key_a = &hex::encode(node_id.serialize())[..FAT32_MAXFILENAMESIZE]; + channel_path.push_str(&key_a); + if !Path::new(&channel_path).exists() { + return res; + } + for channel in fs::read_dir(channel_path).unwrap() { + let channel = channel.unwrap(); + let mut buf = Vec::new(); + let entry: ChannelEntry = read(channel.path().to_str().unwrap().to_string(), &mut buf); + let id = entry.id.clone().unwrap(); + res.push((id, entry.into())) + } + res + } + fn update_node_allowlist(&self, node_id: &PublicKey, allowlist: Vec) -> Result<(), ()> { + let mut allowlist_path = self.allowlist_path.clone(); + allowlist_path.push_str(&hex::encode(node_id.serialize())[..FAT32_MAXFILENAMESIZE]); + let entry = AllowlistItemEntry { allowlist }; + if let Err(e) = write(allowlist_path, entry) { + println!("Write error: {:?}", e); + } + Ok(()) + } + fn get_node_allowlist(&self, node_id: &PublicKey) -> Vec { + let mut allowlist_path = self.allowlist_path.clone(); + allowlist_path.push_str(&hex::encode(node_id.serialize())[..FAT32_MAXFILENAMESIZE]); + let mut buf = Vec::new(); + let entry: AllowlistItemEntry = read(allowlist_path, &mut buf); + entry.allowlist + } + fn get_nodes(&self) -> Vec<(PublicKey, CoreNodeEntry)> { + let mut res = Vec::new(); + let pubkey_path = self.pubkey_path.clone(); + let node_path = self.node_path.clone(); + for (pubkey, node) in fs::read_dir(pubkey_path) + .unwrap() + .zip(fs::read_dir(node_path).unwrap()) + { + let node = node.unwrap(); + let pubkey = pubkey.unwrap(); + let mut buf_a = Vec::new(); + let mut buf_b = Vec::new(); + let pubkey: PublicKey = read(pubkey.path().to_str().unwrap().to_string(), &mut buf_a); + let entry: NodeEntry = read(node.path().to_str().unwrap().to_string(), &mut buf_b); + res.push((pubkey, entry.into())) + } + res + } + fn clear_database(&self) { + fs::remove_dir_all(NODE).unwrap(); + fs::remove_dir_all(CHAN).unwrap(); + fs::remove_dir_all(ALLO).unwrap(); + fs::remove_dir_all(CHAI).unwrap(); + fs::remove_dir_all(PUBS).unwrap(); + } +} diff --git a/signer/Cargo.toml b/signer/Cargo.toml index 7732b29..c6e4150 100644 --- a/signer/Cargo.toml +++ b/signer/Cargo.toml @@ -6,6 +6,7 @@ edition = "2018" [dependencies] sphinx-key-parser = { path = "../parser" } +sphinx-key-persister = { path = "../persister" } # vls-protocol-signer = { path = "../../../evanf/validating-lightning-signer/vls-protocol-signer", default-features = false, features = ["std", "secp-lowmemory"] } # vls-protocol-signer = { git = "https://gitlab.com/lightning-signer/validating-lightning-signer", default-features = false, features = ["secp-lowmemory"] } vls-protocol-signer = { git = "https://gitlab.com/Evanfeenstra/validating-lightning-signer", branch = "patch-sign-chan", default-features = false, features = ["std", "secp-lowmemory"] } diff --git a/signer/src/lib.rs b/signer/src/lib.rs index 644b3fb..904910c 100644 --- a/signer/src/lib.rs +++ b/signer/src/lib.rs @@ -10,6 +10,7 @@ pub use vls_protocol_signer::lightning_signer; pub use vls_protocol_signer::lightning_signer::bitcoin::Network; pub use vls_protocol_signer::vls_protocol; pub use sphinx_key_parser::MsgDriver; +pub use sphinx_key_persister::persist_fs::FsPersister; pub struct InitResponse { pub root_handler: RootHandler, @@ -17,7 +18,8 @@ pub struct InitResponse { } pub fn init(bytes: Vec, network: Network) -> anyhow::Result { - let persister: Arc = Arc::new(DummyPersister); + //let persister: Arc = Arc::new(DummyPersister); + let persister: Arc = Arc::new(FsPersister::new()); let mut md = MsgDriver::new(bytes); let (sequence, dbid) = read_serial_request_header(&mut md).expect("read init header"); assert_eq!(dbid, 0); diff --git a/sphinx-key/Cargo.toml b/sphinx-key/Cargo.toml index 854895a..89b3cd6 100644 --- a/sphinx-key/Cargo.toml +++ b/sphinx-key/Cargo.toml @@ -23,7 +23,6 @@ bitflags = "1.3.2" esp-idf-sys = { version = "0.31.5", features = ["binstart"] } sphinx-key-signer = { path = "../signer", optional = true } sphinx-key-crypter = { path = "../crypter" } -sphinx-key-persister = { path = "../persister" } embedded-svc = { version = "0.21.2" } esp-idf-svc = "0.41" esp-idf-hal = "0.37"