diff --git a/parser/src/control.rs b/parser/src/control.rs index 01d98c1..cf83ab6 100644 --- a/parser/src/control.rs +++ b/parser/src/control.rs @@ -4,6 +4,33 @@ use sphinx_auther::nonce; use sphinx_auther::secp256k1::{PublicKey, SecretKey}; use std::sync::{Arc, Mutex}; +#[derive(Serialize, Deserialize, Debug, Clone)] +pub enum ControlMessage { + Nonce, + ResetWifi, + ResetKeys, + ResetAll, + QueryPolicy, + UpdatePolicy(Policy), + QueryAllowlist, + UpdateAllowlist(Vec), + Ota(OtaParams), +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub enum ControlResponse { + Nonce(u64), + ResetWifi, + ResetKeys, + ResetAll, + PolicyCurrent(Policy), + PolicyUpdated(Policy), + AllowlistCurrent(Vec), + AllowlistUpdated(Vec), + OtaConfirm(OtaParams), + Error(String), +} + #[derive(Clone, Debug, Deserialize, Serialize, Default)] pub struct Config { pub broker: String, @@ -13,27 +40,27 @@ pub struct Config { // pub seed: [u8; 32], } -#[derive(Serialize, Deserialize, Debug, Clone)] -pub enum ControlMessage { - Nonce, - ResetWifi, - QueryPolicy, - UpdatePolicy(Policy), - Ota(OtaParams), -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub enum ControlResponse { - Nonce(u64), - ResetWifi, - PolicyCurrent(Policy), - PolicyUpdated(Policy), - OtaConfirm(OtaParams), -} - #[derive(Serialize, Deserialize, Debug, Clone)] pub struct Policy { - pub sats_per_day: u64, + pub sat_limit: u64, + pub interval: Interval, + pub htlc_limit: u64, +} + +impl Default for Policy { + fn default() -> Self { + Self { + sat_limit: 1_000_000, + interval: Interval::Daily, + htlc_limit: 1_000_000, + } + } +} + +#[derive(Serialize, Deserialize, Debug, Clone, Copy)] +pub enum Interval { + Hourly, + Daily, } #[derive(Serialize, Deserialize, Debug, Clone)] @@ -103,11 +130,40 @@ impl Controller { let res = match msg.clone() { ControlMessage::Nonce => ControlResponse::Nonce(self.2), ControlMessage::ResetWifi => { - store.reset(); + store.remove_config()?; ControlResponse::ResetWifi } - ControlMessage::UpdatePolicy(np) => ControlResponse::PolicyUpdated(np), - _ => ControlResponse::Nonce(self.2), + ControlMessage::ResetKeys => { + store.remove_seed()?; + ControlResponse::ResetKeys + } + ControlMessage::ResetAll => { + store.remove_config()?; + store.remove_seed()?; + store.remove_policy()?; + store.set_nonce(0)?; + ControlResponse::ResetAll + } + ControlMessage::QueryPolicy => { + let p = store.read_policy().unwrap_or_default(); + ControlResponse::PolicyCurrent(p) + } + ControlMessage::UpdatePolicy(np) => { + store.write_policy(np.clone())?; + ControlResponse::PolicyUpdated(np) + } + ControlMessage::QueryAllowlist => { + // this response is overwritten in the event handler + ControlResponse::AllowlistCurrent(vec![]) + } + ControlMessage::UpdateAllowlist(na) => { + // the actual writing happens in the event handler + ControlResponse::AllowlistUpdated(na) + } + ControlMessage::Ota(params) => { + // ... + ControlResponse::OtaConfirm(params) + } }; let response = self.build_response(res)?; Ok((response, msg)) @@ -119,6 +175,7 @@ pub enum FlashKey { Config, Seed, Nonce, + Policy, } impl FlashKey { pub fn as_str(&self) -> &'static str { @@ -126,24 +183,28 @@ impl FlashKey { FlashKey::Config => "config", FlashKey::Seed => "seed", FlashKey::Nonce => "nonce", + FlashKey::Policy => "policy", } } } pub trait ControlPersist: Sync + Send { - fn reset(&mut self); fn read_nonce(&self) -> Result; fn set_nonce(&mut self, nonce: u64) -> Result<()>; fn read_config(&self) -> Result; fn write_config(&mut self, c: Config) -> Result<()>; + fn remove_config(&mut self) -> Result<()>; fn read_seed(&self) -> Result<[u8; 32]>; fn write_seed(&mut self, s: [u8; 32]) -> Result<()>; + fn remove_seed(&mut self) -> Result<()>; + fn read_policy(&self) -> Result; + fn write_policy(&mut self, s: Policy) -> Result<()>; + fn remove_policy(&mut self) -> Result<()>; } pub struct DummyPersister; impl ControlPersist for DummyPersister { - fn reset(&mut self) {} fn read_nonce(&self) -> Result { Ok(0u64) } @@ -156,10 +217,25 @@ impl ControlPersist for DummyPersister { fn write_config(&mut self, _conf: Config) -> Result<()> { Ok(()) } + fn remove_config(&mut self) -> Result<()> { + Ok(()) + } fn read_seed(&self) -> Result<[u8; 32]> { Ok([0; 32]) } fn write_seed(&mut self, _s: [u8; 32]) -> Result<()> { Ok(()) } + fn remove_seed(&mut self) -> Result<()> { + Ok(()) + } + fn read_policy(&self) -> Result { + Ok(Default::default()) + } + fn write_policy(&mut self, _s: Policy) -> Result<()> { + Ok(()) + } + fn remove_policy(&mut self) -> Result<()> { + Ok(()) + } } diff --git a/signer/src/lib.rs b/signer/src/lib.rs index 3cf1e81..5f7d1ae 100644 --- a/signer/src/lib.rs +++ b/signer/src/lib.rs @@ -1,25 +1,25 @@ mod derive; +mod policy; mod randomstartingtime; use lightning_signer::bitcoin::blockdata::constants::ChainHash; use lightning_signer::node::NodeServices; use lightning_signer::persist::Persist; -use lightning_signer::policy::filter::PolicyFilter; -use lightning_signer::policy::simple_validator::{make_simple_policy, SimpleValidatorFactory}; +use lightning_signer::policy::simple_validator::SimpleValidatorFactory; use lightning_signer::util::clock::StandardClock; -use lightning_signer::util::velocity::{VelocityControlIntervalType, VelocityControlSpec}; use randomstartingtime::RandomStartingTimeFactory; use std::sync::Arc; use vls_protocol::model::{PubKey, Secret}; use vls_protocol::msgs::{self, read_serial_request_header, write_serial_response_header, Message}; use vls_protocol::serde_bolt::WireString; -use vls_protocol_signer::handler::{Handler, RootHandler}; +pub use vls_protocol_signer::handler::{Handler, RootHandler}; pub use vls_protocol_signer::lightning_signer; use vls_protocol_signer::lightning_signer::bitcoin::Network; use vls_protocol_signer::lightning_signer::wallet::Wallet; pub use vls_protocol_signer::vls_protocol; pub use derive::node_keys as derive_node_keys; +pub use policy::{get_allowlist, make_policy, set_allowlist, set_policy}; pub use sphinx_key_parser::{control, topics, MsgDriver}; pub use sphinx_key_persister::FsPersister; pub struct InitResponse { @@ -29,24 +29,11 @@ pub struct InitResponse { pub const ROOT_STORE: &str = "/sdcard/store"; -pub fn set_policies( - root_handler: &RootHandler, +pub fn init( + bytes: Vec, network: Network, - sats_per_day: u64, -) -> anyhow::Result<()> { - let mut policy = make_simple_policy(network); - policy.filter = PolicyFilter::new_permissive(); - let velocity_spec = VelocityControlSpec { - limit: sats_per_day, - interval_type: VelocityControlIntervalType::Daily, - }; - policy.global_velocity_control = velocity_spec; - let validator_factory = Arc::new(SimpleValidatorFactory::new_with_policy(policy)); - root_handler.node.set_validator_factory(validator_factory); - Ok(()) -} - -pub fn init(bytes: Vec, network: Network) -> anyhow::Result { + po: &control::Policy, +) -> anyhow::Result { // let persister: Arc = Arc::new(DummyPersister); let mut md = MsgDriver::new(bytes); let (sequence, dbid) = read_serial_request_header(&mut md).expect("read init header"); @@ -62,13 +49,7 @@ pub fn init(bytes: Vec, network: Network) -> anyhow::Result { .map(|s| from_wire_string(s)) .collect::>(); log::info!("allowlist {:?}", allowlist); - let mut policy = make_simple_policy(network); - policy.filter = PolicyFilter::new_permissive(); - let velocity_spec = VelocityControlSpec { - limit: 1_000_000, // default a million sats per day - interval_type: VelocityControlIntervalType::Daily, - }; - policy.global_velocity_control = velocity_spec; + let policy = make_policy(network, po); let validator_factory = Arc::new(SimpleValidatorFactory::new_with_policy(policy)); let random_time_factory = RandomStartingTimeFactory::new(); let persister: Arc = Arc::new(FsPersister::new(ROOT_STORE)); @@ -79,7 +60,6 @@ pub fn init(bytes: Vec, network: Network) -> anyhow::Result { persister, clock, }; - log::info!("create root handler now"); let root_handler = RootHandler::new(network, 0, Some(seed), allowlist, services); log::info!("root_handler created"); diff --git a/signer/src/policy.rs b/signer/src/policy.rs new file mode 100644 index 0000000..278161d --- /dev/null +++ b/signer/src/policy.rs @@ -0,0 +1,50 @@ +use lightning_signer::policy::filter::PolicyFilter; +use lightning_signer::policy::simple_validator::{ + make_simple_policy, SimplePolicy, SimpleValidatorFactory, +}; +use lightning_signer::util::velocity::{VelocityControlIntervalType, VelocityControlSpec}; +use sphinx_key_parser::control::{Interval, Policy}; +use std::sync::Arc; +use vls_protocol_signer::handler::RootHandler; +use vls_protocol_signer::lightning_signer; +use vls_protocol_signer::lightning_signer::bitcoin::Network; + +fn policy_interval(int: Interval) -> VelocityControlIntervalType { + match int { + Interval::Hourly => VelocityControlIntervalType::Hourly, + Interval::Daily => VelocityControlIntervalType::Daily, + } +} + +pub fn set_policy(root_handler: &RootHandler, network: Network, po: Policy) -> anyhow::Result<()> { + let policy = make_policy(network, &po); + let validator_factory = Arc::new(SimpleValidatorFactory::new_with_policy(policy)); + root_handler.node.set_validator_factory(validator_factory); + Ok(()) +} + +pub fn set_allowlist(root_handler: &RootHandler, allowlist: &Vec) -> anyhow::Result<()> { + if let Err(e) = root_handler.node.set_allowlist(allowlist) { + return Err(anyhow::anyhow!("error setting allowlist {:?}", e)); + } + Ok(()) +} + +pub fn get_allowlist(root_handler: &RootHandler) -> anyhow::Result> { + match root_handler.node.allowlist() { + Ok(al) => Ok(al), + Err(e) => Err(anyhow::anyhow!("error setting allowlist {:?}", e)), + } +} + +pub fn make_policy(network: Network, po: &Policy) -> SimplePolicy { + let mut p = make_simple_policy(network); + p.max_htlc_value_sat = po.htlc_limit; + p.filter = PolicyFilter::new_permissive(); + let velocity_spec = VelocityControlSpec { + limit: po.sat_limit, + interval_type: policy_interval(po.interval), + }; + p.global_velocity_control = velocity_spec; + p +} diff --git a/sphinx-key/src/core/control.rs b/sphinx-key/src/core/control.rs index 8ef2924..7cb4d3a 100644 --- a/sphinx-key/src/core/control.rs +++ b/sphinx-key/src/core/control.rs @@ -3,7 +3,7 @@ use embedded_svc::storage::RawStorage; use embedded_svc::storage::StorageBase; use esp_idf_svc::nvs::EspDefaultNvs; use esp_idf_svc::nvs_storage::EspNvsStorage; -use sphinx_key_signer::control::{Config, ControlPersist, Controller, FlashKey}; +use sphinx_key_signer::control::{Config, ControlPersist, Controller, FlashKey, Policy}; use sphinx_key_signer::lightning_signer::bitcoin::Network; use std::convert::TryInto; use std::sync::{Arc, Mutex}; @@ -28,11 +28,6 @@ impl FlashPersister { } impl ControlPersist for FlashPersister { - fn reset(&mut self) { - self.0 - .remove(FlashKey::Config.as_str()) - .expect("couldnt remove config 1"); - } fn read_nonce(&self) -> Result { let mut buf = [0u8; 8]; let existing = self.0.get_raw(FlashKey::Nonce.as_str(), &mut buf)?; @@ -60,6 +55,10 @@ impl ControlPersist for FlashPersister { self.0.put_raw(FlashKey::Config.as_str(), &conf1[..])?; Ok(()) } + fn remove_config(&mut self) -> Result<()> { + self.0.remove(FlashKey::Config.as_str())?; + Ok(()) + } fn read_seed(&self) -> Result<[u8; 32]> { let mut buf = [0u8; 32]; let s = self.0.get_raw(FlashKey::Seed.as_str(), &mut buf)?; @@ -73,4 +72,25 @@ impl ControlPersist for FlashPersister { self.0.put_raw(FlashKey::Seed.as_str(), &s[..])?; Ok(()) } + fn remove_seed(&mut self) -> Result<()> { + self.0.remove(FlashKey::Seed.as_str())?; + Ok(()) + } + fn read_policy(&self) -> Result { + let mut buf = [0u8; 250]; + let existing = self.0.get_raw(FlashKey::Policy.as_str(), &mut buf)?; + if let None = existing { + return Err(anyhow!("no existing config")); + } + Ok(rmp_serde::from_slice(existing.unwrap().0)?) + } + fn write_policy(&mut self, pol: Policy) -> Result<()> { + let pol1 = rmp_serde::to_vec(&pol)?; + self.0.put_raw(FlashKey::Policy.as_str(), &pol1[..])?; + Ok(()) + } + fn remove_policy(&mut self) -> Result<()> { + self.0.remove(FlashKey::Policy.as_str())?; + Ok(()) + } } diff --git a/sphinx-key/src/core/events.rs b/sphinx-key/src/core/events.rs index ecca6a8..88420ea 100644 --- a/sphinx-key/src/core/events.rs +++ b/sphinx-key/src/core/events.rs @@ -1,11 +1,10 @@ use crate::conn::mqtt::QOS; use crate::core::control::{controller_from_seed, FlashPersister}; -use sphinx_key_signer::control::{Config, ControlMessage}; +use sphinx_key_signer::control::{Config, ControlMessage, ControlResponse, Policy}; use sphinx_key_signer::lightning_signer::bitcoin::Network; -use sphinx_key_signer::topics; use sphinx_key_signer::vls_protocol::model::PubKey; -use sphinx_key_signer::{self, make_init_msg, InitResponse}; +use sphinx_key_signer::{self, make_init_msg, topics, InitResponse, RootHandler}; use std::sync::{mpsc, Arc, Mutex}; use embedded_svc::httpd::Result; @@ -46,6 +45,7 @@ pub fn make_event_loop( led_tx: mpsc::Sender, config: Config, seed: [u8; 32], + policy: &Policy, flash: Arc>, ) -> Result<()> { while let Ok(event) = rx.recv() { @@ -70,7 +70,7 @@ pub fn make_event_loop( let InitResponse { root_handler, init_reply: _, - } = sphinx_key_signer::init(init_msg, network).expect("failed to init signer"); + } = sphinx_key_signer::init(init_msg, network, policy).expect("failed to init signer"); // make the controller to validate Control messages let mut ctrlr = controller_from_seed(&network, &seed[..], flash); @@ -111,20 +111,11 @@ pub fn make_event_loop( } Event::Control(ref msg_bytes) => { log::info!("GOT A CONTROL MSG"); - match ctrlr.handle(msg_bytes) { - Ok((response, parsed_msg)) => { - // log::info!("CONTROL MSG {:?}", response); - match parsed_msg { - ControlMessage::UpdatePolicy(new_policy) => { - // update here - } - _ => (), - }; - mqtt.publish(topics::CONTROL_RETURN, QOS, false, &response) - .expect("could not publish control response"); - } - Err(e) => log::warn!("error parsing ctrl msg {:?}", e), - }; + let cres = ctrlr.handle(msg_bytes); + if let Some(res_data) = handle_control_response(&root_handler, cres, network) { + mqtt.publish(topics::CONTROL_RETURN, QOS, false, &res_data) + .expect("could not publish control response"); + } } } } @@ -132,6 +123,49 @@ pub fn make_event_loop( Ok(()) } +fn handle_control_response( + root_handler: &RootHandler, + cres: anyhow::Result<(Vec, ControlMessage)>, + network: Network, +) -> Option> { + match cres { + Ok((mut response, parsed_msg)) => { + // the following msg types require other actions besides Flash persistence + match parsed_msg { + ControlMessage::UpdatePolicy(new_policy) => { + if let Err(e) = + sphinx_key_signer::set_policy(&root_handler, network, new_policy) + { + log::error!("set policy failed {:?}", e); + } + } + ControlMessage::UpdateAllowlist(al) => { + if let Err(e) = sphinx_key_signer::set_allowlist(&root_handler, &al) { + log::error!("set allowlist failed {:?}", e); + } + } + // overwrite the real Allowlist response, loaded from Node + ControlMessage::QueryAllowlist => { + if let Ok(al) = sphinx_key_signer::get_allowlist(&root_handler) { + response = rmp_serde::to_vec(&ControlResponse::AllowlistCurrent(al)) + .expect("couldnt build ControlResponse::AllowlistCurrent"); + } else { + log::error!("read allowlist failed"); + } + } + _ => (), + }; + Some(response) + } + Err(e) => { + let response = rmp_serde::to_vec(&ControlResponse::Error(e.to_string())) + .expect("couldnt build ControlResponse::Error"); + log::warn!("error parsing ctrl msg {:?}", e); + Some(response) + } + } +} + #[cfg(feature = "pingpong")] pub fn make_event_loop( mut mqtt: EspMqttClient>, @@ -139,7 +173,10 @@ pub fn make_event_loop( _network: Network, do_log: bool, led_tx: mpsc::Sender, + _config: Config, _seed: [u8; 32], + _policy: &Policy, + _flash: Arc>, ) -> Result<()> { log::info!("About to subscribe to the mpsc channel"); while let Ok(event) = rx.recv() { diff --git a/sphinx-key/src/main.rs b/sphinx-key/src/main.rs index a269a93..f7a8e03 100644 --- a/sphinx-key/src/main.rs +++ b/sphinx-key/src/main.rs @@ -19,7 +19,7 @@ use std::time::SystemTime; use esp_idf_hal::peripherals::Peripherals; use esp_idf_svc::nvs::*; -use sphinx_key_signer::control::{Config, ControlPersist}; +use sphinx_key_signer::control::{Config, ControlPersist, Policy}; use sphinx_key_signer::lightning_signer::bitcoin::Network; #[cfg(not(feature = "pingpong"))] @@ -56,6 +56,7 @@ fn main() -> Result<()> { let mut flash = FlashPersister::new(default_nvs.clone()); if let Ok(exist) = flash.read_config() { let seed = flash.read_seed().expect("no seed..."); + let policy = flash.read_policy().unwrap_or_default(); println!( "=============> START CLIENT NOW <============== {:?}", exist @@ -85,9 +86,13 @@ fn main() -> Result<()> { let flash_arc = Arc::new(Mutex::new(flash)); loop { - if let Ok(()) = - make_and_launch_client(exist.clone(), seed, led_tx.clone(), flash_arc.clone()) - { + if let Ok(()) = make_and_launch_client( + exist.clone(), + seed, + &policy, + led_tx.clone(), + flash_arc.clone(), + ) { println!("Exited out of the event loop, trying again in 5 seconds..."); thread::sleep(Duration::from_secs(5)); } else { @@ -112,6 +117,7 @@ fn main() -> Result<()> { fn make_and_launch_client( config: Config, seed: [u8; 32], + policy: &Policy, led_tx: mpsc::Sender, flash: Arc>, ) -> anyhow::Result<()> { @@ -140,6 +146,7 @@ fn make_and_launch_client( led_tx, config, seed, + policy, flash, )?; Ok(()) diff --git a/tester/src/main.rs b/tester/src/main.rs index 07aae3b..e105b21 100644 --- a/tester/src/main.rs +++ b/tester/src/main.rs @@ -134,7 +134,8 @@ async fn main() -> Result<(), Box> { let InitResponse { root_handler, init_reply: _, - } = sphinx_key_signer::init(init_msg, network).expect("failed to init signer"); + } = sphinx_key_signer::init(init_msg, network, &Default::default()) + .expect("failed to init signer"); // the actual handler loop loop { match eventloop.poll().await {