Skip to content

Commit 7f9c840

Browse files
committed
Add gethdkeys method model and test
Add the struct, model, error, into_model fn and test. Add the reexports and update the types table.
1 parent d6873da commit 7f9c840

File tree

11 files changed

+183
-6
lines changed

11 files changed

+183
-6
lines changed

client/src/client_sync/v28/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
//! We ignore option arguments unless they effect the shape of the returned JSON data.
66
77
pub mod raw_transactions;
8+
pub mod wallet;
89

910
use std::collections::BTreeMap;
1011
use std::path::Path;
@@ -148,6 +149,7 @@ crate::impl_client_v17__get_addresses_by_label!();
148149
crate::impl_client_v17__get_address_info!();
149150
crate::impl_client_v17__get_balance!();
150151
crate::impl_client_v19__get_balances!();
152+
crate::impl_client_v28__get_hd_keys!();
151153
crate::impl_client_v18__get_received_by_label!();
152154
crate::impl_client_v17__get_new_address!();
153155
crate::impl_client_v17__get_raw_change_address!();

client/src/client_sync/v28/wallet.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// SPDX-License-Identifier: CC0-1.0
2+
3+
//! Macros for implementing JSON-RPC methods on a client.
4+
//!
5+
//! Specifically this is methods found under the `== Wallet ==` section of the
6+
//! API docs of Bitcoin Core `v28`.
7+
//!
8+
//! All macros require `Client` to be in scope.
9+
//!
10+
//! See or use the `define_jsonrpc_minreq_client!` macro to define a `Client`.
11+
12+
/// Implements Bitcoin Core JSON-RPC API method `gethdkeys`.
13+
#[macro_export]
14+
macro_rules! impl_client_v28__get_hd_keys {
15+
() => {
16+
impl Client {
17+
pub fn get_hd_keys(&self) -> Result<GetHdKeys> { self.call("gethdkeys", &[]) }
18+
}
19+
};
20+
}

client/src/client_sync/v29/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ crate::impl_client_v17__get_addresses_by_label!();
149149
crate::impl_client_v17__get_address_info!();
150150
crate::impl_client_v17__get_balance!();
151151
crate::impl_client_v19__get_balances!();
152+
crate::impl_client_v28__get_hd_keys!();
152153
crate::impl_client_v18__get_received_by_label!();
153154
crate::impl_client_v17__get_new_address!();
154155
crate::impl_client_v17__get_raw_change_address!();

integration_test/tests/wallet.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,19 @@ fn wallet__get_balances() {
247247
model.unwrap();
248248
}
249249

250+
#[test]
251+
#[cfg(not(feature = "v27_and_below"))]
252+
fn wallet__get_hd_keys__modelled() {
253+
let node = Node::with_wallet(Wallet::Default, &[]);
254+
255+
let json: GetHdKeys = node.client.get_hd_keys().expect("gethdkeys");
256+
let model: Result<mtype::GetHdKeys, _> = json.into_model();
257+
let hdkey = model.unwrap().0;
258+
259+
let descriptor_type = hdkey[0].descriptors[0].descriptor[..3].to_string();
260+
assert_eq!(descriptor_type, "pkh");
261+
}
262+
250263
#[test]
251264
fn wallet__get_new_address__modelled() {
252265
let node = Node::with_wallet(Wallet::Default, &[]);

types/src/model/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ pub use self::{
6262
ListTransactionsItem, ListUnspent, ListUnspentItem, ListWallets, LoadWallet, PsbtBumpFee,
6363
RescanBlockchain, ScriptType, Send, SendAll, SendMany, SendToAddress, SignMessage,
6464
SimulateRawTransaction, TransactionCategory, UnloadWallet, WalletCreateFundedPsbt,
65-
WalletDisplayAddress, WalletProcessPsbt,
65+
WalletDisplayAddress, WalletProcessPsbt, GetHdKeys, HdKey,
66+
HdKeyDescriptor,
6667
},
6768
};

types/src/model/wallet.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use alloc::collections::BTreeMap;
99

1010
use bitcoin::address::NetworkUnchecked;
11+
use bitcoin::bip32::{Xpriv, Xpub};
1112
use bitcoin::hashes::hash160;
1213
use bitcoin::{
1314
bip32, sign_message, Address, Amount, BlockHash, FeeRate, PrivateKey, Psbt, PublicKey,
@@ -284,6 +285,35 @@ pub struct GetBalancesWatchOnly {
284285
pub immature: Amount,
285286
}
286287

288+
/// Models the result of JSON-RPC method `gethdkeys`.
289+
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
290+
#[serde(deny_unknown_fields)]
291+
pub struct GetHdKeys(pub Vec<HdKey>);
292+
293+
/// An HD key entry returned by `gethdkeys`.
294+
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
295+
#[serde(deny_unknown_fields)]
296+
pub struct HdKey {
297+
/// The extended public key.
298+
pub xpub: Xpub,
299+
/// Whether the wallet has the private key for this xpub.
300+
pub has_private: bool,
301+
/// The extended private key if "private" is true.
302+
pub xpriv: Option<Xpriv>,
303+
/// Array of descriptor objects that use this HD key.
304+
pub descriptors: Vec<HdKeyDescriptor>,
305+
}
306+
307+
/// Descriptor object used in `gethdkeys` result.
308+
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
309+
#[serde(deny_unknown_fields)]
310+
pub struct HdKeyDescriptor {
311+
/// Descriptor string representation.
312+
pub descriptor: String,
313+
/// Whether this descriptor is currently used to generate new addresses.
314+
pub active: bool,
315+
}
316+
287317
/// Models the result of JSON-RPC method `getnewaddress`.
288318
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
289319
#[serde(deny_unknown_fields)]

types/src/v28/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@
184184
//! | getaddressinfo | version + model | |
185185
//! | getbalance | version + model | |
186186
//! | getbalances | version + model | |
187-
//! | gethdkeys | version + model | TODO |
187+
//! | gethdkeys | version + model | |
188188
//! | getnewaddress | version + model | |
189189
//! | getrawchangeaddress | version + model | |
190190
//! | getreceivedbyaddress | version + model | |
@@ -267,7 +267,7 @@ pub use self::{
267267
SubmitPackage, SubmitPackageError, SubmitPackageTxResult, SubmitPackageTxResultError,
268268
SubmitPackageTxResultFees, SubmitPackageTxResultFeesError,
269269
},
270-
wallet::{GetAddressInfo, GetAddressInfoEmbedded, GetTransaction},
270+
wallet::{GetAddressInfo, GetAddressInfoEmbedded, GetHdKeys, HdKey, HdKeyDescriptor, GetHdKeysError, GetTransaction},
271271
};
272272
#[doc(inline)]
273273
pub use crate::{

types/src/v28/wallet/error.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// SPDX-License-Identifier: CC0-1.0
2+
3+
use core::fmt;
4+
5+
use bitcoin::bip32;
6+
7+
use crate::error::write_err;
8+
use crate::NumericError;
9+
10+
/// Error when converting a `GetHdKeys` type into the model type.
11+
#[derive(Debug)]
12+
pub enum GetHdKeysError {
13+
/// Conversion of the `xpub` field failed.
14+
Xpub(bip32::Error),
15+
/// Conversion of the `xpriv` field failed.
16+
Xpriv(bip32::Error),
17+
/// Conversion of numeric type to expected type failed.
18+
Numeric(NumericError),
19+
}
20+
21+
impl fmt::Display for GetHdKeysError {
22+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
23+
use GetHdKeysError::*;
24+
match *self {
25+
Xpub(ref e) => write_err!(f, "conversion of the `xpub` field failed"; e),
26+
Xpriv(ref e) => write_err!(f, "conversion of the `xpriv` field failed"; e),
27+
Numeric(ref e) => write_err!(f, "numeric"; e),
28+
}
29+
}
30+
}
31+
32+
#[cfg(feature = "std")]
33+
impl std::error::Error for GetHdKeysError {
34+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
35+
use GetHdKeysError::*;
36+
match *self {
37+
Xpub(ref e) => Some(e),
38+
Xpriv(ref e) => Some(e),
39+
Numeric(ref e) => Some(e),
40+
}
41+
}
42+
}
43+
44+
impl From<NumericError> for GetHdKeysError {
45+
fn from(e: NumericError) -> Self { Self::Numeric(e) }
46+
}

types/src/v28/wallet/into.rs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use bitcoin::{
1111

1212
use super::{
1313
GetAddressInfo, GetAddressInfoEmbedded, GetAddressInfoEmbeddedError, GetAddressInfoError,
14-
GetTransaction, GetTransactionError,
14+
GetHdKeys, GetHdKeysError, GetTransaction, GetTransactionError,
1515
};
1616
use crate::model;
1717

@@ -155,6 +155,33 @@ impl GetAddressInfoEmbedded {
155155
}
156156
}
157157

158+
impl GetHdKeys {
159+
/// Converts version specific type to a version nonspecific, more strongly typed type.
160+
pub fn into_model(self) -> Result<model::GetHdKeys, GetHdKeysError> {
161+
let keys = self
162+
.0
163+
.into_iter()
164+
.map(|item| {
165+
let xpub = item.xpub.parse().map_err(GetHdKeysError::Xpub)?;
166+
let xpriv = match item.xpriv {
167+
Some(xpriv) => Some(xpriv.parse().map_err(GetHdKeysError::Xpriv)?),
168+
None => None,
169+
};
170+
let descriptors = item
171+
.descriptors
172+
.into_iter()
173+
.map(|desc| model::HdKeyDescriptor {
174+
descriptor: desc.descriptor,
175+
active: desc.active,
176+
})
177+
.collect();
178+
Ok(model::HdKey { xpub, has_private: item.has_private, xpriv, descriptors })
179+
})
180+
.collect::<Result<Vec<_>, GetHdKeysError>>()?;
181+
Ok(model::GetHdKeys(keys))
182+
}
183+
}
184+
158185
impl GetTransaction {
159186
/// Converts version specific type to a version nonspecific, more strongly typed type.
160187
pub fn into_model(self) -> Result<model::GetTransaction, GetTransactionError> {

types/src/v28/wallet/mod.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44
//!
55
//! Types for methods found under the `== Wallet ==` section of the API docs.
66
7+
mod error;
78
mod into;
89

910
use bitcoin::Transaction;
11+
pub use error::GetHdKeysError;
1012
use serde::{Deserialize, Serialize};
1113

1214
pub use super::{
@@ -144,6 +146,41 @@ pub struct GetAddressInfoEmbedded {
144146
pub labels: Option<Vec<String>>,
145147
}
146148

149+
/// Result of the JSON-RPC method `gethdkeys`.
150+
///
151+
/// > gethdkeys ( {"active_only":bool,"private":bool,...} )
152+
/// >
153+
/// > List all BIP 32 HD keys in the wallet and which descriptors use them.
154+
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
155+
#[serde(deny_unknown_fields)]
156+
pub struct GetHdKeys(pub Vec<HdKey>);
157+
158+
/// HD key entry returned as part of `gethdkeys`.
159+
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
160+
#[serde(deny_unknown_fields)]
161+
pub struct HdKey {
162+
/// The extended public key.
163+
pub xpub: String,
164+
/// Whether the wallet has the private key for this xpub.
165+
pub has_private: bool,
166+
/// The extended private key if "private" is true.
167+
#[serde(rename = "xprv")]
168+
pub xpriv: Option<String>,
169+
/// Array of descriptor objects that use this HD key.
170+
pub descriptors: Vec<HdKeyDescriptor>,
171+
}
172+
173+
/// Descriptor object returned as part of `gethdkeys`.
174+
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
175+
#[serde(deny_unknown_fields)]
176+
pub struct HdKeyDescriptor {
177+
/// Descriptor string representation.
178+
#[serde(rename = "desc")]
179+
pub descriptor: String,
180+
/// Whether this descriptor is currently used to generate new addresses.
181+
pub active: bool,
182+
}
183+
147184
/// Result of the JSON-RPC method `gettransaction`.
148185
///
149186
/// > gettransaction "txid" ( include_watchonly )

0 commit comments

Comments
 (0)