Skip to content

Commit b17157e

Browse files
committed
Fix getaddressinfo
The test was marked as TODO and the fields in the structs do not match what is returned by the RPC. Fix all of the fields in v17. Redefine the types for changes in v18, v29, v22 and v28. Update the reexports. Update the model for to allow for the changes in return types. Update the error in v18 and reorganise wallet imports. Update the test using different Address types to check the inner structs contain expected values.
1 parent c085b5e commit b17157e

File tree

27 files changed

+1368
-140
lines changed

27 files changed

+1368
-140
lines changed

integration_test/tests/wallet.rs

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
#![allow(unused_imports)] // Some imports are only used in specific versions.
77

88
use bitcoin::address::{Address, KnownHrp, NetworkChecked};
9-
use bitcoin::{secp256k1, Amount, CompressedPublicKey, FeeRate, PrivateKey, PublicKey};
9+
use bitcoin::{secp256k1, Amount, CompressedPublicKey, FeeRate, Network, PrivateKey, PublicKey};
1010
use integration_test::{Node, NodeExt as _, Wallet};
1111
use node::{mtype, AddressType, ImportMultiRequest, ImportMultiScriptPubKey, ImportMultiTimestamp};
1212

@@ -192,15 +192,34 @@ fn wallet__get_addresses_by_label__modelled() {
192192
}
193193

194194
#[test]
195-
#[cfg(feature = "TODO")] // FIXME: The types are broken.
196-
// TODO: Consider testing a few different address types.
197195
fn wallet__get_address_info__modelled() {
198196
let node = Node::with_wallet(Wallet::Default, &[]);
199-
let address = node.client.new_address().expect("failed to create new address");
200197

201-
let json: GetAddressInfo = node.client.get_address_info(&address).expect("getaddressinfo");
198+
// Test an address with a label.
199+
let label_name = "test-label";
200+
let addr = node.client.new_address_with_label(label_name).unwrap().assume_checked();
201+
let json: GetAddressInfo = node.client.get_address_info(&addr).expect("getaddressinfo legacy");
202202
let model: Result<mtype::GetAddressInfo, GetAddressInfoError> = json.into_model();
203-
model.unwrap();
203+
let model = model.unwrap();
204+
assert_eq!(model.address.assume_checked(), addr);
205+
assert_eq!(model.labels[0], label_name);
206+
207+
// Test a SegWit address with embedded information.
208+
let addr_p2sh = node.client.new_address_with_type(AddressType::P2shSegwit).unwrap();
209+
let json: GetAddressInfo = node.client.get_address_info(&addr_p2sh).expect("getaddressinfo p2sh-segwit");
210+
let model: Result<mtype::GetAddressInfo, GetAddressInfoError> = json.into_model();
211+
let model = model.unwrap();
212+
let embedded = model.embedded.unwrap();
213+
assert_eq!(model.address.assume_checked(), addr_p2sh);
214+
assert_eq!(model.script.unwrap(), mtype::ScriptType::WitnessV0KeyHash);
215+
assert!(embedded.address.is_valid_for_network(Network::Regtest));
216+
217+
// Test a Bech32 address.
218+
let addr_bech32 = node.client.new_address_with_type(AddressType::Bech32).unwrap();
219+
let json: GetAddressInfo = node.client.get_address_info(&addr_bech32).expect("getaddressinfo bech32");
220+
let model: Result<mtype::GetAddressInfo, GetAddressInfoError> = json.into_model();
221+
let model = model.unwrap();
222+
assert_eq!(model.address.assume_checked(), addr_bech32);
204223
}
205224

206225
#[test]

types/src/model/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ pub use self::{
5151
SignMessageWithPrivKey, ValidateAddress,
5252
},
5353
wallet::{
54-
AddMultisigAddress, AddressInformation, AddressLabel, AddressPurpose, Bip125Replaceable,
54+
AddMultisigAddress, AddressInformation, AddressPurpose, Bip125Replaceable,
5555
BumpFee, CreateWallet, DumpPrivKey, GetAddressInfo, GetAddressInfoEmbedded,
5656
GetAddressesByLabel, GetBalance, GetBalances, GetBalancesMine, GetBalancesWatchOnly,
5757
GetNewAddress, GetRawChangeAddress, GetReceivedByAddress, GetReceivedByLabel,

types/src/model/wallet.rs

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,16 @@ pub struct GetAddressInfo {
117117
pub is_mine: bool,
118118
/// If the address is watchonly.
119119
pub is_watch_only: bool,
120+
/// Whether we know how to spend coins sent to this address, ignoring the possible lack of private keys.
121+
pub solvable: Option<bool>,
122+
/// A descriptor for spending coins sent to this address (only when solvable).
123+
pub descriptor: Option<String>,
124+
/// The descriptor used to derive this address if this is a descriptor wallet
125+
pub parent_descriptor: Option<String>,
120126
/// If the key is a script.
121-
pub is_script: bool,
127+
pub is_script: Option<bool>,
128+
/// If the address was used for change output.
129+
pub is_change: Option<bool>,
122130
/// If the address is a witness address.
123131
pub is_witness: bool,
124132
/// The version number of the witness program.
@@ -140,18 +148,20 @@ pub struct GetAddressInfo {
140148
pub pubkey: Option<PublicKey>,
141149
/// Information about the address embedded in P2SH or P2WSH, if relevant and known.
142150
pub embedded: Option<GetAddressInfoEmbedded>,
143-
/// If the address is compressed.
144-
pub is_compressed: bool,
151+
/// If the pubkey is compressed.
152+
pub is_compressed: Option<bool>,
145153
/// The label associated with the address, "" is the default account.
146-
pub label: String,
154+
pub label: Option<String>,
147155
/// The creation time of the key if available in seconds since epoch (Jan 1 1970 GMT).
148156
pub timestamp: Option<u32>,
149157
/// The HD keypath if the key is HD and available.
150158
pub hd_key_path: Option<bip32::DerivationPath>,
151159
/// The Hash160 of the HD seed.
152160
pub hd_seed_id: Option<hash160::Hash>,
161+
/// The fingerprint of the master key.
162+
pub hd_master_fingerprint: Option<bip32::Fingerprint>,
153163
/// Labels associated with the address.
154-
pub labels: Vec<AddressLabel>,
164+
pub labels: Vec<String>,
155165
}
156166

157167
/// An address script type.
@@ -177,16 +187,6 @@ pub enum ScriptType {
177187
WitnessUnknown,
178188
}
179189

180-
/// An address label.
181-
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
182-
#[serde(deny_unknown_fields)]
183-
pub struct AddressLabel {
184-
/// The address label.
185-
pub name: String,
186-
/// Purpose of address (send or receive).
187-
pub purpose: AddressPurpose,
188-
}
189-
190190
/// The `embedded` field of `GetAddressInfo`.
191191
///
192192
/// It includes all getaddressinfo output fields for the embedded address, excluding metadata
@@ -200,8 +200,16 @@ pub struct GetAddressInfoEmbedded {
200200
pub address: Address<NetworkUnchecked>,
201201
/// The hex encoded scriptPubKey generated by the address.
202202
pub script_pubkey: ScriptBuf,
203+
/// Whether we know how to spend coins sent to this address, ignoring the possible lack of private keys.
204+
pub solvable: Option<bool>,
205+
/// A descriptor for spending coins sent to this address (only when solvable).
206+
pub descriptor: Option<String>,
207+
/// The descriptor used to derive this address if this is a descriptor wallet
208+
pub parent_descriptor: Option<String>,
203209
/// If the key is a script.
204-
pub is_script: bool,
210+
pub is_script: Option<bool>,
211+
/// If the address was used for change output.
212+
pub is_change: Option<bool>,
205213
/// If the address is a witness address.
206214
pub is_witness: bool,
207215
/// The version number of the witness program.
@@ -215,17 +223,17 @@ pub struct GetAddressInfoEmbedded {
215223
/// The redeemscript for the p2sh address.
216224
pub hex: Option<ScriptBuf>,
217225
/// Array of pubkeys associated with the known redeemscript (only if "script" is "multisig").
218-
pub pubkeys: Vec<PublicKey>,
226+
pub pubkeys: Option<Vec<PublicKey>>,
219227
/// Number of signatures required to spend multisig output (only if "script" is "multisig").
220228
pub sigs_required: Option<u32>,
221229
/// The hex value of the raw public key, for single-key addresses (possibly embedded in P2SH or P2WSH).
222230
pub pubkey: Option<PublicKey>,
223231
/// If the address is compressed.
224-
pub is_compressed: bool,
232+
pub is_compressed: Option<bool>,
225233
/// The label associated with the address, "" is the default account.
226-
pub label: String,
234+
pub label: Option<String>,
227235
/// Labels associated with the address.
228-
pub labels: Vec<AddressLabel>,
236+
pub labels: Option<Vec<String>>,
229237
}
230238

231239
/// Models the result of JSON-RPC method `getbalance`.

types/src/v17/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@
163163
//! | getaccountaddress | returns nothing | |
164164
//! | getaddressbyaccount | returns nothing | |
165165
//! | getaddressesbylabel | version + model | |
166-
//! | getaddressinfo | version + model | UNTESTED |
166+
//! | getaddressinfo | version + model | |
167167
//! | getbalance | version + model | |
168168
//! | getnewaddress | version + model | |
169169
//! | getrawchangeaddress | version + model | |
@@ -285,7 +285,7 @@ pub use self::{
285285
ListTransactionsItem, ListTransactionsItemError, ListUnspent, ListUnspentItem,
286286
ListUnspentItemError, ListWallets, LoadWallet, LockUnspent, RescanBlockchain, SendMany,
287287
SendToAddress, SetTxFee, SignMessage, TransactionCategory, WalletCreateFundedPsbt,
288-
WalletCreateFundedPsbtError, WalletProcessPsbt,
288+
WalletCreateFundedPsbtError, WalletProcessPsbt, ScriptType,
289289
},
290290
zmq::GetZmqNotifications,
291291
};

types/src/v17/wallet/into.rs

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -169,14 +169,18 @@ impl GetAddressInfo {
169169
.map_err(E::HdKeyPath)?;
170170
let hd_seed_id =
171171
self.hd_seed_id.map(|s| s.parse::<hash160::Hash>()).transpose().map_err(E::HdSeedId)?;
172-
let labels = self.labels.into_iter().map(|label| label.into_model()).collect();
172+
let labels = self.labels.into_iter().map(|label| label.name).collect();
173173

174174
Ok(model::GetAddressInfo {
175175
address,
176176
script_pubkey,
177177
is_mine: self.is_mine,
178178
is_watch_only: self.is_watch_only,
179-
is_script: self.is_script,
179+
solvable: None, // v18 and above only.
180+
descriptor: None, // v18 and above only.
181+
parent_descriptor: None, // v22 and above only.
182+
is_script: Some(self.is_script),
183+
is_change: None, // v18 and above only.
180184
is_witness: self.is_witness,
181185
witness_version,
182186
witness_program,
@@ -187,10 +191,11 @@ impl GetAddressInfo {
187191
pubkey,
188192
embedded,
189193
is_compressed: self.is_compressed,
190-
label: self.label,
194+
label: Some(self.label),
191195
timestamp: self.timestamp,
192196
hd_key_path,
193197
hd_seed_id,
198+
hd_master_fingerprint: None, // v18 and above only.
194199
labels,
195200
})
196201
}
@@ -243,21 +248,20 @@ impl GetAddressInfoEmbedded {
243248
let script = self.script.map(|s| s.into_model());
244249
let redeem_script =
245250
self.hex.map(|hex| ScriptBuf::from_hex(&hex).map_err(E::Hex)).transpose()?;
246-
let pubkeys = self
247-
.pubkeys
248-
.iter()
249-
.map(|s| s.parse::<PublicKey>())
250-
.collect::<Result<Vec<_>, _>>()
251-
.map_err(E::Pubkeys)?;
251+
let pubkeys = None;
252252
let sigs_required =
253253
self.sigs_required.map(|s| crate::to_u32(s, "sigs_required")).transpose()?;
254254
let pubkey = self.pubkey.map(|s| s.parse::<PublicKey>()).transpose().map_err(E::Pubkey)?;
255-
let labels = self.labels.into_iter().map(|label| label.into_model()).collect();
255+
let labels = self.labels.map(|labels| labels.into_iter().map(|label| label.name).collect());
256256

257257
Ok(model::GetAddressInfoEmbedded {
258258
address,
259259
script_pubkey,
260+
solvable: None, // v18 and above only.
261+
descriptor: None, // v18 and above only.
262+
parent_descriptor: None, // v22 and above only.
260263
is_script: self.is_script,
264+
is_change: None, // v18 and above only.
261265
is_witness: self.is_witness,
262266
witness_version,
263267
witness_program,
@@ -273,13 +277,6 @@ impl GetAddressInfoEmbedded {
273277
}
274278
}
275279

276-
impl GetAddressInfoLabel {
277-
/// Converts version specific type to a version nonspecific, more strongly typed type.
278-
pub fn into_model(self) -> model::AddressLabel {
279-
model::AddressLabel { name: self.name, purpose: self.purpose.into_model() }
280-
}
281-
}
282-
283280
impl GetBalance {
284281
/// Converts version specific type to a version nonspecific, more strongly typed type.
285282
pub fn into_model(self) -> Result<model::GetBalance, ParseAmountError> {

types/src/v17/wallet/mod.rs

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -273,11 +273,9 @@ pub struct GetAddressInfo {
273273
pub embedded: Option<GetAddressInfoEmbedded>,
274274
/// If the address is compressed.
275275
#[serde(rename = "iscompressed")]
276-
pub is_compressed: bool,
276+
pub is_compressed: Option<bool>,
277277
/// The label associated with the address, "" is the default account.
278278
pub label: String,
279-
/// DEPRECATED. The account associated with the address, "" is the default account.
280-
pub account: String,
281279
/// The creation time of the key if available in seconds since epoch (Jan 1 1970 GMT).
282280
pub timestamp: Option<u32>,
283281
/// The HD keypath if the key is HD and available.
@@ -342,7 +340,7 @@ pub struct GetAddressInfoEmbedded {
342340
pub script_pubkey: String,
343341
/// If the key is a script.
344342
#[serde(rename = "isscript")]
345-
pub is_script: bool,
343+
pub is_script: Option<bool>,
346344
/// If the address is a witness address.
347345
#[serde(rename = "iswitness")]
348346
pub is_witness: bool,
@@ -356,20 +354,18 @@ pub struct GetAddressInfoEmbedded {
356354
pub script: Option<ScriptType>,
357355
/// The redeemscript for the p2sh address.
358356
pub hex: Option<String>,
359-
/// Array of pubkeys associated with the known redeemscript (only if "script" is "multisig").
360-
pub pubkeys: Vec<String>,
361357
/// Number of signatures required to spend multisig output (only if "script" is "multisig").
362358
#[serde(rename = "sigsrequired")]
363359
pub sigs_required: Option<i64>,
364360
/// The hex value of the raw public key, for single-key addresses (possibly embedded in P2SH or P2WSH).
365361
pub pubkey: Option<String>,
366362
/// If the address is compressed.
367363
#[serde(rename = "iscompressed")]
368-
pub is_compressed: bool,
364+
pub is_compressed: Option<bool>,
369365
/// The label associated with the address, "" is the default account.
370-
pub label: String,
366+
pub label: Option<String>,
371367
/// Array of labels associated with the address.
372-
pub labels: Vec<GetAddressInfoLabel>,
368+
pub labels: Option<Vec<GetAddressInfoLabel>>,
373369
}
374370

375371
/// The `label` field of `GetAddressInfo` (and `GetAddressInfoEmbedded`).

types/src/v18/mod.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@
167167
//! | dumpwallet | version + model | |
168168
//! | encryptwallet | version | |
169169
//! | getaddressesbylabel | version + model | |
170-
//! | getaddressinfo | version + model | UNTESTED |
170+
//! | getaddressinfo | version + model | |
171171
//! | getbalance | version + model | |
172172
//! | getnewaddress | version + model | |
173173
//! | getrawchangeaddress | version + model | |
@@ -243,6 +243,7 @@ pub use self::{
243243
wallet::{
244244
GetReceivedByLabel, ImportMulti, ImportMultiEntry, JsonRpcError, ListReceivedByLabel,
245245
ListReceivedByLabelError, ListUnspent, ListUnspentItem, ListWalletDir, ListWalletDirWallet,
246+
GetAddressInfo, GetAddressInfoError, GetAddressInfoEmbedded,
246247
},
247248
};
248249
#[doc(inline)]
@@ -254,8 +255,8 @@ pub use crate::v17::{
254255
CreateWallet, DecodePsbt, DecodePsbtError, DecodeRawTransaction, DecodeScript,
255256
DecodeScriptError, DumpPrivKey, DumpWallet, EncryptWallet, EstimateSmartFee, FinalizePsbt,
256257
FinalizePsbtError, FundRawTransaction, FundRawTransactionError, Generate, GenerateToAddress,
257-
GetAddedNodeInfo, GetAddressInfo, GetAddressInfoEmbedded, GetAddressInfoEmbeddedError,
258-
GetAddressInfoError, GetAddressInfoLabel, GetAddressesByLabel, GetBalance, GetBestBlockHash,
258+
GetAddedNodeInfo, GetAddressInfoEmbeddedError,
259+
GetAddressInfoLabel, GetAddressesByLabel, GetBalance, GetBestBlockHash,
259260
GetBlockCount, GetBlockHash, GetBlockHeader, GetBlockHeaderError, GetBlockHeaderVerbose,
260261
GetBlockHeaderVerboseError, GetBlockStats, GetBlockStatsError, GetBlockTemplate,
261262
GetBlockTemplateError, GetBlockVerboseOne, GetBlockVerboseOneError, GetBlockVerboseZero,
@@ -281,5 +282,5 @@ pub use crate::v17::{
281282
SignMessage, SignMessageWithPrivKey, SignRawTransaction, SignRawTransactionError, Softfork,
282283
SoftforkReject, TestMempoolAccept, TransactionCategory, UploadTarget, ValidateAddress,
283284
ValidateAddressError, VerifyChain, VerifyMessage, VerifyTxOutProof, WalletCreateFundedPsbt,
284-
WalletCreateFundedPsbtError, WalletProcessPsbt, WitnessUtxo,
285+
WalletCreateFundedPsbtError, WalletProcessPsbt, WitnessUtxo, ScriptType,
285286
};

0 commit comments

Comments
 (0)