@@ -46,6 +46,8 @@ use chain::Staged;
46
46
use core:: fmt;
47
47
use core:: mem;
48
48
use core:: ops:: Deref ;
49
+ #[ cfg( feature = "labels" ) ]
50
+ use core:: str:: FromStr ;
49
51
use rand_core:: RngCore ;
50
52
51
53
use descriptor:: error:: Error as DescriptorError ;
@@ -297,6 +299,32 @@ impl fmt::Display for ApplyBlockError {
297
299
#[ cfg( feature = "std" ) ]
298
300
impl std:: error:: Error for ApplyBlockError { }
299
301
302
+ #[ cfg( feature = "labels" ) ]
303
+ /// The error type when importing [`Label`]s into a [`Wallet`].
304
+ #[ derive( Debug , PartialEq ) ]
305
+ pub enum LabelError {
306
+ /// There was a problem with the [`Label::Input`] type.
307
+ Input ( String ) ,
308
+ /// There was a problem with the [`Label::Output`] type.
309
+ Output ( String ) ,
310
+ /// There was a problem with the [`Label::Address`] type.
311
+ Address ( String ) ,
312
+ }
313
+
314
+ #[ cfg( feature = "labels" ) ]
315
+ impl fmt:: Display for LabelError {
316
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
317
+ match self {
318
+ LabelError :: Input ( l) => write ! ( f, "input label error: {l}" ) ,
319
+ LabelError :: Output ( l) => write ! ( f, "output label error: {l}" ) ,
320
+ LabelError :: Address ( l) => write ! ( f, "address label error: {l}" ) ,
321
+ }
322
+ }
323
+ }
324
+
325
+ #[ cfg( all( feature = "std" , feature = "labels" ) ) ]
326
+ impl std:: error:: Error for LabelError { }
327
+
300
328
impl Wallet {
301
329
/// Build a new [`Wallet`].
302
330
///
@@ -1570,6 +1598,8 @@ impl Wallet {
1570
1598
is_spent : true ,
1571
1599
derivation_index,
1572
1600
confirmation_time,
1601
+ #[ cfg( feature = "labels" ) ]
1602
+ label : None ,
1573
1603
} ) ,
1574
1604
satisfaction_weight,
1575
1605
}
@@ -2310,6 +2340,67 @@ impl Wallet {
2310
2340
. batch_insert_relevant_unconfirmed ( unconfirmed_txs) ;
2311
2341
self . stage . merge ( indexed_graph_changeset. into ( ) ) ;
2312
2342
}
2343
+
2344
+ #[ cfg( feature = "labels" ) ]
2345
+ /// Exports the labels of all the wallet's UTXOs.
2346
+ ///
2347
+ /// # Note
2348
+ ///
2349
+ /// The labels follow the [BIP 329](https://github.com/bitcoin/bips/blob/master/bip-0329.mediawiki)
2350
+ /// export/import format.
2351
+ pub fn export_labels ( & self ) -> Vec < Option < Label > > {
2352
+ let labels = self . list_output ( ) . map ( |utxo| utxo. label ) . collect ( ) ;
2353
+ labels
2354
+ }
2355
+
2356
+ #[ cfg( feature = "labels" ) ]
2357
+ /// Imports labels into a wallet
2358
+ ///
2359
+ /// # Note
2360
+ ///
2361
+ /// The labels follow the [BIP 329](https://github.com/bitcoin/bips/blob/master/bip-0329.mediawiki)
2362
+ /// export/import format.
2363
+ pub fn import_labels ( & self , labels : Vec < Label > ) -> Result < ( ) , LabelError > {
2364
+ labels. iter ( ) . try_for_each ( |label| {
2365
+ match label {
2366
+ Label :: Input ( l) => {
2367
+ // parse the string into an OutPoint and then match
2368
+ let parts = l. split ( ':' ) . collect :: < Vec < _ > > ( ) ;
2369
+ if parts. len ( ) != 2 {
2370
+ return Err ( LabelError :: Input ( l. to_string ( ) ) ) ;
2371
+ } else {
2372
+ let outpoint = OutPoint :: new (
2373
+ // TODO: deal with the Error types in expect
2374
+ Txid :: from_str ( parts[ 0 ] ) . expect ( "valid txid" ) ,
2375
+ u32:: from_str ( parts[ 1 ] ) . expect ( "valid vout" ) ,
2376
+ ) ;
2377
+ let local_output = self . get_utxo ( outpoint) ;
2378
+ if let Some ( mut local_output) = local_output {
2379
+ local_output. label = Some ( label. clone ( ) ) ;
2380
+ } ;
2381
+ }
2382
+ }
2383
+ Label :: Output ( l) => {
2384
+ // parse the string into an OutPoint and then match
2385
+ let parts = l. split ( ':' ) . collect :: < Vec < _ > > ( ) ;
2386
+ if parts. len ( ) != 2 {
2387
+ return Err ( LabelError :: Input ( l. to_string ( ) ) ) ;
2388
+ } else {
2389
+ let outpoint = OutPoint :: new (
2390
+ // TODO: deal with the Error types in expect
2391
+ Txid :: from_str ( parts[ 0 ] ) . expect ( "valid txid" ) ,
2392
+ u32:: from_str ( parts[ 1 ] ) . expect ( "valid vout" ) ,
2393
+ ) ;
2394
+ let local_output = self . get_utxo ( outpoint) ;
2395
+ if let Some ( mut local_output) = local_output {
2396
+ local_output. label = Some ( label. clone ( ) ) ;
2397
+ } ;
2398
+ }
2399
+ }
2400
+ }
2401
+ Ok ( ( ) )
2402
+ } )
2403
+ }
2313
2404
}
2314
2405
2315
2406
/// Methods to construct sync/full-scan requests for spk-based chain sources.
@@ -2386,6 +2477,8 @@ fn new_local_utxo(
2386
2477
confirmation_time : full_txo. chain_position . into ( ) ,
2387
2478
keychain,
2388
2479
derivation_index,
2480
+ #[ cfg( feature = "labels" ) ]
2481
+ label : None ,
2389
2482
}
2390
2483
}
2391
2484
0 commit comments