diff --git a/DEMONOTES.md b/DEMONOTES.md index 02becc1..e3ee2b7 100644 --- a/DEMONOTES.md +++ b/DEMONOTES.md @@ -31,6 +31,7 @@ Password: password of the wifi from the previous step - In window B, launch `aliced`. This launches alice, a generic regtest CLN node. - In window C, run `alice-cli newaddr`. - In the same window, run `touchwallet && genbtc {address of previous step} && blkdump` +- export BITCOIND_RPC_URL=http://localhost - In window D, launch `bobd`. This launches bob, our MQTT remote signer node. - On the ESP32, the LED should blink white when the signer is ready to sign for the node. - Once its pubkey is logged, copy it. diff --git a/persister/Cargo.toml b/persister/Cargo.toml index e5ecff7..6c78c4a 100644 --- a/persister/Cargo.toml +++ b/persister/Cargo.toml @@ -10,4 +10,4 @@ lightning-signer-core = { git = "https://gitlab.com/Evanfeenstra/validating-ligh 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" } hex = "0.4.3" -fsdb = "0.1.8" \ No newline at end of file +fsdb = "0.1.9" \ No newline at end of file diff --git a/persister/src/lib.rs b/persister/src/lib.rs index f485c10..13d0aea 100644 --- a/persister/src/lib.rs +++ b/persister/src/lib.rs @@ -1 +1,182 @@ -pub mod persist_fs; +use fsdb::{Bucket, DoubleBucket, Fsdb}; +use lightning_signer::bitcoin::secp256k1::PublicKey; +use lightning_signer::chain::tracker::ChainTracker; +use lightning_signer::channel::{Channel, ChannelId, ChannelStub}; +use lightning_signer::monitor::ChainMonitor; +use lightning_signer::node::NodeConfig; +use lightning_signer::persist::Persist; +use lightning_signer::policy::validator::EnforcementState; +use lightning_signer_server::persist::model::{ + AllowlistItemEntry, ChainTrackerEntry, ChannelEntry, NodeEntry, +}; +use std::string::String; + +use lightning_signer::persist::model::{ + ChannelEntry as CoreChannelEntry, NodeEntry as CoreNodeEntry, +}; + +const FAT32_MAXFILENAMESIZE: usize = 8; + +pub struct FsPersister { + nodes: Bucket, + channels: DoubleBucket, + allowlist: Bucket, + chaintracker: Bucket, + pubkeys: Bucket, +} + +impl FsPersister { + pub fn new(dir: &str) -> Self { + let db = Fsdb::new(dir).expect("could not create db"); + let max = Some(FAT32_MAXFILENAMESIZE); + Self { + nodes: db.bucket("nodes", max).expect("fail nodes"), + channels: db.double_bucket("channel", max).expect("fail channel"), + allowlist: db.bucket("allowlis", max).expect("fail allowlis"), + chaintracker: db.bucket("chaintra", max).expect("fail chaintra"), + pubkeys: db.bucket("pubkey", max).expect("fail pubkey"), + } + } +} + +fn get_channel_key(channel_id: &[u8]) -> &[u8] { + let length = channel_id.len(); + channel_id.get(length - 11..length - 7).unwrap() +} + +impl Persist for FsPersister { + fn new_node(&self, node_id: &PublicKey, config: &NodeConfig, seed: &[u8]) { + 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(), + }; + let _ = self.nodes.put(&pk, entry); + let _ = self.pubkeys.put(&pk, node_id.clone()); + } + fn delete_node(&self, node_id: &PublicKey) { + let pk = hex::encode(node_id.serialize()); + // clear all channel entries within "pk" sub-bucket + let _ = self.channels.clear(&pk); + let _ = self.nodes.remove(&pk); + let _ = self.pubkeys.remove(&pk); + } + fn new_channel(&self, node_id: &PublicKey, stub: &ChannelStub) -> Result<(), ()> { + let pk = hex::encode(node_id.serialize()); + let chan_id = hex::encode(get_channel_key(stub.id0.as_slice())); + // should not exist + if let Ok(_) = self.channels.get(&pk, &chan_id) { + return Err(()); // already exists + } + let entry = ChannelEntry { + id: Some(stub.id0.clone()), + channel_value_satoshis: 0, + channel_setup: None, + enforcement_state: EnforcementState::new(0), + }; + let _ = self.channels.put(&pk, &chan_id, entry); + Ok(()) + } + fn new_chain_tracker(&self, node_id: &PublicKey, tracker: &ChainTracker) { + 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 pk = hex::encode(node_id.serialize()); + let _ = self.chaintracker.put(&pk, tracker.into()); + Ok(()) + } + fn get_tracker(&self, node_id: &PublicKey) -> Result, ()> { + 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<(), ()> { + let pk = hex::encode(node_id.serialize()); + let chan_id = hex::encode(get_channel_key(channel.id0.as_slice())); + // should exist + if let Err(_) = self.channels.get(&pk, &chan_id) { + return Err(()); // not found + } + let entry = ChannelEntry { + id: Some(channel.id0.clone()), + channel_value_satoshis: channel.setup.channel_value_sat, + channel_setup: Some(channel.setup.clone()), + enforcement_state: channel.enforcement_state.clone(), + }; + let _ = self.channels.put(&pk, &chan_id, entry); + Ok(()) + } + fn get_channel( + &self, + node_id: &PublicKey, + channel_id: &ChannelId, + ) -> Result { + let pk = hex::encode(node_id.serialize()); + let chan_id = hex::encode(get_channel_key(channel_id.as_slice())); + let ret: ChannelEntry = match self.channels.get(&pk, &chan_id) { + 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 pk = hex::encode(node_id.serialize()); + let list = match self.channels.list(&pk) { + Ok(l) => l, + Err(_) => return res, + }; + for channel in list { + if let Ok(entry) = self.channels.get(&pk, &channel) { + let id = entry.id.clone().unwrap(); + res.push((id, entry.into())); + }; + } + res + } + fn update_node_allowlist(&self, node_id: &PublicKey, allowlist: Vec) -> Result<(), ()> { + let pk = hex::encode(node_id.serialize()); + let entry = AllowlistItemEntry { allowlist }; + let _ = self.allowlist.put(&pk, entry); + Ok(()) + } + fn get_node_allowlist(&self, node_id: &PublicKey) -> Vec { + 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 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) { + let _ = self.nodes.clear(); + let _ = self.channels.clear_all(); + let _ = self.allowlist.clear(); + let _ = self.chaintracker.clear(); + let _ = self.pubkeys.clear(); + } +} diff --git a/persister/src/persist_fs.rs b/persister/src/persist_fs.rs deleted file mode 100644 index 13d0aea..0000000 --- a/persister/src/persist_fs.rs +++ /dev/null @@ -1,182 +0,0 @@ -use fsdb::{Bucket, DoubleBucket, Fsdb}; -use lightning_signer::bitcoin::secp256k1::PublicKey; -use lightning_signer::chain::tracker::ChainTracker; -use lightning_signer::channel::{Channel, ChannelId, ChannelStub}; -use lightning_signer::monitor::ChainMonitor; -use lightning_signer::node::NodeConfig; -use lightning_signer::persist::Persist; -use lightning_signer::policy::validator::EnforcementState; -use lightning_signer_server::persist::model::{ - AllowlistItemEntry, ChainTrackerEntry, ChannelEntry, NodeEntry, -}; -use std::string::String; - -use lightning_signer::persist::model::{ - ChannelEntry as CoreChannelEntry, NodeEntry as CoreNodeEntry, -}; - -const FAT32_MAXFILENAMESIZE: usize = 8; - -pub struct FsPersister { - nodes: Bucket, - channels: DoubleBucket, - allowlist: Bucket, - chaintracker: Bucket, - pubkeys: Bucket, -} - -impl FsPersister { - pub fn new(dir: &str) -> Self { - let db = Fsdb::new(dir).expect("could not create db"); - let max = Some(FAT32_MAXFILENAMESIZE); - Self { - nodes: db.bucket("nodes", max).expect("fail nodes"), - channels: db.double_bucket("channel", max).expect("fail channel"), - allowlist: db.bucket("allowlis", max).expect("fail allowlis"), - chaintracker: db.bucket("chaintra", max).expect("fail chaintra"), - pubkeys: db.bucket("pubkey", max).expect("fail pubkey"), - } - } -} - -fn get_channel_key(channel_id: &[u8]) -> &[u8] { - let length = channel_id.len(); - channel_id.get(length - 11..length - 7).unwrap() -} - -impl Persist for FsPersister { - fn new_node(&self, node_id: &PublicKey, config: &NodeConfig, seed: &[u8]) { - 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(), - }; - let _ = self.nodes.put(&pk, entry); - let _ = self.pubkeys.put(&pk, node_id.clone()); - } - fn delete_node(&self, node_id: &PublicKey) { - let pk = hex::encode(node_id.serialize()); - // clear all channel entries within "pk" sub-bucket - let _ = self.channels.clear(&pk); - let _ = self.nodes.remove(&pk); - let _ = self.pubkeys.remove(&pk); - } - fn new_channel(&self, node_id: &PublicKey, stub: &ChannelStub) -> Result<(), ()> { - let pk = hex::encode(node_id.serialize()); - let chan_id = hex::encode(get_channel_key(stub.id0.as_slice())); - // should not exist - if let Ok(_) = self.channels.get(&pk, &chan_id) { - return Err(()); // already exists - } - let entry = ChannelEntry { - id: Some(stub.id0.clone()), - channel_value_satoshis: 0, - channel_setup: None, - enforcement_state: EnforcementState::new(0), - }; - let _ = self.channels.put(&pk, &chan_id, entry); - Ok(()) - } - fn new_chain_tracker(&self, node_id: &PublicKey, tracker: &ChainTracker) { - 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 pk = hex::encode(node_id.serialize()); - let _ = self.chaintracker.put(&pk, tracker.into()); - Ok(()) - } - fn get_tracker(&self, node_id: &PublicKey) -> Result, ()> { - 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<(), ()> { - let pk = hex::encode(node_id.serialize()); - let chan_id = hex::encode(get_channel_key(channel.id0.as_slice())); - // should exist - if let Err(_) = self.channels.get(&pk, &chan_id) { - return Err(()); // not found - } - let entry = ChannelEntry { - id: Some(channel.id0.clone()), - channel_value_satoshis: channel.setup.channel_value_sat, - channel_setup: Some(channel.setup.clone()), - enforcement_state: channel.enforcement_state.clone(), - }; - let _ = self.channels.put(&pk, &chan_id, entry); - Ok(()) - } - fn get_channel( - &self, - node_id: &PublicKey, - channel_id: &ChannelId, - ) -> Result { - let pk = hex::encode(node_id.serialize()); - let chan_id = hex::encode(get_channel_key(channel_id.as_slice())); - let ret: ChannelEntry = match self.channels.get(&pk, &chan_id) { - 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 pk = hex::encode(node_id.serialize()); - let list = match self.channels.list(&pk) { - Ok(l) => l, - Err(_) => return res, - }; - for channel in list { - if let Ok(entry) = self.channels.get(&pk, &channel) { - let id = entry.id.clone().unwrap(); - res.push((id, entry.into())); - }; - } - res - } - fn update_node_allowlist(&self, node_id: &PublicKey, allowlist: Vec) -> Result<(), ()> { - let pk = hex::encode(node_id.serialize()); - let entry = AllowlistItemEntry { allowlist }; - let _ = self.allowlist.put(&pk, entry); - Ok(()) - } - fn get_node_allowlist(&self, node_id: &PublicKey) -> Vec { - 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 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) { - let _ = self.nodes.clear(); - let _ = self.channels.clear_all(); - let _ = self.allowlist.clear(); - let _ = self.chaintracker.clear(); - let _ = self.pubkeys.clear(); - } -} diff --git a/signer/src/lib.rs b/signer/src/lib.rs index 9b60eb5..72e594b 100644 --- a/signer/src/lib.rs +++ b/signer/src/lib.rs @@ -9,7 +9,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 use sphinx_key_persister::FsPersister; pub struct InitResponse { pub root_handler: RootHandler,