Merge bitcoin/bitcoin#34141: miniscript: Use Func and Expr when parsing keys, hashes, and locktimes

4b53cbd692 test: Test for musig() in various miniscript expressions (Ava Chow)
ec0f47b15c miniscript: Using Func and Expr when parsing keys, hashes, and locktimes (Ava Chow)
6fd780d4fb descriptors: Increment key_exp_index in ParsePubkey(Inner) (Ava Chow)
b12281bd86 miniscript: Use a reference to key_exp_index in KeyParser (Ava Chow)
ce4c66eb7c test: Test that key expression indexes match key count (Ava Chow)

Pull request description:

  The miniscript parser currently only looks for the next `)` when parsing key, hash, and locktime expressions. This fails to parse when the expressions contain a nested expression. Currently, this is only possible with `musig()` inside of key expressions. However, this pattern can be generalized to handling hashes and locktimes, so I implemented those too.

  Fixes #34076

ACKs for top commit:
  rkrux:
    ACK 4b53cbd692
  sipa:
    ACK 4b53cbd692
  darosior:
    Other than that, Approach ACK 4b53cbd692. That makes sense to me but i have not closely reviewed the code.

Tree-SHA512: 01040c7b07a59d8e3725ff11ab9543b256aea22535fb94059f490a5bb45319e859666af04c2f0a4edcb8cf1e6dfc7bd8a8271b21ad81143bafccd4d0a39cae9c
This commit is contained in:
merge-script
2026-02-21 12:18:56 +01:00
9 changed files with 148 additions and 103 deletions

View File

@@ -61,6 +61,10 @@ static void TestDescriptor(const Descriptor& desc, FlatSigningProvider& sig_prov
const bool is_nontop_or_nonsolvable{!*is_solvable || !desc.GetOutputType()};
const bool is_input_size_info_set{max_sat_maxsig && max_sat_nonmaxsig && max_elems};
assert(is_input_size_info_set || is_nontop_or_nonsolvable);
auto max_key_expr = desc.GetMaxKeyExpr();
auto key_count = desc.GetKeyCount();
assert((max_key_expr == 0 && key_count == 0) || max_key_expr + 1 == key_count);
}
void initialize_descriptor_parse()

View File

@@ -154,10 +154,9 @@ struct ParserContext {
return {h.begin(), h.end()};
}
template<typename I>
std::optional<Key> FromString(I first, I last) const {
if (last - first != 2) return {};
auto idx = ParseHex(std::string(first, last));
std::optional<Key> FromString(std::span<const char>& in) const {
if (in.size() != 2) return {};
auto idx = ParseHex(std::string(in.begin(), in.end()));
if (idx.size() != 1) return {};
return TEST_DATA.dummy_keys[idx[0]];
}