You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Merge bitcoin#22838: descriptors: Be able to specify change and receiving in a single descriptor string
a0abcbd doc: Mention multipath specifier (Ava Chow)
0019f61 tests: Test importing of multipath descriptors (Ava Chow)
f97d5c1 wallet, rpc: Allow importdescriptors to import multipath descriptors (Ava Chow)
32dcbca rpc: Allow importmulti to import multipath descriptors correctly (Ava Chow)
64dfe3c wallet: Move internal to be per key when importing (Ava Chow)
1692245 tests: Multipath descriptors for scantxoutset and deriveaddresses (Ava Chow)
cddc0ba rpc: Have deriveaddresses derive receiving and change (Ava Chow)
360456c tests: Multipath descriptors for getdescriptorinfo (Ava Chow)
a90eee4 tests: Add unit tests for multipath descriptors (Ava Chow)
1bbf46e descriptors: Change Parse to return vector of descriptors (Ava Chow)
0d640c6 descriptors: Have ParseKeypath handle multipath specifiers (Ava Chow)
a5f39b1 descriptors: Change ParseScript to return vector of descriptors (Ava Chow)
0d55dea descriptors: Add DescriptorImpl::Clone (Ava Chow)
7e86541 descriptors: Add PubkeyProvider::Clone (Ava Chow)
Pull request description:
It is convenient to have a descriptor which specifies both receiving and change addresses in a single string. However, as discussed in bitcoin#17190 (comment), it is not feasible to use a generic multipath specification like BIP 88 due to combinatorial blow up and that it would result in unexpected descriptors.
To resolve that problem, this PR proposes a targeted solution which allows only a single pair of 2 derivation indexes to be inserted in the place of a single derivation index. So instead of two descriptor `wpkh(xpub.../0/0/*)` and `wpkh(xpub.../0/1/*)` to represent receive and change addresses, this could be written as `wpkh(xpub.../0/<0;1>/*)`. The multipath specifier is of the form `<NUM;NUM>`. Each `NUM` can have its own hardened specifier, e.g. `<0;1h>` is valid. The multipath specifier can also only appear in one path index in the derivation path.
This results in the parser returning two descriptors. The first descriptor uses the first `NUM` in all pairs present, and the second uses the second `NUM`. In our implementation, if a multipath descriptor is not provided, a pair is still returned, but the second element is just `nullptr`.
The wallet will not output the multipath descriptors (yet). Furthermore, when a multipath descriptor is imported, it is expanded to the two descriptors and each imported on its own, with the second descriptor being implicitly for internal (change) addresses. There is no change to how the wallet stores or outputs descriptors (yet).
Note that the path specifier is different from what was proposed. It uses angle brackets and the semicolon because these are unused characters available in the character set and I wanted to avoid conflicts with characters already in use in descriptors.
Closesbitcoin#17190
ACKs for top commit:
darosior:
re-ACK a0abcbd
mjdietzx:
reACK a0abcbd
pythcoiner:
reACK a0abcbd
furszy:
Code review ACK a0abcbd
glozow:
light code review ACK a0abcbd
Tree-SHA512: 84ea40b3fd1b762194acd021cae018c2f09b98e595f5e87de5c832c265cfe8a6d0bc4dae25785392fa90db0f6301ddf9aea787980a29c74f81d04b711ac446c2
Copy file name to clipboardExpand all lines: doc/descriptors.md
+25Lines changed: 25 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -98,6 +98,7 @@ Descriptors consist of several types of expressions. The top level expression is
98
98
-[WIF](https://en.bitcoin.it/wiki/Wallet_import_format) encoded private keys may be specified instead of the corresponding public key, with the same meaning.
99
99
-`xpub` encoded extended public key or `xprv` encoded extended private key (as defined in [BIP 32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki)).
100
100
- Followed by zero or more `/NUM` unhardened and `/NUM'` hardened BIP32 derivation steps.
101
+
- No more than one of these derivation steps may be of the form `<NUM;NUM;...;NUM>` (including hardened indicators with either or both `NUM`). If such specifiers are included, the descriptor will be parsed as multiple descriptors where the first descriptor uses all of the first `NUM` in the pair, and the second descriptor uses the second `NUM` in the pair for all `KEY` expressions, and so on.
101
102
- Optionally followed by a single `/*` or `/*'` final step to denote all (direct) unhardened or hardened children.
102
103
- The usage of hardened derivation steps requires providing the private key.
103
104
@@ -257,6 +258,30 @@ Note how the first key is an xprv private key with a specific derivation path,
257
258
while the other two are public keys.
258
259
259
260
261
+
### Specifying receiving and change descriptors in one descriptor
262
+
263
+
Since receiving and change addresses are frequently derived from the same
264
+
extended key(s) but with a single derivation index changed, it is convenient
265
+
to be able to specify a descriptor that can derive at the two different
266
+
indexes. Thus a single tuple of indexes is allowed in each derivation path
267
+
following the extended key. When this descriptor is parsed, multiple descriptors
268
+
will be produced, the first one will use the first index in the tuple for all
269
+
key expressions, the second will use the second index, the third will use the
270
+
third index, and so on..
271
+
272
+
For example, a descriptor of the form:
273
+
274
+
multi(2,xpub.../<0;1;2>/0/*,xpub.../<2;3;4>/*)
275
+
276
+
will expand to the two descriptors
277
+
278
+
multi(2,xpub.../0/0/*,xpub.../2/*)
279
+
multi(2,xpub.../1/0/*,xpub.../3/*)
280
+
multi(2,xpub.../2/0/*,xpub.../4*)
281
+
282
+
When this tuple contains only two elements, wallet implementations can use the
283
+
first descriptor for receiving addresses and the second descriptor for change addresses.
284
+
260
285
### Compatibility with old wallets
261
286
262
287
In order to easily represent the sets of scripts currently supported by
{RPCResult::Type::STR, "descriptor", "The descriptor in canonical form, without private keys"},
178
+
{RPCResult::Type::STR, "descriptor", "The descriptor in canonical form, without private keys. For a multipath descriptor, only the first will be returned."},
179
+
{RPCResult::Type::ARR, "multipath_expansion", /*optional=*/true, "All descriptors produced by expanding multipath derivation elements. Only if the provided descriptor specifies multipath derivation elements.",
180
+
{
181
+
{RPCResult::Type::STR, "", ""},
182
+
}},
179
183
{RPCResult::Type::STR, "checksum", "The checksum for the input descriptor"},
180
184
{RPCResult::Type::BOOL, "isrange", "Whether the descriptor is ranged"},
181
185
{RPCResult::Type::BOOL, "issolvable", "Whether the descriptor is solvable"},
{"descriptor", RPCArg::Type::STR, RPCArg::Optional::NO, "The descriptor."},
227
274
{"range", RPCArg::Type::RANGE, RPCArg::Optional::OMITTED, "If a ranged descriptor is used, this specifies the end or the range (in [begin,end] notation) to derive."},
228
275
},
229
-
RPCResult{
230
-
RPCResult::Type::ARR, "", "",
231
-
{
232
-
{RPCResult::Type::STR, "address", "the derived addresses"},
233
-
}
276
+
{
277
+
RPCResult{"for single derivation descriptors",
278
+
RPCResult::Type::ARR, "", "",
279
+
{
280
+
{RPCResult::Type::STR, "address", "the derived addresses"},
281
+
}
282
+
},
283
+
RPCResult{"for multipath descriptors",
284
+
RPCResult::Type::ARR, "", "The derived addresses for each of the multipath expansions of the descriptor, in multipath specifier order",
285
+
{
286
+
{
287
+
RPCResult::Type::ARR, "", "The derived addresses for a multipath descriptor expansion",
288
+
{
289
+
{RPCResult::Type::STR, "address", "the derived address"},
0 commit comments