Skip to content

Commit 0a8b7b4

Browse files
author
MarcoFalke
committed
Merge #11739: Enforce SCRIPT_VERIFY_P2SH and SCRIPT_VERIFY_WITNESS from genesis
8b56fc0 [qa] Test that v0 segwit outputs can't be spent pre-activation (Suhas Daftuar) ccb8ca4 Always enforce SCRIPT_VERIFY_WITNESS with P2SH (Suhas Daftuar) 5c31b20 [qa] Remove some pre-activation segwit tests (Suhas Daftuar) 95749a5 Separate NULLDUMMY enforcement from SEGWIT enforcement (Suhas Daftuar) ce65018 Use P2SH consensus rules for all blocks (Suhas Daftuar) Pull request description: As discussed at the IRC meeting back in October (https://botbot.me/freenode/bitcoin-core-dev/2017-10-12/?msg=92231929&page=2), I had looked into the feasibility of enforcing P2SH and SCRIPT_VERIFY_WITNESS back to the genesis block. The P2SH change is pretty straightforward -- there was only one historical block on mainnet that violated the rule, so I carved out an exception to it, similar to the way we have exceptions for the BIP30 violators. The segwit change is not entirely as clear. The code changes themselves are relatively straightforward: we can just always turn on SCRIPT_VERIFY_WITNESS whenever P2SH is active. However conceptually, this amounts to splitting up BIP141 into two parts, the part that implements new script rules, and the part that handles witness commitments in blocks. Arguably though the script rules are really defined in BIP 143 anyway, and so this really amounts to backdating BIP 143 -- script rules for v0 segwit outputs -- back to genesis. So maybe conceptually this isn't so bad... I don't feel strongly about this change in either direction; I started working on it because I was searching for a way to simplify the way we understand and implement the consensus rules around segwit, but I'm not yet sure whether I think this achieves anything toward that goal. ping @TheBlueMatt Tree-SHA512: 73551d4a983eb9792c7ac67f56005822528ac4d1fd52c27cee6d305ebee953f69687ef4ddee8bdc0fec77f77e6b5a9d669750793efee54c076533a095e233042
2 parents 9b3a67e + 8b56fc0 commit 0a8b7b4

File tree

6 files changed

+127
-24
lines changed

6 files changed

+127
-24
lines changed

src/chainparams.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ class CMainParams : public CChainParams {
7575
CMainParams() {
7676
strNetworkID = "main";
7777
consensus.nSubsidyHalvingInterval = 210000;
78-
consensus.BIP16Height = 173805; // 00000000000000ce80a7e057163a4db1d5ad7b20fb6f598c9597b9665c8fb0d4 - April 1, 2012
78+
consensus.BIP16Exception = uint256S("0x00000000000002dc756eebf4f49723ed8d30cc28a5f108eb94b1ba88ac4f9c22");
7979
consensus.BIP34Height = 227931;
8080
consensus.BIP34Hash = uint256S("0x000000000000024b89b42a942fe0d9fea3bb44ab7bd1b19115dd6a759c0808b8");
8181
consensus.BIP65Height = 388381; // 000000000000000004c2b624ed5d7756c508d90fd0da2c7c679febfa6c4735f0
@@ -190,7 +190,7 @@ class CTestNetParams : public CChainParams {
190190
CTestNetParams() {
191191
strNetworkID = "test";
192192
consensus.nSubsidyHalvingInterval = 210000;
193-
consensus.BIP16Height = 514; // 00000000040b4e986385315e14bee30ad876d8b47f748025b26683116d21aa65
193+
consensus.BIP16Exception = uint256S("0x00000000dd30457c001f4095d208cc1296b0eed002427aa599874af7a432b105");
194194
consensus.BIP34Height = 21111;
195195
consensus.BIP34Hash = uint256S("0x0000000023b3a96d3484e5abb3755c413e7d41500f8e2a5c3f0dd01299cd8ef8");
196196
consensus.BIP65Height = 581885; // 00000000007f6655f22f98e72ed80d8b06dc761d5da09df0fa1dc4be4f861eb6
@@ -283,7 +283,7 @@ class CRegTestParams : public CChainParams {
283283
CRegTestParams() {
284284
strNetworkID = "regtest";
285285
consensus.nSubsidyHalvingInterval = 150;
286-
consensus.BIP16Height = 0; // always enforce P2SH BIP16 on regtest
286+
consensus.BIP16Exception = uint256();
287287
consensus.BIP34Height = 100000000; // BIP34 has not activated on regtest (far in the future so block v1 are not rejected in tests)
288288
consensus.BIP34Hash = uint256();
289289
consensus.BIP65Height = 1351; // BIP65 activated on regtest (Used in rpc activation tests)

src/consensus/params.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@ struct BIP9Deployment {
4949
struct Params {
5050
uint256 hashGenesisBlock;
5151
int nSubsidyHalvingInterval;
52-
/** Block height at which BIP16 becomes active */
53-
int BIP16Height;
52+
/* Block hash that is excepted from BIP16 enforcement */
53+
uint256 BIP16Exception;
5454
/** Block height and hash at which BIP34 becomes active */
5555
int BIP34Height;
5656
uint256 BIP34Hash;

src/validation.cpp

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1726,16 +1726,38 @@ class WarningBitsConditionChecker : public AbstractThresholdConditionChecker
17261726
// Protected by cs_main
17271727
static ThresholdConditionCache warningcache[VERSIONBITS_NUM_BITS];
17281728

1729+
// 0.13.0 was shipped with a segwit deployment defined for testnet, but not for
1730+
// mainnet. We no longer need to support disabling the segwit deployment
1731+
// except for testing purposes, due to limitations of the functional test
1732+
// environment. See test/functional/p2p-segwit.py.
1733+
static bool IsScriptWitnessEnabled(const Consensus::Params& params)
1734+
{
1735+
return params.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout != 0;
1736+
}
1737+
17291738
static unsigned int GetBlockScriptFlags(const CBlockIndex* pindex, const Consensus::Params& consensusparams) {
17301739
AssertLockHeld(cs_main);
17311740

17321741
unsigned int flags = SCRIPT_VERIFY_NONE;
17331742

1734-
// Start enforcing P2SH (BIP16)
1735-
if (pindex->nHeight >= consensusparams.BIP16Height) {
1743+
// BIP16 didn't become active until Apr 1 2012 (on mainnet, and
1744+
// retroactively applied to testnet)
1745+
// However, only one historical block violated the P2SH rules (on both
1746+
// mainnet and testnet), so for simplicity, always leave P2SH
1747+
// on except for the one violating block.
1748+
if (consensusparams.BIP16Exception.IsNull() || // no bip16 exception on this chain
1749+
pindex->phashBlock == nullptr || // this is a new candidate block, eg from TestBlockValidity()
1750+
*pindex->phashBlock != consensusparams.BIP16Exception) // this block isn't the historical exception
1751+
{
17361752
flags |= SCRIPT_VERIFY_P2SH;
17371753
}
17381754

1755+
// Enforce WITNESS rules whenever P2SH is in effect (and the segwit
1756+
// deployment is defined).
1757+
if (flags & SCRIPT_VERIFY_P2SH && IsScriptWitnessEnabled(consensusparams)) {
1758+
flags |= SCRIPT_VERIFY_WITNESS;
1759+
}
1760+
17391761
// Start enforcing the DERSIG (BIP66) rule
17401762
if (pindex->nHeight >= consensusparams.BIP66Height) {
17411763
flags |= SCRIPT_VERIFY_DERSIG;
@@ -1751,9 +1773,7 @@ static unsigned int GetBlockScriptFlags(const CBlockIndex* pindex, const Consens
17511773
flags |= SCRIPT_VERIFY_CHECKSEQUENCEVERIFY;
17521774
}
17531775

1754-
// Start enforcing WITNESS rules using versionbits logic.
1755-
if (IsWitnessEnabled(pindex->pprev, consensusparams)) {
1756-
flags |= SCRIPT_VERIFY_WITNESS;
1776+
if (IsNullDummyEnabled(pindex->pprev, consensusparams)) {
17571777
flags |= SCRIPT_VERIFY_NULLDUMMY;
17581778
}
17591779

@@ -3099,6 +3119,12 @@ bool IsWitnessEnabled(const CBlockIndex* pindexPrev, const Consensus::Params& pa
30993119
return (VersionBitsState(pindexPrev, params, Consensus::DEPLOYMENT_SEGWIT, versionbitscache) == ThresholdState::ACTIVE);
31003120
}
31013121

3122+
bool IsNullDummyEnabled(const CBlockIndex* pindexPrev, const Consensus::Params& params)
3123+
{
3124+
LOCK(cs_main);
3125+
return (VersionBitsState(pindexPrev, params, Consensus::DEPLOYMENT_SEGWIT, versionbitscache) == ThresholdState::ACTIVE);
3126+
}
3127+
31023128
// Compute at which vout of the block's coinbase transaction the witness
31033129
// commitment occurs, or -1 if not found.
31043130
static int GetWitnessCommitmentIndex(const CBlock& block)
@@ -4091,6 +4117,9 @@ bool CChainState::RewindBlockIndex(const CChainParams& params)
40914117

40924118
int nHeight = 1;
40934119
while (nHeight <= chainActive.Height()) {
4120+
// Although SCRIPT_VERIFY_WITNESS is now generally enforced on all
4121+
// blocks in ConnectBlock, we don't need to go back and
4122+
// re-download/re-verify blocks from before segwit actually activated.
40944123
if (IsWitnessEnabled(chainActive[nHeight - 1], params.GetConsensus()) && !(chainActive[nHeight]->nStatus & BLOCK_OPT_WITNESS)) {
40954124
break;
40964125
}

src/validation.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,9 @@ bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams,
411411
/** Check whether witness commitments are required for block. */
412412
bool IsWitnessEnabled(const CBlockIndex* pindexPrev, const Consensus::Params& params);
413413

414+
/** Check whether NULLDUMMY (BIP 147) has activated. */
415+
bool IsNullDummyEnabled(const CBlockIndex* pindexPrev, const Consensus::Params& params);
416+
414417
/** When there are blocks in the active chain with missing data, rewind the chainstate and remove them from the block index */
415418
bool RewindBlockIndex(const CChainParams& params);
416419

test/functional/feature_segwit.py

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -150,19 +150,11 @@ def run_test(self):
150150
self.skip_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V0][0], True) #block 426
151151
self.skip_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V1][0], True) #block 427
152152

153-
# TODO: An old node would see these txs without witnesses and be able to mine them
154-
155-
self.log.info("Verify unsigned bare witness txs in versionbits-setting blocks are valid before the fork")
156-
self.success_mine(self.nodes[2], wit_ids[NODE_2][WIT_V0][1], False) #block 428
157-
self.success_mine(self.nodes[2], wit_ids[NODE_2][WIT_V1][1], False) #block 429
158-
159153
self.log.info("Verify unsigned p2sh witness txs without a redeem script are invalid")
160154
self.fail_accept(self.nodes[2], "mandatory-script-verify-flag", p2sh_ids[NODE_2][WIT_V0][1], False)
161155
self.fail_accept(self.nodes[2], "mandatory-script-verify-flag", p2sh_ids[NODE_2][WIT_V1][1], False)
162156

163-
self.log.info("Verify unsigned p2sh witness txs with a redeem script in versionbits-settings blocks are valid before the fork")
164-
self.success_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V0][1], False, witness_script(False, self.pubkey[2])) #block 430
165-
self.success_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V1][1], False, witness_script(True, self.pubkey[2])) #block 431
157+
self.nodes[2].generate(4) # blocks 428-431
166158

167159
self.log.info("Verify previous witness txs skipped for mining can now be mined")
168160
assert_equal(len(self.nodes[2].getrawmempool()), 4)

test/functional/p2p_segwit.py

Lines changed: 84 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ def test_transaction_acceptance(rpc, p2p, tx, with_witness, accepted, reason=Non
4848
with mininode_lock:
4949
assert_equal(p2p.last_message["reject"].reason, reason)
5050

51-
def test_witness_block(rpc, p2p, block, accepted, with_witness=True):
51+
def test_witness_block(rpc, p2p, block, accepted, with_witness=True, reason=None):
5252
"""Send a block to the node and check that it's accepted
5353
5454
- Submit the block over the p2p interface
@@ -59,6 +59,10 @@ def test_witness_block(rpc, p2p, block, accepted, with_witness=True):
5959
p2p.send_message(msg_block(block))
6060
p2p.sync_with_ping()
6161
assert_equal(rpc.getbestblockhash() == block.hash, accepted)
62+
if (reason != None and not accepted):
63+
# Check the rejection reason as well.
64+
with mininode_lock:
65+
assert_equal(p2p.last_message["reject"].reason, reason)
6266

6367
class TestP2PConn(P2PInterface):
6468
def __init__(self):
@@ -272,6 +276,80 @@ def test_unnecessary_witness_before_segwit_activation(self):
272276
self.utxo.pop(0)
273277
self.utxo.append(UTXO(tx4.sha256, 0, tx4.vout[0].nValue))
274278

279+
# ~6 months after segwit activation, the SCRIPT_VERIFY_WITNESS flag was
280+
# backdated so that it applies to all blocks, going back to the genesis
281+
# block.
282+
#
283+
# Consequently, version 0 witness outputs are never spendable without
284+
# witness, and so can't be spent before segwit activation (the point at which
285+
# blocks are permitted to contain witnesses).
286+
def test_v0_outputs_arent_spendable(self):
287+
self.log.info("Testing that v0 witness program outputs aren't spendable before activation")
288+
289+
assert len(self.utxo), "self.utxo is empty"
290+
291+
# Create two outputs, a p2wsh and p2sh-p2wsh
292+
witness_program = CScript([OP_TRUE])
293+
witness_hash = sha256(witness_program)
294+
scriptPubKey = CScript([OP_0, witness_hash])
295+
296+
p2sh_pubkey = hash160(scriptPubKey)
297+
p2sh_scriptPubKey = CScript([OP_HASH160, p2sh_pubkey, OP_EQUAL])
298+
299+
value = self.utxo[0].nValue // 3
300+
301+
tx = CTransaction()
302+
tx.vin = [CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b'')]
303+
tx.vout = [CTxOut(value, scriptPubKey), CTxOut(value, p2sh_scriptPubKey)]
304+
tx.vout.append(CTxOut(value, CScript([OP_TRUE])))
305+
tx.rehash()
306+
txid = tx.sha256
307+
308+
# Add it to a block
309+
block = self.build_next_block()
310+
self.update_witness_block_with_transactions(block, [tx])
311+
# Verify that segwit isn't activated. A block serialized with witness
312+
# should be rejected prior to activation.
313+
test_witness_block(self.nodes[0], self.test_node, block, accepted=False, with_witness=True, reason = b'unexpected-witness')
314+
# Now send the block without witness. It should be accepted
315+
test_witness_block(self.nodes[0], self.test_node, block, accepted=True, with_witness=False)
316+
317+
# Now try to spend the outputs. This should fail since SCRIPT_VERIFY_WITNESS is always enabled.
318+
p2wsh_tx = CTransaction()
319+
p2wsh_tx.vin = [CTxIn(COutPoint(txid, 0), b'')]
320+
p2wsh_tx.vout = [CTxOut(value, CScript([OP_TRUE]))]
321+
p2wsh_tx.wit.vtxinwit.append(CTxInWitness())
322+
p2wsh_tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])]
323+
p2wsh_tx.rehash()
324+
325+
p2sh_p2wsh_tx = CTransaction()
326+
p2sh_p2wsh_tx.vin = [CTxIn(COutPoint(txid, 1), CScript([scriptPubKey]))]
327+
p2sh_p2wsh_tx.vout = [CTxOut(value, CScript([OP_TRUE]))]
328+
p2sh_p2wsh_tx.wit.vtxinwit.append(CTxInWitness())
329+
p2sh_p2wsh_tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])]
330+
p2sh_p2wsh_tx.rehash()
331+
332+
for tx in [p2wsh_tx, p2sh_p2wsh_tx]:
333+
334+
block = self.build_next_block()
335+
self.update_witness_block_with_transactions(block, [tx])
336+
337+
# When the block is serialized with a witness, the block will be rejected because witness
338+
# data isn't allowed in blocks that don't commit to witness data.
339+
test_witness_block(self.nodes[0], self.test_node, block, accepted=False, with_witness=True, reason=b'unexpected-witness')
340+
341+
# When the block is serialized without witness, validation fails because the transaction is
342+
# invalid (transactions are always validated with SCRIPT_VERIFY_WITNESS so a segwit v0 transaction
343+
# without a witness is invalid).
344+
# Note: The reject reason for this failure could be
345+
# 'block-validation-failed' (if script check threads > 1) or
346+
# 'non-mandatory-script-verify-flag (Witness program was passed an
347+
# empty witness)' (otherwise).
348+
# TODO: support multiple acceptable reject reasons.
349+
test_witness_block(self.nodes[0], self.test_node, block, accepted=False, with_witness=False)
350+
351+
self.utxo.pop(0)
352+
self.utxo.append(UTXO(txid, 2, value))
275353

276354
# Mine enough blocks for segwit's vb state to be 'started'.
277355
def advance_to_segwit_started(self):
@@ -1479,9 +1557,10 @@ def test_p2sh_witness(self, segwit_activated):
14791557
block = self.build_next_block()
14801558
self.update_witness_block_with_transactions(block, [spend_tx])
14811559

1482-
# If we're before activation, then sending this without witnesses
1483-
# should be valid. If we're after activation, then sending this with
1484-
# witnesses should be valid.
1560+
# If we're after activation, then sending this with witnesses should be valid.
1561+
# This no longer works before activation, because SCRIPT_VERIFY_WITNESS
1562+
# is always set.
1563+
# TODO: rewrite this test to make clear that it only works after activation.
14851564
if segwit_activated:
14861565
test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
14871566
else:
@@ -1900,6 +1979,7 @@ def run_test(self):
19001979
self.test_witness_services() # Verifies NODE_WITNESS
19011980
self.test_non_witness_transaction() # non-witness tx's are accepted
19021981
self.test_unnecessary_witness_before_segwit_activation()
1982+
self.test_v0_outputs_arent_spendable()
19031983
self.test_block_relay(segwit_activated=False)
19041984

19051985
# Advance to segwit being 'started'
@@ -1917,7 +1997,6 @@ def run_test(self):
19171997
self.test_unnecessary_witness_before_segwit_activation()
19181998
self.test_witness_tx_relay_before_segwit_activation()
19191999
self.test_block_relay(segwit_activated=False)
1920-
self.test_p2sh_witness(segwit_activated=False)
19212000
self.test_standardness_v0(segwit_activated=False)
19222001

19232002
sync_blocks(self.nodes)

0 commit comments

Comments
 (0)