|
|
@ -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): |
|
|
|
def setup_chain(self): |
|
|
|
def setup_chain(self): |
|
|
@ -1320,13 +1331,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 ]: |
|
|
@ -1440,7 +1444,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 |
|
|
|
|
|
|
|
|
|
|
@ -1703,6 +1707,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') |
|
|
@ -1884,6 +1992,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) |
|
|
|