lightning_signer/persist/
mod.rs

1use crate::chain::tracker::{ChainTracker, ListenSlot};
2use alloc::sync::Arc;
3use bitcoin::hashes::sha256::Hash as Sha256Hash;
4use bitcoin::hashes::{Hash, HashEngine, Hmac, HmacEngine};
5use bitcoin::secp256k1::PublicKey;
6use bitcoin::OutPoint;
7use core::fmt::{Debug, Display};
8use core::ops::Index;
9use lightning::sign::EntropySource;
10
11use crate::channel::{Channel, ChannelId, ChannelStub};
12use crate::monitor::{ChainMonitor, State as ChainMonitorState};
13use crate::node::{NodeConfig, NodeState};
14use crate::policy::validator::ValidatorFactory;
15use crate::prelude::*;
16
17/// Models for persistence
18pub mod model;
19
20/// A list of mutations memorized by a memorizing persister
21#[derive(Clone)]
22#[must_use]
23pub struct Mutations(Vec<(String, (u64, Vec<u8>))>);
24
25impl Mutations {
26    /// Create a new empty list of mutations
27    pub fn new() -> Self {
28        Mutations(vec![])
29    }
30
31    /// Create a new list of mutations from a vector
32    pub fn from_vec(mutations: Vec<(String, (u64, Vec<u8>))>) -> Self {
33        Mutations(mutations)
34    }
35
36    /// Add a new mutation to the list
37    pub fn add(&mut self, key: String, version: u64, value: Vec<u8>) {
38        self.0.push((key, (version, value)));
39    }
40
41    /// Return a reference to the list of mutations
42    pub fn inner(&self) -> &Vec<(String, (u64, Vec<u8>))> {
43        &self.0
44    }
45
46    /// Return the list of mutations
47    pub fn into_inner(self) -> Vec<(String, (u64, Vec<u8>))> {
48        self.0
49    }
50
51    /// Return an iterator
52    pub fn iter(&self) -> impl Iterator<Item = &(String, (u64, Vec<u8>))> {
53        self.0.iter()
54    }
55
56    /// Into iterator
57    pub fn into_iter(self) -> impl Iterator<Item = (String, (u64, Vec<u8>))> {
58        self.0.into_iter()
59    }
60
61    /// Whether the list is empty
62    pub fn is_empty(&self) -> bool {
63        self.0.is_empty()
64    }
65
66    /// Return the number of mutations
67    pub fn len(&self) -> usize {
68        self.0.len()
69    }
70}
71
72impl Index<usize> for Mutations {
73    type Output = (String, (u64, Vec<u8>));
74
75    fn index(&self, index: usize) -> &Self::Output {
76        &self.0[index]
77    }
78}
79
80/// Debug printer for Mutations which uses hex encoded strings.
81impl Debug for Mutations {
82    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
83        f.debug_list()
84            .entries(self.0.iter().map(|(k, v)| (k.clone(), (&v.0, DebugBytes(&v.1[..])))))
85            .finish()
86    }
87}
88
89#[derive(Clone, Debug)]
90/// Error returned by persister
91pub enum Error {
92    /// Persister is temporarily unavailable, might work later
93    Unavailable(String),
94    /// Inconsistent state, needed resource is missing
95    NotFound(String),
96    /// Inconsistent state, resource already present
97    AlreadyExists(String),
98    /// Non-recoverable internal error
99    Internal(String),
100    /// Version mismatch
101    VersionMismatch,
102    /// Serialization, deserialization error
103    SerdeError(String),
104}
105
106impl Display for Error {
107    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
108        match self {
109            Error::Unavailable(s) => write!(f, "Unavailable: {}", s),
110            Error::NotFound(s) => write!(f, "Not found: {}", s),
111            Error::AlreadyExists(s) => write!(f, "Already exists: {}", s),
112            Error::Internal(s) => write!(f, "Internal error: {}", s),
113            Error::VersionMismatch => write!(f, "Version mismatch"),
114            Error::SerdeError(s) => write!(f, "Serialization error: {}", s),
115        }
116    }
117}
118
119#[cfg(feature = "std")]
120impl std::error::Error for Error {}
121
122/// Used to keep track of the chain monitor listeners while restoring from persistence
123pub struct ChainTrackerListenerEntry(pub OutPoint, pub (ChainMonitorState, ListenSlot));
124
125/// A unique signer ID for this signer, used by persisters to identify themselves
126pub type SignerId = [u8; 16];
127
128/// Persister of nodes and channels
129///
130/// A Node will call the relevant methods here as needed.
131///
132/// There are two types of persisters:
133///
134/// - Memorizing persisters, which only store the mutations in memory, for later
135/// retrieval and storage by the caller.  This is used in embedded environments
136/// to return the mutations to the host system.
137///
138/// - Real persisters, which store the mutations directly, for example to disk.
139/// This is used in non-embedded environments. This kind of persister should
140/// persist durably before returning, for safety.
141///
142pub trait Persist: SendSync {
143    /// Enter a persistence context
144    ///
145    /// Must call `prepare()`, commit the mutations in the cloud and then
146    /// call `commit()` to persist the mutations locally.
147    ///
148    /// If this is not a transactional persister, this is a no-op and
149    /// `prepare()` will return an empty list of mutations.
150    fn enter(&self) -> Result<(), Error> {
151        Ok(())
152    }
153
154    /// Get the logged mutations since the last call to `enter()`.
155    ///
156    /// If this is not a transactional persister, this returns an empty list.
157    fn prepare(&self) -> Mutations {
158        Mutations::new()
159    }
160
161    /// Commit the logged mutations.
162    ///
163    /// If this is not a transactional persister, this is a no-op and the
164    /// mutations were already persisted.
165    fn commit(&self) -> Result<(), Error> {
166        Ok(())
167    }
168
169    /// Update the persister with the given mutations.
170    ///
171    /// This doesn't require a call to `enter()`.
172    fn put_batch_unlogged(&self, _m: Mutations) -> Result<(), Error> {
173        unimplemented!("put_batch_unlogged is only implemented for KVV persisters")
174    }
175
176    /// Create a new node
177    fn new_node(
178        &self,
179        node_id: &PublicKey,
180        config: &NodeConfig,
181        state: &NodeState,
182    ) -> Result<(), Error>;
183
184    /// Update node enforcement state
185    fn update_node(&self, node_id: &PublicKey, state: &NodeState) -> Result<(), Error>;
186
187    /// Delete a node and all of its channels.  Used in test mode.
188    fn delete_node(&self, node_id: &PublicKey) -> Result<(), Error>;
189
190    /// Will error if exists
191    fn new_channel(&self, node_id: &PublicKey, stub: &ChannelStub) -> Result<(), Error>;
192
193    /// Delete a channel
194    fn delete_channel(&self, node_id: &PublicKey, channel: &ChannelId) -> Result<(), Error>;
195
196    /// Create a new tracker
197    fn new_tracker(
198        &self,
199        node_id: &PublicKey,
200        tracker: &ChainTracker<ChainMonitor>,
201    ) -> Result<(), Error>;
202
203    /// Update the tracker
204    fn update_tracker(
205        &self,
206        node_id: &PublicKey,
207        tracker: &ChainTracker<ChainMonitor>,
208    ) -> Result<(), Error>;
209
210    /// Get the tracker
211    fn get_tracker(
212        &self,
213        node_id: PublicKey,
214        validator_factory: Arc<dyn ValidatorFactory>,
215    ) -> Result<(ChainTracker<ChainMonitor>, Vec<ChainTrackerListenerEntry>), Error>;
216
217    /// Will error if doesn't exist.
218    ///
219    /// * `id0` original channel ID supplied to [`Persist::new_channel()`]
220    /// * `id` an optional additional permanent channel ID
221    fn update_channel(&self, node_id: &PublicKey, channel: &Channel) -> Result<(), Error>;
222
223    /// Get a channel from store
224    fn get_channel(
225        &self,
226        node_id: &PublicKey,
227        channel_id: &ChannelId,
228    ) -> Result<model::ChannelEntry, Error>;
229
230    /// Get all channels for a node from store
231    fn get_node_channels(
232        &self,
233        node_id: &PublicKey,
234    ) -> Result<Vec<(ChannelId, model::ChannelEntry)>, Error>;
235
236    /// Persist the allowlist to the store.
237    fn update_node_allowlist(
238        &self,
239        node_id: &PublicKey,
240        allowlist: Vec<String>,
241    ) -> Result<(), Error>;
242
243    /// Get the allowlist from the store.
244    fn get_node_allowlist(&self, node_id: &PublicKey) -> Result<Vec<String>, Error>;
245
246    /// Get all nodes from store
247    fn get_nodes(&self) -> Result<Vec<(PublicKey, model::NodeEntry)>, Error>;
248
249    /// Clears the database.  Not for production use.
250    fn clear_database(&self) -> Result<(), Error>;
251
252    /// Notifies the persister that the initial restore from persistence is done
253    /// and queries whether a sync is required.
254    ///
255    /// A sync is required when using a composite persister, since one of the
256    /// persisters may have fallen behind due to a crash.
257    fn on_initial_restore(&self) -> bool {
258        false
259    }
260
261    /// Whether recovery from backup is required on signer startup.
262    /// Should return true if the persister is in a state where it
263    /// needs to recover from a backup (e.g. empty).
264    fn recovery_required(&self) -> bool {
265        false
266    }
267
268    /// Start replication by putting the local store into a compatible starting
269    /// state for a cloud persister.
270    ///
271    /// All versions are reset to zero. Gets the entire stored content as Mutations
272    /// that the caller must store into the empty cloud store.
273    fn begin_replication(&self) -> Result<Mutations, Error> {
274        unimplemented!("begin_replication is only implemented for KVV persisters")
275    }
276
277    /// Get our unique 128-bit signer ID
278    fn signer_id(&self) -> SignerId;
279}
280
281/// A null persister for testing
282pub struct DummyPersister;
283
284impl SendSync for DummyPersister {}
285
286#[allow(unused_variables)]
287impl Persist for DummyPersister {
288    fn new_node(
289        &self,
290        node_id: &PublicKey,
291        config: &NodeConfig,
292        state: &NodeState,
293    ) -> Result<(), Error> {
294        Ok(())
295    }
296
297    fn update_node(&self, node_id: &PublicKey, state: &NodeState) -> Result<(), Error> {
298        Ok(())
299    }
300
301    fn delete_node(&self, node_id: &PublicKey) -> Result<(), Error> {
302        Ok(())
303    }
304
305    fn new_channel(&self, node_id: &PublicKey, stub: &ChannelStub) -> Result<(), Error> {
306        Ok(())
307    }
308
309    fn delete_channel(&self, node_id: &PublicKey, channel_id: &ChannelId) -> Result<(), Error> {
310        Ok(())
311    }
312
313    fn new_tracker(
314        &self,
315        node_id: &PublicKey,
316        tracker: &ChainTracker<ChainMonitor>,
317    ) -> Result<(), Error> {
318        Ok(())
319    }
320
321    fn update_tracker(
322        &self,
323        node_id: &PublicKey,
324        tracker: &ChainTracker<ChainMonitor>,
325    ) -> Result<(), Error> {
326        Ok(())
327    }
328
329    fn get_tracker(
330        &self,
331        node_id: PublicKey,
332        validator_factory: Arc<dyn ValidatorFactory>,
333    ) -> Result<(ChainTracker<ChainMonitor>, Vec<ChainTrackerListenerEntry>), Error> {
334        Err(Error::Internal(format!("get_tracker unimplemented")))
335    }
336
337    fn update_channel(&self, node_id: &PublicKey, channel: &Channel) -> Result<(), Error> {
338        Ok(())
339    }
340
341    fn get_channel(
342        &self,
343        node_id: &PublicKey,
344        channel_id: &ChannelId,
345    ) -> Result<model::ChannelEntry, Error> {
346        Err(Error::Internal(format!("get_channel unimplemented")))
347    }
348
349    fn get_node_channels(
350        &self,
351        node_id: &PublicKey,
352    ) -> Result<Vec<(ChannelId, model::ChannelEntry)>, Error> {
353        Ok(Vec::new())
354    }
355
356    fn update_node_allowlist(
357        &self,
358        node_id: &PublicKey,
359        allowlist: Vec<String>,
360    ) -> Result<(), Error> {
361        Ok(())
362    }
363
364    fn get_node_allowlist(&self, node_id: &PublicKey) -> Result<Vec<String>, Error> {
365        Ok(Vec::new())
366    }
367
368    fn get_nodes(&self) -> Result<Vec<(PublicKey, model::NodeEntry)>, Error> {
369        Ok(Vec::new())
370    }
371
372    fn clear_database(&self) -> Result<(), Error> {
373        Ok(())
374    }
375
376    fn signer_id(&self) -> [u8; 16] {
377        unimplemented!("unused in tests")
378    }
379}
380
381/// Seed persister
382///
383/// By convention, the `key` is the hex-encoded public key, but this may change
384/// in the future.
385pub trait SeedPersist: Sync + Send {
386    /// Persist the seed
387    fn put(&self, key: &str, seed: &[u8]);
388    /// Get the seed, if exists
389    fn get(&self, key: &str) -> Option<Vec<u8>>;
390    /// List the seeds
391    fn list(&self) -> Vec<String>;
392}
393
394/// A null seed persister for testing
395pub struct DummySeedPersister;
396
397impl SeedPersist for DummySeedPersister {
398    fn put(&self, _key: &str, _seed: &[u8]) {}
399
400    fn get(&self, _key: &str) -> Option<Vec<u8>> {
401        None
402    }
403
404    fn list(&self) -> Vec<String> {
405        Vec::new()
406    }
407}
408
409/// A single in-memory seed persister - for testing
410pub struct MemorySeedPersister {
411    seed: Vec<u8>,
412}
413
414impl MemorySeedPersister {
415    /// Create a new in-memory seed persister
416    pub fn new(seed: Vec<u8>) -> Self {
417        Self { seed }
418    }
419}
420
421impl SeedPersist for MemorySeedPersister {
422    fn put(&self, _key: &str, _seed: &[u8]) {
423        unimplemented!()
424    }
425
426    fn get(&self, _key: &str) -> Option<Vec<u8>> {
427        Some(self.seed.clone())
428    }
429
430    fn list(&self) -> Vec<String> {
431        Vec::new()
432    }
433}
434
435#[cfg(feature = "std")]
436/// File system persisters
437pub mod fs {
438    use crate::persist::SeedPersist;
439    use bitcoin::hashes::hex::FromHex;
440    use std::fs;
441    use std::path::PathBuf;
442
443    use vls_common::HexEncode;
444
445    /// A file system directory seed persister
446    ///
447    /// Stores seed in a file named `<node_id_hex>.seed` in the directory
448    pub struct FileSeedPersister {
449        path: PathBuf,
450    }
451
452    impl FileSeedPersister {
453        /// Create
454        pub fn new<P: Into<PathBuf>>(path: P) -> Self {
455            Self { path: path.into() }
456        }
457
458        fn seed_path_for_key(&self, node_id: &str) -> PathBuf {
459            let mut path = self.path.clone();
460            path.push(format!("{}.seed", node_id));
461            path
462        }
463    }
464
465    impl SeedPersist for FileSeedPersister {
466        fn put(&self, key: &str, seed: &[u8]) {
467            write_seed(self.seed_path_for_key(key), seed);
468        }
469
470        fn get(&self, key: &str) -> Option<Vec<u8>> {
471            read_seed(self.seed_path_for_key(key))
472        }
473
474        fn list(&self) -> Vec<String> {
475            let mut keys = Vec::new();
476            for entry in fs::read_dir(&self.path).unwrap() {
477                let entry = entry.unwrap();
478                let path = entry.path();
479                if let Some(fileext) = path.extension() {
480                    if fileext == "seed" {
481                        let key = path.file_stem().unwrap().to_str().unwrap();
482                        keys.push(key.to_string());
483                    }
484                }
485            }
486            keys
487        }
488    }
489
490    fn write_seed(path: PathBuf, seed: &[u8]) {
491        fs::write(path.clone(), seed.to_hex()).expect("unable to write the seed to file");
492
493        // Set the read-only permissions
494        let mut permission =
495            fs::metadata(path.to_owned()).expect("unable to get metadata").permissions();
496        permission.set_readonly(true);
497        fs::set_permissions(path, permission).expect("unable to set the permission to file");
498    }
499
500    fn read_seed(path: PathBuf) -> Option<Vec<u8>> {
501        fs::read_to_string(path).ok().map(|s| Vec::from_hex(s.trim()).expect("bad hex seed"))
502    }
503
504    #[cfg(test)]
505    mod test {
506        use crate::persist::SeedPersist;
507
508        use super::FileSeedPersister;
509
510        use tempfile::tempdir;
511
512        #[test]
513        fn test_list() {
514            let temp_dir = tempdir().unwrap();
515            let persister = FileSeedPersister::new(temp_dir.path());
516            let seeds = vec![("node1", b"seed1"), ("node2", b"seed2"), ("node3", b"seed3")];
517            for (node, seed) in &seeds {
518                persister.put(node, seed.as_slice());
519            }
520            let listed_seeds = persister.list();
521            assert_eq!(listed_seeds.len(), seeds.len());
522            for (node, _) in &seeds {
523                assert!(listed_seeds.contains(&node.to_string()));
524            }
525        }
526    }
527}
528
529/// An external persister helper
530#[derive(Clone)]
531pub struct ExternalPersistHelper {
532    shared_secret: [u8; 32],
533    last_nonce: [u8; 32],
534}
535
536impl ExternalPersistHelper {
537    /// Create a new helper
538    pub fn new(shared_secret: [u8; 32]) -> Self {
539        Self { shared_secret, last_nonce: [0; 32] }
540    }
541
542    /// Generate and store a new nonce
543    pub fn new_nonce(&mut self, entropy_source: &dyn EntropySource) -> [u8; 32] {
544        let nonce = entropy_source.get_secure_random_bytes();
545        self.last_nonce = nonce;
546        nonce
547    }
548
549    /// Generate a client HMAC - this proves the client constructed the data
550    pub fn client_hmac(&self, kvs: &Mutations) -> [u8; 32] {
551        compute_shared_hmac(&self.shared_secret, &[0x01], kvs)
552    }
553
554    /// Generate a server HMAC - this proves the server saw and persisted the data
555    /// for a put request.
556    pub fn server_hmac(&self, kvs: &Mutations) -> [u8; 32] {
557        compute_shared_hmac(&self.shared_secret, &[0x02], kvs)
558    }
559
560    /// Check the HMAC from the server on a get response - this proves that the
561    /// server returned the data as requested with no replay, since it covers
562    /// the nonce we sent to the server.
563    pub fn check_hmac(&self, kvs: &Mutations, received_hmac: Vec<u8>) -> bool {
564        let hmac = compute_shared_hmac(&self.shared_secret, &self.last_nonce, &kvs); // in signer
565        received_hmac == hmac
566    }
567}
568
569use crate::util::debug_utils::DebugBytes;
570#[cfg(feature = "std")]
571pub use simple_entropy::SimpleEntropy;
572
573#[cfg(feature = "std")]
574mod simple_entropy {
575    use super::EntropySource;
576    use bitcoin::secp256k1::rand::{self, RngCore};
577    /// A simple entropy source for std environments
578    pub struct SimpleEntropy {}
579
580    impl SimpleEntropy {
581        /// Create a new entropy source
582        pub fn new() -> Self {
583            Self {}
584        }
585    }
586
587    impl EntropySource for SimpleEntropy {
588        fn get_secure_random_bytes(&self) -> [u8; 32] {
589            let mut bytes = [0u8; 32];
590            let mut rng = rand::thread_rng();
591            rng.fill_bytes(&mut bytes);
592            bytes
593        }
594    }
595}
596
597/// Compute a client/server HMAC - which proves the client or server initiated this
598/// call and no replay occurred.
599pub fn compute_shared_hmac(secret: &[u8], nonce: &[u8], kvs: &Mutations) -> [u8; 32] {
600    let mut hmac_engine = HmacEngine::<Sha256Hash>::new(&secret);
601    hmac_engine.input(secret);
602    hmac_engine.input(nonce);
603    for (key, (version, value)) in kvs.iter() {
604        add_to_hmac(key, *version, value, &mut hmac_engine);
605    }
606    Hmac::from_engine(hmac_engine).to_byte_array()
607}
608
609fn add_to_hmac(key: &str, version: u64, value: &[u8], hmac: &mut HmacEngine<Sha256Hash>) {
610    hmac.input(key.as_bytes());
611    hmac.input(&version.to_be_bytes());
612    hmac.input(&value);
613}
614
615#[cfg(test)]
616mod tests {
617    use super::*;
618
619    #[test]
620    fn hmac_test() {
621        let shared_secret = [0; 32];
622        let mut helper = ExternalPersistHelper::new(shared_secret);
623        let mut kvs = Mutations::new();
624        kvs.add("foo".to_string(), 0, vec![0x01]);
625        kvs.add("bar".to_string(), 0, vec![0x02]);
626
627        let nonce = helper.new_nonce(&SimpleEntropy::new());
628        let hmac = compute_shared_hmac(&shared_secret, &nonce, &kvs);
629        assert!(helper.check_hmac(&kvs, hmac.to_vec()));
630
631        // mutating the data should fail the hmac
632        kvs.add("baz".to_string(), 0, vec![0x03]);
633        assert!(!helper.check_hmac(&kvs, hmac.to_vec()));
634
635        let client_secret = "2e3c1864370a95cbd641d09ae0cf7c0dd5bd0b1c30707ee5ec23775e41f19f2e";
636
637        assert_eq!(client_secret, hex::encode(helper.client_hmac(&kvs)));
638
639        let server_secret = "8fe3d55b41ae5f1c0d2b1015e3d190ff4c6d419bd792fccf8f349505031f9fec";
640
641        assert_eq!(server_secret, hex::encode(helper.server_hmac(&kvs)));
642    }
643}