diff options
Diffstat (limited to 'test/functional')
-rw-r--r-- | test/functional/README.md | 2 | ||||
-rwxr-xr-x | test/functional/bip65-cltv-p2p.py | 241 | ||||
-rwxr-xr-x | test/functional/bip65-cltv.py | 82 | ||||
-rwxr-xr-x | test/functional/bipdersig-p2p.py | 217 | ||||
-rwxr-xr-x | test/functional/bipdersig.py | 81 | ||||
-rwxr-xr-x | test/functional/fundrawtransaction.py | 17 | ||||
-rwxr-xr-x | test/functional/listsinceblock.py | 190 | ||||
-rwxr-xr-x | test/functional/multiwallet.py | 78 | ||||
-rwxr-xr-x | test/functional/p2p-leaktests.py | 34 | ||||
-rwxr-xr-x | test/functional/rawtransactions.py | 57 | ||||
-rwxr-xr-x | test/functional/segwit.py | 11 | ||||
-rwxr-xr-x | test/functional/signrawtransactions.py | 16 | ||||
-rw-r--r-- | test/functional/test_framework/authproxy.py | 3 | ||||
-rw-r--r-- | test/functional/test_framework/coverage.py | 2 | ||||
-rwxr-xr-x | test/functional/test_framework/mininode.py | 2 | ||||
-rwxr-xr-x | test/functional/test_runner.py | 7 | ||||
-rwxr-xr-x | test/functional/zapwallettxes.py | 100 |
17 files changed, 623 insertions, 517 deletions
diff --git a/test/functional/README.md b/test/functional/README.md index 96fe0becce..44efda33d3 100644 --- a/test/functional/README.md +++ b/test/functional/README.md @@ -90,7 +90,7 @@ on nodes 2 and up. - Implement a (generator) function called `get_tests()` which yields `TestInstance`s. Each `TestInstance` consists of: - - a list of `[object, outcome, hash]` entries + - A list of `[object, outcome, hash]` entries * `object` is a `CBlock`, `CTransaction`, or `CBlockHeader`. `CBlock`'s and `CTransaction`'s are tested for acceptance. `CBlockHeader`s can be used so that the test runner can deliver diff --git a/test/functional/bip65-cltv-p2p.py b/test/functional/bip65-cltv-p2p.py index bb83042f35..7e5e4cf682 100755 --- a/test/functional/bip65-cltv-p2p.py +++ b/test/functional/bip65-cltv-p2p.py @@ -4,173 +4,162 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test BIP65 (CHECKLOCKTIMEVERIFY). -Connect to a single node. -Mine 2 (version 3) blocks (save the coinbases for later). -Generate 98 more version 3 blocks, verify the node accepts. -Mine 749 version 4 blocks, verify the node accepts. -Check that the new CLTV rules are not enforced on the 750th version 4 block. -Check that the new CLTV rules are enforced on the 751st version 4 block. -Mine 199 new version blocks. -Mine 1 old-version block. -Mine 1 new version block. -Mine 1 old version block, see that the node rejects. +Test that the CHECKLOCKTIMEVERIFY soft-fork activates at (regtest) block height +1351. """ -from test_framework.test_framework import ComparisonTestFramework +from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * -from test_framework.mininode import CTransaction, NetworkThread +from test_framework.mininode import * from test_framework.blocktools import create_coinbase, create_block -from test_framework.comptool import TestInstance, TestManager -from test_framework.script import CScript, OP_1NEGATE, OP_CHECKLOCKTIMEVERIFY, OP_DROP +from test_framework.script import CScript, OP_1NEGATE, OP_CHECKLOCKTIMEVERIFY, OP_DROP, CScriptNum from io import BytesIO -import time + +CLTV_HEIGHT = 1351 + +# Reject codes that we might receive in this test +REJECT_INVALID = 16 +REJECT_OBSOLETE = 17 +REJECT_NONSTANDARD = 64 def cltv_invalidate(tx): '''Modify the signature in vin 0 of the tx to fail CLTV Prepends -1 CLTV DROP in the scriptSig itself. + + TODO: test more ways that transactions using CLTV could be invalid (eg + locktime requirements fail, sequence time requirements fail, etc). ''' tx.vin[0].scriptSig = CScript([OP_1NEGATE, OP_CHECKLOCKTIMEVERIFY, OP_DROP] + list(CScript(tx.vin[0].scriptSig))) - -class BIP65Test(ComparisonTestFramework): +def cltv_validate(node, tx, height): + '''Modify the signature in vin 0 of the tx to pass CLTV + Prepends <height> CLTV DROP in the scriptSig, and sets + the locktime to height''' + tx.vin[0].nSequence = 0 + tx.nLockTime = height + + # Need to re-sign, since nSequence and nLockTime changed + signed_result = node.signrawtransaction(ToHex(tx)) + new_tx = CTransaction() + new_tx.deserialize(BytesIO(hex_str_to_bytes(signed_result['hex']))) + + new_tx.vin[0].scriptSig = CScript([CScriptNum(height), OP_CHECKLOCKTIMEVERIFY, OP_DROP] + + list(CScript(new_tx.vin[0].scriptSig))) + return new_tx + +def create_transaction(node, coinbase, to_address, amount): + from_txid = node.getblock(coinbase)['tx'][0] + inputs = [{ "txid" : from_txid, "vout" : 0}] + outputs = { to_address : amount } + rawtx = node.createrawtransaction(inputs, outputs) + signresult = node.signrawtransaction(rawtx) + tx = CTransaction() + tx.deserialize(BytesIO(hex_str_to_bytes(signresult['hex']))) + return tx + +class BIP65Test(BitcoinTestFramework): def __init__(self): super().__init__() self.num_nodes = 1 - self.extra_args = [['-whitelist=127.0.0.1', '-blockversion=3']] + self.extra_args = [['-promiscuousmempoolflags=1', '-whitelist=127.0.0.1']] + self.setup_clean_chain = True def run_test(self): - test = TestManager(self, self.options.tmpdir) - test.add_all_connections(self.nodes) + node0 = NodeConnCB() + connections = [] + connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], node0)) + node0.add_connection(connections[0]) + NetworkThread().start() # Start up network handling in another thread - test.run() - - def create_transaction(self, node, coinbase, to_address, amount): - from_txid = node.getblock(coinbase)['tx'][0] - inputs = [{ "txid" : from_txid, "vout" : 0}] - outputs = { to_address : amount } - rawtx = node.createrawtransaction(inputs, outputs) - signresult = node.signrawtransaction(rawtx) - tx = CTransaction() - f = BytesIO(hex_str_to_bytes(signresult['hex'])) - tx.deserialize(f) - return tx - - def get_tests(self): - - self.coinbase_blocks = self.nodes[0].generate(2) - height = 3 # height of the next block to build - self.tip = int("0x" + self.nodes[0].getbestblockhash(), 0) + + # wait_for_verack ensures that the P2P connection is fully up. + node0.wait_for_verack() + + self.log.info("Mining %d blocks", CLTV_HEIGHT - 2) + self.coinbase_blocks = self.nodes[0].generate(CLTV_HEIGHT - 2) self.nodeaddress = self.nodes[0].getnewaddress() - self.last_block_time = int(time.time()) - - ''' 398 more version 3 blocks ''' - test_blocks = [] - for i in range(398): - block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1) - block.nVersion = 3 - block.rehash() - block.solve() - test_blocks.append([block, True]) - self.last_block_time += 1 - self.tip = block.sha256 - height += 1 - yield TestInstance(test_blocks, sync_every_block=False) - - ''' Mine 749 version 4 blocks ''' - test_blocks = [] - for i in range(749): - block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1) - block.nVersion = 4 - block.rehash() - block.solve() - test_blocks.append([block, True]) - self.last_block_time += 1 - self.tip = block.sha256 - height += 1 - yield TestInstance(test_blocks, sync_every_block=False) - - ''' - Check that the new CLTV rules are not enforced in the 750th - version 3 block. - ''' - spendtx = self.create_transaction(self.nodes[0], - self.coinbase_blocks[0], self.nodeaddress, 1.0) + + self.log.info("Test that an invalid-according-to-CLTV transaction can still appear in a block") + + spendtx = create_transaction(self.nodes[0], self.coinbase_blocks[0], + self.nodeaddress, 1.0) cltv_invalidate(spendtx) spendtx.rehash() - block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1) - block.nVersion = 4 + 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(spendtx) block.hashMerkleRoot = block.calc_merkle_root() - block.rehash() block.solve() - self.last_block_time += 1 - self.tip = block.sha256 - height += 1 - yield TestInstance([[block, True]]) - - ''' Mine 199 new version blocks on last valid tip ''' - test_blocks = [] - for i in range(199): - block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1) - block.nVersion = 4 - block.rehash() - block.solve() - test_blocks.append([block, True]) - self.last_block_time += 1 - self.tip = block.sha256 - height += 1 - yield TestInstance(test_blocks, sync_every_block=False) - - ''' Mine 1 old version block ''' - block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1) + node0.send_and_ping(msg_block(block)) + 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.rehash() block.solve() - self.last_block_time += 1 - self.tip = block.sha256 - height += 1 - yield TestInstance([[block, True]]) + node0.send_and_ping(msg_block(block)) + assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip) - ''' Mine 1 new version block ''' - block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1) + assert wait_until(lambda: "reject" in node0.last_message.keys()) + with mininode_lock: + assert_equal(node0.last_message["reject"].code, REJECT_OBSOLETE) + assert_equal(node0.last_message["reject"].reason, b'bad-version(0x00000003)') + assert_equal(node0.last_message["reject"].data, block.sha256) + del node0.last_message["reject"] + + self.log.info("Test that invalid-according-to-cltv transactions cannot appear in a block") block.nVersion = 4 - block.rehash() - block.solve() - self.last_block_time += 1 - self.tip = block.sha256 - height += 1 - yield TestInstance([[block, True]]) - - ''' - Check that the new CLTV rules are enforced in the 951st version 4 - block. - ''' - spendtx = self.create_transaction(self.nodes[0], - self.coinbase_blocks[1], self.nodeaddress, 1.0) + + spendtx = create_transaction(self.nodes[0], self.coinbase_blocks[1], + self.nodeaddress, 1.0) cltv_invalidate(spendtx) spendtx.rehash() - block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1) - block.nVersion = 4 + # First we show that this tx is valid except for CLTV by getting it + # accepted to the mempool (which we can achieve with + # -promiscuousmempoolflags). + node0.send_and_ping(msg_tx(spendtx)) + assert spendtx.hash in self.nodes[0].getrawmempool() + + # Now we verify that a block with this transaction is invalid. block.vtx.append(spendtx) block.hashMerkleRoot = block.calc_merkle_root() - block.rehash() block.solve() - self.last_block_time += 1 - yield TestInstance([[block, False]]) - ''' Mine 1 old version block, should be invalid ''' - block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1) - block.nVersion = 3 - block.rehash() + node0.send_and_ping(msg_block(block)) + assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip) + + assert wait_until (lambda: "reject" in node0.last_message.keys()) + with mininode_lock: + assert node0.last_message["reject"].code in [REJECT_INVALID, REJECT_NONSTANDARD] + assert_equal(node0.last_message["reject"].data, block.sha256) + if node0.last_message["reject"].code == REJECT_INVALID: + # Generic rejection when a block is invalid + assert_equal(node0.last_message["reject"].reason, b'block-validation-failed') + else: + assert b'Negative locktime' in node0.last_message["reject"].reason + + self.log.info("Test that a version 4 block with a valid-according-to-CLTV transaction is accepted") + spendtx = cltv_validate(self.nodes[0], spendtx, CLTV_HEIGHT - 1) + spendtx.rehash() + + block.vtx.pop(1) + block.vtx.append(spendtx) + block.hashMerkleRoot = block.calc_merkle_root() block.solve() - self.last_block_time += 1 - yield TestInstance([[block, False]]) + + node0.send_and_ping(msg_block(block)) + assert_equal(int(self.nodes[0].getbestblockhash(), 16), block.sha256) + if __name__ == '__main__': BIP65Test().main() diff --git a/test/functional/bip65-cltv.py b/test/functional/bip65-cltv.py deleted file mode 100755 index ddf932c746..0000000000 --- a/test/functional/bip65-cltv.py +++ /dev/null @@ -1,82 +0,0 @@ -#!/usr/bin/env python3 -# Copyright (c) 2015-2016 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 the CHECKLOCKTIMEVERIFY (BIP65) soft-fork logic.""" - -from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import * - -class BIP65Test(BitcoinTestFramework): - def __init__(self): - super().__init__() - self.num_nodes = 3 - self.setup_clean_chain = False - self.extra_args = [[], ["-blockversion=3"], ["-blockversion=4"]] - - def setup_network(self): - self.setup_nodes() - connect_nodes(self.nodes[1], 0) - connect_nodes(self.nodes[2], 0) - self.sync_all() - - def run_test(self): - cnt = self.nodes[0].getblockcount() - - # Mine some old-version blocks - self.nodes[1].generate(200) - cnt += 100 - self.sync_all() - if (self.nodes[0].getblockcount() != cnt + 100): - raise AssertionError("Failed to mine 100 version=3 blocks") - - # Mine 750 new-version blocks - for i in range(15): - self.nodes[2].generate(50) - self.sync_all() - if (self.nodes[0].getblockcount() != cnt + 850): - raise AssertionError("Failed to mine 750 version=4 blocks") - - # TODO: check that new CHECKLOCKTIMEVERIFY rules are not enforced - - # Mine 1 new-version block - self.nodes[2].generate(1) - self.sync_all() - if (self.nodes[0].getblockcount() != cnt + 851): - raise AssertionError("Failed to mine a version=4 blocks") - - # TODO: check that new CHECKLOCKTIMEVERIFY rules are enforced - - # Mine 198 new-version blocks - for i in range(2): - self.nodes[2].generate(99) - self.sync_all() - if (self.nodes[0].getblockcount() != cnt + 1049): - raise AssertionError("Failed to mine 198 version=4 blocks") - - # Mine 1 old-version block - self.nodes[1].generate(1) - self.sync_all() - if (self.nodes[0].getblockcount() != cnt + 1050): - raise AssertionError("Failed to mine a version=3 block after 949 version=4 blocks") - - # Mine 1 new-version blocks - self.nodes[2].generate(1) - self.sync_all() - if (self.nodes[0].getblockcount() != cnt + 1051): - raise AssertionError("Failed to mine a version=4 block") - - # Mine 1 old-version blocks. This should fail - assert_raises_jsonrpc(-1,"CreateNewBlock: TestBlockValidity failed: bad-version(0x00000003)", self.nodes[1].generate, 1) - self.sync_all() - if (self.nodes[0].getblockcount() != cnt + 1051): - raise AssertionError("Accepted a version=3 block after 950 version=4 blocks") - - # Mine 1 new-version blocks - self.nodes[2].generate(1) - self.sync_all() - if (self.nodes[0].getblockcount() != cnt + 1052): - raise AssertionError("Failed to mine a version=4 block") - -if __name__ == '__main__': - BIP65Test().main() diff --git a/test/functional/bipdersig-p2p.py b/test/functional/bipdersig-p2p.py index 31c7ebba90..38a9009544 100755 --- a/test/functional/bipdersig-p2p.py +++ b/test/functional/bipdersig-p2p.py @@ -4,28 +4,24 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test BIP66 (DER SIG). -Connect to a single node. -Mine 2 (version 2) blocks (save the coinbases for later). -Generate 98 more version 2 blocks, verify the node accepts. -Mine 749 version 3 blocks, verify the node accepts. -Check that the new DERSIG rules are not enforced on the 750th version 3 block. -Check that the new DERSIG rules are enforced on the 751st version 3 block. -Mine 199 new version blocks. -Mine 1 old-version block. -Mine 1 new version block. -Mine 1 old version block, see that the node rejects. +Test that the DERSIG soft-fork activates at (regtest) height 1251. """ -from test_framework.test_framework import ComparisonTestFramework +from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * -from test_framework.mininode import CTransaction, NetworkThread +from test_framework.mininode import * from test_framework.blocktools import create_coinbase, create_block -from test_framework.comptool import TestInstance, TestManager from test_framework.script import CScript from io import BytesIO -import time -# A canonical signature consists of: +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): """ @@ -40,143 +36,122 @@ def unDERify(tx): else: newscript.append(i) tx.vin[0].scriptSig = CScript(newscript) - -class BIP66Test(ComparisonTestFramework): + +def create_transaction(node, coinbase, to_address, amount): + from_txid = node.getblock(coinbase)['tx'][0] + inputs = [{ "txid" : from_txid, "vout" : 0}] + outputs = { to_address : amount } + rawtx = node.createrawtransaction(inputs, outputs) + signresult = node.signrawtransaction(rawtx) + tx = CTransaction() + tx.deserialize(BytesIO(hex_str_to_bytes(signresult['hex']))) + return tx + +class BIP66Test(BitcoinTestFramework): def __init__(self): super().__init__() self.num_nodes = 1 + self.extra_args = [['-promiscuousmempoolflags=1', '-whitelist=127.0.0.1']] + self.setup_clean_chain = True def run_test(self): - test = TestManager(self, self.options.tmpdir) - test.add_all_connections(self.nodes) + node0 = NodeConnCB() + connections = [] + connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], node0)) + node0.add_connection(connections[0]) NetworkThread().start() # Start up network handling in another thread - test.run() - - def create_transaction(self, node, coinbase, to_address, amount): - from_txid = node.getblock(coinbase)['tx'][0] - inputs = [{ "txid" : from_txid, "vout" : 0}] - outputs = { to_address : amount } - rawtx = node.createrawtransaction(inputs, outputs) - signresult = node.signrawtransaction(rawtx) - tx = CTransaction() - f = BytesIO(hex_str_to_bytes(signresult['hex'])) - tx.deserialize(f) - return tx - - def get_tests(self): - - self.coinbase_blocks = self.nodes[0].generate(2) - height = 3 # height of the next block to build - self.tip = int("0x" + self.nodes[0].getbestblockhash(), 0) + + # wait_for_verack ensures that the P2P connection is fully up. + node0.wait_for_verack() + + self.log.info("Mining %d blocks", DERSIG_HEIGHT - 2) + self.coinbase_blocks = self.nodes[0].generate(DERSIG_HEIGHT - 2) self.nodeaddress = self.nodes[0].getnewaddress() - self.last_block_time = int(time.time()) - - ''' 298 more version 2 blocks ''' - test_blocks = [] - for i in range(298): - block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1) - block.nVersion = 2 - block.rehash() - block.solve() - test_blocks.append([block, True]) - self.last_block_time += 1 - self.tip = block.sha256 - height += 1 - yield TestInstance(test_blocks, sync_every_block=False) - - ''' Mine 749 version 3 blocks ''' - test_blocks = [] - for i in range(749): - block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1) - block.nVersion = 3 - block.rehash() - block.solve() - test_blocks.append([block, True]) - self.last_block_time += 1 - self.tip = block.sha256 - height += 1 - yield TestInstance(test_blocks, sync_every_block=False) - - ''' - Check that the new DERSIG rules are not enforced in the 750th - version 3 block. - ''' - spendtx = self.create_transaction(self.nodes[0], - self.coinbase_blocks[0], self.nodeaddress, 1.0) + + self.log.info("Test that a transaction with non-DER signature can still appear in a block") + + spendtx = create_transaction(self.nodes[0], self.coinbase_blocks[0], + self.nodeaddress, 1.0) unDERify(spendtx) spendtx.rehash() - block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1) - block.nVersion = 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 - 1), block_time) + block.nVersion = 2 block.vtx.append(spendtx) block.hashMerkleRoot = block.calc_merkle_root() block.rehash() block.solve() - self.last_block_time += 1 - self.tip = block.sha256 - height += 1 - yield TestInstance([[block, True]]) - - ''' Mine 199 new version blocks on last valid tip ''' - test_blocks = [] - for i in range(199): - block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1) - block.nVersion = 3 - block.rehash() - block.solve() - test_blocks.append([block, True]) - self.last_block_time += 1 - self.tip = block.sha256 - height += 1 - yield TestInstance(test_blocks, sync_every_block=False) - - ''' Mine 1 old version block ''' - block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1) + node0.send_and_ping(msg_block(block)) + assert_equal(self.nodes[0].getbestblockhash(), block.hash) + + self.log.info("Test that blocks must now be at least version 3") + tip = block.sha256 + block_time += 1 + block = create_block(tip, create_coinbase(DERSIG_HEIGHT), block_time) block.nVersion = 2 block.rehash() block.solve() - self.last_block_time += 1 - self.tip = block.sha256 - height += 1 - yield TestInstance([[block, True]]) + node0.send_and_ping(msg_block(block)) + assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip) - ''' Mine 1 new version block ''' - block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1) + assert wait_until(lambda: "reject" in node0.last_message.keys()) + with mininode_lock: + assert_equal(node0.last_message["reject"].code, REJECT_OBSOLETE) + assert_equal(node0.last_message["reject"].reason, b'bad-version(0x00000002)') + assert_equal(node0.last_message["reject"].data, block.sha256) + del node0.last_message["reject"] + + self.log.info("Test that transactions with non-DER signatures cannot appear in a block") block.nVersion = 3 - block.rehash() - block.solve() - self.last_block_time += 1 - self.tip = block.sha256 - height += 1 - yield TestInstance([[block, True]]) - - ''' - Check that the new DERSIG rules are enforced in the 951st version 3 - block. - ''' - spendtx = self.create_transaction(self.nodes[0], - self.coinbase_blocks[1], self.nodeaddress, 1.0) + + spendtx = create_transaction(self.nodes[0], self.coinbase_blocks[1], + self.nodeaddress, 1.0) unDERify(spendtx) spendtx.rehash() - block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1) - block.nVersion = 3 + # First we show that this tx is valid except for DERSIG by getting it + # accepted to the mempool (which we can achieve with + # -promiscuousmempoolflags). + node0.send_and_ping(msg_tx(spendtx)) + assert spendtx.hash in self.nodes[0].getrawmempool() + + # Now we verify that a block with this transaction is invalid. block.vtx.append(spendtx) block.hashMerkleRoot = block.calc_merkle_root() block.rehash() block.solve() - self.last_block_time += 1 - yield TestInstance([[block, False]]) - ''' Mine 1 old version block, should be invalid ''' - block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1) - block.nVersion = 2 + node0.send_and_ping(msg_block(block)) + assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip) + + assert wait_until (lambda: "reject" in node0.last_message.keys()) + with mininode_lock: + # We can receive different reject messages depending on whether + # bitcoind is running with multiple script check threads. If script + # check threads are not in use, then transaction script validation + # happens sequentially, and bitcoind produces more specific reject + # reasons. + assert node0.last_message["reject"].code in [REJECT_INVALID, REJECT_NONSTANDARD] + assert_equal(node0.last_message["reject"].data, block.sha256) + if node0.last_message["reject"].code == REJECT_INVALID: + # Generic rejection when a block is invalid + assert_equal(node0.last_message["reject"].reason, b'block-validation-failed') + else: + assert b'Non-canonical DER signature' in node0.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_blocks[1], self.nodeaddress, 1.0) + block.hashMerkleRoot = block.calc_merkle_root() block.rehash() block.solve() - self.last_block_time += 1 - yield TestInstance([[block, False]]) + + node0.send_and_ping(msg_block(block)) + assert_equal(int(self.nodes[0].getbestblockhash(), 16), block.sha256) if __name__ == '__main__': BIP66Test().main() diff --git a/test/functional/bipdersig.py b/test/functional/bipdersig.py deleted file mode 100755 index 41f88fb664..0000000000 --- a/test/functional/bipdersig.py +++ /dev/null @@ -1,81 +0,0 @@ -#!/usr/bin/env python3 -# Copyright (c) 2014-2016 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 the BIP66 changeover logic.""" - -from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import * - -class BIP66Test(BitcoinTestFramework): - def __init__(self): - super().__init__() - self.num_nodes = 3 - self.setup_clean_chain = False - self.extra_args = [[], ["-blockversion=2"], ["-blockversion=3"]] - - def setup_network(self): - self.setup_nodes() - connect_nodes(self.nodes[1], 0) - connect_nodes(self.nodes[2], 0) - self.sync_all() - - def run_test(self): - cnt = self.nodes[0].getblockcount() - - # Mine some old-version blocks - self.nodes[1].generate(100) - self.sync_all() - if (self.nodes[0].getblockcount() != cnt + 100): - raise AssertionError("Failed to mine 100 version=2 blocks") - - # Mine 750 new-version blocks - for i in range(15): - self.nodes[2].generate(50) - self.sync_all() - if (self.nodes[0].getblockcount() != cnt + 850): - raise AssertionError("Failed to mine 750 version=3 blocks") - - # TODO: check that new DERSIG rules are not enforced - - # Mine 1 new-version block - self.nodes[2].generate(1) - self.sync_all() - if (self.nodes[0].getblockcount() != cnt + 851): - raise AssertionError("Failed to mine a version=3 blocks") - - # TODO: check that new DERSIG rules are enforced - - # Mine 198 new-version blocks - for i in range(2): - self.nodes[2].generate(99) - self.sync_all() - if (self.nodes[0].getblockcount() != cnt + 1049): - raise AssertionError("Failed to mine 198 version=3 blocks") - - # Mine 1 old-version block - self.nodes[1].generate(1) - self.sync_all() - if (self.nodes[0].getblockcount() != cnt + 1050): - raise AssertionError("Failed to mine a version=2 block after 949 version=3 blocks") - - # Mine 1 new-version blocks - self.nodes[2].generate(1) - self.sync_all() - if (self.nodes[0].getblockcount() != cnt + 1051): - raise AssertionError("Failed to mine a version=3 block") - - # Mine 1 old-version blocks. This should fail - assert_raises_jsonrpc(-1, "CreateNewBlock: TestBlockValidity failed: bad-version(0x00000002)", self.nodes[1].generate, 1) - self.sync_all() - if (self.nodes[0].getblockcount() != cnt + 1051): - raise AssertionError("Accepted a version=2 block after 950 version=3 blocks") - - # Mine 1 new-version blocks - self.nodes[2].generate(1) - self.sync_all() - if (self.nodes[0].getblockcount() != cnt + 1052): - raise AssertionError("Failed to mine a version=3 block") - -if __name__ == '__main__': - BIP66Test().main() diff --git a/test/functional/fundrawtransaction.py b/test/functional/fundrawtransaction.py index 0baab6d01c..e52e773918 100755 --- a/test/functional/fundrawtransaction.py +++ b/test/functional/fundrawtransaction.py @@ -636,20 +636,9 @@ class RawTransactionsTest(BitcoinTestFramework): assert_fee_amount(result2['fee'], count_bytes(result2['hex']), 2 * result_fee_rate) assert_fee_amount(result3['fee'], count_bytes(result3['hex']), 10 * result_fee_rate) - ############################# - # Test address reuse option # - ############################# - - result3 = self.nodes[3].fundrawtransaction(rawtx, {"reserveChangeKey": False}) - res_dec = self.nodes[0].decoderawtransaction(result3["hex"]) - changeaddress = "" - for out in res_dec['vout']: - if out['value'] > 1.0: - changeaddress += out['scriptPubKey']['addresses'][0] - assert(changeaddress != "") - nextaddr = self.nodes[3].getrawchangeaddress() - # frt should not have removed the key from the keypool - assert(changeaddress == nextaddr) + ################################ + # Test no address reuse occurs # + ################################ result3 = self.nodes[3].fundrawtransaction(rawtx) res_dec = self.nodes[0].decoderawtransaction(result3["hex"]) diff --git a/test/functional/listsinceblock.py b/test/functional/listsinceblock.py index f3d41e573e..ce2d556ef0 100755 --- a/test/functional/listsinceblock.py +++ b/test/functional/listsinceblock.py @@ -14,7 +14,15 @@ class ListSinceBlockTest (BitcoinTestFramework): self.setup_clean_chain = True self.num_nodes = 4 - def run_test (self): + def run_test(self): + self.nodes[2].generate(101) + self.sync_all() + + self.test_reorg() + self.test_double_spend() + self.test_double_send() + + def test_reorg(self): ''' `listsinceblock` did not behave correctly when handed a block that was no longer in the main chain: @@ -43,14 +51,6 @@ class ListSinceBlockTest (BitcoinTestFramework): This test only checks that [tx0] is present. ''' - self.nodes[2].generate(101) - self.sync_all() - - assert_equal(self.nodes[0].getbalance(), 0) - assert_equal(self.nodes[1].getbalance(), 0) - assert_equal(self.nodes[2].getbalance(), 50) - assert_equal(self.nodes[3].getbalance(), 0) - # Split network into two self.split_network() @@ -73,7 +73,177 @@ class ListSinceBlockTest (BitcoinTestFramework): if tx['txid'] == senttx: found = True break - assert_equal(found, True) + assert found + + def test_double_spend(self): + ''' + This tests the case where the same UTXO is spent twice on two separate + blocks as part of a reorg. + + ab0 + / \ + aa1 [tx1] bb1 [tx2] + | | + aa2 bb2 + | | + aa3 bb3 + | + bb4 + + Problematic case: + + 1. User 1 receives BTC in tx1 from utxo1 in block aa1. + 2. User 2 receives BTC in tx2 from utxo1 (same) in block bb1 + 3. User 1 sees 2 confirmations at block aa3. + 4. Reorg into bb chain. + 5. User 1 asks `listsinceblock aa3` and does not see that tx1 is now + invalidated. + + Currently the solution to this is to detect that a reorg'd block is + asked for in listsinceblock, and to iterate back over existing blocks up + until the fork point, and to include all transactions that relate to the + node wallet. + ''' + + self.sync_all() + + # Split network into two + self.split_network() + + # share utxo between nodes[1] and nodes[2] + utxos = self.nodes[2].listunspent() + utxo = utxos[0] + privkey = self.nodes[2].dumpprivkey(utxo['address']) + self.nodes[1].importprivkey(privkey) + + # send from nodes[1] using utxo to nodes[0] + change = '%.8f' % (float(utxo['amount']) - 1.0003) + recipientDict = { + self.nodes[0].getnewaddress(): 1, + self.nodes[1].getnewaddress(): change, + } + utxoDicts = [{ + 'txid': utxo['txid'], + 'vout': utxo['vout'], + }] + txid1 = self.nodes[1].sendrawtransaction( + self.nodes[1].signrawtransaction( + self.nodes[1].createrawtransaction(utxoDicts, recipientDict))['hex']) + + # send from nodes[2] using utxo to nodes[3] + recipientDict2 = { + self.nodes[3].getnewaddress(): 1, + self.nodes[2].getnewaddress(): change, + } + self.nodes[2].sendrawtransaction( + self.nodes[2].signrawtransaction( + self.nodes[2].createrawtransaction(utxoDicts, recipientDict2))['hex']) + + # generate on both sides + lastblockhash = self.nodes[1].generate(3)[2] + self.nodes[2].generate(4) + + self.join_network() + + self.sync_all() + + # gettransaction should work for txid1 + assert self.nodes[0].gettransaction(txid1)['txid'] == txid1, "gettransaction failed to find txid1" + + # listsinceblock(lastblockhash) should now include txid1, as seen from nodes[0] + lsbres = self.nodes[0].listsinceblock(lastblockhash) + assert any(tx['txid'] == txid1 for tx in lsbres['removed']) + + # but it should not include 'removed' if include_removed=false + lsbres2 = self.nodes[0].listsinceblock(blockhash=lastblockhash, include_removed=False) + assert 'removed' not in lsbres2 + + def test_double_send(self): + ''' + This tests the case where the same transaction is submitted twice on two + separate blocks as part of a reorg. The former will vanish and the + latter will appear as the true transaction (with confirmations dropping + as a result). + + ab0 + / \ + aa1 [tx1] bb1 + | | + aa2 bb2 + | | + aa3 bb3 [tx1] + | + bb4 + + Asserted: + + 1. tx1 is listed in listsinceblock. + 2. It is included in 'removed' as it was removed, even though it is now + present in a different block. + 3. It is listed with a confirmations count of 2 (bb3, bb4), not + 3 (aa1, aa2, aa3). + ''' + + self.sync_all() + + # Split network into two + self.split_network() + + # create and sign a transaction + utxos = self.nodes[2].listunspent() + utxo = utxos[0] + change = '%.8f' % (float(utxo['amount']) - 1.0003) + recipientDict = { + self.nodes[0].getnewaddress(): 1, + self.nodes[2].getnewaddress(): change, + } + utxoDicts = [{ + 'txid': utxo['txid'], + 'vout': utxo['vout'], + }] + signedtxres = self.nodes[2].signrawtransaction( + self.nodes[2].createrawtransaction(utxoDicts, recipientDict)) + assert signedtxres['complete'] + + signedtx = signedtxres['hex'] + + # send from nodes[1]; this will end up in aa1 + txid1 = self.nodes[1].sendrawtransaction(signedtx) + + # generate bb1-bb2 on right side + self.nodes[2].generate(2) + + # send from nodes[2]; this will end up in bb3 + txid2 = self.nodes[2].sendrawtransaction(signedtx) + + assert_equal(txid1, txid2) + + # generate on both sides + lastblockhash = self.nodes[1].generate(3)[2] + self.nodes[2].generate(2) + + self.join_network() + + self.sync_all() + + # gettransaction should work for txid1 + self.nodes[0].gettransaction(txid1) + + # listsinceblock(lastblockhash) should now include txid1 in transactions + # as well as in removed + lsbres = self.nodes[0].listsinceblock(lastblockhash) + assert any(tx['txid'] == txid1 for tx in lsbres['transactions']) + assert any(tx['txid'] == txid1 for tx in lsbres['removed']) + + # find transaction and ensure confirmations is valid + for tx in lsbres['transactions']: + if tx['txid'] == txid1: + assert_equal(tx['confirmations'], 2) + + # the same check for the removed array; confirmations should STILL be 2 + for tx in lsbres['removed']: + if tx['txid'] == txid1: + assert_equal(tx['confirmations'], 2) if __name__ == '__main__': ListSinceBlockTest().main() diff --git a/test/functional/multiwallet.py b/test/functional/multiwallet.py new file mode 100755 index 0000000000..5679f40503 --- /dev/null +++ b/test/functional/multiwallet.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python3 +# Copyright (c) 2017 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 multiwallet. + +Verify that a bitcoind node can load multiple wallet files +""" +import os + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import assert_equal, assert_raises_jsonrpc + +class MultiWalletTest(BitcoinTestFramework): + + def __init__(self): + super().__init__() + self.setup_clean_chain = True + self.num_nodes = 1 + self.extra_args = [['-wallet=w1', '-wallet=w2', '-wallet=w3']] + + def run_test(self): + self.stop_node(0) + + # should not initialize if there are duplicate wallets + self.assert_start_raises_init_error(0, self.options.tmpdir, ['-wallet=w1', '-wallet=w1'], 'Error loading wallet w1. Duplicate -wallet filename specified.') + + # should not initialize if wallet file is a directory + os.mkdir(os.path.join(self.options.tmpdir, 'node0', 'regtest', 'w11')) + self.assert_start_raises_init_error(0, self.options.tmpdir, ['-wallet=w11'], 'Error loading wallet w11. -wallet filename must be a regular file.') + + # should not initialize if wallet file is a symlink + os.symlink(os.path.join(self.options.tmpdir, 'node0', 'regtest', 'w1'), os.path.join(self.options.tmpdir, 'node0', 'regtest', 'w12')) + self.assert_start_raises_init_error(0, self.options.tmpdir, ['-wallet=w12'], 'Error loading wallet w12. -wallet filename must be a regular file.') + + self.nodes[0] = self.start_node(0, self.options.tmpdir, self.extra_args[0]) + + w1 = self.nodes[0] / "wallet/w1" + w1.generate(1) + + # accessing invalid wallet fails + assert_raises_jsonrpc(-18, "Requested wallet does not exist or is not loaded", (self.nodes[0] / "wallet/bad").getwalletinfo) + + # accessing wallet RPC without using wallet endpoint fails + assert_raises_jsonrpc(-19, "Wallet file not specified", self.nodes[0].getwalletinfo) + + # check w1 wallet balance + w1_info = w1.getwalletinfo() + assert_equal(w1_info['immature_balance'], 50) + w1_name = w1_info['walletname'] + assert_equal(w1_name, "w1") + + # check w1 wallet balance + w2 = self.nodes[0] / "wallet/w2" + w2_info = w2.getwalletinfo() + assert_equal(w2_info['immature_balance'], 0) + w2_name = w2_info['walletname'] + assert_equal(w2_name, "w2") + + w3 = self.nodes[0] / "wallet/w3" + w3_name = w3.getwalletinfo()['walletname'] + assert_equal(w3_name, "w3") + + assert_equal({"w1", "w2", "w3"}, {w1_name, w2_name, w3_name}) + + w1.generate(101) + assert_equal(w1.getbalance(), 100) + assert_equal(w2.getbalance(), 0) + assert_equal(w3.getbalance(), 0) + + w1.sendtoaddress(w2.getnewaddress(), 1) + w1.sendtoaddress(w3.getnewaddress(), 2) + w1.generate(1) + assert_equal(w2.getbalance(), 1) + assert_equal(w3.getbalance(), 2) + +if __name__ == '__main__': + MultiWalletTest().main() diff --git a/test/functional/p2p-leaktests.py b/test/functional/p2p-leaktests.py index 33b57ef33d..5611c876ae 100755 --- a/test/functional/p2p-leaktests.py +++ b/test/functional/p2p-leaktests.py @@ -9,7 +9,10 @@ received a VERACK. This test connects to a node and sends it a few messages, trying to intice it into sending us something it shouldn't. -""" + +Also test that nodes that send unsupported service bits to bitcoind are disconnected +and don't receive a VERACK. Unsupported service bits are currently 1 << 5 and +1 << 7 (until August 1st 2018).""" from test_framework.mininode import * from test_framework.test_framework import BitcoinTestFramework @@ -98,20 +101,29 @@ class P2PLeakTest(BitcoinTestFramework): no_version_bannode = CNodeNoVersionBan() no_version_idlenode = CNodeNoVersionIdle() no_verack_idlenode = CNodeNoVerackIdle() + unsupported_service_bit5_node = CLazyNode() + unsupported_service_bit7_node = CLazyNode() + self.nodes[0].setmocktime(1501545600) # August 1st 2017 connections = [] connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], no_version_bannode, send_version=False)) connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], no_version_idlenode, send_version=False)) connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], no_verack_idlenode)) + connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], unsupported_service_bit5_node, services=NODE_NETWORK|NODE_UNSUPPORTED_SERVICE_BIT_5)) + connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], unsupported_service_bit7_node, services=NODE_NETWORK|NODE_UNSUPPORTED_SERVICE_BIT_7)) no_version_bannode.add_connection(connections[0]) no_version_idlenode.add_connection(connections[1]) no_verack_idlenode.add_connection(connections[2]) + unsupported_service_bit5_node.add_connection(connections[3]) + unsupported_service_bit7_node.add_connection(connections[4]) NetworkThread().start() # Start up network handling in another thread assert wait_until(lambda: no_version_bannode.ever_connected, timeout=10) assert wait_until(lambda: no_version_idlenode.ever_connected, timeout=10) assert wait_until(lambda: no_verack_idlenode.version_received, timeout=10) + assert wait_until(lambda: unsupported_service_bit5_node.ever_connected, timeout=10) + assert wait_until(lambda: unsupported_service_bit7_node.ever_connected, timeout=10) # Mine a block and make sure that it's not sent to the connected nodes self.nodes[0].generate(1) @@ -122,12 +134,32 @@ class P2PLeakTest(BitcoinTestFramework): #This node should have been banned assert not no_version_bannode.connected + # These nodes should have been disconnected + assert not unsupported_service_bit5_node.connected + assert not unsupported_service_bit7_node.connected + [conn.disconnect_node() for conn in connections] # Make sure no unexpected messages came in assert(no_version_bannode.unexpected_msg == False) assert(no_version_idlenode.unexpected_msg == False) assert(no_verack_idlenode.unexpected_msg == False) + assert not unsupported_service_bit5_node.unexpected_msg + assert not unsupported_service_bit7_node.unexpected_msg + + self.log.info("Service bits 5 and 7 are allowed after August 1st 2018") + self.nodes[0].setmocktime(1533168000) # August 2nd 2018 + + allowed_service_bit5_node = NodeConnCB() + allowed_service_bit7_node = NodeConnCB() + + connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], allowed_service_bit5_node, services=NODE_NETWORK|NODE_UNSUPPORTED_SERVICE_BIT_5)) + connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], allowed_service_bit7_node, services=NODE_NETWORK|NODE_UNSUPPORTED_SERVICE_BIT_7)) + allowed_service_bit5_node.add_connection(connections[5]) + allowed_service_bit7_node.add_connection(connections[6]) + + assert wait_until(lambda: allowed_service_bit5_node.message_count["verack"], timeout=10) + assert wait_until(lambda: allowed_service_bit7_node.message_count["verack"], timeout=10) if __name__ == '__main__': P2PLeakTest().main() diff --git a/test/functional/rawtransactions.py b/test/functional/rawtransactions.py index 35debf9cab..6272fc69b7 100755 --- a/test/functional/rawtransactions.py +++ b/test/functional/rawtransactions.py @@ -114,7 +114,7 @@ class RawTransactionsTest(BitcoinTestFramework): rawTx = self.nodes[2].createrawtransaction(inputs, outputs) rawTxPartialSigned = self.nodes[1].signrawtransaction(rawTx, inputs) assert_equal(rawTxPartialSigned['complete'], False) #node1 only has one key, can't comp. sign the tx - + rawTxSigned = self.nodes[2].signrawtransaction(rawTx, inputs) assert_equal(rawTxSigned['complete'], True) #node2 can sign the tx compl., own two of three keys self.nodes[2].sendrawtransaction(rawTxSigned['hex']) @@ -124,6 +124,55 @@ class RawTransactionsTest(BitcoinTestFramework): self.sync_all() assert_equal(self.nodes[0].getbalance(), bal+Decimal('50.00000000')+Decimal('2.19000000')) #block reward + tx + # 2of2 test for combining transactions + bal = self.nodes[2].getbalance() + addr1 = self.nodes[1].getnewaddress() + addr2 = self.nodes[2].getnewaddress() + + addr1Obj = self.nodes[1].validateaddress(addr1) + addr2Obj = self.nodes[2].validateaddress(addr2) + + self.nodes[1].addmultisigaddress(2, [addr1Obj['pubkey'], addr2Obj['pubkey']]) + mSigObj = self.nodes[2].addmultisigaddress(2, [addr1Obj['pubkey'], addr2Obj['pubkey']]) + mSigObjValid = self.nodes[2].validateaddress(mSigObj) + + txId = self.nodes[0].sendtoaddress(mSigObj, 2.2) + decTx = self.nodes[0].gettransaction(txId) + rawTx2 = self.nodes[0].decoderawtransaction(decTx['hex']) + self.sync_all() + self.nodes[0].generate(1) + self.sync_all() + + assert_equal(self.nodes[2].getbalance(), bal) # the funds of a 2of2 multisig tx should not be marked as spendable + + txDetails = self.nodes[0].gettransaction(txId, True) + rawTx2 = self.nodes[0].decoderawtransaction(txDetails['hex']) + vout = False + for outpoint in rawTx2['vout']: + if outpoint['value'] == Decimal('2.20000000'): + vout = outpoint + break + + bal = self.nodes[0].getbalance() + inputs = [{ "txid" : txId, "vout" : vout['n'], "scriptPubKey" : vout['scriptPubKey']['hex'], "redeemScript" : mSigObjValid['hex']}] + outputs = { self.nodes[0].getnewaddress() : 2.19 } + rawTx2 = self.nodes[2].createrawtransaction(inputs, outputs) + rawTxPartialSigned1 = self.nodes[1].signrawtransaction(rawTx2, inputs) + self.log.info(rawTxPartialSigned1) + assert_equal(rawTxPartialSigned['complete'], False) #node1 only has one key, can't comp. sign the tx + + rawTxPartialSigned2 = self.nodes[2].signrawtransaction(rawTx2, inputs) + self.log.info(rawTxPartialSigned2) + assert_equal(rawTxPartialSigned2['complete'], False) #node2 only has one key, can't comp. sign the tx + rawTxComb = self.nodes[2].combinerawtransaction([rawTxPartialSigned1['hex'], rawTxPartialSigned2['hex']]) + self.log.info(rawTxComb) + self.nodes[2].sendrawtransaction(rawTxComb) + rawTx2 = self.nodes[0].decoderawtransaction(rawTxComb) + self.sync_all() + self.nodes[0].generate(1) + self.sync_all() + assert_equal(self.nodes[0].getbalance(), bal+Decimal('50.00000000')+Decimal('2.19000000')) #block reward + tx + # getrawtransaction tests # 1. valid parameters - only supply txid txHash = rawTx["hash"] @@ -156,17 +205,17 @@ class RawTransactionsTest(BitcoinTestFramework): rawtx = self.nodes[0].createrawtransaction(inputs, outputs) decrawtx= self.nodes[0].decoderawtransaction(rawtx) assert_equal(decrawtx['vin'][0]['sequence'], 1000) - + # 9. invalid parameters - sequence number out of range inputs = [ {'txid' : "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000", 'vout' : 1, 'sequence' : -1}] outputs = { self.nodes[0].getnewaddress() : 1 } assert_raises_jsonrpc(-8, 'Invalid parameter, sequence number is out of range', self.nodes[0].createrawtransaction, inputs, outputs) - + # 10. invalid parameters - sequence number out of range inputs = [ {'txid' : "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000", 'vout' : 1, 'sequence' : 4294967296}] outputs = { self.nodes[0].getnewaddress() : 1 } assert_raises_jsonrpc(-8, 'Invalid parameter, sequence number is out of range', self.nodes[0].createrawtransaction, inputs, outputs) - + inputs = [ {'txid' : "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000", 'vout' : 1, 'sequence' : 4294967294}] outputs = { self.nodes[0].getnewaddress() : 1 } rawtx = self.nodes[0].createrawtransaction(inputs, outputs) diff --git a/test/functional/segwit.py b/test/functional/segwit.py index ac95d66466..51eaa34a54 100755 --- a/test/functional/segwit.py +++ b/test/functional/segwit.py @@ -459,13 +459,14 @@ class SegWitTest(BitcoinTestFramework): self.mine_and_test_listunspent(unsolvable_after_importaddress, 1) self.mine_and_test_listunspent(unseen_anytime, 0) - # addwitnessaddress should refuse to return a witness address if an uncompressed key is used or the address is - # not in the wallet + # addwitnessaddress should refuse to return a witness address if an uncompressed key is used # note that no witness address should be returned by unsolvable addresses - # the multisig_without_privkey_address will fail because its keys were not added with importpubkey - for i in uncompressed_spendable_address + uncompressed_solvable_address + unknown_address + unsolvable_address + [multisig_without_privkey_address]: + for i in uncompressed_spendable_address + uncompressed_solvable_address + unknown_address + unsolvable_address: assert_raises_jsonrpc(-4, "Public key or redeemscript not known to wallet, or the key is uncompressed", self.nodes[0].addwitnessaddress, i) + # addwitnessaddress should return a witness addresses even if keys are not in the wallet + self.nodes[0].addwitnessaddress(multisig_without_privkey_address) + for i in compressed_spendable_address + compressed_solvable_address: witaddress = self.nodes[0].addwitnessaddress(i) # addwitnessaddress should return the same address if it is a known P2SH-witness address @@ -542,7 +543,7 @@ class SegWitTest(BitcoinTestFramework): # addwitnessaddress should refuse to return a witness address if an uncompressed key is used # note that a multisig address returned by addmultisigaddress is not solvable until it is added with importaddress # premature_witaddress are not accepted until the script is added with addwitnessaddress first - for i in uncompressed_spendable_address + uncompressed_solvable_address + premature_witaddress + [compressed_solvable_address[1]]: + for i in uncompressed_spendable_address + uncompressed_solvable_address + premature_witaddress: # This will raise an exception assert_raises_jsonrpc(-4, "Public key or redeemscript not known to wallet, or the key is uncompressed", self.nodes[0].addwitnessaddress, i) diff --git a/test/functional/signrawtransactions.py b/test/functional/signrawtransactions.py index 437905e764..415727268a 100755 --- a/test/functional/signrawtransactions.py +++ b/test/functional/signrawtransactions.py @@ -43,22 +43,6 @@ class SignRawTransactionsTest(BitcoinTestFramework): # 2) No script verification error occurred assert 'errors' not in rawTxSigned - # Check that signrawtransaction doesn't blow up on garbage merge attempts - dummyTxInconsistent = self.nodes[0].createrawtransaction([inputs[0]], outputs) - rawTxUnsigned = self.nodes[0].signrawtransaction(rawTx + dummyTxInconsistent, inputs) - - assert 'complete' in rawTxUnsigned - assert_equal(rawTxUnsigned['complete'], False) - - # Check that signrawtransaction properly merges unsigned and signed txn, even with garbage in the middle - rawTxSigned2 = self.nodes[0].signrawtransaction(rawTxUnsigned["hex"] + dummyTxInconsistent + rawTxSigned["hex"], inputs) - - assert 'complete' in rawTxSigned2 - assert_equal(rawTxSigned2['complete'], True) - - assert 'errors' not in rawTxSigned2 - - def script_verification_error_test(self): """Create and sign a raw transaction with valid (vin 0), invalid (vin 1) and one missing (vin 2) input script. diff --git a/test/functional/test_framework/authproxy.py b/test/functional/test_framework/authproxy.py index dfcc524313..b3671cbdc5 100644 --- a/test/functional/test_framework/authproxy.py +++ b/test/functional/test_framework/authproxy.py @@ -191,3 +191,6 @@ class AuthServiceProxy(object): else: log.debug("<-- [%.6f] %s"%(elapsed,responsedata)) return response + + def __truediv__(self, relative_uri): + return AuthServiceProxy("{}/{}".format(self.__service_url, relative_uri), self._service_name, connection=self.__conn) diff --git a/test/functional/test_framework/coverage.py b/test/functional/test_framework/coverage.py index 3f87ef91f6..227b1a17af 100644 --- a/test/functional/test_framework/coverage.py +++ b/test/functional/test_framework/coverage.py @@ -56,6 +56,8 @@ class AuthServiceProxyWrapper(object): def url(self): return self.auth_service_proxy_instance.url + def __truediv__(self, relative_uri): + return AuthServiceProxyWrapper(self.auth_service_proxy_instance / relative_uri) def get_filename(dirname, n_node): """ diff --git a/test/functional/test_framework/mininode.py b/test/functional/test_framework/mininode.py index 688347a68f..a4d85501e7 100755 --- a/test/functional/test_framework/mininode.py +++ b/test/functional/test_framework/mininode.py @@ -51,6 +51,8 @@ NODE_NETWORK = (1 << 0) NODE_GETUTXO = (1 << 1) NODE_BLOOM = (1 << 2) NODE_WITNESS = (1 << 3) +NODE_UNSUPPORTED_SERVICE_BIT_5 = (1 << 5) +NODE_UNSUPPORTED_SERVICE_BIT_7 = (1 << 7) logger = logging.getLogger("TestFramework.mininode") diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index b7bc6e841b..dfd3b89895 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -88,6 +88,7 @@ BASE_SCRIPTS= [ 'mempool_spendcoinbase.py', 'mempool_reorg.py', 'mempool_persist.py', + 'multiwallet.py', 'httpbasics.py', 'multi_rpc.py', 'proxy_test.py', @@ -114,6 +115,8 @@ BASE_SCRIPTS= [ 'listsinceblock.py', 'p2p-leaktests.py', 'wallet-encryption.py', + 'bipdersig-p2p.py', + 'bip65-cltv-p2p.py', 'uptime.py', ] @@ -137,10 +140,6 @@ EXTENDED_SCRIPTS = [ 'rpcbind_test.py', # vv Tests less than 30s vv 'assumevalid.py', - 'bip65-cltv.py', - 'bip65-cltv-p2p.py', - 'bipdersig-p2p.py', - 'bipdersig.py', 'example_test.py', 'txn_doublespend.py', 'txn_clone.py --mineblock', diff --git a/test/functional/zapwallettxes.py b/test/functional/zapwallettxes.py index e4d40520ef..af867d7a52 100755 --- a/test/functional/zapwallettxes.py +++ b/test/functional/zapwallettxes.py @@ -4,77 +4,73 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test the zapwallettxes functionality. -- start three bitcoind nodes -- create four transactions on node 0 - two are confirmed and two are - unconfirmed. -- restart node 1 and verify that both the confirmed and the unconfirmed +- start two bitcoind nodes +- create two transactions on node 0 - one is confirmed and one is unconfirmed. +- restart node 0 and verify that both the confirmed and the unconfirmed transactions are still available. -- restart node 0 and verify that the confirmed transactions are still - available, but that the unconfirmed transaction has been zapped. +- restart node 0 with zapwallettxes and persistmempool, and verify that both + the confirmed and the unconfirmed transactions are still available. +- restart node 0 with just zapwallettxed and verify that the confirmed + transactions are still available, but that the unconfirmed transaction has + been zapped. """ from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import * - +from test_framework.util import (assert_equal, + assert_raises_jsonrpc, + ) class ZapWalletTXesTest (BitcoinTestFramework): def __init__(self): super().__init__() self.setup_clean_chain = True - self.num_nodes = 3 - - def setup_network(self): - super().setup_network() - connect_nodes_bi(self.nodes,0,2) + self.num_nodes = 2 - def run_test (self): + def run_test(self): self.log.info("Mining blocks...") self.nodes[0].generate(1) self.sync_all() - self.nodes[1].generate(101) - self.sync_all() - - assert_equal(self.nodes[0].getbalance(), 50) - - txid0 = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11) - txid1 = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 10) + self.nodes[1].generate(100) self.sync_all() + + # This transaction will be confirmed + txid1 = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 10) + self.nodes[0].generate(1) self.sync_all() - - txid2 = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11) - txid3 = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 10) - - tx0 = self.nodes[0].gettransaction(txid0) - assert_equal(tx0['txid'], txid0) #tx0 must be available (confirmed) - - tx1 = self.nodes[0].gettransaction(txid1) - assert_equal(tx1['txid'], txid1) #tx1 must be available (confirmed) - - tx2 = self.nodes[0].gettransaction(txid2) - assert_equal(tx2['txid'], txid2) #tx2 must be available (unconfirmed) - - tx3 = self.nodes[0].gettransaction(txid3) - assert_equal(tx3['txid'], txid3) #tx3 must be available (unconfirmed) - - #restart bitcoind + + # This transaction will not be confirmed + txid2 = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 20) + + # Confirmed and unconfirmed transactions are now in the wallet. + assert_equal(self.nodes[0].gettransaction(txid1)['txid'], txid1) + assert_equal(self.nodes[0].gettransaction(txid2)['txid'], txid2) + + # Stop-start node0. Both confirmed and unconfirmed transactions remain in the wallet. + self.stop_node(0) + self.nodes[0] = self.start_node(0, self.options.tmpdir) + + assert_equal(self.nodes[0].gettransaction(txid1)['txid'], txid1) + assert_equal(self.nodes[0].gettransaction(txid2)['txid'], txid2) + + # Stop node0 and restart with zapwallettxes and persistmempool. The unconfirmed + # transaction is zapped from the wallet, but is re-added when the mempool is reloaded. self.stop_node(0) - self.nodes[0] = self.start_node(0,self.options.tmpdir) - - tx3 = self.nodes[0].gettransaction(txid3) - assert_equal(tx3['txid'], txid3) #tx must be available (unconfirmed) - + self.nodes[0] = self.start_node(0, self.options.tmpdir, ["-persistmempool=1", "-zapwallettxes=2"]) + + assert_equal(self.nodes[0].gettransaction(txid1)['txid'], txid1) + assert_equal(self.nodes[0].gettransaction(txid2)['txid'], txid2) + + # Stop node0 and restart with zapwallettxes, but not persistmempool. + # The unconfirmed transaction is zapped and is no longer in the wallet. self.stop_node(0) - - #restart bitcoind with zapwallettxes - self.nodes[0] = self.start_node(0,self.options.tmpdir, ["-zapwallettxes=1"]) - - assert_raises(JSONRPCException, self.nodes[0].gettransaction, [txid3]) - #there must be an exception because the unconfirmed wallettx0 must be gone by now + self.nodes[0] = self.start_node(0, self.options.tmpdir, ["-zapwallettxes=2"]) - tx0 = self.nodes[0].gettransaction(txid0) - assert_equal(tx0['txid'], txid0) #tx0 (confirmed) must still be available because it was confirmed + # tx1 is still be available because it was confirmed + assert_equal(self.nodes[0].gettransaction(txid1)['txid'], txid1) + # This will raise an exception because the unconfirmed transaction has been zapped + assert_raises_jsonrpc(-5, 'Invalid or non-wallet transaction id', self.nodes[0].gettransaction, txid2) if __name__ == '__main__': - ZapWalletTXesTest ().main () + ZapWalletTXesTest().main() |