Skip to content

Commit a9bfdbc

Browse files
refactor: move wallet errors into their dedicated file
1 parent 35502e0 commit a9bfdbc

3 files changed

Lines changed: 150 additions & 144 deletions

File tree

src/wallet/error.rs

Lines changed: 145 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,154 @@
1212
//! Errors that can be thrown by the [`Wallet`](crate::wallet::Wallet)
1313
1414
use crate::descriptor::policy::PolicyError;
15-
use crate::descriptor::DescriptorError;
15+
use crate::descriptor::{DescriptorError, ExtendedDescriptor};
1616
use crate::wallet::coin_selection;
17-
use crate::{descriptor, KeychainKind};
18-
use alloc::string::String;
19-
use bitcoin::{absolute, psbt, Amount, OutPoint, Sequence, Txid};
17+
use crate::{descriptor, KeychainKind, LoadWithPersistError};
18+
use alloc::{
19+
boxed::Box,
20+
string::{String, ToString},
21+
};
22+
use bitcoin::{absolute, psbt, Amount, BlockHash, Network, OutPoint, Sequence, Txid};
23+
use chain::local_chain::CannotConnectError;
2024
use core::fmt;
2125

26+
/// The error type when loading a [`Wallet`] from a [`ChangeSet`].
27+
#[derive(Debug, PartialEq)]
28+
pub enum LoadError {
29+
/// There was a problem with the passed-in descriptor(s).
30+
Descriptor(crate::descriptor::DescriptorError),
31+
/// Data loaded from persistence is missing network type.
32+
MissingNetwork,
33+
/// Data loaded from persistence is missing genesis hash.
34+
MissingGenesis,
35+
/// Data loaded from persistence is missing descriptor.
36+
MissingDescriptor(KeychainKind),
37+
/// Data loaded is unexpected.
38+
Mismatch(LoadMismatch),
39+
}
40+
41+
impl fmt::Display for LoadError {
42+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43+
match self {
44+
LoadError::Descriptor(e) => e.fmt(f),
45+
LoadError::MissingNetwork => write!(f, "loaded data is missing network type"),
46+
LoadError::MissingGenesis => write!(f, "loaded data is missing genesis hash"),
47+
LoadError::MissingDescriptor(k) => {
48+
write!(f, "loaded data is missing descriptor for {k} keychain")
49+
}
50+
LoadError::Mismatch(e) => write!(f, "{e}"),
51+
}
52+
}
53+
}
54+
55+
#[cfg(feature = "std")]
56+
impl std::error::Error for LoadError {}
57+
58+
/// Represents a mismatch with what is loaded and what is expected from [`LoadParams`].
59+
#[derive(Debug, PartialEq)]
60+
pub enum LoadMismatch {
61+
/// Network does not match.
62+
Network {
63+
/// The network that is loaded.
64+
loaded: Network,
65+
/// The expected network.
66+
expected: Network,
67+
},
68+
/// Genesis hash does not match.
69+
Genesis {
70+
/// The genesis hash that is loaded.
71+
loaded: BlockHash,
72+
/// The expected genesis hash.
73+
expected: BlockHash,
74+
},
75+
/// Descriptor's [`DescriptorId`](bdk_chain::DescriptorId) does not match.
76+
Descriptor {
77+
/// Keychain identifying the descriptor.
78+
keychain: KeychainKind,
79+
/// The loaded descriptor.
80+
loaded: Option<Box<ExtendedDescriptor>>,
81+
/// The expected descriptor.
82+
expected: Option<Box<ExtendedDescriptor>>,
83+
},
84+
}
85+
86+
impl fmt::Display for LoadMismatch {
87+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
88+
match self {
89+
LoadMismatch::Network { loaded, expected } => {
90+
write!(f, "Network mismatch: loaded {loaded}, expected {expected}")
91+
}
92+
LoadMismatch::Genesis { loaded, expected } => {
93+
write!(
94+
f,
95+
"Genesis hash mismatch: loaded {loaded}, expected {expected}"
96+
)
97+
}
98+
LoadMismatch::Descriptor {
99+
keychain,
100+
loaded,
101+
expected,
102+
} => {
103+
write!(
104+
f,
105+
"Descriptor mismatch for {} keychain: loaded {}, expected {}",
106+
keychain,
107+
loaded
108+
.as_ref()
109+
.map_or("None".to_string(), |d| d.to_string()),
110+
expected
111+
.as_ref()
112+
.map_or("None".to_string(), |d| d.to_string())
113+
)
114+
}
115+
}
116+
}
117+
}
118+
119+
impl<E> From<LoadMismatch> for LoadWithPersistError<E> {
120+
fn from(mismatch: LoadMismatch) -> Self {
121+
Self::InvalidChangeSet(LoadError::Mismatch(mismatch))
122+
}
123+
}
124+
125+
impl From<LoadMismatch> for LoadError {
126+
fn from(mismatch: LoadMismatch) -> Self {
127+
Self::Mismatch(mismatch)
128+
}
129+
}
130+
131+
/// An error that may occur when applying a block to [`Wallet`].
132+
#[derive(Debug)]
133+
pub enum ApplyBlockError {
134+
/// Occurs when the update chain cannot connect with original chain.
135+
CannotConnect(CannotConnectError),
136+
/// Occurs when the `connected_to` hash does not match the hash derived from `block`.
137+
UnexpectedConnectedToHash {
138+
/// Block hash of `connected_to`.
139+
connected_to_hash: BlockHash,
140+
/// Expected block hash of `connected_to`, as derived from `block`.
141+
expected_hash: BlockHash,
142+
},
143+
}
144+
145+
impl fmt::Display for ApplyBlockError {
146+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
147+
match self {
148+
ApplyBlockError::CannotConnect(err) => err.fmt(f),
149+
ApplyBlockError::UnexpectedConnectedToHash {
150+
expected_hash: block_hash,
151+
connected_to_hash: checkpoint_hash,
152+
} => write!(
153+
f,
154+
"`connected_to` hash {checkpoint_hash} differs from the expected hash {block_hash} (which is derived from `block`)"
155+
),
156+
}
157+
}
158+
}
159+
160+
#[cfg(feature = "std")]
161+
impl std::error::Error for ApplyBlockError {}
162+
22163
/// Errors returned by miniscript when updating inconsistent PSBTs
23164
#[derive(Debug, Clone)]
24165
pub enum MiniscriptPsbtError {

src/wallet/mod.rs

Lines changed: 3 additions & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ use bitcoin::{
4040
psbt,
4141
secp256k1::Secp256k1,
4242
sighash::{EcdsaSighashType, TapSighashType},
43-
transaction, Address, Amount, Block, BlockHash, FeeRate, Network, NetworkKind, OutPoint, Psbt,
44-
ScriptBuf, Sequence, SignedAmount, Transaction, TxOut, Txid, Weight, Witness,
43+
transaction, Address, Amount, Block, FeeRate, Network, NetworkKind, OutPoint, Psbt, ScriptBuf,
44+
Sequence, SignedAmount, Transaction, TxOut, Txid, Weight, Witness,
4545
};
4646
use miniscript::{
4747
descriptor::KeyMap,
@@ -80,6 +80,7 @@ use crate::wallet::{
8080
// re-exports
8181
pub use bdk_chain::Balance;
8282
pub use changeset::ChangeSet;
83+
pub use error::{ApplyBlockError, LoadError, LoadMismatch};
8384
pub use event::*;
8485
pub use params::*;
8586
pub use persisted::*;
@@ -177,143 +178,6 @@ impl fmt::Display for AddressInfo {
177178
}
178179
}
179180

180-
/// The error type when loading a [`Wallet`] from a [`ChangeSet`].
181-
#[derive(Debug, PartialEq)]
182-
pub enum LoadError {
183-
/// There was a problem with the passed-in descriptor(s).
184-
Descriptor(crate::descriptor::DescriptorError),
185-
/// Data loaded from persistence is missing network type.
186-
MissingNetwork,
187-
/// Data loaded from persistence is missing genesis hash.
188-
MissingGenesis,
189-
/// Data loaded from persistence is missing descriptor.
190-
MissingDescriptor(KeychainKind),
191-
/// Data loaded is unexpected.
192-
Mismatch(LoadMismatch),
193-
}
194-
195-
impl fmt::Display for LoadError {
196-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
197-
match self {
198-
LoadError::Descriptor(e) => e.fmt(f),
199-
LoadError::MissingNetwork => write!(f, "loaded data is missing network type"),
200-
LoadError::MissingGenesis => write!(f, "loaded data is missing genesis hash"),
201-
LoadError::MissingDescriptor(k) => {
202-
write!(f, "loaded data is missing descriptor for {k} keychain")
203-
}
204-
LoadError::Mismatch(e) => write!(f, "{e}"),
205-
}
206-
}
207-
}
208-
209-
#[cfg(feature = "std")]
210-
impl std::error::Error for LoadError {}
211-
212-
/// Represents a mismatch with what is loaded and what is expected from [`LoadParams`].
213-
#[derive(Debug, PartialEq)]
214-
pub enum LoadMismatch {
215-
/// Network does not match.
216-
Network {
217-
/// The network that is loaded.
218-
loaded: Network,
219-
/// The expected network.
220-
expected: Network,
221-
},
222-
/// Genesis hash does not match.
223-
Genesis {
224-
/// The genesis hash that is loaded.
225-
loaded: BlockHash,
226-
/// The expected genesis hash.
227-
expected: BlockHash,
228-
},
229-
/// Descriptor's [`DescriptorId`](bdk_chain::DescriptorId) does not match.
230-
Descriptor {
231-
/// Keychain identifying the descriptor.
232-
keychain: KeychainKind,
233-
/// The loaded descriptor.
234-
loaded: Option<Box<ExtendedDescriptor>>,
235-
/// The expected descriptor.
236-
expected: Option<Box<ExtendedDescriptor>>,
237-
},
238-
}
239-
240-
impl fmt::Display for LoadMismatch {
241-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
242-
match self {
243-
LoadMismatch::Network { loaded, expected } => {
244-
write!(f, "Network mismatch: loaded {loaded}, expected {expected}")
245-
}
246-
LoadMismatch::Genesis { loaded, expected } => {
247-
write!(
248-
f,
249-
"Genesis hash mismatch: loaded {loaded}, expected {expected}"
250-
)
251-
}
252-
LoadMismatch::Descriptor {
253-
keychain,
254-
loaded,
255-
expected,
256-
} => {
257-
write!(
258-
f,
259-
"Descriptor mismatch for {} keychain: loaded {}, expected {}",
260-
keychain,
261-
loaded
262-
.as_ref()
263-
.map_or("None".to_string(), |d| d.to_string()),
264-
expected
265-
.as_ref()
266-
.map_or("None".to_string(), |d| d.to_string())
267-
)
268-
}
269-
}
270-
}
271-
}
272-
273-
impl From<LoadMismatch> for LoadError {
274-
fn from(mismatch: LoadMismatch) -> Self {
275-
Self::Mismatch(mismatch)
276-
}
277-
}
278-
279-
impl<E> From<LoadMismatch> for LoadWithPersistError<E> {
280-
fn from(mismatch: LoadMismatch) -> Self {
281-
Self::InvalidChangeSet(LoadError::Mismatch(mismatch))
282-
}
283-
}
284-
285-
/// An error that may occur when applying a block to [`Wallet`].
286-
#[derive(Debug)]
287-
pub enum ApplyBlockError {
288-
/// Occurs when the update chain cannot connect with original chain.
289-
CannotConnect(CannotConnectError),
290-
/// Occurs when the `connected_to` hash does not match the hash derived from `block`.
291-
UnexpectedConnectedToHash {
292-
/// Block hash of `connected_to`.
293-
connected_to_hash: BlockHash,
294-
/// Expected block hash of `connected_to`, as derived from `block`.
295-
expected_hash: BlockHash,
296-
},
297-
}
298-
299-
impl fmt::Display for ApplyBlockError {
300-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
301-
match self {
302-
ApplyBlockError::CannotConnect(err) => err.fmt(f),
303-
ApplyBlockError::UnexpectedConnectedToHash {
304-
expected_hash: block_hash,
305-
connected_to_hash: checkpoint_hash,
306-
} => write!(
307-
f,
308-
"`connected_to` hash {checkpoint_hash} differs from the expected hash {block_hash} (which is derived from `block`)"
309-
),
310-
}
311-
}
312-
}
313-
314-
#[cfg(feature = "std")]
315-
impl std::error::Error for ApplyBlockError {}
316-
317181
/// A `CanonicalTx` managed by a `Wallet`.
318182
pub type WalletTx<'a> = CanonicalTx<'a, Arc<Transaction>, ConfirmationBlockTime>;
319183

src/wallet/persisted.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use core::{
99
use alloc::{boxed::Box, string::ToString};
1010
use chain::Merge;
1111

12+
use crate::error::LoadError;
1213
use crate::{
1314
descriptor::{calc_checksum, DescriptorError},
1415
ChangeSet, CreateParams, LoadParams, Wallet,
@@ -344,7 +345,7 @@ pub enum LoadWithPersistError<E> {
344345
/// Error from persistence.
345346
Persist(E),
346347
/// Occurs when the loaded changeset cannot construct [`Wallet`].
347-
InvalidChangeSet(crate::LoadError),
348+
InvalidChangeSet(LoadError),
348349
}
349350

350351
impl<E: fmt::Display> fmt::Display for LoadWithPersistError<E> {

0 commit comments

Comments
 (0)