diff --git a/bip-0110/test-vectors.json b/bip-0110/test-vectors.json index 80124af7..f45e87b9 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 1644bdf2..03d39228 100755 --- a/bip-0110/test-vectors.py +++ b/bip-0110/test-vectors.py @@ -13,7 +13,8 @@ exact same vectors can be replayed against any other implementation. 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 @@ class ReducedDataTestVectors(BitcoinTestFramework): # 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 @@ class ReducedDataTestVectors(BitcoinTestFramework): 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 @@ class ReducedDataTestVectors(BitcoinTestFramework): [(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",