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