test: Descriptor roundtrip and raw()/ addr() coverage #36013

pull pablomartin4btc wants to merge 2 commits into bitcoin:master from pablomartin4btc:descriptor/roundtrip-raw-addr-tests changing 1 files +99 −6
  1. pablomartin4btc commented at 7:29 PM on August 18, 2026: member

    Part 1 of 2, reviving #24361.

    <details> <summary>Ports the two test-only commits from the original PR above, re-applied against the current <code>descriptor_tests.cpp</code> — the original no longer applies cleanly, since <code>DoCheck()</code>'s signature has changed substantially since the original PR was created back in 2022.</summary> <br>

    norm_prv was dropped, and op_desc_id, spender_nlocktime, spender_nsequence, preimages, expected_prv/expected_pub, and desc_index were all added - so the original diff no longer applies...

    diff -u <(git show 15220ec903:src/test/descriptor_tests.cpp | sed -n '/^void DoCheck/,/^{/p') \
            <(git show HEAD:src/test/descriptor_tests.cpp | sed -n '/^void DoCheck/,/^{/p')
    
    @@ -1,3 +1,7 @@
    -void DoCheck(const std::string& prv, const std::string& pub, const std::string& norm_prv, const std::string& norm_pub, int flags, const std::vector<std::vector<std::string>>& scripts, const std::optional<OutputType>& type, const std::set<std::vector<uint32_t>>& paths = ONLY_EMPTY,
    -    bool replace_apostrophe_with_h_in_prv=false, bool replace_apostrophe_with_h_in_pub=false)
    +void DoCheck(std::string prv, std::string pub, const std::string& norm_pub, int flags,
    +             const std::vector<std::vector<std::string>>& scripts, const std::optional<OutputType>& type, std::optional<uint256> op_desc_id = std::nullopt,
    +             const std::set<std::vector<uint32_t>>& paths = ONLY_EMPTY, bool replace_apostrophe_with_h_in_prv=false,
    +             bool replace_apostrophe_with_h_in_pub=false, uint32_t spender_nlocktime=0, uint32_t spender_nsequence=CTxIn::SEQUENCE_FINAL,
    +             std::map<std::vector<uint8_t>, std::vector<uint8_t>> preimages={},
    +             std::optional<std::string> expected_prv = std::nullopt, std::optional<std::string> expected_pub = std::nullopt, int desc_index = 0)
     {
     
    

    </details>

    • Roundtrip testing that inferring a descriptor from a generated scriptPubKey reproduces the original descriptor's structure (keys stripped from both sides for comparison). Added extension for MuSig key expressions (#31244) and BIP389 multipath (#22838), both added since 2022, and skipping for multi-branch taproot trees, where sibling order isn't meaningful. (For more details check 1st commit body)
    • Check() coverage for valid raw() and addr() descriptors, previously exercised only for invalid inputs and only in the script-to-descriptor direction. Added a new NO_KEYS flag, since these descriptors have zero keys and several existing checks assumed at least one. (For more details check 2nd commit body)

    No behavior change, test-only.


    Part 2 (not yet opened): the ToString()/ToPrivateString() merge from #24361, independent of this PR — needs more design work before it's ready.

  2. test: Roundtripping of descriptors ignoring keys
    Add DropKeys(), which strips a descriptor string down to structure
    only (key material replaced with "<KEY>", sortedmulti() normalized to
    multi(), checksum dropped), and use it to check that inferring a
    descriptor back from a script it generated reproduces the original
    descriptor's structure.
    
    A few descriptor features need special handling for this comparison
    to hold:
    
    - MuSig key expressions (musig(...)) aren't recognized by the plain
      key-matching regex. Added a separate pass collapsing musig()
      expressions (and any trailing derivation path) to <KEY> before the
      plain-key regex runs, rather than teaching that regex to understand
      musig()'s internals recursively.
    - BIP389 multipath key expressions (<1;2;3>) in derivation paths.
      Extended the path-segment pattern to recognize them, which added
      two capture groups to the key-matching regex and shifted the
      position of the group the replacement substitutes back in.
      Computed that position from the regex's own capture count instead
      of hardcoding it, so it can't silently drift out of sync again.
    - Sibling branches within a taproot script tree have no meaningful
      order (it's a Merkle tree), so InferDescriptor() reconstructing a
      multi-leaf tree in a different but equally valid branch order isn't
      something a plain string comparison can account for. Skipped the
      check for any taproot descriptor with more than one script leaf,
      detected via the presence of '{' in the descriptor string (the
      grammar only emits '{'/'}' for grouping 2+ branches).
    
    Co-authored-by: Pieter Wuille <pieter@wuille.net>
    d840df45ea
  3. test: raw() and addr() descriptors in unit tests
    Add Check() coverage for valid raw() and addr() descriptors: a raw
    script, legacy and P2SH addresses, two bech32 v0 addresses, and two
    future-witness-version addresses (v1 and v2, both expected
    non-standard/unsolvable) - verifying checksum handling, solvability,
    script derivation, and structural roundtripping. Address/script pairs
    verified against a live node's own validateaddress before use.
    
    These descriptors have no key expressions at all, which DoCheck()
    didn't previously account for:
    
    - keys_priv.keys is expected to be empty rather than non-empty, gated
      on a new NO_KEYS flag.
    - GetMaxKeyExpr()/GetKeyCount() are expected to both report zero
      rather than the usual "highest index + 1 == count" relationship.
      Added the NO_KEYS-aware branch for it.
    - HavePrivateKeys() returns false for a keyless descriptor, not
      vacuously true - it didn't exist when the original patch was
      written, so this wasn't previously exercised. Gated
      have_all_private_keys on NO_KEYS in addition to the existing
      MISSING_PRIVKEYS.
    - raw()/addr() hardcode ToPrivateString() to always fail, so the
      existing "can serialize back to the private version" check needs
      skipping for these descriptors too. Extended its MISSING_PRIVKEYS
      gate to also cover NO_KEYS.
    
    Co-authored-by: Pieter Wuille <pieter@wuille.net>
    5b4c861a60
  4. DrahtBot added the label Tests on Aug 18, 2026
  5. DrahtBot commented at 7:30 PM on August 18, 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/36013.

    <!--021abf342d371248e50ceaed478a90ca-->

    Reviews

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

    Type Reviewers
    Concept ACK w0xlt

    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.

    <!--5faf32d7da4f0f540f40219e4f7537a3-->

  6. w0xlt commented at 9:17 PM on August 18, 2026: contributor

    Concept ACK


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-08-19 11:51 UTC

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