We introduce support for tr() descriptors alongside wsh() descriptors in
creating (compiling from policy, parsing from string) and working with
(analyizing its policy, getting spend information) a descriptor.
When compiling a Taproot descriptor, if no key from the policy could be
used as single internal key we deterministically generate an unspendable
internal key as per
https://delvingbitcoin.org/t/unspendable-keys-in-descriptors/304/21.
Similarly when lifting the policy of a Taproot descriptor, if the
internal key matches the deterministic unspendable key for this
descriptor we discard it from the analysis.
To fill information about an output for signers, we re-use
rust-miniscript PSBT input updated instead of re-inventing the wheel. It
does necessitate a hack however to use a type they would accept.
We don't change the "max size of a spending input" for now, even though
it means we would significantly overpay fees for descriptors with a
spendable internal key.
The most notable change is rust-bitcoin's change in the serialization of
transaction with no input. It now accounts for the segwit marker even
for those. The base tx weight in coin selection had to be adapted to
handle this.
See https://gnusha.org/bitcoin-rust/2024-01-04.log for details.
This is necessary to support signers which sign for a single key at
once. It also doesn't make any sense to reuse a signer within the same
spending path, so rule it out before it creates any new edge cases.
For more about the Bitbox signer support, which motivated this change,
see
https://github.com/wizardsardine/liana/pull/706#issuecomment-1744705808.
Ledger and wallet policies disallow having more than 2 depth after the
placeholder, therefore we can't do `@1/0/<0;1>/*`, `@1/1/<0;1>/*`, ..
Instead we have to do `@1/<0;1>/*`, `@1/<2;3>/*`, ..
Why not? Salvatore also says the cost of deriving another depth is
non-trivial on a signing device.
Don't pick a fight with Salvatore, instead just let the GUI (or whatever
creates the desc) use different multipath steps for keys derived from
the same xpubs.
It's supposed to represent the number of signature per "master" key, i
guess. At the moment it would always be 1 because the origin changes
when we queried more keys from the signing device (because we increased
the account).
28049d4f7cd2001207cc2b204c31b33d9640077d descriptor: make it possible to use the same xpub at different paths (Antoine Poinsot)
Pull request description:
This is unnecessary to bump a hardened step to get another xpub for the same participant:
- It's more hurdle when sharing it
- It's more hurdle when verifying it on the device's screen
- It's for the same person within the same script anyways
Fix this by allowing to use the same xpub multiple times in a descriptor as long as the derivation path is different. Then the GUI will be able to use a new unhardened derivation step instead of bumping the BIP48 "accounts". A unit test is introduced that showcases this.
See also https://github.com/wizardsardine/liana/issues/542.
ACKs for top commit:
edouardparis:
ACK 28049d4f7cd2001207cc2b204c31b33d9640077d
Tree-SHA512: e864a8193998667d36b34d96e6e32bfff1c507b3c31faa324b7f264604c41b5d2d4aefeec3b71a1d3edf5b0242966861887baf97d7a410e43e7449f22c3453f4
It's a much better UX to be able to share and verify one xpub and just
use different unhardened paths for the various public keys used in the
same script that originate from the same master key.
Rust-bitcoin, that we use through rust-miniscript, has seen plenty of
breaking changes in the latest version. I've tried to keep the necessary
changes here minimal, still it had to be a single commit to keep it
hygienic. But i'll try to summarize the main things here. Tobin also
wrote a guide about the release at
https://rust-bitcoin.org/blog/release-0.30.0/.
The most verbose change in this commit is probably due to the `Address`
type overhaul. It's overengineered if you ask me but hey here we are. I
tried to keep network validation in commands, and otherwise passing
around unchecked addresses (to avoid having to pass around a global
state between our various components).
Another non-obvious change was changes in hash types upstream and the
removal of `ToHex`, forcing us to get the hex representation of a txid
through its `Display` implementation. It is however displayed backward
in this case ("little-endian" if you will), and we need a regular hex
encoding for some queries to the database. We needed to make sure we
didn't implement any silent bug here.
The rest (Script type changes, PSBT serialization updates, ..) is
probably self-explanatory.
This makes it possible to have more than one recovery path in a Liana
descriptor. The descriptor and partial spend analysis are adapted to
report information about all recovery paths.
This makes it possible for a LianaPolicy to be created from a user
configuration. This in turn centralizes the descriptor creation inside
it as well and make `MultipathDescriptor` take a `LianaPolicy` directly.
This is useful to centralize all the Miniscript and Miniscript policy
handling under in a single place as we'll soon be managing much more
complex policies (and make use of the Minsicript policy compiler).
Unfortunately this is an invasive API change. But at least the API now
makes a lot more sense: you can create a spending policy from a
configuration and create a descriptor from it. And vice-versa you can
infer a spending policy from a descriptor and inspect the configuration
from it.
This merges the Miniscript policy semantic analysis we perform both when
parsing a descriptor and when gathering information about a Liana
descriptor in one, right, place: the analysis submodule.