From ae98a6ed470c8ee3420bc497d11ef717f8374548 Mon Sep 17 00:00:00 2001 From: Dathon Ohm Date: Wed, 29 Jul 2026 10:55:08 -0600 Subject: [PATCH 1/3] BIP-110: Add Defined witness versions subsection clarifying the rule 3 P2A exemption --- bip-0110.mediawiki | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/bip-0110.mediawiki b/bip-0110.mediawiki index 6147361987..542cbf4302 100644 --- a/bip-0110.mediawiki +++ b/bip-0110.mediawiki @@ -24,7 +24,7 @@ Blocks during a temporary, one-year deployment are checked with these additional # New output scriptPubKeys exceeding 34 bytes are invalid, unless the first opcode is OP_RETURN, in which case up to 83 bytes are valid. # OP_PUSHDATA* payloads and [[#script-argument-witness-items|script argument witness items]] exceeding 256 bytes are invalid, except for the redeemScript push in BIP16 scriptSigs. -# Spending undefined witness (or Tapleaf) versions (ie, not Witness v0/BIP 141, Taproot/BIP 341, or P2A) is invalid. (Creating outputs with undefined witness versions is still valid.) +# Spending undefined witness (or Tapleaf) versions (ie, anything not listed under [[#defined-witness-versions|Defined witness versions]] below) is invalid. (Creating outputs with undefined witness versions is still valid.) # Witness stacks with a Taproot annex are invalid. # Taproot control blocks larger than 257 bytes (a merkle tree with 128 script leaves) are invalid. # Tapscripts including OP_SUCCESS* opcodes anywhere (even unexecuted) are invalid. @@ -37,6 +37,15 @@ This grandfathering ensures that no existing coins can be frozen or rendered uns The new rules apply only to UTXOs created at or after the activation height. Once the softfork expires, UTXOs of all heights are once again unrestricted. + +===Defined witness versions=== + +For the purposes of rule 3, these are the witness versions (and the one Tapleaf version) that are defined as of this BIP: + +* '''Witness v0''' with a 20-byte program (P2WPKH) or a 32-byte program (P2WSH), as defined in [[bip-0141.mediawiki|BIP 141]]. Other v0 program lengths are already invalid under BIP 141 itself. +* '''Witness v1''' with a 32-byte program (Taproot/P2TR), as defined in [[bip-0341.mediawiki|BIP 341]]. In a script path spend, the only defined Tapleaf version is 0xc0 (Tapscript), as defined in [[bip-0342.mediawiki|BIP 342]]. +* '''Witness v1''' with the 2-byte program 0x4e73 (P2A), and only when spent with an empty witness stack, as defined in [[bip-0433.mediawiki#specification|BIP 433]]. + ===GetBlockTemplate=== This deployment uses the GBT deployment name "reduced_data" as defined in [[bip-0009.mediawiki#getblocktemplate_changes|BIP 9]]. During mandatory signaling, the deployment's bit is included in "vbrequired". From 2dfb201b271d4620baa3ce17cbd8f13d40009668 Mon Sep 17 00:00:00 2001 From: Dathon Ohm Date: Wed, 29 Jul 2026 11:24:29 -0600 Subject: [PATCH 2/3] BIP-110: Add rule 3 test vectors for the P2A empty-witness requirement Co-Authored-By: jarolrod --- bip-0110/test-vectors.json | 88 ++++++++++++++++++++++++++++++++++++-- bip-0110/test-vectors.py | 26 ++++++++++- 2 files changed, 109 insertions(+), 5 deletions(-) diff --git a/bip-0110/test-vectors.json b/bip-0110/test-vectors.json index 80124af79f..f45e87b985 100644 --- a/bip-0110/test-vectors.json +++ b/bip-0110/test-vectors.json @@ -281,6 +281,66 @@ "expected": "valid", "reject_reason": null }, + { + "rule": 3, + "name": "p2a_empty_witness_valid", + "description": "Spend a P2A output with an empty witness stack", + "reduced_data_active": true, + "spent_utxo": "post-activation", + "spent_outputs": [ + { + "prevout": { + "txid": "110000000000000000000000000000000000000000000000000000000000000f", + "vout": 0 + }, + "scriptPubKey": "51024e73", + "amount": 100000 + } + ], + "tx": "02000000010f0000000000000000000000000000000000000000000000000000000000001100000000000000000001b882010000000000015100000000", + "expected": "valid", + "reject_reason": null + }, + { + "rule": 3, + "name": "p2a_empty_item_invalid", + "description": "Spend a P2A output with one empty witness item (non-empty stack)", + "reduced_data_active": true, + "spent_utxo": "post-activation", + "spent_outputs": [ + { + "prevout": { + "txid": "1100000000000000000000000000000000000000000000000000000000000010", + "vout": 0 + }, + "scriptPubKey": "51024e73", + "amount": 100000 + } + ], + "tx": "02000000000101100000000000000000000000000000000000000000000000000000000000001100000000000000000001b8820100000000000151010000000000", + "expected": "invalid", + "reject_reason": "script-verify-flag-failed (Witness version reserved for soft-fork upgrades)" + }, + { + "rule": 3, + "name": "p2a_one_byte_item_invalid", + "description": "Spend a P2A output with one one-byte witness item", + "reduced_data_active": true, + "spent_utxo": "post-activation", + "spent_outputs": [ + { + "prevout": { + "txid": "1100000000000000000000000000000000000000000000000000000000000011", + "vout": 0 + }, + "scriptPubKey": "51024e73", + "amount": 100000 + } + ], + "tx": "02000000000101110000000000000000000000000000000000000000000000000000000000001100000000000000000001b882010000000000015101010100000000", + "expected": "invalid", + "reject_reason": "script-verify-flag-failed (Witness version reserved for soft-fork upgrades)" + }, { "rule": 2, "name": "grandfathered_witness_item_257_valid", @@ -290,14 +350,34 @@ "spent_outputs": [ { "prevout": { - "txid": "110000000000000000000000000000000000000000000000000000000000000f", + "txid": "1100000000000000000000000000000000000000000000000000000000000012", "vout": 0 }, "scriptPubKey": "002033198a9bfef674ebddb9ffaa52928017b8472791e54c609cb95f278ac6b1e349", "amount": 100000 } ], - "tx": "020000000001010f0000000000000000000000000000000000000000000000000000000000001100000000000000000001b882010000000000015102fd0101424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424202755100000000", + "tx": "02000000000101120000000000000000000000000000000000000000000000000000000000001100000000000000000001b882010000000000015102fd0101424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424202755100000000", + "expected": "valid", + "reject_reason": null + }, + { + "rule": 3, + "name": "grandfathered_p2a_nonempty_witness_valid", + "description": "Spend a PRE-activation P2A output with a non-empty witness stack (grandfathered, exempt)", + "reduced_data_active": true, + "spent_utxo": "pre-activation", + "spent_outputs": [ + { + "prevout": { + "txid": "1100000000000000000000000000000000000000000000000000000000000013", + "vout": 0 + }, + "scriptPubKey": "51024e73", + "amount": 100000 + } + ], + "tx": "02000000000101130000000000000000000000000000000000000000000000000000000000001100000000000000000001b882010000000000015101010100000000", "expected": "valid", "reject_reason": null }, @@ -310,14 +390,14 @@ "spent_outputs": [ { "prevout": { - "txid": "1100000000000000000000000000000000000000000000000000000000000010", + "txid": "1100000000000000000000000000000000000000000000000000000000000014", "vout": 0 }, "scriptPubKey": "00204ae81572f06e1b88fd5ced7a1a000945432e83e1551e6f721ee9c00b8cc33260", "amount": 100000 } ], - "tx": "02000000000101100000000000000000000000000000000000000000000000000000000000001100000000000000000001b88201000000000023510000000000000000000000000000000000000000000000000000000000000000000001015100000000", + "tx": "02000000000101140000000000000000000000000000000000000000000000000000000000001100000000000000000001b88201000000000023510000000000000000000000000000000000000000000000000000000000000000000001015100000000", "expected": "invalid", "reject_reason": "bad-txns-vout-script-toolarge" } diff --git a/bip-0110/test-vectors.py b/bip-0110/test-vectors.py index 1644bdf2d2..03d39228a8 100755 --- a/bip-0110/test-vectors.py +++ b/bip-0110/test-vectors.py @@ -13,7 +13,8 @@ Coverage: Rule 1: output scriptPubKey size (<=34, or OP_RETURN <=83) [per-output] Rule 2: push / script-argument witness item size (<=256) - Rule 3: spending undefined witness / Tapleaf versions + Rule 3: spending undefined witness / Tapleaf versions (the P2A exemption + covers only spends with an empty witness stack) Rule 4: Taproot annex Rule 5: Taproot control block size (<=257) Rule 6: OP_SUCCESS* in tapscript @@ -255,17 +256,20 @@ def run_test(self): # P2WSH(OP_DROP OP_TRUE) lets us inject an arbitrary witness data element (rule 2) wsh_drop = CScript([OP_DROP, OP_TRUE]) wsh_drop_spk = script_to_p2wsh_script(wsh_drop) + p2a_spk = CScript([OP_1, bytes.fromhex("4e73")]) # Fund "old" UTXOs BEFORE activation so they are grandfathered (exempt # from the per-input script rules). Done first, at a low height. self.log.info("Funding pre-activation (grandfathered) UTXOs...") old_drop_o, old_drop_a, old_drop_h = self.fund(wsh_drop_spk) old_true_o, old_true_a, old_true_h = self.fund(wsh_true_spk) + old_p2a_o, old_p2a_a, old_p2a_h = self.fund(p2a_spk) self.log.info("Activating REDUCED_DATA...") self.activate() assert old_drop_h < self.activation_height assert old_true_h < self.activation_height + assert old_p2a_h < self.activation_height self.generate(self.wallet, 20) # spendable coins for funding "new" UTXOs self.log.info("=== Rule 1: output scriptPubKey size (per-output) ===") @@ -365,6 +369,21 @@ def run_test(self): self.check(7, "witness_v0_op_if_valid", "OP_IF in a witness v0 script is valid (rule is tapscript-only)", [(wsh_if_spk, a)], self.spend(o, a, [bytes(wsh_if)]), True, "post-activation") + # The rule 3 exemption for P2A covers only spends with an empty witness + # stack; any witness item makes the spend invalid (cf. BIP 433). + self.log.info("=== Rule 3: P2A witness stack must be empty ===") + o, a = self.fund(p2a_spk)[0:2] + self.check(3, "p2a_empty_witness_valid", "Spend a P2A output with an empty witness stack", + [(p2a_spk, a)], self.spend(o, a, []), True, "post-activation") + o, a = self.fund(p2a_spk)[0:2] + self.check(3, "p2a_empty_item_invalid", + "Spend a P2A output with one empty witness item (non-empty stack)", + [(p2a_spk, a)], self.spend(o, a, [b'']), False, "post-activation") + o, a = self.fund(p2a_spk)[0:2] + self.check(3, "p2a_one_byte_item_invalid", + "Spend a P2A output with one one-byte witness item", + [(p2a_spk, a)], self.spend(o, a, [b'\x01']), False, "post-activation") + self.log.info("=== Grandfathering: pre-activation UTXOs ===") # An input spending a pre-activation UTXO is exempt from the per-input # script rules: a 257-byte witness item is accepted here (cf. rule 2). @@ -373,6 +392,11 @@ def run_test(self): [(wsh_drop_spk, old_drop_a)], self.spend(old_drop_o, old_drop_a, [b'\x42' * 257, bytes(wsh_drop)]), True, "pre-activation") + self.check(3, "grandfathered_p2a_nonempty_witness_valid", + "Spend a PRE-activation P2A output with a non-empty witness stack (grandfathered, exempt)", + [(p2a_spk, old_p2a_a)], + self.spend(old_p2a_o, old_p2a_a, [b'\x01']), + True, "pre-activation") # But the per-output rule 1 still applies even when spending an old UTXO: # creating an oversized output is rejected regardless of input age. self.check(1, "grandfathered_input_oversized_output_invalid", From b01048ebee6a942b96a26acaed858d7c3636b4e0 Mon Sep 17 00:00:00 2001 From: Murch Date: Sun, 9 Aug 2026 08:46:25 -0700 Subject: [PATCH 3/3] =?UTF-8?q?bip110:=20Adopt=20John=20Moffett=E2=80=99s?= =?UTF-8?q?=20description=20of=20BIP433=20relationship?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: John Moffett <116917595+john-moffett@users.noreply.github.com> --- bip-0110.mediawiki | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bip-0110.mediawiki b/bip-0110.mediawiki index 542cbf4302..cb0bc354c9 100644 --- a/bip-0110.mediawiki +++ b/bip-0110.mediawiki @@ -44,7 +44,8 @@ For the purposes of rule 3, these are the witness versions (and the one Tapleaf * '''Witness v0''' with a 20-byte program (P2WPKH) or a 32-byte program (P2WSH), as defined in [[bip-0141.mediawiki|BIP 141]]. Other v0 program lengths are already invalid under BIP 141 itself. * '''Witness v1''' with a 32-byte program (Taproot/P2TR), as defined in [[bip-0341.mediawiki|BIP 341]]. In a script path spend, the only defined Tapleaf version is 0xc0 (Tapscript), as defined in [[bip-0342.mediawiki|BIP 342]]. -* '''Witness v1''' with the 2-byte program 0x4e73 (P2A), and only when spent with an empty witness stack, as defined in [[bip-0433.mediawiki#specification|BIP 433]]. + +* '''Witness v1''' with the 2-byte program 0x4e73 (P2A, as defined in [[bip-0433.mediawiki#specification|BIP 433]]), and only when spent with an empty witness stack. ===GetBlockTemplate===