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.

    Type Reviewers
    ACK petertodd
    Concept ACK Rob1Ham

    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:

    • #36521 <sub><img src="https://drahtbot.space/ack_count/bitcoin/bitcoin/36521.svg"></sub> (Keep witness stacks in serialized form in CScriptWitness by sipa)
    • #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
  20. petertodd commented at 5:55 PM on October 12, 2026: contributor

    utACK b4179ad2fb6154a4e93f46389cca00b6926fbd2f

  21. sipa commented at 10:24 AM on October 20, 2026: member

    What is the purpose of this? I was imagining that annex standardness would be added at the same time consensus-relevant meaning would be given to annexes.

    Of course, if there were active use of annexes on the network it would be useful to accommodate relay, but as of now I don't see the point.

  22. RobinLinus commented at 3:39 AM on October 22, 2026: none

    @sipa The motivation is data availability for metaprotocols, including a range of shielded protocols such as Shielded CSV.

    Annexes would let these protocols publish data directly in a Taproot key-path spend, avoiding the script-path commitment and reveal required by inscription-style encoding.

    The motivation for enabling relay now is to support these applications. They need data availability independently of future consensus semantics for the annex; the proposed 0x00 prefix distinguishes this unstructured use from future extensions.

    Standard relay would also let these applications reach miners through the public P2P network, reducing the incentive to build private mempools or depend on arrangements with individual mining pools.

  23. Rob1Ham commented at 10:07 PM on October 24, 2026: contributor

    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-10-30 09:40 UTC