1use std::cmp;
24use std::collections::{BTreeMap, BTreeSet, HashMap, VecDeque};
25use std::marker::PhantomData;
26use std::ops::{AddAssign, Deref};
27
28use bpstd::{
29 Address, AddressNetwork, DerivedAddr, Descriptor, Idx, IdxBase, Keychain, Network, NormalIndex,
30 Outpoint, Sats, ScriptPubkey, Txid, Vout,
31};
32use nonasync::persistence::{
33 CloneNoPersistence, Persistence, PersistenceError, PersistenceProvider, Persisting,
34};
35use psbt::{Psbt, PsbtConstructor, PsbtMeta, Utxo};
36
37use crate::{
38 BlockInfo, CoinRow, Indexer, Layer2, Layer2Cache, Layer2Data, Layer2Descriptor, Layer2Empty,
39 MayError, MiningInfo, NoLayer2, Party, TxCredit, TxDebit, TxRow, TxStatus, WalletAddr,
40 WalletTx, WalletUtxo,
41};
42
43#[derive(Copy, Clone, Eq, PartialEq, Debug, Display, Error)]
44#[display(doc_comments)]
45pub enum NonWalletItem {
46 NonWalletTx(Txid),
48 NoOutput(Txid, Vout),
50 NonWalletUtxo(Outpoint),
52}
53
54pub struct AddrIter<'descr, K, D: Descriptor<K>> {
55 generator: &'descr D,
56 network: AddressNetwork,
57 keychain: Keychain,
58 index: NormalIndex,
59 remainder: VecDeque<DerivedAddr>,
60 _phantom: PhantomData<K>,
61}
62
63impl<K, D: Descriptor<K>> Iterator for AddrIter<'_, K, D> {
64 type Item = DerivedAddr;
65
66 fn next(&mut self) -> Option<Self::Item> {
67 loop {
68 if let Some(derived) = self.remainder.pop_front() {
69 return Some(derived);
70 }
71 self.remainder = self
72 .generator
73 .derive_address(self.network, self.keychain, self.index)
74 .map(|addr| DerivedAddr::new(addr, self.keychain, self.index))
75 .collect();
76 self.index.checked_inc_assign()?;
77 }
78 }
79}
80
81#[cfg_attr(
82 feature = "serde",
83 derive(serde::Serialize, serde::Deserialize),
84 serde(
85 crate = "serde_crate",
86 rename_all = "camelCase",
87 bound(
88 serialize = "D: serde::Serialize, L2: serde::Serialize",
89 deserialize = "D: serde::Deserialize<'de>, L2: serde::Deserialize<'de>"
90 )
91 )
92)]
93#[derive(Getters, Debug)]
94pub struct WalletDescr<K, D, L2 = Layer2Empty>
95where
96 D: Descriptor<K>,
97 L2: Layer2Descriptor,
98{
99 #[getter(skip)]
100 #[cfg_attr(feature = "serde", serde(skip))]
101 persistence: Option<Persistence<Self>>,
102
103 generator: D,
104 #[getter(as_copy)]
105 network: Network,
106 layer2: L2,
107 #[cfg_attr(feature = "serde", serde(skip))]
108 _phantom: PhantomData<K>,
109}
110
111impl<K, D: Descriptor<K>> WalletDescr<K, D, Layer2Empty> {
112 pub fn new_standard(descr: D, network: Network) -> Self {
113 WalletDescr {
114 persistence: None,
115 generator: descr,
116 network,
117 layer2: none!(),
118 _phantom: PhantomData,
119 }
120 }
121}
122
123impl<K, D: Descriptor<K>, L2: Layer2Descriptor> WalletDescr<K, D, L2> {
124 pub fn new_layer2(descr: D, layer2: L2, network: Network) -> Self {
125 WalletDescr {
126 persistence: None,
127 generator: descr,
128 network,
129 layer2,
130 _phantom: PhantomData,
131 }
132 }
133
134 pub fn addresses(&self, keychain: impl Into<Keychain>) -> AddrIter<K, D> {
135 AddrIter {
136 generator: &self.generator,
137 network: self.network.into(),
138 keychain: keychain.into(),
139 index: NormalIndex::ZERO,
140 remainder: VecDeque::new(),
141 _phantom: PhantomData,
142 }
143 }
144
145 pub fn with_descriptor<T, E>(
146 &mut self,
147 f: impl FnOnce(&mut D) -> Result<T, E>,
148 ) -> Result<T, E> {
149 let res = f(&mut self.generator)?;
150 self.mark_dirty();
151 Ok(res)
152 }
153}
154
155impl<K, D: Descriptor<K>, L2: Layer2Descriptor> Deref for WalletDescr<K, D, L2> {
156 type Target = D;
157
158 fn deref(&self) -> &Self::Target { &self.generator }
159}
160
161impl<K, D: Descriptor<K>, L2: Layer2Descriptor> CloneNoPersistence for WalletDescr<K, D, L2> {
162 fn clone_no_persistence(&self) -> Self {
163 Self {
164 persistence: None,
165 generator: self.generator.clone(),
166 network: self.network,
167 layer2: self.layer2.clone(),
168 _phantom: PhantomData,
169 }
170 }
171}
172
173impl<K, D: Descriptor<K>, L2: Layer2Descriptor> Persisting for WalletDescr<K, D, L2> {
174 #[inline]
175 fn persistence(&self) -> Option<&Persistence<Self>> { self.persistence.as_ref() }
176 #[inline]
177 fn persistence_mut(&mut self) -> Option<&mut Persistence<Self>> { self.persistence.as_mut() }
178 #[inline]
179 fn as_mut_persistence(&mut self) -> &mut Option<Persistence<Self>> { &mut self.persistence }
180}
181
182impl<K, D: Descriptor<K>, L2: Layer2Descriptor> Drop for WalletDescr<K, D, L2> {
183 fn drop(&mut self) {
184 if self.is_autosave() && self.is_dirty() {
185 if let Err(e) = self.store() {
186 #[cfg(feature = "log")]
187 log::error!("impossible to automatically-save wallet descriptor on Drop: {e}");
188 #[cfg(not(feature = "log"))]
189 eprintln!("impossible to automatically-save wallet descriptor on Drop: {e}")
190 }
191 }
192 }
193}
194
195#[derive(Debug)]
196#[cfg_attr(
197 feature = "serde",
198 derive(serde::Serialize, serde::Deserialize),
199 serde(
200 crate = "serde_crate",
201 rename_all = "camelCase",
202 bound(serialize = "L2: serde::Serialize", deserialize = "L2: serde::Deserialize<'de>")
203 )
204)]
205pub struct WalletData<L2: Layer2Data> {
206 #[cfg_attr(feature = "serde", serde(skip))]
207 persistence: Option<Persistence<Self>>,
208
209 #[cfg_attr(feature = "serde", serde(skip))]
211 pub id: Option<String>,
212 pub name: String,
213 pub tx_annotations: BTreeMap<Txid, String>,
214 pub txout_annotations: BTreeMap<Outpoint, String>,
215 pub txin_annotations: BTreeMap<Outpoint, String>,
216 pub addr_annotations: BTreeMap<Address, String>,
217 pub last_used: BTreeMap<Keychain, NormalIndex>,
218 pub layer2: L2,
219}
220
221impl<L2: Layer2Data> CloneNoPersistence for WalletData<L2> {
222 fn clone_no_persistence(&self) -> Self {
223 Self {
224 persistence: None,
225 id: self.id.clone(),
226 name: self.name.clone(),
227 tx_annotations: self.tx_annotations.clone(),
228 txout_annotations: self.txout_annotations.clone(),
229 txin_annotations: self.txin_annotations.clone(),
230 addr_annotations: self.addr_annotations.clone(),
231 layer2: self.layer2.clone(),
232 last_used: self.last_used.clone(),
233 }
234 }
235}
236
237impl<L2: Layer2Data> Persisting for WalletData<L2> {
238 #[inline]
239 fn persistence(&self) -> Option<&Persistence<Self>> { self.persistence.as_ref() }
240 #[inline]
241 fn persistence_mut(&mut self) -> Option<&mut Persistence<Self>> { self.persistence.as_mut() }
242 #[inline]
243 fn as_mut_persistence(&mut self) -> &mut Option<Persistence<Self>> { &mut self.persistence }
244}
245
246impl WalletData<Layer2Empty> {
247 pub fn new_layer1() -> Self {
248 WalletData {
249 persistence: None,
250 id: None,
251 name: none!(),
252 tx_annotations: empty!(),
253 txout_annotations: empty!(),
254 txin_annotations: empty!(),
255 addr_annotations: empty!(),
256 layer2: none!(),
257 last_used: empty!(),
258 }
259 }
260}
261
262impl<L2: Layer2Data> WalletData<L2> {
263 pub fn new_layer2() -> Self
264 where L2: Default {
265 WalletData {
266 persistence: None,
267 id: None,
268 name: none!(),
269 tx_annotations: empty!(),
270 txout_annotations: empty!(),
271 txin_annotations: empty!(),
272 addr_annotations: empty!(),
273 layer2: none!(),
274 last_used: empty!(),
275 }
276 }
277}
278
279impl<L2: Layer2Data> Drop for WalletData<L2> {
280 fn drop(&mut self) {
281 if self.is_autosave() && self.is_dirty() {
282 if let Err(e) = self.store() {
283 #[cfg(feature = "log")]
284 log::error!("impossible to automatically-save wallet data on Drop: {e}");
285 #[cfg(not(feature = "log"))]
286 eprintln!("impossible to automatically-save wallet data on Drop: {e}")
287 }
288 }
289 }
290}
291
292#[cfg_attr(
293 feature = "serde",
294 derive(serde::Serialize, serde::Deserialize),
295 serde(
296 crate = "serde_crate",
297 rename_all = "camelCase",
298 bound(serialize = "L2: serde::Serialize", deserialize = "L2: serde::Deserialize<'de>")
299 )
300)]
301#[derive(Debug)]
302pub struct WalletCache<L2: Layer2Cache> {
303 #[cfg_attr(feature = "serde", serde(skip))]
304 persistence: Option<Persistence<Self>>,
305
306 #[cfg_attr(feature = "serde", serde(skip))]
308 pub id: Option<String>,
309 pub last_block: MiningInfo,
310 pub last_change: NormalIndex,
311 pub headers: BTreeSet<BlockInfo>,
312 pub tx: BTreeMap<Txid, WalletTx>,
313 pub utxo: BTreeSet<Outpoint>,
314 pub addr: BTreeMap<Keychain, BTreeSet<WalletAddr>>,
315 pub layer2: L2,
316}
317
318impl<L2C: Layer2Cache> WalletCache<L2C> {
319 pub(crate) fn new_nonsync() -> Self {
320 WalletCache {
321 persistence: None,
322 id: None,
323 last_block: MiningInfo::genesis(),
324 last_change: NormalIndex::ZERO,
325 headers: none!(),
326 tx: none!(),
327 utxo: none!(),
328 addr: none!(),
329 layer2: none!(),
330 }
331 }
332
333 pub fn with<I: Indexer, K, D: Descriptor<K>, L2: Layer2<Cache = L2C>>(
334 descriptor: &WalletDescr<K, D, L2::Descr>,
335 indexer: &I,
336 ) -> MayError<Self, Vec<I::Error>> {
337 indexer.create::<K, D, L2>(descriptor)
338 }
339
340 pub fn update<I: Indexer, K, D: Descriptor<K>, L2: Layer2<Cache = L2C>>(
341 &mut self,
342 descriptor: &WalletDescr<K, D, L2::Descr>,
343 indexer: &I,
344 ) -> MayError<usize, Vec<I::Error>> {
345 let res = indexer.update::<K, D, L2>(descriptor, self);
346 self.mark_dirty();
347 res
348 }
349
350 pub fn register_psbt(&mut self, psbt: &Psbt, meta: &PsbtMeta) {
351 let unsigned_tx = psbt.to_unsigned_tx();
352 let txid = unsigned_tx.txid();
353 let wallet_tx = WalletTx {
354 txid,
355 status: TxStatus::Mempool,
356 inputs: psbt
357 .inputs()
358 .map(|input| {
359 let addr = Address::with(&input.prev_txout().script_pubkey, meta.network).ok();
360 TxCredit {
361 outpoint: input.previous_outpoint,
362 payer: match (self.utxo.get(&input.previous_outpoint), addr) {
363 (Some(_), Some(addr)) => {
364 let (keychain, index) = self
365 .addr
366 .iter()
367 .flat_map(|(keychain, addrs)| {
368 addrs.iter().map(|a| (*keychain, a))
369 })
370 .find(|(_, a)| a.addr == addr)
371 .map(|(keychain, a)| (keychain, a.terminal.index))
372 .expect("address cache inconsistency");
373 Party::Wallet(DerivedAddr::new(addr, keychain, index))
374 }
375 (_, Some(addr)) => Party::Counterparty(addr),
376 _ => Party::Unknown(input.prev_txout().script_pubkey.clone()),
377 },
378 sequence: unsigned_tx.inputs[input.index()].sequence,
379 coinbase: false,
380 script_sig: none!(),
381 witness: none!(),
382 value: input.value(),
383 }
384 })
385 .collect(),
386 outputs: psbt
387 .outputs()
388 .map(|output| {
389 let vout = Vout::from_u32(output.index() as u32);
390 let addr = Address::with(&output.script, meta.network).ok();
391 TxDebit {
392 outpoint: Outpoint::new(txid, vout),
393 beneficiary: match (meta.change, addr) {
394 (Some(change), Some(addr)) if change.vout == vout => {
395 Party::Wallet(DerivedAddr::new(
396 addr,
397 change.terminal.keychain,
398 change.terminal.index,
399 ))
400 }
401 (_, Some(addr)) => Party::Counterparty(addr),
402 (_, _) => Party::Unknown(output.script.clone()),
403 },
404 value: output.value(),
405 spent: None,
406 }
407 })
408 .collect(),
409 fee: meta.fee,
410 size: meta.size,
411 weight: meta.weight,
412 version: unsigned_tx.version,
413 locktime: unsigned_tx.lock_time,
414 };
415 self.tx.insert(txid, wallet_tx);
416 if let Some(change) = meta.change {
417 self.utxo.insert(Outpoint::new(txid, change.vout));
418 }
419 }
420
421 pub fn addresses_on(&self, keychain: Keychain) -> &BTreeSet<WalletAddr> {
422 self.addr.get(&keychain).unwrap_or_else(|| {
423 panic!("keychain #{keychain} is not supported by the wallet descriptor")
424 })
425 }
426
427 pub fn has_outpoint(&self, outpoint: Outpoint) -> bool {
428 let Some(tx) = self.tx.get(&outpoint.txid) else {
429 return false;
430 };
431 let Some(out) = tx.outputs.get(outpoint.vout.to_usize()) else {
432 return false;
433 };
434 matches!(out.beneficiary, Party::Wallet(_))
435 }
436
437 #[inline]
438 pub fn is_unspent(&self, outpoint: Outpoint) -> bool { self.utxo.contains(&outpoint) }
439
440 pub fn outpoint_by(
441 &self,
442 outpoint: Outpoint,
443 ) -> Result<(WalletUtxo, ScriptPubkey), NonWalletItem> {
444 let tx = self.tx.get(&outpoint.txid).ok_or(NonWalletItem::NonWalletTx(outpoint.txid))?;
445 let debit = tx
446 .outputs
447 .get(outpoint.vout.into_usize())
448 .ok_or(NonWalletItem::NoOutput(outpoint.txid, outpoint.vout))?;
449 let terminal = debit.derived_addr().ok_or(NonWalletItem::NonWalletUtxo(outpoint))?.terminal;
450 let utxo = WalletUtxo {
452 outpoint,
453 value: debit.value,
454 terminal,
455 status: tx.status,
456 };
457 let spk =
458 debit.beneficiary.script_pubkey().ok_or(NonWalletItem::NonWalletUtxo(outpoint))?;
459 Ok((utxo, spk))
460 }
461
462 pub fn txos(&self) -> impl Iterator<Item = WalletUtxo> + '_ {
464 self.tx.iter().flat_map(|(txid, tx)| {
465 tx.outputs.iter().enumerate().filter_map(|(vout, out)| {
466 if let Party::Wallet(w) = out.beneficiary {
467 Some(WalletUtxo {
468 outpoint: Outpoint::new(*txid, vout as u32),
469 value: out.value,
470 terminal: w.terminal,
471 status: tx.status,
472 })
473 } else {
474 None
475 }
476 })
477 })
478 }
479
480 pub fn utxos(&self) -> impl Iterator<Item = WalletUtxo> + '_ {
481 self.utxo.iter().map(|outpoint| {
482 let tx = self.tx.get(&outpoint.txid).expect("cache data inconsistency");
483 let debit = tx.outputs.get(outpoint.vout_usize()).expect("cache data inconsistency");
484 let terminal =
485 debit.derived_addr().expect("UTXO doesn't belong to the wallet").terminal;
486 WalletUtxo {
488 outpoint: *outpoint,
489 value: debit.value,
490 terminal,
491 status: tx.status,
492 }
493 })
494 }
495}
496
497impl<L2: Layer2Cache> CloneNoPersistence for WalletCache<L2> {
498 fn clone_no_persistence(&self) -> Self {
499 Self {
500 persistence: None,
501 id: self.id.clone(),
502 last_block: self.last_block,
503 last_change: self.last_change,
504 headers: self.headers.clone(),
505 tx: self.tx.clone(),
506 utxo: self.utxo.clone(),
507 addr: self.addr.clone(),
508 layer2: self.layer2.clone(),
509 }
510 }
511}
512
513impl<L2: Layer2Cache> Persisting for WalletCache<L2> {
514 #[inline]
515 fn persistence(&self) -> Option<&Persistence<Self>> { self.persistence.as_ref() }
516 #[inline]
517 fn persistence_mut(&mut self) -> Option<&mut Persistence<Self>> { self.persistence.as_mut() }
518 #[inline]
519 fn as_mut_persistence(&mut self) -> &mut Option<Persistence<Self>> { &mut self.persistence }
520}
521
522impl<L2: Layer2Cache> Drop for WalletCache<L2> {
523 fn drop(&mut self) {
524 if self.is_autosave() && self.is_dirty() {
525 if let Err(e) = self.store() {
526 #[cfg(feature = "log")]
527 log::error!("impossible to automatically-save wallet cache on Drop: {e}");
528 #[cfg(not(feature = "log"))]
529 eprintln!("impossible to automatically-save wallet cache on Drop: {e}")
530 }
531 }
532 }
533}
534
535#[derive(Debug)]
536pub struct Wallet<K, D: Descriptor<K>, L2: Layer2 = NoLayer2> {
537 descr: WalletDescr<K, D, L2::Descr>,
538 data: WalletData<L2::Data>,
539 cache: WalletCache<L2::Cache>,
540 layer2: L2,
541}
542
543impl<K, D: Descriptor<K>, L2: Layer2> Deref for Wallet<K, D, L2> {
544 type Target = WalletDescr<K, D, L2::Descr>;
545
546 fn deref(&self) -> &Self::Target { &self.descr }
547}
548
549impl<K, D: Descriptor<K>, L2: Layer2> CloneNoPersistence for Wallet<K, D, L2> {
550 fn clone_no_persistence(&self) -> Self {
551 Self {
552 descr: self.descr.clone_no_persistence(),
553 data: self.data.clone_no_persistence(),
554 cache: self.cache.clone_no_persistence(),
555 layer2: self.layer2.clone_no_persistence(),
556 }
557 }
558}
559
560impl<K, D: Descriptor<K>, L2: Layer2> PsbtConstructor for Wallet<K, D, L2> {
561 type Key = K;
562 type Descr = D;
563
564 fn descriptor(&self) -> &D { &self.descr.generator }
565
566 fn utxo(&self, outpoint: Outpoint) -> Option<(Utxo, ScriptPubkey)> {
567 self.cache.outpoint_by(outpoint).ok().map(|(utxo, spk)| (utxo.into_utxo(), spk))
568 }
569
570 fn network(&self) -> Network { self.descr.network }
571
572 fn next_derivation_index(&mut self, keychain: impl Into<Keychain>, shift: bool) -> NormalIndex {
573 let keychain = keychain.into();
574 let mut idx = self.last_published_derivation_index(keychain);
575 let last_index = self.data.last_used.entry(keychain).or_default();
576 idx = cmp::max(*last_index, idx);
577 if shift {
578 *last_index = idx.saturating_add(1u32);
579 self.data.mark_dirty();
580 }
581 idx
582 }
583
584 fn after_construct_psbt(&mut self, psbt: &Psbt, meta: &PsbtMeta) {
585 debug_assert_eq!(AddressNetwork::from(self.network), meta.network);
586 self.cache.register_psbt(psbt, meta);
587 }
588}
589
590impl<K, D: Descriptor<K>> Wallet<K, D> {
591 pub fn new_layer1(descr: D, network: Network) -> Self {
592 Wallet {
593 cache: WalletCache::new_nonsync(),
594 data: WalletData::new_layer1(),
595 descr: WalletDescr::new_standard(descr, network),
596 layer2: none!(),
597 }
598 }
599}
600
601impl<K, D: Descriptor<K>, L2: Layer2> Wallet<K, D, L2> {
602 pub fn new_layer2(descr: D, l2_descr: L2::Descr, layer2: L2, network: Network) -> Self {
603 Wallet {
604 cache: WalletCache::new_nonsync(),
605 data: WalletData::new_layer2(),
606 descr: WalletDescr::new_layer2(descr, l2_descr, network),
607 layer2,
608 }
609 }
610
611 pub fn set_name(&mut self, name: String) {
612 self.data.name = name;
613 self.data.mark_dirty();
614 }
615
616 pub fn with_descriptor<T, E>(
617 &mut self,
618 f: impl FnOnce(&mut D) -> Result<T, E>,
619 ) -> Result<T, E> {
620 self.descr.with_descriptor(f)
621 }
622
623 pub fn data_l2(&self) -> &L2::Data { &self.data.layer2 }
624 pub fn cache_l2(&self) -> &L2::Cache { &self.cache.layer2 }
625
626 pub fn with_data<T, E>(
627 &mut self,
628 f: impl FnOnce(&mut WalletData<L2::Data>) -> Result<T, E>,
629 ) -> Result<T, E> {
630 let res = f(&mut self.data)?;
631 self.data.mark_dirty();
632 Ok(res)
633 }
634
635 pub fn with_data_l2<T, E>(
636 &mut self,
637 f: impl FnOnce(&mut L2::Data) -> Result<T, E>,
638 ) -> Result<T, E> {
639 let res = f(&mut self.data.layer2)?;
640 self.data.mark_dirty();
641 Ok(res)
642 }
643
644 pub fn with_cache_l2<T, E>(
645 &mut self,
646 f: impl FnOnce(&mut L2::Cache) -> Result<T, E>,
647 ) -> Result<T, E> {
648 let res = f(&mut self.cache.layer2)?;
649 self.cache.mark_dirty();
650 Ok(res)
651 }
652
653 #[must_use]
654 pub fn update<I: Indexer>(&mut self, indexer: &I) -> MayError<(), Vec<I::Error>> {
655 self.cache.update::<I, K, D, L2>(&self.descr, indexer).map(|_| ())
656 }
657
658 pub fn to_deriver(&self) -> D
659 where
660 D: Clone,
661 K: Clone,
662 {
663 self.descr.clone()
664 }
665
666 fn last_published_derivation_index(&self, keychain: impl Into<Keychain>) -> NormalIndex {
667 let keychain = keychain.into();
668 self.address_coins()
669 .keys()
670 .filter(|ad| ad.terminal.keychain == keychain)
671 .map(|ad| ad.terminal.index)
672 .max()
673 .as_ref()
674 .map(NormalIndex::saturating_inc)
675 .unwrap_or_default()
676 }
677
678 pub fn last_derivation_index(&self, keychain: impl Into<Keychain>) -> NormalIndex {
679 let keychain = keychain.into();
680 let last_index = self.data.last_used.get(&keychain).copied().unwrap_or_default();
681 cmp::max(last_index, self.last_published_derivation_index(keychain))
682 }
683
684 pub fn next_address(&mut self, keychain: impl Into<Keychain>, shift: bool) -> Address {
685 let keychain = keychain.into();
686 let index = self.next_derivation_index(keychain, shift);
687 self.addresses(keychain)
688 .nth(index.index() as usize)
689 .expect("address iterator always can produce address")
690 .addr
691 }
692
693 pub fn balance(&self) -> Sats { self.cache.coins().map(|utxo| utxo.amount).sum::<Sats>() }
694
695 #[inline]
696 pub fn transactions(&self) -> &BTreeMap<Txid, WalletTx> { &self.cache.tx }
697
698 #[inline]
699 pub fn coins(&self) -> impl Iterator<Item = CoinRow<<L2::Cache as Layer2Cache>::Coin>> + '_ {
700 self.cache.coins()
701 }
702
703 pub fn address_coins(
704 &self,
705 ) -> HashMap<DerivedAddr, Vec<CoinRow<<L2::Cache as Layer2Cache>::Coin>>> {
706 let map = HashMap::new();
707 self.coins().fold(map, |mut acc, txo| {
708 acc.entry(txo.address).or_default().push(txo);
709 acc
710 })
711 }
712
713 pub fn address_balance(&self) -> impl Iterator<Item = WalletAddr> + '_ {
714 self.cache.addr.values().flat_map(|set| set.iter()).copied()
715 }
716
717 #[inline]
718 pub fn history(&self) -> impl Iterator<Item = TxRow<<L2::Cache as Layer2Cache>::Tx>> + '_ {
719 self.cache.history()
720 }
721
722 pub fn has_outpoint(&self, outpoint: Outpoint) -> bool { self.cache.has_outpoint(outpoint) }
723 pub fn is_unspent(&self, outpoint: Outpoint) -> bool { self.cache.is_unspent(outpoint) }
724
725 pub fn outpoint_by(
726 &self,
727 outpoint: Outpoint,
728 ) -> Result<(WalletUtxo, ScriptPubkey), NonWalletItem> {
729 self.cache.outpoint_by(outpoint)
730 }
731
732 pub fn txos(&self) -> impl Iterator<Item = WalletUtxo> + '_ { self.cache.txos() }
733 pub fn utxos(&self) -> impl Iterator<Item = WalletUtxo> + '_ { self.cache.utxos() }
734
735 pub fn coinselect<'a>(
736 &'a self,
737 up_to: Sats,
738 selector: impl Fn(&WalletUtxo) -> bool + 'a,
739 ) -> impl Iterator<Item = Outpoint> + 'a {
740 let mut selected = Sats::ZERO;
741 self.utxos()
742 .filter(selector)
743 .take_while(move |utxo| {
744 if selected <= up_to {
745 selected.add_assign(utxo.value);
746 true
747 } else {
748 false
749 }
750 })
751 .map(|utxo| utxo.outpoint)
752 }
753}
754
755impl<K, D: Descriptor<K>, L2: Layer2> Wallet<K, D, L2> {
756 pub fn load<P>(provider: P, autosave: bool) -> Result<Wallet<K, D, L2>, PersistenceError>
757 where P: Clone
758 + PersistenceProvider<WalletDescr<K, D, L2::Descr>>
759 + PersistenceProvider<WalletData<L2::Data>>
760 + PersistenceProvider<WalletCache<L2::Cache>>
761 + PersistenceProvider<L2>
762 + 'static {
763 let descr = WalletDescr::<K, D, L2::Descr>::load(provider.clone(), autosave)?;
764 let data = WalletData::<L2::Data>::load(provider.clone(), autosave)?;
765 let cache = WalletCache::<L2::Cache>::load(provider.clone(), autosave)?;
766 let layer2 = L2::load(provider, autosave)?;
767
768 Ok(Wallet {
769 descr,
770 data,
771 cache,
772 layer2,
773 })
774 }
775
776 pub fn set_id(&mut self, id: &impl ToString) {
777 self.data.id = Some(id.to_string());
778 self.cache.id = Some(id.to_string());
779 }
780
781 pub fn make_persistent<P>(
782 &mut self,
783 provider: P,
784 autosave: bool,
785 ) -> Result<bool, PersistenceError>
786 where
787 P: Clone
788 + PersistenceProvider<WalletDescr<K, D, L2::Descr>>
789 + PersistenceProvider<WalletData<L2::Data>>
790 + PersistenceProvider<WalletCache<L2::Cache>>
791 + PersistenceProvider<L2>
792 + 'static,
793 {
794 let a = self.descr.make_persistent(provider.clone(), autosave)?;
795 let b = self.data.make_persistent(provider.clone(), autosave)?;
796 let c = self.cache.make_persistent(provider.clone(), autosave)?;
797 let d = self.layer2.make_persistent(provider, autosave)?;
798 Ok(a && b && c && d)
799 }
800
801 pub fn store(&mut self) -> Result<(), PersistenceError> {
802 self.descr.store()?;
805 self.data.store()?;
806 self.cache.store()?;
807 self.layer2.store()?;
808
809 Ok(())
810 }
811}