diff --git a/persister/Cargo.toml b/persister/Cargo.toml index ca2dfe7..9305d10 100644 --- a/persister/Cargo.toml +++ b/persister/Cargo.toml @@ -9,6 +9,5 @@ edition = "2021" lightning-signer-core = { git = "https://gitlab.com/Evanfeenstra/validating-lightning-signer", branch = "patch-sign-chan", default-features = false, features = ["std", "secp-lowmemory"] } lightning-signer-server = { git = "https://gitlab.com/Evanfeenstra/validating-lightning-signer", branch = "patch-sign-chan", default-features = false, features = ["persist"] } serde = { version = "1.0.105" } -postcard = "1.0.0" hex = "0.4.3" -anyhow = { version = "1.0.58", features = ["backtrace"] } +fsdb = "0.1.4" \ No newline at end of file diff --git a/persister/src/persist_fs.rs b/persister/src/persist_fs.rs index e61550f..e78ad94 100644 --- a/persister/src/persist_fs.rs +++ b/persister/src/persist_fs.rs @@ -1,12 +1,6 @@ +use fsdb::{Bucket, Fsdb}; 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; @@ -20,8 +14,6 @@ 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, @@ -29,183 +21,104 @@ use lightning_signer::persist::model::{ 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, + nodes: Bucket, + channels: Bucket, + allowlist: Bucket, + chaintracker: Bucket, + pubkeys: Bucket, } 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("/"); - + let db = Fsdb::new("home/ubuntu/sdcard").expect("could not create db"); + let mut nodes = db.bucket("nodes").expect("fail nodes"); + nodes.set_max_file_name(FAT32_MAXFILENAMESIZE); + let mut channels = db.bucket("channel").expect("fail channel"); + channels.set_max_file_name(FAT32_MAXFILENAMESIZE); + let mut allowlist = db.bucket("allowlis").expect("fail allowlis"); + allowlist.set_max_file_name(FAT32_MAXFILENAMESIZE); + let mut chaintracker = db.bucket("chaintra").expect("fail chaintra"); + chaintracker.set_max_file_name(FAT32_MAXFILENAMESIZE); + let mut pubkeys = db.bucket("pubkey").expect("fail pubkey"); + pubkeys.set_max_file_name(FAT32_MAXFILENAMESIZE); Self { - node_path, - channel_path, - allowlist_path, - chaintracker_path, - pubkey_path, + nodes, + channels, + allowlist, + chaintracker, + pubkeys, } } } -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 pk = hex::encode(node_id.serialize()); 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); - } + let _ = self.nodes.put(&pk, entry); + let _ = self.pubkeys.put(&pk, node_id.clone()); } 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(); + let pk = hex::encode(node_id.serialize()); + // clear all channel entries within "pk" sub-bucket + let _ = self.channels.clear_within(&pk); + let _ = self.nodes.remove(&pk); + let _ = self.pubkeys.remove(&pk); } 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 pk = hex::encode(node_id.serialize()); 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 chan_id = hex::encode(id.channel_id().as_slice()); let entry = ChannelEntry { - channel_value_satoshis, + channel_value_satoshis: 0, 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); - } + let _ = self.channels.put_within(&chan_id, entry, &pk); 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); - } + let pk = hex::encode(node_id.serialize()); + let _ = self.chaintracker.put(&pk, tracker.into()); } 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); - } + let pk = hex::encode(node_id.serialize()); + let _ = self.chaintracker.put(&pk, tracker.into()); 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); + let pk = hex::encode(node_id.serialize()); + let ret: ChainTrackerEntry = match self.chaintracker.get(&pk) { + Ok(ct) => ct, + Err(_) => return Err(()), + }; 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 pk = hex::encode(node_id.serialize()); let id = NodeChannelId::new(node_id, &channel.id0); - channel_path.push_str(&hex::encode( - &id.channel_id().as_slice()[..FAT32_MAXFILENAMESIZE], - )); + let chan_id = hex::encode(id.channel_id().as_slice()); 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() }, + channel_value_satoshis: channel.setup.channel_value_sat, + channel_setup: Some(channel.setup.clone()), enforcement_state: channel.enforcement_state.clone(), }; - if let Err(e) = write(channel_path, entry) { - println!("Write error: {:?}", e); - } + let _ = self.channels.put_within(&chan_id, entry, &pk); Ok(()) } fn get_channel( @@ -213,74 +126,64 @@ impl Persist for FsPersister { 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 pk = hex::encode(node_id.serialize()); 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); + let chan_id = hex::encode(id.channel_id().as_slice()); + let ret: ChannelEntry = match self.channels.get_within(&chan_id, &pk) { + Ok(ce) => ce, + Err(_) => return Err(()), + }; 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())) + let pk = hex::encode(node_id.serialize()); + let list = match self.channels.list_within(&pk) { + Ok(l) => l, + Err(_) => return res, + }; + for channel in list { + if let Ok(entry) = self.channels.get_within(&channel, &pk) { + 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 pk = hex::encode(node_id.serialize()); let entry = AllowlistItemEntry { allowlist }; - if let Err(e) = write(allowlist_path, entry) { - println!("Write error: {:?}", e); - } + let _ = self.allowlist.put(&pk, entry); 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); + let pk = hex::encode(node_id.serialize()); + let entry: AllowlistItemEntry = match self.allowlist.get(&pk) { + Ok(e) => e, + Err(_) => return Vec::new(), + }; 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())) + let list = match self.nodes.list() { + Ok(ns) => ns, + Err(_) => return res, + }; + for pk in list { + if let Ok(pubkey) = self.pubkeys.get(&pk) { + if let Ok(node) = self.nodes.get(&pk) { + res.push((pubkey, node.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(); + let _ = self.nodes.clear(); + let _ = self.channels.clear(); + let _ = self.allowlist.clear(); + let _ = self.chaintracker.clear(); + let _ = self.pubkeys.clear(); } }