[qa] Test that v0 segwit outputs can't be spent pre-activation
Also updates the comments for an existing test, that now should be rewritten. Includes changes suggested by John Newbery.
This commit is contained in:
parent
ccb8ca42a4
commit
8b56fc0b91
1 changed files with 84 additions and 4 deletions
|
@ -47,7 +47,7 @@ def test_transaction_acceptance(rpc, p2p, tx, with_witness, accepted, reason=Non
|
|||
with mininode_lock:
|
||||
assert_equal(p2p.last_message["reject"].reason, reason)
|
||||
|
||||
def test_witness_block(rpc, p2p, block, accepted, with_witness=True):
|
||||
def test_witness_block(rpc, p2p, block, accepted, with_witness=True, reason=None):
|
||||
"""Send a block to the node and check that it's accepted
|
||||
|
||||
- Submit the block over the p2p interface
|
||||
|
@ -58,6 +58,10 @@ def test_witness_block(rpc, p2p, block, accepted, with_witness=True):
|
|||
p2p.send_message(msg_block(block))
|
||||
p2p.sync_with_ping()
|
||||
assert_equal(rpc.getbestblockhash() == block.hash, accepted)
|
||||
if (reason != None and not accepted):
|
||||
# Check the rejection reason as well.
|
||||
with mininode_lock:
|
||||
assert_equal(p2p.last_message["reject"].reason, reason)
|
||||
|
||||
class TestP2PConn(P2PInterface):
|
||||
def __init__(self):
|
||||
|
@ -271,6 +275,80 @@ class SegWitTest(BitcoinTestFramework):
|
|||
self.utxo.pop(0)
|
||||
self.utxo.append(UTXO(tx4.sha256, 0, tx4.vout[0].nValue))
|
||||
|
||||
# ~6 months after segwit activation, the SCRIPT_VERIFY_WITNESS flag was
|
||||
# backdated so that it applies to all blocks, going back to the genesis
|
||||
# block.
|
||||
#
|
||||
# Consequently, version 0 witness outputs are never spendable without
|
||||
# witness, and so can't be spent before segwit activation (the point at which
|
||||
# blocks are permitted to contain witnesses).
|
||||
def test_v0_outputs_arent_spendable(self):
|
||||
self.log.info("Testing that v0 witness program outputs aren't spendable before activation")
|
||||
|
||||
assert len(self.utxo), "self.utxo is empty"
|
||||
|
||||
# Create two outputs, a p2wsh and p2sh-p2wsh
|
||||
witness_program = CScript([OP_TRUE])
|
||||
witness_hash = sha256(witness_program)
|
||||
scriptPubKey = CScript([OP_0, witness_hash])
|
||||
|
||||
p2sh_pubkey = hash160(scriptPubKey)
|
||||
p2sh_scriptPubKey = CScript([OP_HASH160, p2sh_pubkey, OP_EQUAL])
|
||||
|
||||
value = self.utxo[0].nValue // 3
|
||||
|
||||
tx = CTransaction()
|
||||
tx.vin = [CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b'')]
|
||||
tx.vout = [CTxOut(value, scriptPubKey), CTxOut(value, p2sh_scriptPubKey)]
|
||||
tx.vout.append(CTxOut(value, CScript([OP_TRUE])))
|
||||
tx.rehash()
|
||||
txid = tx.sha256
|
||||
|
||||
# Add it to a block
|
||||
block = self.build_next_block()
|
||||
self.update_witness_block_with_transactions(block, [tx])
|
||||
# Verify that segwit isn't activated. A block serialized with witness
|
||||
# should be rejected prior to activation.
|
||||
test_witness_block(self.nodes[0], self.test_node, block, accepted=False, with_witness=True, reason = b'unexpected-witness')
|
||||
# Now send the block without witness. It should be accepted
|
||||
test_witness_block(self.nodes[0], self.test_node, block, accepted=True, with_witness=False)
|
||||
|
||||
# Now try to spend the outputs. This should fail since SCRIPT_VERIFY_WITNESS is always enabled.
|
||||
p2wsh_tx = CTransaction()
|
||||
p2wsh_tx.vin = [CTxIn(COutPoint(txid, 0), b'')]
|
||||
p2wsh_tx.vout = [CTxOut(value, CScript([OP_TRUE]))]
|
||||
p2wsh_tx.wit.vtxinwit.append(CTxInWitness())
|
||||
p2wsh_tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])]
|
||||
p2wsh_tx.rehash()
|
||||
|
||||
p2sh_p2wsh_tx = CTransaction()
|
||||
p2sh_p2wsh_tx.vin = [CTxIn(COutPoint(txid, 1), CScript([scriptPubKey]))]
|
||||
p2sh_p2wsh_tx.vout = [CTxOut(value, CScript([OP_TRUE]))]
|
||||
p2sh_p2wsh_tx.wit.vtxinwit.append(CTxInWitness())
|
||||
p2sh_p2wsh_tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])]
|
||||
p2sh_p2wsh_tx.rehash()
|
||||
|
||||
for tx in [p2wsh_tx, p2sh_p2wsh_tx]:
|
||||
|
||||
block = self.build_next_block()
|
||||
self.update_witness_block_with_transactions(block, [tx])
|
||||
|
||||
# When the block is serialized with a witness, the block will be rejected because witness
|
||||
# data isn't allowed in blocks that don't commit to witness data.
|
||||
test_witness_block(self.nodes[0], self.test_node, block, accepted=False, with_witness=True, reason=b'unexpected-witness')
|
||||
|
||||
# When the block is serialized without witness, validation fails because the transaction is
|
||||
# invalid (transactions are always validated with SCRIPT_VERIFY_WITNESS so a segwit v0 transaction
|
||||
# without a witness is invalid).
|
||||
# Note: The reject reason for this failure could be
|
||||
# 'block-validation-failed' (if script check threads > 1) or
|
||||
# 'non-mandatory-script-verify-flag (Witness program was passed an
|
||||
# empty witness)' (otherwise).
|
||||
# TODO: support multiple acceptable reject reasons.
|
||||
test_witness_block(self.nodes[0], self.test_node, block, accepted=False, with_witness=False)
|
||||
|
||||
self.utxo.pop(0)
|
||||
self.utxo.append(UTXO(txid, 2, value))
|
||||
|
||||
# Mine enough blocks for segwit's vb state to be 'started'.
|
||||
def advance_to_segwit_started(self):
|
||||
|
@ -1476,9 +1554,10 @@ class SegWitTest(BitcoinTestFramework):
|
|||
block = self.build_next_block()
|
||||
self.update_witness_block_with_transactions(block, [spend_tx])
|
||||
|
||||
# If we're before activation, then sending this without witnesses
|
||||
# should be valid. If we're after activation, then sending this with
|
||||
# witnesses should be valid.
|
||||
# If we're after activation, then sending this with witnesses should be valid.
|
||||
# This no longer works before activation, because SCRIPT_VERIFY_WITNESS
|
||||
# is always set.
|
||||
# TODO: rewrite this test to make clear that it only works after activation.
|
||||
if segwit_activated:
|
||||
test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
|
||||
else:
|
||||
|
@ -1897,6 +1976,7 @@ class SegWitTest(BitcoinTestFramework):
|
|||
self.test_witness_services() # Verifies NODE_WITNESS
|
||||
self.test_non_witness_transaction() # non-witness tx's are accepted
|
||||
self.test_unnecessary_witness_before_segwit_activation()
|
||||
self.test_v0_outputs_arent_spendable()
|
||||
self.test_block_relay(segwit_activated=False)
|
||||
|
||||
# Advance to segwit being 'started'
|
||||
|
|
Loading…
Reference in a new issue