|
|
@ -166,6 +166,17 @@ class UTXO(object):
|
|
|
|
self.n = n
|
|
|
|
self.n = n
|
|
|
|
self.nValue = nValue
|
|
|
|
self.nValue = nValue
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Helper for getting the script associated with a P2PKH
|
|
|
|
|
|
|
|
def GetP2PKHScript(pubkeyhash):
|
|
|
|
|
|
|
|
return CScript([CScriptOp(OP_DUP), CScriptOp(OP_HASH160), pubkeyhash, CScriptOp(OP_EQUALVERIFY), CScriptOp(OP_CHECKSIG)])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Add signature for a P2PK witness program.
|
|
|
|
|
|
|
|
def sign_P2PK_witness_input(script, txTo, inIdx, hashtype, value, key):
|
|
|
|
|
|
|
|
tx_hash = SegwitVersion1SignatureHash(script, txTo, inIdx, hashtype, value)
|
|
|
|
|
|
|
|
signature = key.sign(tx_hash) + chr(hashtype).encode('latin-1')
|
|
|
|
|
|
|
|
txTo.wit.vtxinwit[inIdx].scriptWitness.stack = [signature, script]
|
|
|
|
|
|
|
|
txTo.rehash()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SegWitTest(BitcoinTestFramework):
|
|
|
|
class SegWitTest(BitcoinTestFramework):
|
|
|
|
|
|
|
|
|
|
|
@ -1323,13 +1334,6 @@ class SegWitTest(BitcoinTestFramework):
|
|
|
|
sync_blocks(self.nodes)
|
|
|
|
sync_blocks(self.nodes)
|
|
|
|
self.utxo.pop(0)
|
|
|
|
self.utxo.pop(0)
|
|
|
|
|
|
|
|
|
|
|
|
# Add signature for a P2PK witness program.
|
|
|
|
|
|
|
|
def sign_P2PK_witness_input(script, txTo, inIdx, hashtype, value, key):
|
|
|
|
|
|
|
|
tx_hash = SegwitVersion1SignatureHash(script, txTo, inIdx, hashtype, value)
|
|
|
|
|
|
|
|
signature = key.sign(tx_hash) + chr(hashtype).encode('latin-1')
|
|
|
|
|
|
|
|
txTo.wit.vtxinwit[inIdx].scriptWitness.stack = [signature, script]
|
|
|
|
|
|
|
|
txTo.rehash()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Test each hashtype
|
|
|
|
# Test each hashtype
|
|
|
|
prev_utxo = UTXO(tx.sha256, 0, tx.vout[0].nValue)
|
|
|
|
prev_utxo = UTXO(tx.sha256, 0, tx.vout[0].nValue)
|
|
|
|
for sigflag in [ 0, SIGHASH_ANYONECANPAY ]:
|
|
|
|
for sigflag in [ 0, SIGHASH_ANYONECANPAY ]:
|
|
|
@ -1443,7 +1447,7 @@ class SegWitTest(BitcoinTestFramework):
|
|
|
|
tx2.vin.append(CTxIn(COutPoint(tx.sha256, 0), b""))
|
|
|
|
tx2.vin.append(CTxIn(COutPoint(tx.sha256, 0), b""))
|
|
|
|
tx2.vout.append(CTxOut(tx.vout[0].nValue, CScript([OP_TRUE])))
|
|
|
|
tx2.vout.append(CTxOut(tx.vout[0].nValue, CScript([OP_TRUE])))
|
|
|
|
|
|
|
|
|
|
|
|
script = CScript([CScriptOp(OP_DUP), CScriptOp(OP_HASH160), pubkeyhash, CScriptOp(OP_EQUALVERIFY), CScriptOp(OP_CHECKSIG)])
|
|
|
|
script = GetP2PKHScript(pubkeyhash)
|
|
|
|
sig_hash = SegwitVersion1SignatureHash(script, tx2, 0, SIGHASH_ALL, tx.vout[0].nValue)
|
|
|
|
sig_hash = SegwitVersion1SignatureHash(script, tx2, 0, SIGHASH_ALL, tx.vout[0].nValue)
|
|
|
|
signature = key.sign(sig_hash) + b'\x01' # 0x1 is SIGHASH_ALL
|
|
|
|
signature = key.sign(sig_hash) + b'\x01' # 0x1 is SIGHASH_ALL
|
|
|
|
|
|
|
|
|
|
|
@ -1706,6 +1710,110 @@ class SegWitTest(BitcoinTestFramework):
|
|
|
|
assert(block_version & (1 << VB_WITNESS_BIT) != 0)
|
|
|
|
assert(block_version & (1 << VB_WITNESS_BIT) != 0)
|
|
|
|
self.nodes[0].setmocktime(0) # undo mocktime
|
|
|
|
self.nodes[0].setmocktime(0) # undo mocktime
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Uncompressed pubkeys are no longer supported in default relay policy,
|
|
|
|
|
|
|
|
# but (for now) are still valid in blocks.
|
|
|
|
|
|
|
|
def test_uncompressed_pubkey(self):
|
|
|
|
|
|
|
|
print("\tTesting uncompressed pubkeys")
|
|
|
|
|
|
|
|
# Segwit transactions using uncompressed pubkeys are not accepted
|
|
|
|
|
|
|
|
# under default policy, but should still pass consensus.
|
|
|
|
|
|
|
|
key = CECKey()
|
|
|
|
|
|
|
|
key.set_secretbytes(b"9")
|
|
|
|
|
|
|
|
key.set_compressed(False)
|
|
|
|
|
|
|
|
pubkey = CPubKey(key.get_pubkey())
|
|
|
|
|
|
|
|
assert_equal(len(pubkey), 65) # This should be an uncompressed pubkey
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assert(len(self.utxo) > 0)
|
|
|
|
|
|
|
|
utxo = self.utxo.pop(0)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Test 1: P2WPKH
|
|
|
|
|
|
|
|
# First create a P2WPKH output that uses an uncompressed pubkey
|
|
|
|
|
|
|
|
pubkeyhash = hash160(pubkey)
|
|
|
|
|
|
|
|
scriptPKH = CScript([OP_0, pubkeyhash])
|
|
|
|
|
|
|
|
tx = CTransaction()
|
|
|
|
|
|
|
|
tx.vin.append(CTxIn(COutPoint(utxo.sha256, utxo.n), b""))
|
|
|
|
|
|
|
|
tx.vout.append(CTxOut(utxo.nValue-1000, scriptPKH))
|
|
|
|
|
|
|
|
tx.rehash()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Confirm it in a block.
|
|
|
|
|
|
|
|
block = self.build_next_block()
|
|
|
|
|
|
|
|
self.update_witness_block_with_transactions(block, [tx])
|
|
|
|
|
|
|
|
self.test_node.test_witness_block(block, accepted=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Now try to spend it. Send it to a P2WSH output, which we'll
|
|
|
|
|
|
|
|
# use in the next test.
|
|
|
|
|
|
|
|
witness_program = CScript([pubkey, CScriptOp(OP_CHECKSIG)])
|
|
|
|
|
|
|
|
witness_hash = sha256(witness_program)
|
|
|
|
|
|
|
|
scriptWSH = CScript([OP_0, witness_hash])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tx2 = CTransaction()
|
|
|
|
|
|
|
|
tx2.vin.append(CTxIn(COutPoint(tx.sha256, 0), b""))
|
|
|
|
|
|
|
|
tx2.vout.append(CTxOut(tx.vout[0].nValue-1000, scriptWSH))
|
|
|
|
|
|
|
|
script = GetP2PKHScript(pubkeyhash)
|
|
|
|
|
|
|
|
sig_hash = SegwitVersion1SignatureHash(script, tx2, 0, SIGHASH_ALL, tx.vout[0].nValue)
|
|
|
|
|
|
|
|
signature = key.sign(sig_hash) + b'\x01' # 0x1 is SIGHASH_ALL
|
|
|
|
|
|
|
|
tx2.wit.vtxinwit.append(CTxInWitness())
|
|
|
|
|
|
|
|
tx2.wit.vtxinwit[0].scriptWitness.stack = [ signature, pubkey ]
|
|
|
|
|
|
|
|
tx2.rehash()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Should fail policy test.
|
|
|
|
|
|
|
|
self.test_node.test_transaction_acceptance(tx2, True, False, b'non-mandatory-script-verify-flag (Using non-compressed keys in segwit)')
|
|
|
|
|
|
|
|
# But passes consensus.
|
|
|
|
|
|
|
|
block = self.build_next_block()
|
|
|
|
|
|
|
|
self.update_witness_block_with_transactions(block, [tx2])
|
|
|
|
|
|
|
|
self.test_node.test_witness_block(block, accepted=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Test 2: P2WSH
|
|
|
|
|
|
|
|
# Try to spend the P2WSH output created in last test.
|
|
|
|
|
|
|
|
# Send it to a P2SH(P2WSH) output, which we'll use in the next test.
|
|
|
|
|
|
|
|
p2sh_witness_hash = hash160(scriptWSH)
|
|
|
|
|
|
|
|
scriptP2SH = CScript([OP_HASH160, p2sh_witness_hash, OP_EQUAL])
|
|
|
|
|
|
|
|
scriptSig = CScript([scriptWSH])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tx3 = CTransaction()
|
|
|
|
|
|
|
|
tx3.vin.append(CTxIn(COutPoint(tx2.sha256, 0), b""))
|
|
|
|
|
|
|
|
tx3.vout.append(CTxOut(tx2.vout[0].nValue-1000, scriptP2SH))
|
|
|
|
|
|
|
|
tx3.wit.vtxinwit.append(CTxInWitness())
|
|
|
|
|
|
|
|
sign_P2PK_witness_input(witness_program, tx3, 0, SIGHASH_ALL, tx2.vout[0].nValue, key)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Should fail policy test.
|
|
|
|
|
|
|
|
self.test_node.test_transaction_acceptance(tx3, True, False, b'non-mandatory-script-verify-flag (Using non-compressed keys in segwit)')
|
|
|
|
|
|
|
|
# But passes consensus.
|
|
|
|
|
|
|
|
block = self.build_next_block()
|
|
|
|
|
|
|
|
self.update_witness_block_with_transactions(block, [tx3])
|
|
|
|
|
|
|
|
self.test_node.test_witness_block(block, accepted=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Test 3: P2SH(P2WSH)
|
|
|
|
|
|
|
|
# Try to spend the P2SH output created in the last test.
|
|
|
|
|
|
|
|
# Send it to a P2PKH output, which we'll use in the next test.
|
|
|
|
|
|
|
|
scriptPubKey = GetP2PKHScript(pubkeyhash)
|
|
|
|
|
|
|
|
tx4 = CTransaction()
|
|
|
|
|
|
|
|
tx4.vin.append(CTxIn(COutPoint(tx3.sha256, 0), scriptSig))
|
|
|
|
|
|
|
|
tx4.vout.append(CTxOut(tx3.vout[0].nValue-1000, scriptPubKey))
|
|
|
|
|
|
|
|
tx4.wit.vtxinwit.append(CTxInWitness())
|
|
|
|
|
|
|
|
sign_P2PK_witness_input(witness_program, tx4, 0, SIGHASH_ALL, tx3.vout[0].nValue, key)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Should fail policy test.
|
|
|
|
|
|
|
|
self.test_node.test_transaction_acceptance(tx4, True, False, b'non-mandatory-script-verify-flag (Using non-compressed keys in segwit)')
|
|
|
|
|
|
|
|
block = self.build_next_block()
|
|
|
|
|
|
|
|
self.update_witness_block_with_transactions(block, [tx4])
|
|
|
|
|
|
|
|
self.test_node.test_witness_block(block, accepted=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Test 4: Uncompressed pubkeys should still be valid in non-segwit
|
|
|
|
|
|
|
|
# transactions.
|
|
|
|
|
|
|
|
tx5 = CTransaction()
|
|
|
|
|
|
|
|
tx5.vin.append(CTxIn(COutPoint(tx4.sha256, 0), b""))
|
|
|
|
|
|
|
|
tx5.vout.append(CTxOut(tx4.vout[0].nValue-1000, CScript([OP_TRUE])))
|
|
|
|
|
|
|
|
(sig_hash, err) = SignatureHash(scriptPubKey, tx5, 0, SIGHASH_ALL)
|
|
|
|
|
|
|
|
signature = key.sign(sig_hash) + b'\x01' # 0x1 is SIGHASH_ALL
|
|
|
|
|
|
|
|
tx5.vin[0].scriptSig = CScript([signature, pubkey])
|
|
|
|
|
|
|
|
tx5.rehash()
|
|
|
|
|
|
|
|
# Should pass policy and consensus.
|
|
|
|
|
|
|
|
self.test_node.test_transaction_acceptance(tx5, True, True)
|
|
|
|
|
|
|
|
block = self.build_next_block()
|
|
|
|
|
|
|
|
self.update_witness_block_with_transactions(block, [tx5])
|
|
|
|
|
|
|
|
self.test_node.test_witness_block(block, accepted=True)
|
|
|
|
|
|
|
|
self.utxo.append(UTXO(tx5.sha256, 0, tx5.vout[0].nValue))
|
|
|
|
|
|
|
|
|
|
|
|
def test_non_standard_witness(self):
|
|
|
|
def test_non_standard_witness(self):
|
|
|
|
print("\tTesting detection of non-standard P2WSH witness")
|
|
|
|
print("\tTesting detection of non-standard P2WSH witness")
|
|
|
|
pad = chr(1).encode('latin-1')
|
|
|
|
pad = chr(1).encode('latin-1')
|
|
|
@ -1887,6 +1995,7 @@ class SegWitTest(BitcoinTestFramework):
|
|
|
|
self.test_standardness_v0(segwit_activated=True)
|
|
|
|
self.test_standardness_v0(segwit_activated=True)
|
|
|
|
self.test_segwit_versions()
|
|
|
|
self.test_segwit_versions()
|
|
|
|
self.test_premature_coinbase_witness_spend()
|
|
|
|
self.test_premature_coinbase_witness_spend()
|
|
|
|
|
|
|
|
self.test_uncompressed_pubkey()
|
|
|
|
self.test_signature_version_1()
|
|
|
|
self.test_signature_version_1()
|
|
|
|
self.test_non_standard_witness()
|
|
|
|
self.test_non_standard_witness()
|
|
|
|
sync_blocks(self.nodes)
|
|
|
|
sync_blocks(self.nodes)
|
|
|
|