test: fix TaprootSignatureMsg default codeseparator_pos #36184

pull fametrano wants to merge 1 commits into bitcoin:master from fametrano:test-tapsig-codesep-default changing 1 files +1 −1
  1. fametrano commented at 6:06 PM on September 7, 2026: contributor

    TaprootSignatureMsg defaults codeseparator_pos to -1 and serializes it with .to_bytes(4, "little", signed=False), so any scriptpath=True call that relies on the default raises OverflowError.

    The unsigned encoding was added so callers could pass 0xfffffffe/0xffffffff, and the call sites in feature_taproot.py were updated to default to 0xffffffff; this default was left at -1. The only in-tree scriptpath caller passes codeseparator_pos explicitly, so CI does not hit it.

    Set the default to 0xFFFFFFFF: the value feature_taproot.py uses for "no codeseparator", and the bytes the previous signed encoding produced for -1.

  2. DrahtBot added the label Tests on Sep 7, 2026
  3. DrahtBot commented at 6:06 PM on September 7, 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/36184.

    <!--021abf342d371248e50ceaed478a90ca-->

    Reviews

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

    <!--5faf32d7da4f0f540f40219e4f7537a3-->

    LLM Linter (✨ experimental)

    Possible places where comparison-specific test macros should replace generic comparisons:

    • [test/functional/test_framework/script.py] assert input_index < len(txTo.vin) -> use assert_greater_than(len(txTo.vin), input_index)

    <sup>2026-09-16 06:51:11</sup>

  4. DrahtBot added the label CI failed on Sep 7, 2026
  5. fametrano force-pushed on Sep 12, 2026
  6. DrahtBot removed the label CI failed on Sep 12, 2026
  7. test: fix TaprootSignatureMsg default codeseparator_pos
    TaprootSignatureMsg defaults codeseparator_pos to -1 and serializes it
    with .to_bytes(4, "little", signed=False), so any scriptpath=True call
    that relies on the default raises OverflowError.
    
    The unsigned encoding was added so callers could pass 0xfffffffe and
    0xffffffff, and the call sites in feature_taproot.py were updated to
    default to 0xffffffff, but this default was left at -1. Set it to
    0xFFFFFFFF: the same value feature_taproot.py uses for "no
    codeseparator", and the bytes the previous signed encoding produced.
    8fdc55e52b
  8. fametrano force-pushed on Sep 16, 2026
  9. in test/functional/test_framework/script.py:817 in 8fdc55e52b
     813 | @@ -814,7 +814,7 @@ def BIP341_sha_sequences(txTo):
     814 |  def BIP341_sha_outputs(txTo):
     815 |      return sha256(b"".join(o.serialize() for o in txTo.vout))
     816 |  
     817 | -def TaprootSignatureMsg(txTo, spent_utxos, hash_type, input_index=0, *, scriptpath=False, leaf_script=None, codeseparator_pos=-1, annex=None, leaf_ver=LEAF_VERSION_TAPSCRIPT):
     818 | +def TaprootSignatureMsg(txTo, spent_utxos, hash_type, input_index=0, *, scriptpath=False, leaf_script=None, codeseparator_pos=0xFFFFFFFF, annex=None, leaf_ver=LEAF_VERSION_TAPSCRIPT):
    


    maflcko commented at 7:39 AM on September 16, 2026:

    Could be set to None, like leaf_script?


    fametrano commented at 6:48 PM on September 16, 2026:

    0xFFFFFFFF isn't a sentinel here, it's the BIP342 value for "no codeseparator executed", so it's the correct default as-is. None would need a branch back to 0xFFFFFFFF before the to_bytes call, which doesn't buy anything.


    maflcko commented at 8:05 AM on September 17, 2026:

    What I was trying to say is that there is no need to pass this value, if it isn't used. And if it is used, it seems better to write test code that is obvious and explicit.

    -1 or None achieve that by throwing a Python exception. Your suggestion of 0xFFFFFFFF does not.

    Maybe I am blind, but I don't see the point of this pull request. My recommendation would be to use:

    • -1 (i.e. close this pull), or
    • use None.

    If you think that 0xFFFFFFFF makes sense, it would be good to explain what real-world test scenario or dev experience you are trying to improve.


    fametrano commented at 10:56 AM on September 18, 2026:

    It is used: it is the last 4 bytes of every scriptpath sighash (script.py:856), the field BIP342 calls codesep_pos. The question is only what it should default to when no OP_CODESEPARATOR executed.

    -1 can no longer be that default. It worked while the line was signed=True; 81e5c8385b changed it to signed=False and left the signature alone, so the default now raises OverflowError. Going back is not available either: feature_taproot passes 0xffffffff and 0xfffffffe, which overflow as signed.

    So the choice is None or 0xFFFFFFFF, and the repo has already made it three times: interpreter.cpp:444, feature_taproot.py:436 and :1296.

    I have put the full walkthrough, including the concrete case you asked about, in a comment below. If it does not convince you, say so and I will close.

  10. fametrano commented at 10:56 AM on September 18, 2026: contributor

    The concrete case you asked about: writing a new tapscript test with no OP_CODESEPARATOR, the ordinary case. The natural call,

    TaprootSignatureHash(tx, utxos, hashtype, idx, scriptpath=True, leaf_script=script)
    

    raises OverflowError: can't convert negative int to unsigned today, from inside the framework, for a value BIP342 treats as normal ("...or 0xffffffff if none executed", BIP342, codesep_pos). That's the gap a 0xFFFFFFFF default closes — test-code ergonomics, not a consensus question. No in-tree test exercises this default either way: feature_taproot.py:252 is the only scriptpath caller, and it always passes an explicit codeseppos.

    A few more points, briefly:

    • This isn't a new convention, it's a leftover. 81e5c8385b made the serialisation unsigned and converted the -1 literals it owned — feature_taproot.py:436 and :1296 — to 0xffffffff. It touched two files, and the one -1 left behind is the default in script.py's signature. That one literal is the whole PR.
    • Reverting that commit isn't available either: feature_taproot.py now relies on 0xffffffff and 0xfffffffe (lines 436, 787), which overflow under signed=True.
    • The parameter is real, not decoration: script.py:856 serialises it into every scriptpath sighash.
    • I'd rather this not fail loud, because 0xffffffff isn't an out-of-band sentinel marking a caller mistake — it's BIP342's own value for "no codeseparator executed". interpreter.cpp:444 sets it exactly that way, unconditionally, before the interpreter's opcode loop starts. Failing on it would mean failing on the normal case.
    • fadf621825, which made leaf_script mandatory, set a standard I'd apply the same way here: no default without a real use case for it. codeseparator_pos clears that bar, because the fallback isn't invented for this PR — it's the same 0xffffffff already used in interpreter.cpp:444 and feature_taproot.py:436/:1296.
    • No sighash changes either way: (-1).to_bytes(4, "little", signed=True) and (0xFFFFFFFF).to_bytes(4, "little", signed=False) are both ffffffff.

    If a bare 0xFFFFFFFF literal is the actual objection, I can name it instead — a CODESEPARATOR_POS_NONE = 0xFFFFFFFF constant in script.py, used in the signature and, if useful, in place of the two feature_taproot.py literals. And if you'd still rather this be closed, say so and I will.

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-09-21 01:52 UTC

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