Skip to content

Commit f0d8121

Browse files
committed
descriptor: allow iterating keys
1 parent 3da0588 commit f0d8121

File tree

9 files changed

+114
-24
lines changed

9 files changed

+114
-24
lines changed

include/wally.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,12 @@ inline int descriptor_get_features(const DESCRIPTOR& descriptor, uint32_t* value
504504
return ret;
505505
}
506506

507+
template <class DESCRIPTOR>
508+
inline int descriptor_get_key(const DESCRIPTOR& descriptor, size_t index, char** output) {
509+
int ret = ::wally_descriptor_get_key(detail::get_p(descriptor), index, output);
510+
return ret;
511+
}
512+
507513
template <class DESCRIPTOR>
508514
inline int descriptor_get_network(const DESCRIPTOR& descriptor, uint32_t* value_out) {
509515
int ret = ::wally_descriptor_get_network(detail::get_p(descriptor), value_out);

include/wally_descriptor.h

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -131,18 +131,6 @@ WALLY_CORE_API int wally_descriptor_get_features(
131131
const struct wally_descriptor *descriptor,
132132
uint32_t *value_out);
133133

134-
/**
135-
* Get the number of keys in a parsed output descriptor or miniscript expression.
136-
*
137-
* :param descriptor: Parsed output descriptor or miniscript expression.
138-
* :param value_out: Destination for the number of keys.
139-
*
140-
* .. note:: Repeated keys are counted once for each time they appear.
141-
*/
142-
WALLY_CORE_API int wally_descriptor_get_num_keys(
143-
const struct wally_descriptor *descriptor,
144-
uint32_t *value_out);
145-
146134
/**
147135
* Get the number of variants in a parsed output descriptor or miniscript expression.
148136
*
@@ -193,6 +181,31 @@ WALLY_CORE_API int wally_descriptor_get_depth(
193181
const struct wally_descriptor *descriptor,
194182
uint32_t *value_out);
195183

184+
/**
185+
* Get the number of keys in a parsed output descriptor or miniscript expression.
186+
*
187+
* :param descriptor: Parsed output descriptor or miniscript expression.
188+
* :param value_out: Destination for the number of keys.
189+
*
190+
* .. note:: Repeated keys are counted once for each time they appear.
191+
*/
192+
WALLY_CORE_API int wally_descriptor_get_num_keys(
193+
const struct wally_descriptor *descriptor,
194+
uint32_t *value_out);
195+
196+
/**
197+
* Get the string representation of a key in a parsed output descriptor or miniscript expression.
198+
*
199+
* :param descriptor: Parsed output descriptor or miniscript expression.
200+
* :param index: The zero-based index of the key to get.
201+
* :param output: Destination for the resulting string representation.
202+
*| The string returned should be freed using `wally_free_string`.
203+
*/
204+
WALLY_CORE_API int wally_descriptor_get_key(
205+
const struct wally_descriptor *descriptor,
206+
size_t index,
207+
char **output);
208+
196209
/**
197210
* Get the maximum length of a script corresponding to an output descriptor.
198211
*

src/descriptor.c

Lines changed: 48 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ static int ctx_add_key_node(ms_ctx *ctx, ms_node *node)
206206
{
207207
const char *v = (char *)node;
208208
return map_add(&ctx->keys, NULL, ctx->keys.num_items,
209-
(unsigned char *)v, 1, false, false);
209+
(unsigned char *)v, 1, true, false);
210210
}
211211

212212
/* Built-in miniscript expressions */
@@ -2840,17 +2840,6 @@ int wally_descriptor_get_features(const struct wally_descriptor *descriptor,
28402840
offsetof(struct wally_descriptor, features));
28412841
}
28422842

2843-
int wally_descriptor_get_num_keys(const struct wally_descriptor *descriptor,
2844-
uint32_t *value_out)
2845-
{
2846-
if (value_out)
2847-
*value_out = 0;
2848-
if (!descriptor || !value_out)
2849-
return WALLY_EINVAL;
2850-
*value_out = (uint32_t)descriptor->keys.num_items;
2851-
return WALLY_OK;
2852-
}
2853-
28542843
int wally_descriptor_get_num_variants(const struct wally_descriptor *descriptor,
28552844
uint32_t *value_out)
28562845
{
@@ -2887,3 +2876,50 @@ int wally_descriptor_get_depth(const struct wally_descriptor *descriptor,
28872876
*value_out = node_get_depth(descriptor->top_node) - 1;
28882877
return WALLY_OK;
28892878
}
2879+
2880+
int wally_descriptor_get_num_keys(const struct wally_descriptor *descriptor,
2881+
uint32_t *value_out)
2882+
{
2883+
if (value_out)
2884+
*value_out = 0;
2885+
if (!descriptor || !value_out)
2886+
return WALLY_EINVAL;
2887+
*value_out = (uint32_t)descriptor->keys.num_items;
2888+
return WALLY_OK;
2889+
}
2890+
2891+
/* Ignore incorrect warnings from the ms_node cast below */
2892+
#pragma GCC diagnostic ignored "-Wcast-align"
2893+
#if defined(__clang__)
2894+
#pragma clang diagnostic ignored "-Wcast-align"
2895+
#endif
2896+
2897+
int wally_descriptor_get_key(const struct wally_descriptor *descriptor,
2898+
size_t index, char **output)
2899+
{
2900+
const ms_node *node;
2901+
2902+
if (output)
2903+
*output = 0;
2904+
if (!descriptor || index >= descriptor->keys.num_items || !output)
2905+
return WALLY_EINVAL;
2906+
2907+
node = (ms_node *)descriptor->keys.items[index].value;
2908+
if (node->kind == KIND_PUBLIC_KEY) {
2909+
return wally_hex_from_bytes((const unsigned char *)node->data,
2910+
node->data_len, output);
2911+
}
2912+
if (node->kind == KIND_PRIVATE_KEY) {
2913+
uint32_t flags = node->flags & NF_IS_UNCOMPRESSED ? WALLY_WIF_FLAG_UNCOMPRESSED : 0;
2914+
if (!descriptor->addr_ver)
2915+
return WALLY_EINVAL; /* Must have a network to fetch private keys */
2916+
return wally_wif_from_bytes((const unsigned char *)node->data, node->data_len,
2917+
descriptor->addr_ver->version_wif,
2918+
flags, output);
2919+
}
2920+
if ((node->kind & KIND_BIP32) != KIND_BIP32)
2921+
return WALLY_ERROR; /* Unknown key type, should not happen */
2922+
if (!(*output = wally_strdup_n(node->data, node->data_len)))
2923+
return WALLY_ENOMEM;
2924+
return WALLY_OK;
2925+
}

src/swig_java/swig.i

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,7 @@ static jobjectArray create_jstringArray(JNIEnv *jenv, char **p, size_t len) {
561561
%returns_size_t(wally_descriptor_get_depth);
562562
%returns_size_t(wally_descriptor_get_features);
563563
%returns_size_t(wally_descriptor_get_network);
564+
%returns_string(wally_descriptor_get_key);
564565
%returns_size_t(wally_descriptor_get_num_keys);
565566
%returns_size_t(wally_descriptor_get_num_paths);
566567
%returns_size_t(wally_descriptor_get_num_variants);

src/test/test_descriptor.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,5 +314,35 @@ def make_keys(xpubs):
314314
self.assertEqual(ret, WALLY_EINVAL)
315315
wally_map_free(keys)
316316

317+
def test_key_iteration(self):
318+
"""Test iterating descriptor keys"""
319+
k1 = 'xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB'
320+
k2 = 'xprvA2YKGLieCs6cWCiczALiH1jzk3VCCS5M1pGQfWPkamCdR9UpBgE2Gb8AKAyVjKHkz8v37avcfRjdcnP19dVAmZrvZQfvTcXXSAiFNQ6tTtU'
321+
wif = 'L1AAHuEC7XuDM7pJ7yHLEqYK1QspMo8n1kgxyZVdgvEpVC1rkUrM'
322+
pk = '03b428da420cd337c7208ed42c5331ebb407bb59ffbe3dc27936a227c619804284'
323+
pk_u = '0414fc03b8df87cd7b872996810db8458d61da8448e531569c8517b469a119d267be5645686309c6e6736dbd93940707cc9143d3cf29f1b877ff340e2cb2d259cf'
324+
# Valid args
325+
for descriptor, expected in [
326+
# Bip32 xpub
327+
(f'pkh({k1})', k1),
328+
# BIP32 xprv
329+
(f'pkh({k2}/*)', k2),
330+
# WIF
331+
(f'pkh({wif})', wif),
332+
# Hex pubkey, compressed
333+
(f'pk({pk})', pk),
334+
# Hex pubkey, uncompressed
335+
(f'pk({pk_u})', pk_u),
336+
]:
337+
d = c_void_p()
338+
ret = wally_descriptor_parse(descriptor, None, NETWORK_BTC_MAIN, 0, d)
339+
self.assertEqual(ret, WALLY_OK)
340+
ret, num_keys = wally_descriptor_get_num_keys(d)
341+
self.assertEqual((ret, num_keys), (WALLY_OK, 1))
342+
ret, key_str = wally_descriptor_get_key(d, 0)
343+
self.assertEqual((ret, key_str), (WALLY_OK, expected))
344+
wally_descriptor_free(d)
345+
346+
317347
if __name__ == '__main__':
318348
unittest.main()

src/test/util.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,7 @@ class wally_psbt(Structure):
313313
('wally_descriptor_get_checksum', c_int, [c_void_p, c_uint32, c_char_p_p]),
314314
('wally_descriptor_get_depth', c_int, [c_void_p, c_uint32_p]),
315315
('wally_descriptor_get_features', c_int, [c_void_p, c_uint32_p]),
316+
('wally_descriptor_get_key', c_int, [c_void_p, c_size_t, c_char_p_p]),
316317
('wally_descriptor_get_network', c_int, [c_void_p, c_uint32_p]),
317318
('wally_descriptor_get_num_keys', c_int, [c_void_p, c_uint32_p]),
318319
('wally_descriptor_get_num_paths', c_int, [c_void_p, c_uint32_p]),

src/wasm_package/src/functions.js

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/wasm_package/src/index.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ export function descriptor_free(descriptor: Ref_wally_descriptor): void;
123123
export function descriptor_get_checksum(descriptor: Ref_wally_descriptor, flags: number): string;
124124
export function descriptor_get_depth(descriptor: Ref_wally_descriptor): number;
125125
export function descriptor_get_features(descriptor: Ref_wally_descriptor): number;
126+
export function descriptor_get_key(descriptor: Ref_wally_descriptor, index: number): string;
126127
export function descriptor_get_network(descriptor: Ref_wally_descriptor): number;
127128
export function descriptor_get_num_keys(descriptor: Ref_wally_descriptor): number;
128129
export function descriptor_get_num_paths(descriptor: Ref_wally_descriptor): number;

tools/wasm_exports.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ EXPORTED_FUNCTIONS="['_malloc','_free','_bip32_key_free' \
8181
,'_wally_descriptor_get_checksum' \
8282
,'_wally_descriptor_get_depth' \
8383
,'_wally_descriptor_get_features' \
84+
,'_wally_descriptor_get_key' \
8485
,'_wally_descriptor_get_network' \
8586
,'_wally_descriptor_get_num_keys' \
8687
,'_wally_descriptor_get_num_paths' \

0 commit comments

Comments
 (0)