Skip to content

Commit 76defcd

Browse files
committed
descriptor: allow fetching child paths from iterated keys
1 parent 7b1af2f commit 76defcd

File tree

9 files changed

+107
-10
lines changed

9 files changed

+107
-10
lines changed

include/wally.hpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,18 @@ inline int descriptor_get_key(const DESCRIPTOR& descriptor, size_t index, char**
510510
return ret;
511511
}
512512

513+
template <class DESCRIPTOR>
514+
inline int descriptor_get_key_child_path_str(const DESCRIPTOR& descriptor, size_t index, char** output) {
515+
int ret = ::wally_descriptor_get_key_child_path_str(detail::get_p(descriptor), index, output);
516+
return ret;
517+
}
518+
519+
template <class DESCRIPTOR>
520+
inline int descriptor_get_key_child_path_str_len(const DESCRIPTOR& descriptor, size_t index, size_t* written) {
521+
int ret = ::wally_descriptor_get_key_child_path_str_len(detail::get_p(descriptor), index, written);
522+
return ret;
523+
}
524+
513525
template <class DESCRIPTOR>
514526
inline int descriptor_get_network(const DESCRIPTOR& descriptor, uint32_t* value_out) {
515527
int ret = ::wally_descriptor_get_network(detail::get_p(descriptor), value_out);

include/wally_descriptor.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,33 @@ WALLY_CORE_API int wally_descriptor_get_key(
211211
size_t index,
212212
char **output);
213213

214+
/**
215+
* Get the length of a keys child path string in a parsed output descriptor or miniscript expression.
216+
*
217+
* :param descriptor: Parsed output descriptor or miniscript expression.
218+
* :param index: The zero-based index of the key whose child path to get.
219+
* :param written: Destination for the length of the keys child path string,
220+
*| excluding the NUL terminator.
221+
*/
222+
WALLY_CORE_API int wally_descriptor_get_key_child_path_str_len(
223+
const struct wally_descriptor *descriptor,
224+
size_t index,
225+
size_t *written);
226+
227+
/**
228+
* Get the keys child path string in a parsed output descriptor or miniscript expression.
229+
*
230+
* :param descriptor: Parsed output descriptor or miniscript expression.
231+
* :param index: The zero-based index of the key whose child path to get.
232+
* :param output: Destination for the resulting path string (may be empty).
233+
*| The string returned should be freed using `wally_free_string`.
234+
*/
235+
WALLY_CORE_API int wally_descriptor_get_key_child_path_str(
236+
const struct wally_descriptor *descriptor,
237+
size_t index,
238+
char **output);
239+
240+
214241
/**
215242
* Get the maximum length of a script corresponding to an output descriptor.
216243
*

src/descriptor.c

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2893,18 +2893,24 @@ int wally_descriptor_get_num_keys(const struct wally_descriptor *descriptor,
28932893
#if defined(__clang__)
28942894
#pragma clang diagnostic ignored "-Wcast-align"
28952895
#endif
2896+
static const ms_node *descriptor_get_key(const struct wally_descriptor *descriptor,
2897+
size_t index)
2898+
{
2899+
if (!descriptor || index >= descriptor->keys.num_items)
2900+
return NULL;
2901+
return (ms_node *)descriptor->keys.items[index].value;
2902+
}
28962903

28972904
int wally_descriptor_get_key(const struct wally_descriptor *descriptor,
28982905
size_t index, char **output)
28992906
{
2900-
const ms_node *node;
2907+
const ms_node *node = descriptor_get_key(descriptor, index);
29012908

29022909
if (output)
29032910
*output = 0;
2904-
if (!descriptor || index >= descriptor->keys.num_items || !output)
2911+
if (!node || !output)
29052912
return WALLY_EINVAL;
29062913

2907-
node = (ms_node *)descriptor->keys.items[index].value;
29082914
if (node->kind == KIND_PUBLIC_KEY) {
29092915
return wally_hex_from_bytes((const unsigned char *)node->data,
29102916
node->data_len, output);
@@ -2923,3 +2929,30 @@ int wally_descriptor_get_key(const struct wally_descriptor *descriptor,
29232929
return WALLY_ENOMEM;
29242930
return WALLY_OK;
29252931
}
2932+
2933+
int wally_descriptor_get_key_child_path_str_len(
2934+
const struct wally_descriptor *descriptor, size_t index, size_t *written)
2935+
{
2936+
const ms_node *node = descriptor_get_key(descriptor, index);
2937+
2938+
if (written)
2939+
*written = 0;
2940+
if (!node || !written)
2941+
return WALLY_EINVAL;
2942+
*written = node->child_path_len;
2943+
return WALLY_OK;
2944+
}
2945+
2946+
int wally_descriptor_get_key_child_path_str(
2947+
const struct wally_descriptor *descriptor, size_t index, char **output)
2948+
{
2949+
const ms_node *node = descriptor_get_key(descriptor, index);
2950+
2951+
if (output)
2952+
*output = 0;
2953+
if (!node || !output)
2954+
return WALLY_EINVAL;
2955+
if (!(*output = wally_strdup_n(node->child_path, node->child_path_len)))
2956+
return WALLY_ENOMEM;
2957+
return WALLY_OK;
2958+
}

src/swig_java/swig.i

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,8 @@ static jobjectArray create_jstringArray(JNIEnv *jenv, char **p, size_t len) {
562562
%returns_size_t(wally_descriptor_get_features);
563563
%returns_size_t(wally_descriptor_get_network);
564564
%returns_string(wally_descriptor_get_key);
565+
%returns_string(wally_descriptor_get_key_child_path_str);
566+
%returns_size_t(wally_descriptor_get_key_child_path_str_len);
565567
%returns_size_t(wally_descriptor_get_num_keys);
566568
%returns_size_t(wally_descriptor_get_num_paths);
567569
%returns_size_t(wally_descriptor_get_num_variants);

src/test/test_descriptor.py

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -321,26 +321,41 @@ def test_key_iteration(self):
321321
wif = 'L1AAHuEC7XuDM7pJ7yHLEqYK1QspMo8n1kgxyZVdgvEpVC1rkUrM'
322322
pk = '03b428da420cd337c7208ed42c5331ebb407bb59ffbe3dc27936a227c619804284'
323323
pk_u = '0414fc03b8df87cd7b872996810db8458d61da8448e531569c8517b469a119d267be5645686309c6e6736dbd93940707cc9143d3cf29f1b877ff340e2cb2d259cf'
324+
policy_keys = wally_map_from_dict({f'@{i}': xpub for i,xpub in enumerate([k1])})
325+
P = POLICY
326+
324327
# Valid args
325-
for descriptor, expected in [
328+
for flags, descriptor, expected, child_path in [
326329
# Bip32 xpub
327-
(f'pkh({k1})', k1),
330+
(0, f'pkh({k1})', k1, ''),
331+
(0, f'pkh({k1}/*)', k1, '*'),
332+
(0, f'pkh({k1}/0/1/2/*)', k1, '0/1/2/*'),
333+
(0, f'pkh({k1}/<0;1>/*)', k1, '<0;1>/*'),
334+
# Bip32 xpub (as policy)
335+
(P, 'pkh(@0/*)', k1, '*'),
336+
(P, 'pkh(@0/**)', k1, '<0;1>/*'),
337+
(P, 'pkh(@0/<0;1>/*)', k1, '<0;1>/*'),
328338
# BIP32 xprv
329-
(f'pkh({k2})', k2),
339+
(0, f'pkh({k2})', k2, ''),
330340
# WIF
331-
(f'pkh({wif})', wif),
341+
(0, f'pkh({wif})', wif, ''),
332342
# Hex pubkey, compressed
333-
(f'pk({pk})', pk),
343+
(0, f'pk({pk})', pk, ''),
334344
# Hex pubkey, uncompressed
335-
(f'pk({pk_u})', pk_u),
345+
(0, f'pk({pk_u})', pk_u, ''),
336346
]:
337347
d = c_void_p()
338-
ret = wally_descriptor_parse(descriptor, None, NETWORK_BTC_MAIN, 0, d)
348+
keys = policy_keys if flags & P else None
349+
ret = wally_descriptor_parse(descriptor, keys, NETWORK_BTC_MAIN, flags, d)
339350
self.assertEqual(ret, WALLY_OK)
340351
ret, num_keys = wally_descriptor_get_num_keys(d)
341352
self.assertEqual((ret, num_keys), (WALLY_OK, 1))
342353
ret, key_str = wally_descriptor_get_key(d, 0)
343354
self.assertEqual((ret, key_str), (WALLY_OK, expected))
355+
ret, path_len = wally_descriptor_get_key_child_path_str_len(d, 0)
356+
self.assertEqual((ret, path_len), (WALLY_OK, len(child_path)))
357+
ret, path_str = wally_descriptor_get_key_child_path_str(d, 0)
358+
self.assertEqual((ret, path_str), (WALLY_OK, child_path))
344359
wally_descriptor_free(d)
345360

346361

src/test/util.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,8 @@ class wally_psbt(Structure):
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]),
316316
('wally_descriptor_get_key', c_int, [c_void_p, c_size_t, c_char_p_p]),
317+
('wally_descriptor_get_key_child_path_str', c_int, [c_void_p, c_size_t, c_char_p_p]),
318+
('wally_descriptor_get_key_child_path_str_len', c_int, [c_void_p, c_size_t, c_size_t_p]),
317319
('wally_descriptor_get_network', c_int, [c_void_p, c_uint32_p]),
318320
('wally_descriptor_get_num_keys', c_int, [c_void_p, c_uint32_p]),
319321
('wally_descriptor_get_num_paths', c_int, [c_void_p, c_uint32_p]),

src/wasm_package/src/functions.js

Lines changed: 2 additions & 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: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ export function descriptor_get_checksum(descriptor: Ref_wally_descriptor, flags:
124124
export function descriptor_get_depth(descriptor: Ref_wally_descriptor): number;
125125
export function descriptor_get_features(descriptor: Ref_wally_descriptor): number;
126126
export function descriptor_get_key(descriptor: Ref_wally_descriptor, index: number): string;
127+
export function descriptor_get_key_child_path_str_len(descriptor: Ref_wally_descriptor, index: number): number;
127128
export function descriptor_get_network(descriptor: Ref_wally_descriptor): number;
128129
export function descriptor_get_num_keys(descriptor: Ref_wally_descriptor): number;
129130
export function descriptor_get_num_paths(descriptor: Ref_wally_descriptor): number;
@@ -725,6 +726,7 @@ export function asset_surjectionproof(output_asset: Buffer|Uint8Array, output_ab
725726
export function base58_n_to_bytes(str_in: string, str_len: number, flags: number): Buffer;
726727
export function base58_to_bytes(str_in: string, flags: number): Buffer;
727728
export function base64_to_bytes(str_in: string, flags: number): Buffer;
729+
export function descriptor_get_key_child_path_str(descriptor: Ref_wally_descriptor, index: number): string;
728730
export function descriptor_to_script(descriptor: Ref_wally_descriptor, depth: number, index: number, variant: number, multi_index: number, child_num: number, flags: number): Buffer;
729731
export function ec_sig_from_bytes(priv_key: Buffer|Uint8Array, bytes: Buffer|Uint8Array, flags: number): Buffer;
730732
export function ec_sig_from_bytes_aux(priv_key: Buffer|Uint8Array, bytes: Buffer|Uint8Array, aux_rand: Buffer|Uint8Array, flags: number): Buffer;

tools/wasm_exports.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ EXPORTED_FUNCTIONS="['_malloc','_free','_bip32_key_free' \
8282
,'_wally_descriptor_get_depth' \
8383
,'_wally_descriptor_get_features' \
8484
,'_wally_descriptor_get_key' \
85+
,'_wally_descriptor_get_key_child_path_str' \
86+
,'_wally_descriptor_get_key_child_path_str_len' \
8587
,'_wally_descriptor_get_network' \
8688
,'_wally_descriptor_get_num_keys' \
8789
,'_wally_descriptor_get_num_paths' \

0 commit comments

Comments
 (0)