1use std::fs::{self, OpenOptions};
9use std::io::Write;
10use std::ops::Deref;
11use std::path::Path;
12use std::sync::Arc;
13
14#[cfg(unix)]
15use std::os::unix::fs::OpenOptionsExt;
16
17use bdk_chain::indexer::keychain_txout::ChangeSet as BdkIndexerChangeSet;
18use bdk_chain::local_chain::ChangeSet as BdkLocalChainChangeSet;
19use bdk_chain::miniscript::{Descriptor, DescriptorPublicKey};
20use bdk_chain::tx_graph::ChangeSet as BdkTxGraphChangeSet;
21use bdk_chain::ConfirmationBlockTime;
22use bdk_wallet::ChangeSet as BdkWalletChangeSet;
23use bip39::Mnemonic;
24use bitcoin::Network;
25use lightning::io::Cursor;
26use lightning::ln::msgs::DecodeError;
27use lightning::routing::gossip::NetworkGraph;
28use lightning::routing::scoring::{
29 ChannelLiquidities, ProbabilisticScorer, ProbabilisticScoringDecayParameters,
30};
31use lightning::util::persist::{
32 KVStore, KVStoreSync, KVSTORE_NAMESPACE_KEY_ALPHABET, KVSTORE_NAMESPACE_KEY_MAX_LEN,
33 NETWORK_GRAPH_PERSISTENCE_KEY, NETWORK_GRAPH_PERSISTENCE_PRIMARY_NAMESPACE,
34 NETWORK_GRAPH_PERSISTENCE_SECONDARY_NAMESPACE, OUTPUT_SWEEPER_PERSISTENCE_KEY,
35 OUTPUT_SWEEPER_PERSISTENCE_PRIMARY_NAMESPACE, OUTPUT_SWEEPER_PERSISTENCE_SECONDARY_NAMESPACE,
36 SCORER_PERSISTENCE_KEY, SCORER_PERSISTENCE_PRIMARY_NAMESPACE,
37 SCORER_PERSISTENCE_SECONDARY_NAMESPACE,
38};
39use lightning::util::ser::{Readable, ReadableArgs, Writeable};
40use lightning_types::string::PrintableString;
41use rand::rngs::OsRng;
42use rand::TryRngCore;
43
44use super::*;
45use crate::chain::ChainSource;
46use crate::config::WALLET_KEYS_SEED_LEN;
47use crate::fee_estimator::OnchainFeeEstimator;
48use crate::io::{
49 NODE_METRICS_KEY, NODE_METRICS_PRIMARY_NAMESPACE, NODE_METRICS_SECONDARY_NAMESPACE,
50};
51use crate::logger::{log_error, LdkLogger, Logger};
52use crate::peer_store::PeerStore;
53use crate::types::{Broadcaster, DynStore, KeysManager, Sweeper, WordCount};
54use crate::wallet::ser::{ChangeSetDeserWrapper, ChangeSetSerWrapper};
55use crate::{Error, EventQueue, NodeMetrics, PaymentDetails};
56
57pub const EXTERNAL_PATHFINDING_SCORES_CACHE_KEY: &str = "external_pathfinding_scores_cache";
58
59pub fn generate_entropy_mnemonic(word_count: Option<WordCount>) -> Mnemonic {
70 let word_count = word_count.unwrap_or(WordCount::Words24).word_count();
71 Mnemonic::generate(word_count).expect("Failed to generate mnemonic")
72}
73
74pub(crate) fn read_or_generate_seed_file<L: Deref>(
75 keys_seed_path: &str, logger: L,
76) -> std::io::Result<[u8; WALLET_KEYS_SEED_LEN]>
77where
78 L::Target: LdkLogger,
79{
80 if Path::new(&keys_seed_path).exists() {
81 let seed = fs::read(keys_seed_path).map_err(|e| {
82 log_error!(logger, "Failed to read keys seed file: {}", keys_seed_path);
83 e
84 })?;
85
86 if seed.len() != WALLET_KEYS_SEED_LEN {
87 log_error!(
88 logger,
89 "Failed to read keys seed file due to invalid length: {}",
90 keys_seed_path
91 );
92 return Err(std::io::Error::new(
93 std::io::ErrorKind::InvalidData,
94 "Failed to read keys seed file due to invalid length",
95 ));
96 }
97
98 let mut key = [0; WALLET_KEYS_SEED_LEN];
99 key.copy_from_slice(&seed);
100 Ok(key)
101 } else {
102 let mut key = [0; WALLET_KEYS_SEED_LEN];
103 OsRng.try_fill_bytes(&mut key).map_err(|e| {
104 log_error!(logger, "Failed to generate entropy: {}", e);
105 std::io::Error::new(std::io::ErrorKind::Other, "Failed to generate seed bytes")
106 })?;
107
108 if let Some(parent_dir) = Path::new(&keys_seed_path).parent() {
109 fs::create_dir_all(parent_dir).map_err(|e| {
110 log_error!(
111 logger,
112 "Failed to create parent directory for key seed file: {}.",
113 keys_seed_path
114 );
115 e
116 })?;
117 }
118
119 #[cfg(unix)]
120 let mut f = OpenOptions::new()
121 .write(true)
122 .create_new(true)
123 .mode(0o400)
124 .open(keys_seed_path)
125 .map_err(|e| {
126 log_error!(logger, "Failed to create keys seed file: {}", keys_seed_path);
127 e
128 })?;
129
130 #[cfg(not(unix))]
131 let mut f =
132 OpenOptions::new().write(true).create_new(true).open(keys_seed_path).map_err(|e| {
133 log_error!(logger, "Failed to create keys seed file: {}", keys_seed_path);
134 e
135 })?;
136
137 f.write_all(&key).map_err(|e| {
138 log_error!(logger, "Failed to write node keys seed to disk: {}", keys_seed_path);
139 e
140 })?;
141
142 f.sync_all().map_err(|e| {
143 log_error!(logger, "Failed to sync node keys seed to disk: {}", keys_seed_path);
144 e
145 })?;
146
147 Ok(key)
148 }
149}
150
151pub(crate) fn read_network_graph<L: Deref + Clone>(
153 kv_store: Arc<DynStore>, logger: L,
154) -> Result<NetworkGraph<L>, std::io::Error>
155where
156 L::Target: LdkLogger,
157{
158 let mut reader = Cursor::new(KVStoreSync::read(
159 &*kv_store,
160 NETWORK_GRAPH_PERSISTENCE_PRIMARY_NAMESPACE,
161 NETWORK_GRAPH_PERSISTENCE_SECONDARY_NAMESPACE,
162 NETWORK_GRAPH_PERSISTENCE_KEY,
163 )?);
164 NetworkGraph::read(&mut reader, logger.clone()).map_err(|e| {
165 log_error!(logger, "Failed to deserialize NetworkGraph: {}", e);
166 std::io::Error::new(std::io::ErrorKind::InvalidData, "Failed to deserialize NetworkGraph")
167 })
168}
169
170pub(crate) fn read_scorer<G: Deref<Target = NetworkGraph<L>>, L: Deref + Clone>(
172 kv_store: Arc<DynStore>, network_graph: G, logger: L,
173) -> Result<ProbabilisticScorer<G, L>, std::io::Error>
174where
175 L::Target: LdkLogger,
176{
177 let params = ProbabilisticScoringDecayParameters::default();
178 let mut reader = Cursor::new(KVStoreSync::read(
179 &*kv_store,
180 SCORER_PERSISTENCE_PRIMARY_NAMESPACE,
181 SCORER_PERSISTENCE_SECONDARY_NAMESPACE,
182 SCORER_PERSISTENCE_KEY,
183 )?);
184 let args = (params, network_graph, logger.clone());
185 ProbabilisticScorer::read(&mut reader, args).map_err(|e| {
186 log_error!(logger, "Failed to deserialize scorer: {}", e);
187 std::io::Error::new(std::io::ErrorKind::InvalidData, "Failed to deserialize Scorer")
188 })
189}
190
191pub(crate) fn read_external_pathfinding_scores_from_cache<L: Deref>(
193 kv_store: Arc<DynStore>, logger: L,
194) -> Result<ChannelLiquidities, std::io::Error>
195where
196 L::Target: LdkLogger,
197{
198 let mut reader = Cursor::new(KVStoreSync::read(
199 &*kv_store,
200 SCORER_PERSISTENCE_PRIMARY_NAMESPACE,
201 SCORER_PERSISTENCE_SECONDARY_NAMESPACE,
202 EXTERNAL_PATHFINDING_SCORES_CACHE_KEY,
203 )?);
204 ChannelLiquidities::read(&mut reader).map_err(|e| {
205 log_error!(logger, "Failed to deserialize scorer: {}", e);
206 std::io::Error::new(std::io::ErrorKind::InvalidData, "Failed to deserialize Scorer")
207 })
208}
209
210pub(crate) async fn write_external_pathfinding_scores_to_cache<L: Deref>(
212 kv_store: Arc<DynStore>, data: &ChannelLiquidities, logger: L,
213) -> Result<(), Error>
214where
215 L::Target: LdkLogger,
216{
217 KVStore::write(
218 &*kv_store,
219 SCORER_PERSISTENCE_PRIMARY_NAMESPACE,
220 SCORER_PERSISTENCE_SECONDARY_NAMESPACE,
221 EXTERNAL_PATHFINDING_SCORES_CACHE_KEY,
222 data.encode(),
223 )
224 .await
225 .map_err(|e| {
226 log_error!(
227 logger,
228 "Writing data to key {}/{}/{} failed due to: {}",
229 NODE_METRICS_PRIMARY_NAMESPACE,
230 NODE_METRICS_SECONDARY_NAMESPACE,
231 EXTERNAL_PATHFINDING_SCORES_CACHE_KEY,
232 e
233 );
234 Error::PersistenceFailed
235 })
236}
237
238pub(crate) fn read_event_queue<L: Deref + Clone>(
240 kv_store: Arc<DynStore>, logger: L,
241) -> Result<EventQueue<L>, std::io::Error>
242where
243 L::Target: LdkLogger,
244{
245 let mut reader = Cursor::new(KVStoreSync::read(
246 &*kv_store,
247 EVENT_QUEUE_PERSISTENCE_PRIMARY_NAMESPACE,
248 EVENT_QUEUE_PERSISTENCE_SECONDARY_NAMESPACE,
249 EVENT_QUEUE_PERSISTENCE_KEY,
250 )?);
251 EventQueue::read(&mut reader, (kv_store, logger.clone())).map_err(|e| {
252 log_error!(logger, "Failed to deserialize event queue: {}", e);
253 std::io::Error::new(std::io::ErrorKind::InvalidData, "Failed to deserialize EventQueue")
254 })
255}
256
257pub(crate) fn read_peer_info<L: Deref + Clone>(
259 kv_store: Arc<DynStore>, logger: L,
260) -> Result<PeerStore<L>, std::io::Error>
261where
262 L::Target: LdkLogger,
263{
264 let mut reader = Cursor::new(KVStoreSync::read(
265 &*kv_store,
266 PEER_INFO_PERSISTENCE_PRIMARY_NAMESPACE,
267 PEER_INFO_PERSISTENCE_SECONDARY_NAMESPACE,
268 PEER_INFO_PERSISTENCE_KEY,
269 )?);
270 PeerStore::read(&mut reader, (kv_store, logger.clone())).map_err(|e| {
271 log_error!(logger, "Failed to deserialize peer store: {}", e);
272 std::io::Error::new(std::io::ErrorKind::InvalidData, "Failed to deserialize PeerStore")
273 })
274}
275
276pub(crate) fn read_payments<L: Deref>(
278 kv_store: Arc<DynStore>, logger: L,
279) -> Result<Vec<PaymentDetails>, std::io::Error>
280where
281 L::Target: LdkLogger,
282{
283 let mut res = Vec::new();
284
285 for stored_key in KVStoreSync::list(
286 &*kv_store,
287 PAYMENT_INFO_PERSISTENCE_PRIMARY_NAMESPACE,
288 PAYMENT_INFO_PERSISTENCE_SECONDARY_NAMESPACE,
289 )? {
290 let mut reader = Cursor::new(KVStoreSync::read(
291 &*kv_store,
292 PAYMENT_INFO_PERSISTENCE_PRIMARY_NAMESPACE,
293 PAYMENT_INFO_PERSISTENCE_SECONDARY_NAMESPACE,
294 &stored_key,
295 )?);
296 let payment = PaymentDetails::read(&mut reader).map_err(|e| {
297 log_error!(logger, "Failed to deserialize PaymentDetails: {}", e);
298 std::io::Error::new(
299 std::io::ErrorKind::InvalidData,
300 "Failed to deserialize PaymentDetails",
301 )
302 })?;
303 res.push(payment);
304 }
305 Ok(res)
306}
307
308pub(crate) fn read_output_sweeper(
310 broadcaster: Arc<Broadcaster>, fee_estimator: Arc<OnchainFeeEstimator>,
311 chain_data_source: Arc<ChainSource>, keys_manager: Arc<KeysManager>, kv_store: Arc<DynStore>,
312 logger: Arc<Logger>,
313) -> Result<Sweeper, std::io::Error> {
314 let mut reader = Cursor::new(KVStoreSync::read(
315 &*kv_store,
316 OUTPUT_SWEEPER_PERSISTENCE_PRIMARY_NAMESPACE,
317 OUTPUT_SWEEPER_PERSISTENCE_SECONDARY_NAMESPACE,
318 OUTPUT_SWEEPER_PERSISTENCE_KEY,
319 )?);
320 let args = (
321 broadcaster,
322 fee_estimator,
323 Some(chain_data_source),
324 Arc::clone(&keys_manager),
325 keys_manager,
326 kv_store,
327 logger.clone(),
328 );
329 let (_, sweeper) = <(_, Sweeper)>::read(&mut reader, args).map_err(|e| {
330 log_error!(logger, "Failed to deserialize OutputSweeper: {}", e);
331 std::io::Error::new(std::io::ErrorKind::InvalidData, "Failed to deserialize OutputSweeper")
332 })?;
333 Ok(sweeper)
334}
335
336pub(crate) fn read_node_metrics<L: Deref>(
337 kv_store: Arc<DynStore>, logger: L,
338) -> Result<NodeMetrics, std::io::Error>
339where
340 L::Target: LdkLogger,
341{
342 let mut reader = Cursor::new(KVStoreSync::read(
343 &*kv_store,
344 NODE_METRICS_PRIMARY_NAMESPACE,
345 NODE_METRICS_SECONDARY_NAMESPACE,
346 NODE_METRICS_KEY,
347 )?);
348 NodeMetrics::read(&mut reader).map_err(|e| {
349 log_error!(logger, "Failed to deserialize NodeMetrics: {}", e);
350 std::io::Error::new(std::io::ErrorKind::InvalidData, "Failed to deserialize NodeMetrics")
351 })
352}
353
354pub(crate) fn write_node_metrics<L: Deref>(
355 node_metrics: &NodeMetrics, kv_store: Arc<DynStore>, logger: L,
356) -> Result<(), Error>
357where
358 L::Target: LdkLogger,
359{
360 let data = node_metrics.encode();
361 KVStoreSync::write(
362 &*kv_store,
363 NODE_METRICS_PRIMARY_NAMESPACE,
364 NODE_METRICS_SECONDARY_NAMESPACE,
365 NODE_METRICS_KEY,
366 data,
367 )
368 .map_err(|e| {
369 log_error!(
370 logger,
371 "Writing data to key {}/{}/{} failed due to: {}",
372 NODE_METRICS_PRIMARY_NAMESPACE,
373 NODE_METRICS_SECONDARY_NAMESPACE,
374 NODE_METRICS_KEY,
375 e
376 );
377 Error::PersistenceFailed
378 })
379}
380
381pub(crate) fn is_valid_kvstore_str(key: &str) -> bool {
382 key.len() <= KVSTORE_NAMESPACE_KEY_MAX_LEN
383 && key.chars().all(|c| KVSTORE_NAMESPACE_KEY_ALPHABET.contains(c))
384}
385
386pub(crate) fn check_namespace_key_validity(
387 primary_namespace: &str, secondary_namespace: &str, key: Option<&str>, operation: &str,
388) -> Result<(), std::io::Error> {
389 if let Some(key) = key {
390 if key.is_empty() {
391 debug_assert!(
392 false,
393 "Failed to {} {}/{}/{}: key may not be empty.",
394 operation,
395 PrintableString(primary_namespace),
396 PrintableString(secondary_namespace),
397 PrintableString(key)
398 );
399 let msg = format!(
400 "Failed to {} {}/{}/{}: key may not be empty.",
401 operation,
402 PrintableString(primary_namespace),
403 PrintableString(secondary_namespace),
404 PrintableString(key)
405 );
406 return Err(std::io::Error::new(std::io::ErrorKind::Other, msg));
407 }
408
409 if primary_namespace.is_empty() && !secondary_namespace.is_empty() {
410 debug_assert!(false,
411 "Failed to {} {}/{}/{}: primary namespace may not be empty if a non-empty secondary namespace is given.",
412 operation,
413 PrintableString(primary_namespace), PrintableString(secondary_namespace), PrintableString(key));
414 let msg = format!(
415 "Failed to {} {}/{}/{}: primary namespace may not be empty if a non-empty secondary namespace is given.", operation,
416 PrintableString(primary_namespace), PrintableString(secondary_namespace), PrintableString(key));
417 return Err(std::io::Error::new(std::io::ErrorKind::Other, msg));
418 }
419
420 if !is_valid_kvstore_str(primary_namespace)
421 || !is_valid_kvstore_str(secondary_namespace)
422 || !is_valid_kvstore_str(key)
423 {
424 debug_assert!(
425 false,
426 "Failed to {} {}/{}/{}: primary namespace, secondary namespace, and key must be valid.",
427 operation,
428 PrintableString(primary_namespace),
429 PrintableString(secondary_namespace),
430 PrintableString(key)
431 );
432 let msg = format!(
433 "Failed to {} {}/{}/{}: primary namespace, secondary namespace, and key must be valid.",
434 operation,
435 PrintableString(primary_namespace),
436 PrintableString(secondary_namespace),
437 PrintableString(key)
438 );
439 return Err(std::io::Error::new(std::io::ErrorKind::Other, msg));
440 }
441 } else {
442 if primary_namespace.is_empty() && !secondary_namespace.is_empty() {
443 debug_assert!(false,
444 "Failed to {} {}/{}: primary namespace may not be empty if a non-empty secondary namespace is given.",
445 operation, PrintableString(primary_namespace), PrintableString(secondary_namespace));
446 let msg = format!(
447 "Failed to {} {}/{}: primary namespace may not be empty if a non-empty secondary namespace is given.",
448 operation, PrintableString(primary_namespace), PrintableString(secondary_namespace));
449 return Err(std::io::Error::new(std::io::ErrorKind::Other, msg));
450 }
451 if !is_valid_kvstore_str(primary_namespace) || !is_valid_kvstore_str(secondary_namespace) {
452 debug_assert!(
453 false,
454 "Failed to {} {}/{}: primary namespace and secondary namespace must be valid.",
455 operation,
456 PrintableString(primary_namespace),
457 PrintableString(secondary_namespace)
458 );
459 let msg = format!(
460 "Failed to {} {}/{}: primary namespace and secondary namespace must be valid.",
461 operation,
462 PrintableString(primary_namespace),
463 PrintableString(secondary_namespace)
464 );
465 return Err(std::io::Error::new(std::io::ErrorKind::Other, msg));
466 }
467 }
468
469 Ok(())
470}
471
472macro_rules! impl_read_write_change_set_type {
473 (
474 $read_name:ident,
475 $write_name:ident,
476 $change_set_type:ty,
477 $primary_namespace:expr,
478 $secondary_namespace:expr,
479 $key:expr
480 ) => {
481 pub(crate) fn $read_name<L: Deref>(
482 kv_store: Arc<DynStore>, logger: L,
483 ) -> Result<Option<$change_set_type>, std::io::Error>
484 where
485 L::Target: LdkLogger,
486 {
487 let bytes =
488 match KVStoreSync::read(&*kv_store, $primary_namespace, $secondary_namespace, $key)
489 {
490 Ok(bytes) => bytes,
491 Err(e) => {
492 if e.kind() == lightning::io::ErrorKind::NotFound {
493 return Ok(None);
494 } else {
495 log_error!(
496 logger,
497 "Reading data from key {}/{}/{} failed due to: {}",
498 $primary_namespace,
499 $secondary_namespace,
500 $key,
501 e
502 );
503 return Err(e.into());
504 }
505 },
506 };
507
508 let mut reader = Cursor::new(bytes);
509 let res: Result<ChangeSetDeserWrapper<$change_set_type>, DecodeError> =
510 Readable::read(&mut reader);
511 match res {
512 Ok(res) => Ok(Some(res.0)),
513 Err(e) => {
514 log_error!(logger, "Failed to deserialize BDK wallet field: {}", e);
515 Err(std::io::Error::new(
516 std::io::ErrorKind::InvalidData,
517 "Failed to deserialize BDK wallet field",
518 ))
519 },
520 }
521 }
522
523 pub(crate) fn $write_name<L: Deref>(
524 value: &$change_set_type, kv_store: Arc<DynStore>, logger: L,
525 ) -> Result<(), std::io::Error>
526 where
527 L::Target: LdkLogger,
528 {
529 let data = ChangeSetSerWrapper(value).encode();
530 KVStoreSync::write(&*kv_store, $primary_namespace, $secondary_namespace, $key, data)
531 .map_err(|e| {
532 log_error!(
533 logger,
534 "Writing data to key {}/{}/{} failed due to: {}",
535 $primary_namespace,
536 $secondary_namespace,
537 $key,
538 e
539 );
540 e.into()
541 })
542 }
543 };
544}
545
546impl_read_write_change_set_type!(
547 read_bdk_wallet_descriptor,
548 write_bdk_wallet_descriptor,
549 Descriptor<DescriptorPublicKey>,
550 BDK_WALLET_DESCRIPTOR_PRIMARY_NAMESPACE,
551 BDK_WALLET_DESCRIPTOR_SECONDARY_NAMESPACE,
552 BDK_WALLET_DESCRIPTOR_KEY
553);
554
555impl_read_write_change_set_type!(
556 read_bdk_wallet_change_descriptor,
557 write_bdk_wallet_change_descriptor,
558 Descriptor<DescriptorPublicKey>,
559 BDK_WALLET_CHANGE_DESCRIPTOR_PRIMARY_NAMESPACE,
560 BDK_WALLET_CHANGE_DESCRIPTOR_SECONDARY_NAMESPACE,
561 BDK_WALLET_CHANGE_DESCRIPTOR_KEY
562);
563
564impl_read_write_change_set_type!(
565 read_bdk_wallet_network,
566 write_bdk_wallet_network,
567 Network,
568 BDK_WALLET_NETWORK_PRIMARY_NAMESPACE,
569 BDK_WALLET_NETWORK_SECONDARY_NAMESPACE,
570 BDK_WALLET_NETWORK_KEY
571);
572
573impl_read_write_change_set_type!(
574 read_bdk_wallet_local_chain,
575 write_bdk_wallet_local_chain,
576 BdkLocalChainChangeSet,
577 BDK_WALLET_LOCAL_CHAIN_PRIMARY_NAMESPACE,
578 BDK_WALLET_LOCAL_CHAIN_SECONDARY_NAMESPACE,
579 BDK_WALLET_LOCAL_CHAIN_KEY
580);
581
582impl_read_write_change_set_type!(
583 read_bdk_wallet_tx_graph,
584 write_bdk_wallet_tx_graph,
585 BdkTxGraphChangeSet<ConfirmationBlockTime>,
586 BDK_WALLET_TX_GRAPH_PRIMARY_NAMESPACE,
587 BDK_WALLET_TX_GRAPH_SECONDARY_NAMESPACE,
588 BDK_WALLET_TX_GRAPH_KEY
589);
590
591impl_read_write_change_set_type!(
592 read_bdk_wallet_indexer,
593 write_bdk_wallet_indexer,
594 BdkIndexerChangeSet,
595 BDK_WALLET_INDEXER_PRIMARY_NAMESPACE,
596 BDK_WALLET_INDEXER_SECONDARY_NAMESPACE,
597 BDK_WALLET_INDEXER_KEY
598);
599
600pub(crate) fn read_bdk_wallet_change_set(
602 kv_store: Arc<DynStore>, logger: Arc<Logger>,
603) -> Result<Option<BdkWalletChangeSet>, std::io::Error> {
604 let mut change_set = BdkWalletChangeSet::default();
605
606 if let Some(descriptor) =
608 read_bdk_wallet_descriptor(Arc::clone(&kv_store), Arc::clone(&logger))?
609 {
610 change_set.descriptor = Some(descriptor);
611 } else {
612 return Ok(None);
613 }
614
615 if let Some(change_descriptor) =
617 read_bdk_wallet_change_descriptor(Arc::clone(&kv_store), Arc::clone(&logger))?
618 {
619 change_set.change_descriptor = Some(change_descriptor);
620 } else {
621 return Ok(None);
622 }
623
624 if let Some(network) = read_bdk_wallet_network(Arc::clone(&kv_store), Arc::clone(&logger))? {
626 change_set.network = Some(network);
627 } else {
628 return Ok(None);
629 }
630
631 read_bdk_wallet_local_chain(Arc::clone(&kv_store), Arc::clone(&logger))?
632 .map(|local_chain| change_set.local_chain = local_chain);
633 read_bdk_wallet_tx_graph(Arc::clone(&kv_store), Arc::clone(&logger))?
634 .map(|tx_graph| change_set.tx_graph = tx_graph);
635 read_bdk_wallet_indexer(Arc::clone(&kv_store), Arc::clone(&logger))?
636 .map(|indexer| change_set.indexer = indexer);
637 Ok(Some(change_set))
638}
639
640#[cfg(test)]
641mod tests {
642 use super::*;
643
644 #[test]
645 fn mnemonic_to_entropy_to_mnemonic() {
646 let mnemonic = generate_entropy_mnemonic(None);
648 let entropy = mnemonic.to_entropy();
649 assert_eq!(mnemonic, Mnemonic::from_entropy(&entropy).unwrap());
650 assert_eq!(mnemonic.word_count(), 24);
651
652 let word_counts = [
654 WordCount::Words12,
655 WordCount::Words15,
656 WordCount::Words18,
657 WordCount::Words21,
658 WordCount::Words24,
659 ];
660
661 for word_count in word_counts {
662 let mnemonic = generate_entropy_mnemonic(Some(word_count));
663 let entropy = mnemonic.to_entropy();
664 assert_eq!(mnemonic, Mnemonic::from_entropy(&entropy).unwrap());
665
666 let expected_words = match word_count {
668 WordCount::Words12 => 12,
669 WordCount::Words15 => 15,
670 WordCount::Words18 => 18,
671 WordCount::Words21 => 21,
672 WordCount::Words24 => 24,
673 };
674 assert_eq!(mnemonic.word_count(), expected_words);
675 }
676 }
677}