Miniscript support in Output Descriptors (part 2) (wallet)

Host: stickies-v  -  PR author: darosior


  • This is a 2-part Review Club. See the notes of the first part for an introduction. If you weren’t able to attend, please go through the meeting logs as we won’t discuss those Miniscript basic concepts in this second session again.

  • In this second part, we’ll look at the Miniscript Output Descriptor implementation. We’ll focus on the last 9 commits from “miniscript: tiny doc fixups” to “qa: functional test Miniscript watchonly support”.

  • Output script descriptors are strings that contain all the information necessary to allow a wallet or other program to track payments made to or spent from a particular script or set of related scripts (i.e. an address or a set of related addresses such as in an HD wallet).

  • Descriptors combine well with Miniscript in allowing a wallet to handle tracking and signing for a larger variety of scripts. Since Bitcoin Core 23.0 descriptor wallets have become the default wallet type.

  • This PR #24148 introduces watch-only support for Miniscript descriptors, extending the already existing descriptor language. You’ve probably noticed that both languages have very similar syntax, this is intentional.


  1. Did you review the PR? Concept ACK, approach ACK, tested ACK, or NACK?

  2. Which function is responsible for parsing the output descriptor strings? How does it determine whether the string represents a MiniscriptDescriptor, instead of any other type (including a WSHDescriptor)

  3. Does MiniscriptDescriptor accept Miniscript policy or Miniscript or both?

  4. Node<Key>::ContainsDuplicateKey returns a bool. What is the return type of TreeEvalMaybe<std::set<Key>>(upfn), and how does it get cast to a bool? What does Key represent, and why is it templated?

  5. Why does ScriptMaker use a vector of CPubKey and StringMaker a vector of PubkeyProvider pointers? What’s the difference between the two?

  6. In MiniscriptDescriptor::MakeScripts, why do we store a mapping of keys from their IDs in the FlatSigningProvider provider?

  7. When choosing between two available satisfactions, why should the one that involves less or no signatures be preferred? For example, consider the policy or(and(older(21), pk(B)), thresh(2, pk(A), pk(B))) which can always be spent when both A and B sign, and can be spent after 21 blocks when just B signs. After 21 blocks, both satisfactions are available, but why would the satisfaction that involves just B’s signature be preferable?

  8. In your own words, how does Node::TreeEvalMaybe() work? (Note: there is a helpful example further down the method)

  9. In Node<Key>::FindInsaneSub(), for a given Node& node in the tree, what do we expect Span<const Node*> subs to be? In practice, in if (sub) return sub;, what value would sub have in order to return sub? (Or: what value would it not have?)