For this particular error, the same old suspects are double length-prefixing or unintentionally together with the annex. Double-prefixing is the one I see most frequently.
The management block must be one witness stack ingredient, uncooked bytes. Structure:
<1 byte: leaf_version | parity>
<32 bytes: inner key>
<32 bytes × depth: merkle path hashes>
(parity comes from the tweaked pubkey’s y-coordinate odd/even—you may have it should you derived Q accurately.) No compactSize inside. No splitting.
Your ser_string name — that is the issue. Witness serialization already length-prefixes every stack merchandise. So once you do ser_string(control_block), you are including an additional prefix. The node checks (len - 33) % 32 == 0; one further byte and that test fails, therefore Invalid Taproot management block measurement. Simply concatenate:
control_block = b''.be part of([
bytes([leaf_version | parity]),
internal_pubkey,
merkle_hash_1,
merkle_hash_2
])
witness_stack = [preimage_or_sig, script, control_block]
Splitting into separate components — additionally incorrect. The node takes the final ingredient because the management block. In the event you break up, it solely sees hash2 (32 bytes) or no matter is final, so the dimensions test fails. You may also hit bad-witness-nonstandard earlier than script validation, relying on coverage.
Helpful manner to consider it: layer 1 is BIP 341’s management block format (33+32m bytes, validated by that (len-33)%32==0 test). Layer 2 is witness encoding (size prefix per ingredient). You solely outline layer 1; layer 2 is computerized. Do not combine them.
If dropping ser_string and utilizing a single blob fixes it, that was the difficulty. I’ve reproduced this on regtest—toggle solely the management block construct and the habits matches.
