policy: make unstructured Taproot annexes standard #36466

pull RobinLinus wants to merge 4 commits into bitcoin:master from RobinLinus:policy-unstructured-annex changing 5 files +273 −28
  1. RobinLinus commented at 7:23 AM on October 8, 2026: none

    Make Taproot annexes standard for key and script paths:

    • 0x50: marker-only opt-in.
    • 0x50 0x00 <data>: arbitrary data; other prefixes remain nonstandard.
    • All non-P2A inputs must carry an annex, or none may. P2A witnesses must be empty.

    No annex-specific size limit; the existing 400,000 WU standard transaction limit applies.

    This opt-in rule protects transactions that do not opt in. It does not prevent annex inflation by opted-in participants. Consensus and witness replacement are unchanged.

    Builds on #27926 and Libre Relay.

    Validation: full build, 17 transaction unit tests, full feature_taproot.py, and git diff --check passed.

    AI-assisted implementation and tests.

  2. policy: allow unstructured Taproot annexes
    Permit marker-only annexes and annexes whose first byte after the
    0x50 marker is 0x00, reserving other prefixes for future semantics.
    Annex weight remains subject to MAX_STANDARD_TX_WEIGHT without an
    additional per-input limit.
    
    Require all transaction inputs to carry an annex if any does. This
    prevents unilateral introduction of an annex into transactions with
    participants who did not opt in; it does not prevent witness inflation
    among participants who opted in.
    
    Cover key and script paths, mixed input types, reserved prefixes,
    script stack limits, and the transaction weight boundary. Update the
    Taproot functional tests to exercise standard unstructured annexes.
    
    Builds on the all-input opt-in approach in bitcoin/bitcoin#27926 and
    the Libre Relay implementation.
    aa85bd97d1
  3. DrahtBot added the label TX fees and policy on Oct 8, 2026
  4. DrahtBot commented at 7:23 AM on October 8, 2026: contributor

    <!--e57a25ab6845829454e8d69fc972939a-->

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

    <!--006a51241073e994b41acfe9ec718e94-->

    External sites

    <!--021abf342d371248e50ceaed478a90ca-->

    Reviews

    See the guideline and AI policy for information on the review process. A summary of reviews will appear here.

    <!--174a7506f384e20aa4161008e828411d-->

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #36122 <sub><img src="https://drahtbot.space/ack_count/bitcoin/bitcoin/36122.svg"></sub> (BIP460: CISA for Taproot key path spends by fjahr)
    • #35569 <sub><img src="https://drahtbot.space/ack_count/bitcoin/bitcoin/35569.svg"></sub> (Encapsulation for CTransaction by purpleKarrot)
    • #29491 <sub><img src="https://drahtbot.space/ack_count/bitcoin/bitcoin/29491.svg"></sub> ([EXPERIMENTAL] Schnorr batch verification for blocks by fjahr)

    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. test: name AddCoins arguments in annex policy test 2506b64ff5
  6. petertodd commented at 10:07 AM on October 8, 2026: contributor

    All inputs must carry an annex, or none may.

    We should exclude spends of P2A outputs here, as they can't contain an annex.

  7. policy: exempt P2A inputs from annex opt-in
    Exclude native P2A inputs from the all-input annex requirement while retaining their empty-witness policy. Other inputs must still opt in together.
    
    Cover mixed spends, input ordering, multiple anchors, wrapped and unknown witness programs, and witness stuffing in unit and functional tests.
    bb6ccd0ada
  8. RobinLinus commented at 10:52 AM on October 8, 2026: none

    @petertodd Thanks, fixed in bb6ccd0. Native P2A inputs are exempt; their witnesses must remain empty.

  9. in src/policy/policy.cpp:281 in bb6ccd0ada outdated
     283 |  
     284 | -        // witness stuffing detected
     285 | +        // P2A inputs cannot carry an annex and are exempt from annex opt-in.
     286 |          if (prevScript.IsPayToAnchor()) {
     287 | -            return false;
     288 | +            if (!tx.vin[i].scriptWitness.IsNull()) return false;
    


    petertodd commented at 11:00 AM on October 8, 2026:

    You should re-add the "witness stuffing detected" comment here to explain what this line is doing.

  10. in src/policy/policy.cpp:282 in bb6ccd0ada outdated
     284 | -        // witness stuffing detected
     285 | +        // P2A inputs cannot carry an annex and are exempt from annex opt-in.
     286 |          if (prevScript.IsPayToAnchor()) {
     287 | -            return false;
     288 | +            if (!tx.vin[i].scriptWitness.IsNull()) return false;
     289 | +            ++anchor_inputs;
    


    petertodd commented at 11:00 AM on October 8, 2026:

    ...and the comment about P2A inputs and the annex probably makes more sense here.

  11. in src/policy/policy.cpp:289 in bb6ccd0ada outdated
     291 |          }
     292 |  
     293 | +        // We don't care if witness for this input is empty, since it must not be bloated.
     294 | +        // If the script is invalid without witness, it would be caught sooner or later during validation.
     295 | +        if (tx.vin[i].scriptWitness.IsNull())
     296 | +            continue;
    


    petertodd commented at 11:03 AM on October 8, 2026:

    I'm confused by this fragment. It doesn't look like it's related to the annex stuff at all. Rather it's just skipping further checks if scriptWitness is empty.

  12. in src/policy/policy.cpp:327 in bb6ccd0ada
     323 | @@ -320,13 +324,17 @@ bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
     324 |  
     325 |          // Check policy limits for Taproot spends:
     326 |          // - MAX_STANDARD_TAPSCRIPT_STACK_ITEM_SIZE limit for stack item size
     327 | -        // - No annexes
     328 | +        // - Annexes must be marker-only or start with the unstructured data prefix
    


    petertodd commented at 11:04 AM on October 8, 2026:

    It'd be more clear to say that "Annexes must be zero-length, or start with the unstructured data prefix, 0x00"

  13. in src/policy/policy.cpp:337 in bb6ccd0ada outdated
     335 | +                const auto& annex = SpanPopBack(stack);
     336 | +                // A marker-only annex opts in without carrying data. Otherwise, 0x00
     337 | +                // identifies unstructured data; other prefixes remain reserved.
     338 | +                // The existing MAX_STANDARD_TX_WEIGHT limit includes annex weight.
     339 | +                if (annex.size() > 1 && annex[1] != 0x00) return false;
     340 | +                ++annex_inputs;
    


    petertodd commented at 11:07 AM on October 8, 2026:

    We should explain why the unstructured marker is being used here: 0x00 is reserved, so that future consensus-related usage of the annex can use a different prefix (quite possibly an entire encoding scheme).

  14. policy: clarify annex opt-in and prefix rationale b4179ad2fb
  15. in src/policy/policy.cpp:362 in bb6ccd0ada outdated
     355 | @@ -348,7 +356,10 @@ bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
     356 |              }
     357 |          }
     358 |      }
     359 | -    return true;
     360 | +    // Signatures commit only to the annex of their own input. Requiring all non-P2A inputs
     361 | +    // to opt in prevents a participant from introducing an annex into a transaction
     362 | +    // whose other participants did not opt in. Non-P2A inputs without witness also count.
     363 | +    return annex_inputs == 0 || annex_inputs == tx.vin.size() - anchor_inputs;
    


    petertodd commented at 11:09 AM on October 8, 2026:

    You should use the term "transaction pinning attack" here, so people have something to google.

  16. RobinLinus commented at 6:15 PM on October 8, 2026: none

    @petertodd Thanks, addressed in b4179ad. The empty-witness check moved below P2A handling so anchors are counted before the early continue.

  17. DrahtBot added the label CI failed on Oct 9, 2026
  18. DrahtBot removed the label CI failed on Oct 9, 2026
  19. RobinLinus marked this as ready for review on Oct 10, 2026

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

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