Page MenuHomePhabricator

No OneTemporary

diff --git a/test/functional/feature_assumevalid.py b/test/functional/feature_assumevalid.py
index b99faf84f..30d2169cd 100755
--- a/test/functional/feature_assumevalid.py
+++ b/test/functional/feature_assumevalid.py
@@ -1,204 +1,204 @@
#!/usr/bin/env python3
# Copyright (c) 2014-2019 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test logic for skipping signature validation on old blocks.
Test logic for skipping signature validation on blocks which we've assumed
valid (https://github.com/bitcoin/bitcoin/pull/9484)
We build a chain that includes and invalid signature for one of the
transactions:
0: genesis block
1: block 1 with coinbase transaction output.
2-101: bury that block with 100 blocks so the coinbase transaction
output can be spent
102: a block containing a transaction spending the coinbase
transaction output. The transaction has an invalid signature.
103-2202: bury the bad block with just over two weeks' worth of blocks
(2100 blocks)
Start three nodes:
- node0 has no -assumevalid parameter. Try to sync to block 2202. It will
reject block 102 and only sync as far as block 101
- node1 has -assumevalid set to the hash of block 102. Try to sync to
block 2202. node1 will sync all the way to block 2202.
- node2 has -assumevalid set to the hash of block 102. Try to sync to
block 200. node2 will reject block 102 since it's assumed valid, but it
isn't buried by at least two weeks' work.
"""
import time
from test_framework.blocktools import (create_block, create_coinbase)
from test_framework.key import CECKey
from test_framework.messages import (
CBlockHeader,
COutPoint,
CTransaction,
CTxIn,
CTxOut,
msg_block,
msg_headers,
)
from test_framework.mininode import P2PInterface
from test_framework.script import (CScript, OP_TRUE)
from test_framework.test_framework import BitcoinTestFramework
from test_framework.txtools import pad_tx
from test_framework.util import assert_equal
class BaseNode(P2PInterface):
def send_header_for_blocks(self, new_blocks):
headers_message = msg_headers()
headers_message.headers = [CBlockHeader(b) for b in new_blocks]
self.send_message(headers_message)
class AssumeValidTest(BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 3
def setup_network(self):
self.add_nodes(3)
# Start node0. We don't start the other nodes yet since
# we need to pre-mine a block with an invalid transaction
# signature so we can pass in the block hash as assumevalid.
self.start_node(0)
def send_blocks_until_disconnected(self, p2p_conn):
"""Keep sending blocks to the node until we're disconnected."""
for i in range(len(self.blocks)):
if not p2p_conn.is_connected:
break
try:
p2p_conn.send_message(msg_block(self.blocks[i]))
except IOError:
assert not p2p_conn.is_connected
break
def assert_blockchain_height(self, node, height):
"""Wait until the blockchain is no longer advancing and verify it's reached the expected height."""
last_height = node.getblock(node.getbestblockhash())['height']
timeout = 10
while True:
time.sleep(0.25)
current_height = node.getblock(node.getbestblockhash())['height']
if current_height != last_height:
last_height = current_height
if timeout < 0:
assert False, "blockchain too short after timeout: {}".format(
current_height)
timeout - 0.25
continue
elif current_height > height:
assert False, "blockchain too long: {}".format(current_height)
elif current_height == height:
break
def run_test(self):
p2p0 = self.nodes[0].add_p2p_connection(BaseNode())
# Build the blockchain
self.tip = int(self.nodes[0].getbestblockhash(), 16)
self.block_time = self.nodes[0].getblock(
self.nodes[0].getbestblockhash())['time'] + 1
self.blocks = []
# Get a pubkey for the coinbase TXO
coinbase_key = CECKey()
coinbase_key.set_secretbytes(b"horsebattery")
coinbase_pubkey = coinbase_key.get_pubkey()
# Create the first block with a coinbase output to our key
height = 1
block = create_block(self.tip, create_coinbase(
height, coinbase_pubkey), self.block_time)
self.blocks.append(block)
self.block_time += 1
block.solve()
# Save the coinbase for later
self.block1 = block
self.tip = block.sha256
height += 1
# Bury the block 100 deep so the coinbase output is spendable
for i in range(100):
block = create_block(
self.tip, create_coinbase(height), self.block_time)
block.solve()
self.blocks.append(block)
self.tip = block.sha256
self.block_time += 1
height += 1
# Create a transaction spending the coinbase output with an invalid (null) signature
tx = CTransaction()
tx.vin.append(
CTxIn(COutPoint(self.block1.vtx[0].sha256, 0), scriptSig=b""))
tx.vout.append(CTxOut(49 * 100000000, CScript([OP_TRUE])))
pad_tx(tx)
tx.calc_sha256()
block102 = create_block(
self.tip, create_coinbase(height), self.block_time)
self.block_time += 1
block102.vtx.extend([tx])
block102.hashMerkleRoot = block102.calc_merkle_root()
block102.rehash()
block102.solve()
self.blocks.append(block102)
self.tip = block102.sha256
self.block_time += 1
height += 1
# Bury the assumed valid block 2100 deep
for i in range(2100):
block = create_block(
self.tip, create_coinbase(height), self.block_time)
block.nVersion = 4
block.solve()
self.blocks.append(block)
self.tip = block.sha256
self.block_time += 1
height += 1
self.nodes[0].disconnect_p2ps()
# Start node1 and node2 with assumevalid so they accept a block with a bad signature.
self.start_node(1, extra_args=["-assumevalid=" + hex(block102.sha256)])
self.start_node(2, extra_args=["-assumevalid=" + hex(block102.sha256)])
p2p0 = self.nodes[0].add_p2p_connection(BaseNode())
p2p1 = self.nodes[1].add_p2p_connection(BaseNode())
p2p2 = self.nodes[2].add_p2p_connection(BaseNode())
# send header lists to all three nodes
p2p0.send_header_for_blocks(self.blocks[0:2000])
p2p0.send_header_for_blocks(self.blocks[2000:])
p2p1.send_header_for_blocks(self.blocks[0:2000])
p2p1.send_header_for_blocks(self.blocks[2000:])
p2p2.send_header_for_blocks(self.blocks[0:200])
# Send blocks to node0. Block 102 will be rejected.
self.send_blocks_until_disconnected(p2p0)
self.assert_blockchain_height(self.nodes[0], 101)
# Send all blocks to node1. All blocks will be accepted.
for i in range(2202):
p2p1.send_message(msg_block(self.blocks[i]))
# Syncing 2200 blocks can take a while on slow systems. Give it plenty of time to sync.
- p2p1.sync_with_ping(120)
+ p2p1.sync_with_ping(200)
assert_equal(self.nodes[1].getblock(
self.nodes[1].getbestblockhash())['height'], 2202)
# Send blocks to node2. Block 102 will be rejected.
self.send_blocks_until_disconnected(p2p2)
self.assert_blockchain_height(self.nodes[2], 101)
if __name__ == '__main__':
AssumeValidTest().main()
diff --git a/test/functional/feature_cltv.py b/test/functional/feature_cltv.py
index 61a945217..2675fef51 100755
--- a/test/functional/feature_cltv.py
+++ b/test/functional/feature_cltv.py
@@ -1,214 +1,215 @@
#!/usr/bin/env python3
# Copyright (c) 2015-2019 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test BIP65 (CHECKLOCKTIMEVERIFY).
Test that the CHECKLOCKTIMEVERIFY soft-fork activates at (regtest) block height
1351.
"""
from test_framework.blocktools import create_block, create_coinbase, create_transaction, make_conform_to_ctor
from test_framework.messages import (
CTransaction,
FromHex,
msg_block,
msg_tx,
ToHex,
)
from test_framework.mininode import (
P2PInterface,
)
from test_framework.script import (
CScript,
CScriptNum,
OP_1NEGATE,
OP_CHECKLOCKTIMEVERIFY,
OP_DROP,
OP_TRUE,
)
from test_framework.test_framework import BitcoinTestFramework
from test_framework.txtools import pad_tx
from test_framework.util import assert_equal
CLTV_HEIGHT = 1351
# Reject codes that we might receive in this test
REJECT_INVALID = 16
REJECT_OBSOLETE = 17
REJECT_NONSTANDARD = 64
def cltv_lock_to_height(node, tx, to_address, amount, height=-1):
'''Modify the scriptPubKey to add an OP_CHECKLOCKTIMEVERIFY, and make
a transaction that spends it.
This transforms the output script to anyone can spend (OP_TRUE) if the
lock time condition is valid.
Default height is -1 which leads CLTV to fail
TODO: test more ways that transactions using CLTV could be invalid (eg
locktime requirements fail, sequence time requirements fail, etc).
'''
height_op = OP_1NEGATE
if(height > 0):
tx.vin[0].nSequence = 0
tx.nLockTime = height
height_op = CScriptNum(height)
tx.vout[0].scriptPubKey = CScript(
[height_op, OP_CHECKLOCKTIMEVERIFY, OP_DROP, OP_TRUE])
pad_tx(tx)
fundtx_raw = node.signrawtransactionwithwallet(ToHex(tx))['hex']
fundtx = FromHex(CTransaction(), fundtx_raw)
fundtx.rehash()
# make spending tx
inputs = [{
"txid": fundtx.hash,
"vout": 0
}]
output = {to_address: amount}
spendtx_raw = node.createrawtransaction(inputs, output)
spendtx = FromHex(CTransaction(), spendtx_raw)
pad_tx(spendtx)
return fundtx, spendtx
class BIP65Test(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
self.extra_args = [['-whitelist=127.0.0.1']]
self.setup_clean_chain = True
+ self.rpc_timeout = 120
def run_test(self):
self.nodes[0].add_p2p_connection(P2PInterface())
self.log.info("Mining {} blocks".format(CLTV_HEIGHT - 2))
self.coinbase_txids = [self.nodes[0].getblock(
b)['tx'][0] for b in self.nodes[0].generate(CLTV_HEIGHT - 2)]
self.nodeaddress = self.nodes[0].getnewaddress()
self.log.info(
"Test that an invalid-according-to-CLTV transaction can still appear in a block")
fundtx = create_transaction(self.nodes[0], self.coinbase_txids[0],
self.nodeaddress, 49.99)
fundtx, spendtx = cltv_lock_to_height(
self.nodes[0], fundtx, self.nodeaddress, 49.98)
tip = self.nodes[0].getbestblockhash()
block_time = self.nodes[0].getblockheader(tip)['mediantime'] + 1
block = create_block(int(tip, 16), create_coinbase(
CLTV_HEIGHT - 1), block_time)
block.nVersion = 3
block.vtx.append(fundtx)
# include the -1 CLTV in block
block.vtx.append(spendtx)
make_conform_to_ctor(block)
block.hashMerkleRoot = block.calc_merkle_root()
block.solve()
self.nodes[0].p2p.send_and_ping(msg_block(block))
# This block is valid
assert_equal(self.nodes[0].getbestblockhash(), block.hash)
self.log.info("Test that blocks must now be at least version 4")
tip = block.sha256
block_time += 1
block = create_block(tip, create_coinbase(CLTV_HEIGHT), block_time)
block.nVersion = 3
block.solve()
with self.nodes[0].assert_debug_log(expected_msgs=['{}, bad-version(0x00000003)'.format(block.hash)]):
self.nodes[0].p2p.send_and_ping(msg_block(block))
assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip)
self.nodes[0].p2p.sync_with_ping()
self.log.info(
"Test that invalid-according-to-cltv transactions cannot appear in a block")
block.nVersion = 4
fundtx = create_transaction(self.nodes[0], self.coinbase_txids[1],
self.nodeaddress, 49.99)
fundtx, spendtx = cltv_lock_to_height(
self.nodes[0], fundtx, self.nodeaddress, 49.98)
# The funding tx only has unexecuted bad CLTV, in scriptpubkey; this is valid.
self.nodes[0].p2p.send_and_ping(msg_tx(fundtx))
assert fundtx.hash in self.nodes[0].getrawmempool()
# Mine a block containing the funding transaction
block.vtx.append(fundtx)
block.hashMerkleRoot = block.calc_merkle_root()
block.solve()
self.nodes[0].p2p.send_and_ping(msg_block(block))
# This block is valid
assert_equal(self.nodes[0].getbestblockhash(), block.hash)
# We show that this tx is invalid due to CLTV by getting it
# rejected from the mempool for exactly that reason.
assert_equal(
[{'txid': spendtx.hash, 'allowed': False,
'reject-reason': '64: non-mandatory-script-verify-flag (Negative locktime)'}],
self.nodes[0].testmempoolaccept(
rawtxs=[spendtx.serialize().hex()], allowhighfees=True)
)
rejectedtx_signed = self.nodes[0].signrawtransactionwithwallet(
ToHex(spendtx))
# Couldn't complete signature due to CLTV
assert rejectedtx_signed['errors'][0]['error'] == 'Negative locktime'
tip = block.hash
block_time += 1
block = create_block(
block.sha256, create_coinbase(CLTV_HEIGHT + 1), block_time)
block.nVersion = 4
block.vtx.append(spendtx)
block.hashMerkleRoot = block.calc_merkle_root()
block.solve()
with self.nodes[0].assert_debug_log(expected_msgs=['ConnectBlock {} failed (blk-bad-inputs'.format(block.hash)]):
self.nodes[0].p2p.send_and_ping(msg_block(block))
assert_equal(self.nodes[0].getbestblockhash(), tip)
self.nodes[0].p2p.sync_with_ping()
self.log.info(
"Test that a version 4 block with a valid-according-to-CLTV transaction is accepted")
fundtx = create_transaction(self.nodes[0], self.coinbase_txids[2],
self.nodeaddress, 49.99)
fundtx, spendtx = cltv_lock_to_height(
self.nodes[0], fundtx, self.nodeaddress, 49.98, CLTV_HEIGHT)
# make sure sequence is nonfinal and locktime is good
spendtx.vin[0].nSequence = 0xfffffffe
spendtx.nLockTime = CLTV_HEIGHT
# both transactions are fully valid
self.nodes[0].sendrawtransaction(ToHex(fundtx))
self.nodes[0].sendrawtransaction(ToHex(spendtx))
# Modify the transactions in the block to be valid against CLTV
block.vtx.pop(1)
block.vtx.append(fundtx)
block.vtx.append(spendtx)
make_conform_to_ctor(block)
block.hashMerkleRoot = block.calc_merkle_root()
block.solve()
self.nodes[0].p2p.send_and_ping(msg_block(block))
# This block is now valid
assert_equal(self.nodes[0].getbestblockhash(), block.hash)
if __name__ == '__main__':
BIP65Test().main()
diff --git a/test/functional/feature_dersig.py b/test/functional/feature_dersig.py
index 97b9e049b..b9031b71f 100755
--- a/test/functional/feature_dersig.py
+++ b/test/functional/feature_dersig.py
@@ -1,125 +1,126 @@
#!/usr/bin/env python3
# Copyright (c) 2015-2019 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test BIP66 (DER SIG).
Test that the DERSIG soft-fork activates at (regtest) height 1251.
"""
from test_framework.blocktools import create_block, create_coinbase, create_transaction
from test_framework.messages import msg_block, ToHex
from test_framework.mininode import (
mininode_lock,
P2PInterface,
)
from test_framework.script import CScript
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, wait_until
DERSIG_HEIGHT = 1251
# Reject codes that we might receive in this test
REJECT_INVALID = 16
REJECT_OBSOLETE = 17
REJECT_NONSTANDARD = 64
# A canonical signature consists of:
# <30> <total len> <02> <len R> <R> <02> <len S> <S> <hashtype>
def unDERify(tx):
"""
Make the signature in vin 0 of a tx non-DER-compliant,
by adding padding after the S-value.
"""
scriptSig = CScript(tx.vin[0].scriptSig)
newscript = []
for i in scriptSig:
if (len(newscript) == 0):
newscript.append(i[0:-1] + b'\0' + i[-1:])
else:
newscript.append(i)
tx.vin[0].scriptSig = CScript(newscript)
class BIP66Test(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
self.extra_args = [['-whitelist=127.0.0.1', '-enablebip61']]
self.setup_clean_chain = True
+ self.rpc_timeout = 120
def run_test(self):
self.nodes[0].add_p2p_connection(P2PInterface())
self.log.info("Mining {} blocks".format(DERSIG_HEIGHT - 1))
self.coinbase_txids = [self.nodes[0].getblock(
b)['tx'][0] for b in self.nodes[0].generate(DERSIG_HEIGHT - 1)]
self.nodeaddress = self.nodes[0].getnewaddress()
self.log.info("Test that blocks must now be at least version 3")
tip = self.nodes[0].getbestblockhash()
block_time = self.nodes[0].getblockheader(tip)['mediantime'] + 1
block = create_block(
int(tip, 16), create_coinbase(DERSIG_HEIGHT), block_time)
block.nVersion = 2
block.rehash()
block.solve()
with self.nodes[0].assert_debug_log(expected_msgs=['{}, bad-version(0x00000002)'.format(block.hash)]):
self.nodes[0].p2p.send_and_ping(msg_block(block))
assert_equal(self.nodes[0].getbestblockhash(), tip)
self.nodes[0].p2p.sync_with_ping()
self.log.info(
"Test that transactions with non-DER signatures cannot appear in a block")
block.nVersion = 3
spendtx = create_transaction(self.nodes[0], self.coinbase_txids[1],
self.nodeaddress, 1.0)
unDERify(spendtx)
spendtx.rehash()
# First we show that this tx is valid except for DERSIG by getting it
# rejected from the mempool for exactly that reason.
assert_equal(
[{'txid': spendtx.hash, 'allowed': False,
'reject-reason': '16: mandatory-script-verify-flag-failed (Non-canonical DER signature)'}],
self.nodes[0].testmempoolaccept(
rawtxs=[ToHex(spendtx)], allowhighfees=True)
)
# Now we verify that a block with this transaction is also invalid.
block.vtx.append(spendtx)
block.hashMerkleRoot = block.calc_merkle_root()
block.rehash()
block.solve()
with self.nodes[0].assert_debug_log(expected_msgs=['ConnectBlock {} failed (blk-bad-inputs'.format(block.hash)]):
self.nodes[0].p2p.send_and_ping(msg_block(block))
assert_equal(self.nodes[0].getbestblockhash(), tip)
self.nodes[0].p2p.sync_with_ping()
wait_until(lambda: "reject" in self.nodes[0].p2p.last_message.keys(),
lock=mininode_lock)
with mininode_lock:
assert self.nodes[0].p2p.last_message["reject"].code in [
REJECT_INVALID, REJECT_NONSTANDARD]
assert_equal(
self.nodes[0].p2p.last_message["reject"].data, block.sha256)
assert b'blk-bad-inputs' in self.nodes[0].p2p.last_message["reject"].reason
self.log.info(
"Test that a version 3 block with a DERSIG-compliant transaction is accepted")
block.vtx[1] = create_transaction(self.nodes[0],
self.coinbase_txids[1], self.nodeaddress, 1.0)
block.hashMerkleRoot = block.calc_merkle_root()
block.rehash()
block.solve()
self.nodes[0].p2p.send_and_ping(msg_block(block))
assert_equal(int(self.nodes[0].getbestblockhash(), 16), block.sha256)
if __name__ == '__main__':
BIP66Test().main()

File Metadata

Mime Type
text/x-diff
Expires
Fri, Feb 7, 16:57 (1 d, 21 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5082731
Default Alt Text
(21 KB)

Event Timeline