Skip to content

Commit 540413d

Browse files
jl2012laanwj
authored andcommitted
Add standard limits for P2WSH with tests
Github-Pull: #8499 Rebased-From: 3ade2f6
1 parent 9bb2a02 commit 540413d

File tree

4 files changed

+181
-2
lines changed

4 files changed

+181
-2
lines changed

qa/rpc-tests/p2p-segwit.py

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1703,6 +1703,116 @@ def test_getblocktemplate_before_lockin(self):
17031703
assert(block_version & (1 << VB_WITNESS_BIT) != 0)
17041704
self.nodes[0].setmocktime(0) # undo mocktime
17051705

1706+
def test_non_standard_witness(self):
1707+
print("\tTesting detection of non-standard P2WSH witness")
1708+
pad = chr(1).encode('latin-1')
1709+
1710+
# Create scripts for tests
1711+
scripts = []
1712+
scripts.append(CScript([OP_DROP] * 100))
1713+
scripts.append(CScript([OP_DROP] * 99))
1714+
scripts.append(CScript([pad * 59] * 59 + [OP_DROP] * 60))
1715+
scripts.append(CScript([pad * 59] * 59 + [OP_DROP] * 61))
1716+
1717+
p2wsh_scripts = []
1718+
1719+
assert(len(self.utxo))
1720+
tx = CTransaction()
1721+
tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b""))
1722+
1723+
# For each script, generate a pair of P2WSH and P2SH-P2WSH output.
1724+
outputvalue = (self.utxo[0].nValue - 1000) // (len(scripts) * 2)
1725+
for i in scripts:
1726+
p2wsh = CScript([OP_0, sha256(i)])
1727+
p2sh = hash160(p2wsh)
1728+
p2wsh_scripts.append(p2wsh)
1729+
tx.vout.append(CTxOut(outputvalue, p2wsh))
1730+
tx.vout.append(CTxOut(outputvalue, CScript([OP_HASH160, p2sh, OP_EQUAL])))
1731+
tx.rehash()
1732+
txid = tx.sha256
1733+
self.test_node.test_transaction_acceptance(tx, with_witness=False, accepted=True)
1734+
1735+
self.nodes[0].generate(1)
1736+
sync_blocks(self.nodes)
1737+
1738+
# Creating transactions for tests
1739+
p2wsh_txs = []
1740+
p2sh_txs = []
1741+
for i in range(len(scripts)):
1742+
p2wsh_tx = CTransaction()
1743+
p2wsh_tx.vin.append(CTxIn(COutPoint(txid,i*2)))
1744+
p2wsh_tx.vout.append(CTxOut(outputvalue - 5000, CScript([OP_0, hash160(hex_str_to_bytes(""))])))
1745+
p2wsh_tx.wit.vtxinwit.append(CTxInWitness())
1746+
p2wsh_tx.rehash()
1747+
p2wsh_txs.append(p2wsh_tx)
1748+
p2sh_tx = CTransaction()
1749+
p2sh_tx.vin.append(CTxIn(COutPoint(txid,i*2+1), CScript([p2wsh_scripts[i]])))
1750+
p2sh_tx.vout.append(CTxOut(outputvalue - 5000, CScript([OP_0, hash160(hex_str_to_bytes(""))])))
1751+
p2sh_tx.wit.vtxinwit.append(CTxInWitness())
1752+
p2sh_tx.rehash()
1753+
p2sh_txs.append(p2sh_tx)
1754+
1755+
# Testing native P2WSH
1756+
# Witness stack size, excluding witnessScript, over 100 is non-standard
1757+
p2wsh_txs[0].wit.vtxinwit[0].scriptWitness.stack = [pad] * 101 + [scripts[0]]
1758+
self.std_node.test_transaction_acceptance(p2wsh_txs[0], True, False, b'bad-witness-nonstandard')
1759+
# Non-standard nodes should accept
1760+
self.test_node.test_transaction_acceptance(p2wsh_txs[0], True, True)
1761+
1762+
# Stack element size over 80 bytes is non-standard
1763+
p2wsh_txs[1].wit.vtxinwit[0].scriptWitness.stack = [pad * 81] * 100 + [scripts[1]]
1764+
# It can't be used to blind a node to the transaction
1765+
self.std_node.announce_tx_and_wait_for_getdata(p2wsh_txs[1])
1766+
self.std_node.test_transaction_acceptance(p2wsh_txs[1], True, False, b'bad-witness-nonstandard')
1767+
self.std_node.announce_tx_and_wait_for_getdata(p2wsh_txs[1])
1768+
self.std_node.test_transaction_acceptance(p2wsh_txs[1], True, False, b'bad-witness-nonstandard')
1769+
# Non-standard nodes should accept
1770+
self.test_node.test_transaction_acceptance(p2wsh_txs[1], True, True)
1771+
# Standard nodes should accept if element size is not over 80 bytes
1772+
p2wsh_txs[1].wit.vtxinwit[0].scriptWitness.stack = [pad * 80] * 100 + [scripts[1]]
1773+
self.std_node.announce_tx_and_wait_for_getdata(p2wsh_txs[1])
1774+
self.std_node.test_transaction_acceptance(p2wsh_txs[1], True, True)
1775+
1776+
# witnessScript size at 3600 bytes is standard
1777+
p2wsh_txs[2].wit.vtxinwit[0].scriptWitness.stack = [pad, pad, scripts[2]]
1778+
self.test_node.test_transaction_acceptance(p2wsh_txs[2], True, True)
1779+
self.std_node.test_transaction_acceptance(p2wsh_txs[2], True, True)
1780+
1781+
# witnessScript size at 3601 bytes is non-standard
1782+
p2wsh_txs[3].wit.vtxinwit[0].scriptWitness.stack = [pad, pad, pad, scripts[3]]
1783+
self.std_node.test_transaction_acceptance(p2wsh_txs[3], True, False, b'bad-witness-nonstandard')
1784+
# Non-standard nodes should accept
1785+
self.test_node.test_transaction_acceptance(p2wsh_txs[3], True, True)
1786+
1787+
# Repeating the same tests with P2SH-P2WSH
1788+
p2sh_txs[0].wit.vtxinwit[0].scriptWitness.stack = [pad] * 101 + [scripts[0]]
1789+
self.std_node.test_transaction_acceptance(p2sh_txs[0], True, False, b'bad-witness-nonstandard')
1790+
self.test_node.test_transaction_acceptance(p2sh_txs[0], True, True)
1791+
p2sh_txs[1].wit.vtxinwit[0].scriptWitness.stack = [pad * 81] * 100 + [scripts[1]]
1792+
self.std_node.announce_tx_and_wait_for_getdata(p2sh_txs[1])
1793+
self.std_node.test_transaction_acceptance(p2sh_txs[1], True, False, b'bad-witness-nonstandard')
1794+
self.std_node.announce_tx_and_wait_for_getdata(p2sh_txs[1])
1795+
self.std_node.test_transaction_acceptance(p2sh_txs[1], True, False, b'bad-witness-nonstandard')
1796+
self.test_node.test_transaction_acceptance(p2sh_txs[1], True, True)
1797+
p2sh_txs[1].wit.vtxinwit[0].scriptWitness.stack = [pad * 80] * 100 + [scripts[1]]
1798+
self.std_node.announce_tx_and_wait_for_getdata(p2sh_txs[1])
1799+
self.std_node.test_transaction_acceptance(p2sh_txs[1], True, True)
1800+
p2sh_txs[2].wit.vtxinwit[0].scriptWitness.stack = [pad, pad, scripts[2]]
1801+
self.test_node.test_transaction_acceptance(p2sh_txs[2], True, True)
1802+
self.std_node.test_transaction_acceptance(p2sh_txs[2], True, True)
1803+
p2sh_txs[3].wit.vtxinwit[0].scriptWitness.stack = [pad, pad, pad, scripts[3]]
1804+
self.std_node.test_transaction_acceptance(p2sh_txs[3], True, False, b'bad-witness-nonstandard')
1805+
self.test_node.test_transaction_acceptance(p2sh_txs[3], True, True)
1806+
1807+
self.nodes[0].generate(1) # Mine and clean up the mempool of non-standard node
1808+
# Valid but non-standard transactions in a block should be accepted by standard node
1809+
sync_blocks(self.nodes)
1810+
assert_equal(len(self.nodes[0].getrawmempool()), 0)
1811+
assert_equal(len(self.nodes[1].getrawmempool()), 0)
1812+
1813+
self.utxo.pop(0)
1814+
1815+
17061816
def run_test(self):
17071817
# Setup the p2p connections and start up the network thread.
17081818
self.test_node = TestNode() # sets NODE_WITNESS|NODE_NETWORK
@@ -1775,6 +1885,7 @@ def run_test(self):
17751885
self.test_segwit_versions()
17761886
self.test_premature_coinbase_witness_spend()
17771887
self.test_signature_version_1()
1888+
self.test_non_standard_witness()
17781889
sync_blocks(self.nodes)
17791890
if self.test_upgrade:
17801891
self.test_upgrade_after_activation(self.nodes[2], 2)

src/main.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// Copyright (c) 2009-2010 Satoshi Nakamoto
2-
// Copyright (c) 2009-2015 The Bitcoin Core developers
2+
// Copyright (c) 2009-2016 The Bitcoin Core developers
33
// Distributed under the MIT software license, see the accompanying
44
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
55

@@ -1282,6 +1282,10 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
12821282
if (fRequireStandard && !AreInputsStandard(tx, view))
12831283
return state.Invalid(false, REJECT_NONSTANDARD, "bad-txns-nonstandard-inputs");
12841284

1285+
// Check for non-standard witness in P2WSH
1286+
if (!tx.wit.IsNull() && fRequireStandard && !IsWitnessStandard(tx, view))
1287+
return state.DoS(0, false, REJECT_NONSTANDARD, "bad-witness-nonstandard", true);
1288+
12851289
int64_t nSigOpsCost = GetTransactionSigOpCost(tx, view, STANDARD_SCRIPT_VERIFY_FLAGS);
12861290

12871291
CAmount nValueOut = tx.GetValueOut();

src/policy/policy.cpp

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// Copyright (c) 2009-2010 Satoshi Nakamoto
2-
// Copyright (c) 2009-2015 The Bitcoin developers
2+
// Copyright (c) 2009-2016 The Bitcoin developers
33
// Distributed under the MIT software license, see the accompanying
44
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
55

@@ -154,6 +154,58 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
154154
return true;
155155
}
156156

157+
bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
158+
{
159+
if (tx.IsCoinBase())
160+
return true; // Coinbases are skipped
161+
162+
for (unsigned int i = 0; i < tx.vin.size(); i++)
163+
{
164+
// We don't care if witness for this input is empty, since it must not be bloated.
165+
// If the script is invalid without witness, it would be caught sooner or later during validation.
166+
if (tx.wit.vtxinwit[i].IsNull())
167+
continue;
168+
169+
const CTxOut &prev = mapInputs.GetOutputFor(tx.vin[i]);
170+
171+
// get the scriptPubKey corresponding to this input:
172+
CScript prevScript = prev.scriptPubKey;
173+
174+
if (prevScript.IsPayToScriptHash()) {
175+
std::vector <std::vector<unsigned char> > stack;
176+
// If the scriptPubKey is P2SH, we try to extract the redeemScript casually by converting the scriptSig
177+
// into a stack. We do not check IsPushOnly nor compare the hash as these will be done later anyway.
178+
// If the check fails at this stage, we know that this txid must be a bad one.
179+
if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), SIGVERSION_BASE))
180+
return false;
181+
if (stack.empty())
182+
return false;
183+
prevScript = CScript(stack.back().begin(), stack.back().end());
184+
}
185+
186+
int witnessversion = 0;
187+
std::vector<unsigned char> witnessprogram;
188+
189+
// Non-witness program must not be associated with any witness
190+
if (!prevScript.IsWitnessProgram(witnessversion, witnessprogram))
191+
return false;
192+
193+
// Check P2WSH standard limits
194+
if (witnessversion == 0 && witnessprogram.size() == 32) {
195+
if (tx.wit.vtxinwit[i].scriptWitness.stack.back().size() > MAX_STANDARD_P2WSH_SCRIPT_SIZE)
196+
return false;
197+
size_t sizeWitnessStack = tx.wit.vtxinwit[i].scriptWitness.stack.size() - 1;
198+
if (sizeWitnessStack > MAX_STANDARD_P2WSH_STACK_ITEMS)
199+
return false;
200+
for (unsigned int j = 0; j < sizeWitnessStack; j++) {
201+
if (tx.wit.vtxinwit[i].scriptWitness.stack[j].size() > MAX_STANDARD_P2WSH_STACK_ITEM_SIZE)
202+
return false;
203+
}
204+
}
205+
}
206+
return true;
207+
}
208+
157209
unsigned int nBytesPerSigOp = DEFAULT_BYTES_PER_SIGOP;
158210

159211
int64_t GetVirtualTransactionSize(int64_t nWeight, int64_t nSigOpCost)

src/policy/policy.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ static const unsigned int MAX_STANDARD_TX_SIGOPS_COST = MAX_BLOCK_SIGOPS_COST/5;
3030
static const unsigned int DEFAULT_MAX_MEMPOOL_SIZE = 300;
3131
/** Default for -bytespersigop */
3232
static const unsigned int DEFAULT_BYTES_PER_SIGOP = 20;
33+
/** The maximum number of witness stack items in a standard P2WSH script */
34+
static const unsigned int MAX_STANDARD_P2WSH_STACK_ITEMS = 100;
35+
/** The maximum size of each witness stack item in a standard P2WSH script */
36+
static const unsigned int MAX_STANDARD_P2WSH_STACK_ITEM_SIZE = 80;
37+
/** The maximum size of a standard witnessScript */
38+
static const unsigned int MAX_STANDARD_P2WSH_SCRIPT_SIZE = 3600;
3339
/**
3440
* Standard script verification flags that standard transactions will comply
3541
* with. However scripts violating these flags may still be present in valid
@@ -69,6 +75,12 @@ bool IsStandardTx(const CTransaction& tx, std::string& reason, const bool witnes
6975
* @return True if all inputs (scriptSigs) use only standard transaction forms
7076
*/
7177
bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs);
78+
/**
79+
* Check if the transaction is over standard P2WSH resources limit:
80+
* 3600bytes witnessScript size, 80bytes per witness stack element, 100 witness stack elements
81+
* These limits are adequate for multi-signature up to n-of-100 using OP_CHECKSIG, OP_ADD, and OP_EQUAL,
82+
*/
83+
bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs);
7284

7385
extern unsigned int nBytesPerSigOp;
7486

0 commit comments

Comments
 (0)