Skip to content

Commit 53133c1

Browse files
committed
Merge #8499: Add several policy limits and disable uncompressed keys for segwit scripts
67d6ee1 remove redundant tests in p2p-segwit.py (Johnson Lau) 9260085 test segwit uncompressed key fixes (Johnson Lau) 248f3a7 Fix ismine and addwitnessaddress: no uncompressed keys in segwit (Pieter Wuille) b811124 [qa] Add tests for uncompressed pubkeys in segwit (Suhas Daftuar) 9f0397a Make test framework produce lowS signatures (Johnson Lau) 4c0c25a Require compressed keys in segwit as policy and disable signing with uncompressed keys for segwit scripts (Johnson Lau) 3ade2f6 Add standard limits for P2WSH with tests (Johnson Lau)
2 parents 0329511 + 67d6ee1 commit 53133c1

File tree

18 files changed

+1329
-65
lines changed

18 files changed

+1329
-65
lines changed

qa/rpc-tests/p2p-segwit.py

Lines changed: 219 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,17 @@ def __init__(self, sha256, n, nValue):
166166
self.n = n
167167
self.nValue = nValue
168168

169+
# Helper for getting the script associated with a P2PKH
170+
def GetP2PKHScript(pubkeyhash):
171+
return CScript([CScriptOp(OP_DUP), CScriptOp(OP_HASH160), pubkeyhash, CScriptOp(OP_EQUALVERIFY), CScriptOp(OP_CHECKSIG)])
172+
173+
# Add signature for a P2PK witness program.
174+
def sign_P2PK_witness_input(script, txTo, inIdx, hashtype, value, key):
175+
tx_hash = SegwitVersion1SignatureHash(script, txTo, inIdx, hashtype, value)
176+
signature = key.sign(tx_hash) + chr(hashtype).encode('latin-1')
177+
txTo.wit.vtxinwit[inIdx].scriptWitness.stack = [signature, script]
178+
txTo.rehash()
179+
169180

170181
class SegWitTest(BitcoinTestFramework):
171182

@@ -1323,13 +1334,6 @@ def test_signature_version_1(self):
13231334
sync_blocks(self.nodes)
13241335
self.utxo.pop(0)
13251336

1326-
# Add signature for a P2PK witness program.
1327-
def sign_P2PK_witness_input(script, txTo, inIdx, hashtype, value, key):
1328-
tx_hash = SegwitVersion1SignatureHash(script, txTo, inIdx, hashtype, value)
1329-
signature = key.sign(tx_hash) + chr(hashtype).encode('latin-1')
1330-
txTo.wit.vtxinwit[inIdx].scriptWitness.stack = [signature, script]
1331-
txTo.rehash()
1332-
13331337
# Test each hashtype
13341338
prev_utxo = UTXO(tx.sha256, 0, tx.vout[0].nValue)
13351339
for sigflag in [ 0, SIGHASH_ANYONECANPAY ]:
@@ -1443,7 +1447,7 @@ def sign_P2PK_witness_input(script, txTo, inIdx, hashtype, value, key):
14431447
tx2.vin.append(CTxIn(COutPoint(tx.sha256, 0), b""))
14441448
tx2.vout.append(CTxOut(tx.vout[0].nValue, CScript([OP_TRUE])))
14451449

1446-
script = CScript([CScriptOp(OP_DUP), CScriptOp(OP_HASH160), pubkeyhash, CScriptOp(OP_EQUALVERIFY), CScriptOp(OP_CHECKSIG)])
1450+
script = GetP2PKHScript(pubkeyhash)
14471451
sig_hash = SegwitVersion1SignatureHash(script, tx2, 0, SIGHASH_ALL, tx.vout[0].nValue)
14481452
signature = key.sign(sig_hash) + b'\x01' # 0x1 is SIGHASH_ALL
14491453

@@ -1706,6 +1710,211 @@ def test_getblocktemplate_before_lockin(self):
17061710
assert(block_version & (1 << VB_WITNESS_BIT) != 0)
17071711
self.nodes[0].setmocktime(0) # undo mocktime
17081712

1713+
# Uncompressed pubkeys are no longer supported in default relay policy,
1714+
# but (for now) are still valid in blocks.
1715+
def test_uncompressed_pubkey(self):
1716+
print("\tTesting uncompressed pubkeys")
1717+
# Segwit transactions using uncompressed pubkeys are not accepted
1718+
# under default policy, but should still pass consensus.
1719+
key = CECKey()
1720+
key.set_secretbytes(b"9")
1721+
key.set_compressed(False)
1722+
pubkey = CPubKey(key.get_pubkey())
1723+
assert_equal(len(pubkey), 65) # This should be an uncompressed pubkey
1724+
1725+
assert(len(self.utxo) > 0)
1726+
utxo = self.utxo.pop(0)
1727+
1728+
# Test 1: P2WPKH
1729+
# First create a P2WPKH output that uses an uncompressed pubkey
1730+
pubkeyhash = hash160(pubkey)
1731+
scriptPKH = CScript([OP_0, pubkeyhash])
1732+
tx = CTransaction()
1733+
tx.vin.append(CTxIn(COutPoint(utxo.sha256, utxo.n), b""))
1734+
tx.vout.append(CTxOut(utxo.nValue-1000, scriptPKH))
1735+
tx.rehash()
1736+
1737+
# Confirm it in a block.
1738+
block = self.build_next_block()
1739+
self.update_witness_block_with_transactions(block, [tx])
1740+
self.test_node.test_witness_block(block, accepted=True)
1741+
1742+
# Now try to spend it. Send it to a P2WSH output, which we'll
1743+
# use in the next test.
1744+
witness_program = CScript([pubkey, CScriptOp(OP_CHECKSIG)])
1745+
witness_hash = sha256(witness_program)
1746+
scriptWSH = CScript([OP_0, witness_hash])
1747+
1748+
tx2 = CTransaction()
1749+
tx2.vin.append(CTxIn(COutPoint(tx.sha256, 0), b""))
1750+
tx2.vout.append(CTxOut(tx.vout[0].nValue-1000, scriptWSH))
1751+
script = GetP2PKHScript(pubkeyhash)
1752+
sig_hash = SegwitVersion1SignatureHash(script, tx2, 0, SIGHASH_ALL, tx.vout[0].nValue)
1753+
signature = key.sign(sig_hash) + b'\x01' # 0x1 is SIGHASH_ALL
1754+
tx2.wit.vtxinwit.append(CTxInWitness())
1755+
tx2.wit.vtxinwit[0].scriptWitness.stack = [ signature, pubkey ]
1756+
tx2.rehash()
1757+
1758+
# Should fail policy test.
1759+
self.test_node.test_transaction_acceptance(tx2, True, False, b'non-mandatory-script-verify-flag (Using non-compressed keys in segwit)')
1760+
# But passes consensus.
1761+
block = self.build_next_block()
1762+
self.update_witness_block_with_transactions(block, [tx2])
1763+
self.test_node.test_witness_block(block, accepted=True)
1764+
1765+
# Test 2: P2WSH
1766+
# Try to spend the P2WSH output created in last test.
1767+
# Send it to a P2SH(P2WSH) output, which we'll use in the next test.
1768+
p2sh_witness_hash = hash160(scriptWSH)
1769+
scriptP2SH = CScript([OP_HASH160, p2sh_witness_hash, OP_EQUAL])
1770+
scriptSig = CScript([scriptWSH])
1771+
1772+
tx3 = CTransaction()
1773+
tx3.vin.append(CTxIn(COutPoint(tx2.sha256, 0), b""))
1774+
tx3.vout.append(CTxOut(tx2.vout[0].nValue-1000, scriptP2SH))
1775+
tx3.wit.vtxinwit.append(CTxInWitness())
1776+
sign_P2PK_witness_input(witness_program, tx3, 0, SIGHASH_ALL, tx2.vout[0].nValue, key)
1777+
1778+
# Should fail policy test.
1779+
self.test_node.test_transaction_acceptance(tx3, True, False, b'non-mandatory-script-verify-flag (Using non-compressed keys in segwit)')
1780+
# But passes consensus.
1781+
block = self.build_next_block()
1782+
self.update_witness_block_with_transactions(block, [tx3])
1783+
self.test_node.test_witness_block(block, accepted=True)
1784+
1785+
# Test 3: P2SH(P2WSH)
1786+
# Try to spend the P2SH output created in the last test.
1787+
# Send it to a P2PKH output, which we'll use in the next test.
1788+
scriptPubKey = GetP2PKHScript(pubkeyhash)
1789+
tx4 = CTransaction()
1790+
tx4.vin.append(CTxIn(COutPoint(tx3.sha256, 0), scriptSig))
1791+
tx4.vout.append(CTxOut(tx3.vout[0].nValue-1000, scriptPubKey))
1792+
tx4.wit.vtxinwit.append(CTxInWitness())
1793+
sign_P2PK_witness_input(witness_program, tx4, 0, SIGHASH_ALL, tx3.vout[0].nValue, key)
1794+
1795+
# Should fail policy test.
1796+
self.test_node.test_transaction_acceptance(tx4, True, False, b'non-mandatory-script-verify-flag (Using non-compressed keys in segwit)')
1797+
block = self.build_next_block()
1798+
self.update_witness_block_with_transactions(block, [tx4])
1799+
self.test_node.test_witness_block(block, accepted=True)
1800+
1801+
# Test 4: Uncompressed pubkeys should still be valid in non-segwit
1802+
# transactions.
1803+
tx5 = CTransaction()
1804+
tx5.vin.append(CTxIn(COutPoint(tx4.sha256, 0), b""))
1805+
tx5.vout.append(CTxOut(tx4.vout[0].nValue-1000, CScript([OP_TRUE])))
1806+
(sig_hash, err) = SignatureHash(scriptPubKey, tx5, 0, SIGHASH_ALL)
1807+
signature = key.sign(sig_hash) + b'\x01' # 0x1 is SIGHASH_ALL
1808+
tx5.vin[0].scriptSig = CScript([signature, pubkey])
1809+
tx5.rehash()
1810+
# Should pass policy and consensus.
1811+
self.test_node.test_transaction_acceptance(tx5, True, True)
1812+
block = self.build_next_block()
1813+
self.update_witness_block_with_transactions(block, [tx5])
1814+
self.test_node.test_witness_block(block, accepted=True)
1815+
self.utxo.append(UTXO(tx5.sha256, 0, tx5.vout[0].nValue))
1816+
1817+
def test_non_standard_witness(self):
1818+
print("\tTesting detection of non-standard P2WSH witness")
1819+
pad = chr(1).encode('latin-1')
1820+
1821+
# Create scripts for tests
1822+
scripts = []
1823+
scripts.append(CScript([OP_DROP] * 100))
1824+
scripts.append(CScript([OP_DROP] * 99))
1825+
scripts.append(CScript([pad * 59] * 59 + [OP_DROP] * 60))
1826+
scripts.append(CScript([pad * 59] * 59 + [OP_DROP] * 61))
1827+
1828+
p2wsh_scripts = []
1829+
1830+
assert(len(self.utxo))
1831+
tx = CTransaction()
1832+
tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b""))
1833+
1834+
# For each script, generate a pair of P2WSH and P2SH-P2WSH output.
1835+
outputvalue = (self.utxo[0].nValue - 1000) // (len(scripts) * 2)
1836+
for i in scripts:
1837+
p2wsh = CScript([OP_0, sha256(i)])
1838+
p2sh = hash160(p2wsh)
1839+
p2wsh_scripts.append(p2wsh)
1840+
tx.vout.append(CTxOut(outputvalue, p2wsh))
1841+
tx.vout.append(CTxOut(outputvalue, CScript([OP_HASH160, p2sh, OP_EQUAL])))
1842+
tx.rehash()
1843+
txid = tx.sha256
1844+
self.test_node.test_transaction_acceptance(tx, with_witness=False, accepted=True)
1845+
1846+
self.nodes[0].generate(1)
1847+
sync_blocks(self.nodes)
1848+
1849+
# Creating transactions for tests
1850+
p2wsh_txs = []
1851+
p2sh_txs = []
1852+
for i in range(len(scripts)):
1853+
p2wsh_tx = CTransaction()
1854+
p2wsh_tx.vin.append(CTxIn(COutPoint(txid,i*2)))
1855+
p2wsh_tx.vout.append(CTxOut(outputvalue - 5000, CScript([OP_0, hash160(hex_str_to_bytes(""))])))
1856+
p2wsh_tx.wit.vtxinwit.append(CTxInWitness())
1857+
p2wsh_tx.rehash()
1858+
p2wsh_txs.append(p2wsh_tx)
1859+
p2sh_tx = CTransaction()
1860+
p2sh_tx.vin.append(CTxIn(COutPoint(txid,i*2+1), CScript([p2wsh_scripts[i]])))
1861+
p2sh_tx.vout.append(CTxOut(outputvalue - 5000, CScript([OP_0, hash160(hex_str_to_bytes(""))])))
1862+
p2sh_tx.wit.vtxinwit.append(CTxInWitness())
1863+
p2sh_tx.rehash()
1864+
p2sh_txs.append(p2sh_tx)
1865+
1866+
# Testing native P2WSH
1867+
# Witness stack size, excluding witnessScript, over 100 is non-standard
1868+
p2wsh_txs[0].wit.vtxinwit[0].scriptWitness.stack = [pad] * 101 + [scripts[0]]
1869+
self.std_node.test_transaction_acceptance(p2wsh_txs[0], True, False, b'bad-witness-nonstandard')
1870+
# Non-standard nodes should accept
1871+
self.test_node.test_transaction_acceptance(p2wsh_txs[0], True, True)
1872+
1873+
# Stack element size over 80 bytes is non-standard
1874+
p2wsh_txs[1].wit.vtxinwit[0].scriptWitness.stack = [pad * 81] * 100 + [scripts[1]]
1875+
self.std_node.test_transaction_acceptance(p2wsh_txs[1], True, False, b'bad-witness-nonstandard')
1876+
# Non-standard nodes should accept
1877+
self.test_node.test_transaction_acceptance(p2wsh_txs[1], True, True)
1878+
# Standard nodes should accept if element size is not over 80 bytes
1879+
p2wsh_txs[1].wit.vtxinwit[0].scriptWitness.stack = [pad * 80] * 100 + [scripts[1]]
1880+
self.std_node.test_transaction_acceptance(p2wsh_txs[1], True, True)
1881+
1882+
# witnessScript size at 3600 bytes is standard
1883+
p2wsh_txs[2].wit.vtxinwit[0].scriptWitness.stack = [pad, pad, scripts[2]]
1884+
self.test_node.test_transaction_acceptance(p2wsh_txs[2], True, True)
1885+
self.std_node.test_transaction_acceptance(p2wsh_txs[2], True, True)
1886+
1887+
# witnessScript size at 3601 bytes is non-standard
1888+
p2wsh_txs[3].wit.vtxinwit[0].scriptWitness.stack = [pad, pad, pad, scripts[3]]
1889+
self.std_node.test_transaction_acceptance(p2wsh_txs[3], True, False, b'bad-witness-nonstandard')
1890+
# Non-standard nodes should accept
1891+
self.test_node.test_transaction_acceptance(p2wsh_txs[3], True, True)
1892+
1893+
# Repeating the same tests with P2SH-P2WSH
1894+
p2sh_txs[0].wit.vtxinwit[0].scriptWitness.stack = [pad] * 101 + [scripts[0]]
1895+
self.std_node.test_transaction_acceptance(p2sh_txs[0], True, False, b'bad-witness-nonstandard')
1896+
self.test_node.test_transaction_acceptance(p2sh_txs[0], True, True)
1897+
p2sh_txs[1].wit.vtxinwit[0].scriptWitness.stack = [pad * 81] * 100 + [scripts[1]]
1898+
self.std_node.test_transaction_acceptance(p2sh_txs[1], True, False, b'bad-witness-nonstandard')
1899+
self.test_node.test_transaction_acceptance(p2sh_txs[1], True, True)
1900+
p2sh_txs[1].wit.vtxinwit[0].scriptWitness.stack = [pad * 80] * 100 + [scripts[1]]
1901+
self.std_node.test_transaction_acceptance(p2sh_txs[1], True, True)
1902+
p2sh_txs[2].wit.vtxinwit[0].scriptWitness.stack = [pad, pad, scripts[2]]
1903+
self.test_node.test_transaction_acceptance(p2sh_txs[2], True, True)
1904+
self.std_node.test_transaction_acceptance(p2sh_txs[2], True, True)
1905+
p2sh_txs[3].wit.vtxinwit[0].scriptWitness.stack = [pad, pad, pad, scripts[3]]
1906+
self.std_node.test_transaction_acceptance(p2sh_txs[3], True, False, b'bad-witness-nonstandard')
1907+
self.test_node.test_transaction_acceptance(p2sh_txs[3], True, True)
1908+
1909+
self.nodes[0].generate(1) # Mine and clean up the mempool of non-standard node
1910+
# Valid but non-standard transactions in a block should be accepted by standard node
1911+
sync_blocks(self.nodes)
1912+
assert_equal(len(self.nodes[0].getrawmempool()), 0)
1913+
assert_equal(len(self.nodes[1].getrawmempool()), 0)
1914+
1915+
self.utxo.pop(0)
1916+
1917+
17091918
def run_test(self):
17101919
# Setup the p2p connections and start up the network thread.
17111920
self.test_node = TestNode() # sets NODE_WITNESS|NODE_NETWORK
@@ -1777,7 +1986,9 @@ def run_test(self):
17771986
self.test_standardness_v0(segwit_activated=True)
17781987
self.test_segwit_versions()
17791988
self.test_premature_coinbase_witness_spend()
1989+
self.test_uncompressed_pubkey()
17801990
self.test_signature_version_1()
1991+
self.test_non_standard_witness()
17811992
sync_blocks(self.nodes)
17821993
if self.test_upgrade:
17831994
self.test_upgrade_after_activation(self.nodes[2], 2)

0 commit comments

Comments
 (0)