1pub mod selection;
2pub mod state;
3
4use log::{debug, error, trace};
5use ark::{ProtocolEncoding, Vtxo};
6use ark::vtxo::VtxoRef;
7
8use crate::Wallet;
9use crate::movement::MovementId;
10use crate::vtxo::state::{VtxoState, VtxoStateKind, UNSPENT_STATES};
11
12impl Wallet {
13 pub fn lock_vtxos(
21 &self,
22 vtxos: impl IntoIterator<Item = impl VtxoRef>,
23 movement_id: Option<MovementId>,
24 ) -> anyhow::Result<()> {
25 self.set_vtxo_states(vtxos, &VtxoState::Locked { movement_id }, &UNSPENT_STATES)
26 }
27
28 pub fn mark_vtxos_as_spent(
36 &self,
37 vtxos: impl IntoIterator<Item = impl VtxoRef>,
38 ) -> anyhow::Result<()> {
39 self.set_vtxo_states(vtxos, &VtxoState::Spent, &UNSPENT_STATES)
40 }
41
42 pub fn set_vtxo_states(
55 &self,
56 vtxos: impl IntoIterator<Item = impl VtxoRef>,
57 state: &VtxoState,
58 allowed_states: &[VtxoStateKind],
59 ) -> anyhow::Result<()> {
60 let mut problematic_vtxos = Vec::new();
61 for vtxo in vtxos {
62 let id = vtxo.vtxo_id();
63 if let Err(e) = self.db.update_vtxo_state_checked(
64 id,
65 state.clone(),
66 allowed_states,
67 ) {
68 error!(
69 "Failed to set {} state with allowed states {:?} for VTXO {}: {:#}",
70 state.kind(), allowed_states, id, e,
71 );
72 problematic_vtxos.push(id);
73 }
74 }
75 if problematic_vtxos.is_empty() {
76 Ok(())
77 } else {
78 Err(anyhow!(
79 "Failed to set {} state for {} VTXOs: {:?}",
80 state.kind(),
81 problematic_vtxos.len(),
82 problematic_vtxos
83 ))
84 }
85 }
86
87 pub fn store_locked_vtxos<'a>(
93 &self,
94 vtxos: impl IntoIterator<Item = &'a Vtxo>,
95 movement_id: Option<MovementId>,
96 ) -> anyhow::Result<()> {
97 self.store_vtxos(vtxos, &VtxoState::Locked { movement_id })
98 }
99
100 pub fn store_spendable_vtxos<'a>(
106 &self,
107 vtxos: impl IntoIterator<Item = &'a Vtxo>,
108 ) -> anyhow::Result<()> {
109 self.store_vtxos(vtxos, &VtxoState::Spendable)
110 }
111
112 pub fn store_spent_vtxos<'a>(
118 &self,
119 vtxos: impl IntoIterator<Item = &'a Vtxo>,
120 ) -> anyhow::Result<()> {
121 self.store_vtxos(vtxos, &VtxoState::Spent)
122 }
123
124 pub fn store_vtxos<'a>(
130 &self,
131 vtxos: impl IntoIterator<Item = &'a Vtxo>,
132 state: &VtxoState,
133 ) -> anyhow::Result<()> {
134 let vtxos = vtxos.into_iter().map(|v| (v, state)).collect::<Vec<_>>();
135 if let Err(e) = self.db.store_vtxos(&vtxos) {
136 error!("An error occurred while storing {} VTXOs: {:#}", vtxos.len(), e);
137 error!("Raw VTXOs for debugging:");
138 for (vtxo, _) in vtxos {
139 error!(" - {}", vtxo.serialize_hex());
140 }
141 Err(e)
142 } else {
143 debug!("Stored {} VTXOs", vtxos.len());
144 trace!("New VTXO IDs: {:?}", vtxos.into_iter().map(|(v, _)| v.id()).collect::<Vec<_>>());
145 Ok(())
146 }
147 }
148
149 pub fn unlock_vtxos(
157 &self,
158 vtxos: impl IntoIterator<Item = impl VtxoRef>,
159 ) -> anyhow::Result<()> {
160 self.set_vtxo_states(vtxos, &VtxoState::Spendable, &[VtxoStateKind::Locked])
161 }
162}