test: add coverage for untested descriptor parse error paths #35819

pull azuchi wants to merge 1 commits into bitcoin:master from azuchi:descriptor-parse-error-tests changing 1 files +33 −0
  1. azuchi commented at 2:00 AM on July 27, 2026: contributor

    Looking at the coverage report for master on https://corecheck.dev, a number of error branches in descriptor.cpp are never exercised by any test. This PR adds CheckUnparsable vectors for each reachable one:

    musig()

    • unterminated expression: tr(musig(00) → "Invalid musig() expression"
    • invalid participant key
    • invalid derivation path element (the musig(): -prefixed wrapping of the keypath error; the underlying ParseKeyPath errors were already covered via pkh()/wpkh())
    • participants with multipath derivations of mismatched lengths (/<0;1> vs /<0;1;2>; the multi() and Miniscript variants of this error were covered, the musig() one was not)

    Context restrictions

    • multi() inside tr(), multi_a() at top level, and addr()/tr()/rawtr()/raw() inside sh()

    Taptree structure errors

    • exceeding the 128 nesting level limit (129 {s, built with std::string(129, '{'))
    • missing '}' after a right branch, missing ',' after a left branch, trailing garbage after a script expression and after the internal key

    rawtr()

    • invalid key. 00 is used (rather than the truncated-valid-key pattern used elsewhere in this file) because in Taproot contexts a 32-byte string would parse as a valid x-only key.

    Since CheckUnparsable asserts on the exact error message and each targeted branch produces a distinct one, a passing vector proves the corresponding branch executed.

    One musig() parse error remains uncovered: "musig(): expected ',', got '%c'" (descriptor.cpp line ~2053). As far as I can tell it is unreachable: reaching it requires the leftover after a participant Expr() to start with '}' or ')', but a ')' inside the expression is rejected earlier by the flat Split() ("Too many ')'"), and a stray '}' always unbalances the enclosing Expr() first, truncating the musig span so that Func() fails with "Invalid musig() expression" instead. Attempting to rebalance with extra parentheses runs into one of the earlier checks in every combination I could construct.

  2. test: add coverage for untested descriptor parse error paths
    Coverage measurement of master (unit and functional tests combined)
    shows that a number of error branches in descriptor.cpp are never
    exercised by any test. Add CheckUnparsable vectors for each reachable
    one:
    
    - musig(): unterminated expression, invalid participant key, invalid
      derivation path element, and participants with multipath derivations
      of mismatched lengths
    - context restrictions: multi() inside tr(), multi_a() at top level,
      and addr()/tr()/rawtr()/raw() inside sh()
    - taptree structure errors: exceeding the 128 nesting level limit,
      missing '}' after a right branch, missing ',' after a left branch,
      and trailing garbage after a script expression or the internal key
    - rawtr() with an invalid key
    
    Since CheckUnparsable asserts on the exact error message and each
    targeted branch produces a distinct one, a passing vector proves the
    corresponding branch executed.
    004de4f835
  3. DrahtBot added the label Tests on Jul 27, 2026
  4. DrahtBot commented at 2:00 AM on July 27, 2026: contributor

    <!--e57a25ab6845829454e8d69fc972939a-->

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    <!--006a51241073e994b41acfe9ec718e94-->

    Code Coverage & Benchmarks

    For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/35819.

    <!--021abf342d371248e50ceaed478a90ca-->

    Reviews

    See the guideline and AI policy for information on the review process.

    Type Reviewers
    ACK sorukumar

    If your review is incorrectly listed, please copy-paste <code>&lt;!--meta-tag:bot-skip--&gt;</code> into the comment that the bot should ignore.

    <!--174a7506f384e20aa4161008e828411d-->

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #35302 (Silent Payments: Sending (take 2) by Eunovo)

    If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

    <!--5faf32d7da4f0f540f40219e4f7537a3-->

  5. sorukumar commented at 2:43 AM on July 28, 2026: none

    tACK 004de4f835. Built on macOS ARM and ran ./build/bin/test_bitcoin --run_test=descriptor_tests; all 4 cases passed.

    Verified by temporarily mutating descriptor.cpp:2041 from "Invalid musig() expression" to "MUTATED musig() expression". The new vector caught the failure with: tr(): MUTATED musig() expression != tr(): Invalid musig() expression

    restored the original code and the test passed again.

Labels

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-07-31 20:50 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me