diff options
Diffstat (limited to 'test/functional')
-rwxr-xr-x | test/functional/feature_backwards_compatibility.py | 3 | ||||
-rwxr-xr-x | test/functional/p2p_addr_relay.py | 71 | ||||
-rwxr-xr-x | test/functional/p2p_filter.py | 5 | ||||
-rwxr-xr-x | test/functional/p2p_segwit.py | 6 | ||||
-rwxr-xr-x | test/functional/p2p_sendheaders.py | 4 | ||||
-rwxr-xr-x | test/functional/rpc_signrawtransaction.py | 43 | ||||
-rwxr-xr-x | test/functional/test_framework/messages.py | 19 | ||||
-rwxr-xr-x | test/functional/test_framework/mininode.py | 3 | ||||
-rwxr-xr-x | test/functional/test_framework/test_node.py | 4 | ||||
-rwxr-xr-x | test/functional/test_runner.py | 1 | ||||
-rwxr-xr-x | test/functional/wallet_avoidreuse.py | 25 | ||||
-rwxr-xr-x | test/functional/wallet_bumpfee.py | 17 |
12 files changed, 185 insertions, 16 deletions
diff --git a/test/functional/feature_backwards_compatibility.py b/test/functional/feature_backwards_compatibility.py index 0db74432e2..adf66243b7 100755 --- a/test/functional/feature_backwards_compatibility.py +++ b/test/functional/feature_backwards_compatibility.py @@ -40,6 +40,9 @@ class BackwardsCompatibilityTest(BitcoinTestFramework): ["-nowallet", "-walletrbf=1", "-addresstype=bech32"] # v0.17.1 ] + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def setup_nodes(self): if os.getenv("TEST_PREVIOUS_RELEASES") == "false": raise SkipTest("backwards compatibility tests") diff --git a/test/functional/p2p_addr_relay.py b/test/functional/p2p_addr_relay.py new file mode 100755 index 0000000000..6046237101 --- /dev/null +++ b/test/functional/p2p_addr_relay.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 +# Copyright (c) 2020 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 addr relay +""" + +from test_framework.messages import ( + CAddress, + NODE_NETWORK, + NODE_WITNESS, + msg_addr, +) +from test_framework.mininode import ( + P2PInterface, +) +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import ( + assert_equal, +) +import time + +ADDRS = [] +for i in range(10): + addr = CAddress() + addr.time = int(time.time()) + i + addr.nServices = NODE_NETWORK | NODE_WITNESS + addr.ip = "123.123.123.{}".format(i % 256) + addr.port = 8333 + i + ADDRS.append(addr) + + +class AddrReceiver(P2PInterface): + def on_addr(self, message): + for addr in message.addrs: + assert_equal(addr.nServices, 9) + assert addr.ip.startswith('123.123.123.') + assert (8333 <= addr.port < 8343) + + +class AddrTest(BitcoinTestFramework): + def set_test_params(self): + self.setup_clean_chain = False + self.num_nodes = 1 + + def run_test(self): + self.log.info('Create connection that sends addr messages') + addr_source = self.nodes[0].add_p2p_connection(P2PInterface()) + msg = msg_addr() + + self.log.info('Send too large addr message') + msg.addrs = ADDRS * 101 + with self.nodes[0].assert_debug_log(['message addr size() = 1010']): + addr_source.send_and_ping(msg) + + self.log.info('Check that addr message content is relayed and added to addrman') + addr_receiver = self.nodes[0].add_p2p_connection(AddrReceiver()) + msg.addrs = ADDRS + with self.nodes[0].assert_debug_log([ + 'Added 10 addresses from 127.0.0.1: 0 tried', + 'received: addr (301 bytes) peer=0', + 'sending addr (301 bytes) peer=1', + ]): + addr_source.send_and_ping(msg) + self.nodes[0].setmocktime(int(time.time()) + 30 * 60) + addr_receiver.sync_with_ping() + + +if __name__ == '__main__': + AddrTest().main() diff --git a/test/functional/p2p_filter.py b/test/functional/p2p_filter.py index 2940542e5e..188b130a57 100755 --- a/test/functional/p2p_filter.py +++ b/test/functional/p2p_filter.py @@ -11,6 +11,7 @@ from test_framework.messages import ( MSG_FILTERED_BLOCK, msg_getdata, msg_filterload, + msg_filteradd, msg_filterclear, ) from test_framework.mininode import ( @@ -103,6 +104,10 @@ class FilterTest(BitcoinTestFramework): txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 7) filter_node.wait_for_tx(txid) + self.log.info("Check that division-by-zero remote crash bug [CVE-2013-5700] is fixed") + filter_node.send_and_ping(msg_filterload(data=b'', nHashFuncs=1)) + filter_node.send_and_ping(msg_filteradd(data=b'letstrytocrashthisnode')) + if __name__ == '__main__': FilterTest().main() diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py index 118f31382a..d8dce7fe56 100755 --- a/test/functional/p2p_segwit.py +++ b/test/functional/p2p_segwit.py @@ -125,8 +125,7 @@ def test_transaction_acceptance(node, p2p, tx, with_witness, accepted, reason=No - use the getrawmempool rpc to check for acceptance.""" reason = [reason] if reason else [] with node.assert_debug_log(expected_msgs=reason): - p2p.send_message(msg_tx(tx) if with_witness else msg_no_witness_tx(tx)) - p2p.sync_with_ping() + p2p.send_and_ping(msg_tx(tx) if with_witness else msg_no_witness_tx(tx)) assert_equal(tx.hash in node.getrawmempool(), accepted) @@ -137,8 +136,7 @@ def test_witness_block(node, p2p, block, accepted, with_witness=True, reason=Non - use the getbestblockhash rpc to check for acceptance.""" reason = [reason] if reason else [] with node.assert_debug_log(expected_msgs=reason): - p2p.send_message(msg_block(block) if with_witness else msg_no_witness_block(block)) - p2p.sync_with_ping() + p2p.send_and_ping(msg_block(block) if with_witness else msg_no_witness_block(block)) assert_equal(node.getbestblockhash() == block.hash, accepted) diff --git a/test/functional/p2p_sendheaders.py b/test/functional/p2p_sendheaders.py index e543e647f2..84d818400a 100755 --- a/test/functional/p2p_sendheaders.py +++ b/test/functional/p2p_sendheaders.py @@ -243,10 +243,6 @@ class SendHeadersTest(BitcoinTestFramework): # will occur outside of direct fetching test_node = self.nodes[0].add_p2p_connection(BaseNode(), services=NODE_WITNESS) - # Ensure verack's have been processed by our peer - inv_node.sync_with_ping() - test_node.sync_with_ping() - self.test_null_locators(test_node, inv_node) self.test_nonnull_locators(test_node, inv_node) diff --git a/test/functional/rpc_signrawtransaction.py b/test/functional/rpc_signrawtransaction.py index 780758e219..17686f3a78 100755 --- a/test/functional/rpc_signrawtransaction.py +++ b/test/functional/rpc_signrawtransaction.py @@ -4,10 +4,11 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test transaction signing using the signrawtransaction* RPCs.""" +from test_framework.address import check_script, script_to_p2sh from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import assert_equal, assert_raises_rpc_error, hex_str_to_bytes +from test_framework.util import assert_equal, assert_raises_rpc_error, find_vout_for_address, hex_str_to_bytes from test_framework.messages import sha256 -from test_framework.script import CScript, OP_0 +from test_framework.script import CScript, OP_0, OP_CHECKSIG from decimal import Decimal @@ -168,6 +169,44 @@ class SignRawTransactionsTest(BitcoinTestFramework): assert 'complete' in spending_tx_signed assert_equal(spending_tx_signed['complete'], True) + self.log.info('Try with a P2PKH script as the witnessScript') + embedded_addr_info = self.nodes[1].getaddressinfo(self.nodes[1].getnewaddress('', 'legacy')) + embedded_privkey = self.nodes[1].dumpprivkey(embedded_addr_info['address']) + witness_script = embedded_addr_info['scriptPubKey'] + redeem_script = CScript([OP_0, sha256(check_script(witness_script))]).hex() + addr = script_to_p2sh(redeem_script) + script_pub_key = self.nodes[1].validateaddress(addr)['scriptPubKey'] + # Fund that address + txid = self.nodes[0].sendtoaddress(addr, 10) + vout = find_vout_for_address(self.nodes[0], txid, addr) + self.nodes[0].generate(1) + # Now create and sign a transaction spending that output on node[0], which doesn't know the scripts or keys + spending_tx = self.nodes[0].createrawtransaction([{'txid': txid, 'vout': vout}], {self.nodes[1].getnewaddress(): Decimal("9.999")}) + spending_tx_signed = self.nodes[0].signrawtransactionwithkey(spending_tx, [embedded_privkey], [{'txid': txid, 'vout': vout, 'scriptPubKey': script_pub_key, 'redeemScript': redeem_script, 'witnessScript': witness_script, 'amount': 10}]) + # Check the signing completed successfully + assert 'complete' in spending_tx_signed + assert_equal(spending_tx_signed['complete'], True) + self.nodes[0].sendrawtransaction(spending_tx_signed['hex']) + + self.log.info('Try with a P2PK script as the witnessScript') + embedded_addr_info = self.nodes[1].getaddressinfo(self.nodes[1].getnewaddress('', 'legacy')) + embedded_privkey = self.nodes[1].dumpprivkey(embedded_addr_info['address']) + witness_script = CScript([hex_str_to_bytes(embedded_addr_info['pubkey']), OP_CHECKSIG]).hex() + redeem_script = CScript([OP_0, sha256(check_script(witness_script))]).hex() + addr = script_to_p2sh(redeem_script) + script_pub_key = self.nodes[1].validateaddress(addr)['scriptPubKey'] + # Fund that address + txid = self.nodes[0].sendtoaddress(addr, 10) + vout = find_vout_for_address(self.nodes[0], txid, addr) + self.nodes[0].generate(1) + # Now create and sign a transaction spending that output on node[0], which doesn't know the scripts or keys + spending_tx = self.nodes[0].createrawtransaction([{'txid': txid, 'vout': vout}], {self.nodes[1].getnewaddress(): Decimal("9.999")}) + spending_tx_signed = self.nodes[0].signrawtransactionwithkey(spending_tx, [embedded_privkey], [{'txid': txid, 'vout': vout, 'scriptPubKey': script_pub_key, 'redeemScript': redeem_script, 'witnessScript': witness_script, 'amount': 10}]) + # Check the signing completed successfully + assert 'complete' in spending_tx_signed + assert_equal(spending_tx_signed['complete'], True) + self.nodes[0].sendrawtransaction(spending_tx_signed['hex']) + def run_test(self): self.successful_signing_test() self.script_verification_error_test() diff --git a/test/functional/test_framework/messages.py b/test/functional/test_framework/messages.py index ff0c763b72..5f8fcc6fd8 100755 --- a/test/functional/test_framework/messages.py +++ b/test/functional/test_framework/messages.py @@ -1356,6 +1356,25 @@ class msg_filterload: self.data, self.nHashFuncs, self.nTweak, self.nFlags) +class msg_filteradd: + __slots__ = ("data") + command = b"filteradd" + + def __init__(self, data): + self.data = data + + def deserialize(self, f): + self.data = deser_string(f) + + def serialize(self): + r = b"" + r += ser_string(self.data) + return r + + def __repr__(self): + return "msg_filteradd(data={})".format(self.data) + + class msg_filterclear: __slots__ = () command = b"filterclear" diff --git a/test/functional/test_framework/mininode.py b/test/functional/test_framework/mininode.py index ce51513ce9..ad330f2a93 100755 --- a/test/functional/test_framework/mininode.py +++ b/test/functional/test_framework/mininode.py @@ -30,6 +30,7 @@ from test_framework.messages import ( msg_blocktxn, msg_cmpctblock, msg_feefilter, + msg_filteradd, msg_filterclear, msg_filterload, msg_getaddr, @@ -65,6 +66,7 @@ MESSAGEMAP = { b"blocktxn": msg_blocktxn, b"cmpctblock": msg_cmpctblock, b"feefilter": msg_feefilter, + b"filteradd": msg_filteradd, b"filterclear": msg_filterclear, b"filterload": msg_filterload, b"getaddr": msg_getaddr, @@ -324,6 +326,7 @@ class P2PInterface(P2PConnection): def on_blocktxn(self, message): pass def on_cmpctblock(self, message): pass def on_feefilter(self, message): pass + def on_filteradd(self, message): pass def on_filterclear(self, message): pass def on_filterload(self, message): pass def on_getaddr(self, message): pass diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index 8260c917fe..53bc5ca9e7 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -233,6 +233,10 @@ class TestNode(): # -342 Service unavailable, RPC server started but is shutting down due to error if e.error['code'] != -28 and e.error['code'] != -342: raise # unknown JSON RPC exception + except ConnectionResetError: + # This might happen when the RPC server is in warmup, but shut down before the call to getblockcount + # succeeds. Try again to properly raise the FailedToStartError + pass except ValueError as e: # cookie file not found and no rpcuser or rpcassword. bitcoind still starting if "No RPC credentials" not in str(e): raise diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index 2f307750a9..faa2dee4ed 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -144,6 +144,7 @@ BASE_SCRIPTS = [ 'rpc_blockchain.py', 'rpc_deprecated.py', 'wallet_disable.py', + 'p2p_addr_relay.py', 'rpc_net.py', 'wallet_keypool.py', 'p2p_mempool.py', diff --git a/test/functional/wallet_avoidreuse.py b/test/functional/wallet_avoidreuse.py index 8e2dc03ac2..2ce8d459c6 100755 --- a/test/functional/wallet_avoidreuse.py +++ b/test/functional/wallet_avoidreuse.py @@ -83,6 +83,7 @@ class AvoidReuseTest(BitcoinTestFramework): self.nodes[0].generate(110) self.sync_all() + self.test_change_remains_change(self.nodes[1]) reset_balance(self.nodes[1], self.nodes[0].getnewaddress()) self.test_fund_send_fund_senddirty() reset_balance(self.nodes[1], self.nodes[0].getnewaddress()) @@ -137,6 +138,30 @@ class AvoidReuseTest(BitcoinTestFramework): # Unload temp wallet self.nodes[1].unloadwallet(tempwallet) + def test_change_remains_change(self, node): + self.log.info("Test that change doesn't turn into non-change when spent") + + reset_balance(node, node.getnewaddress()) + addr = node.getnewaddress() + txid = node.sendtoaddress(addr, 1) + out = node.listunspent(minconf=0, query_options={'minimumAmount': 2}) + assert_equal(len(out), 1) + assert_equal(out[0]['txid'], txid) + changeaddr = out[0]['address'] + + # Make sure it's starting out as change as expected + assert node.getaddressinfo(changeaddr)['ischange'] + for logical_tx in node.listtransactions(): + assert logical_tx.get('address') != changeaddr + + # Spend it + reset_balance(node, node.getnewaddress()) + + # It should still be change + assert node.getaddressinfo(changeaddr)['ischange'] + for logical_tx in node.listtransactions(): + assert logical_tx.get('address') != changeaddr + def test_fund_send_fund_senddirty(self): ''' Test the same as test_fund_send_fund_send, except send the 10 BTC with diff --git a/test/functional/wallet_bumpfee.py b/test/functional/wallet_bumpfee.py index 38c9807757..0b3dea94d5 100755 --- a/test/functional/wallet_bumpfee.py +++ b/test/functional/wallet_bumpfee.py @@ -253,12 +253,17 @@ def test_dust_to_fee(self, rbf_node, dest_address): self.log.info('Test that bumped output that is dust is dropped to fee') rbfid = spend_one_input(rbf_node, dest_address) fulltx = rbf_node.getrawtransaction(rbfid, 1) - # size of transaction (p2wpkh, 1 input, 2 outputs): 141 vbytes - assert_equal(fulltx["vsize"], 141) - # bump with fee_rate of 0.00350000 BTC per 1000 vbytes - # expected bump fee of 141 vbytes * fee_rate 0.00350000 BTC / 1000 vbytes = 0.00049350 BTC - # but dust is dropped, so actual bump fee is 0.00050000 - bumped_tx = rbf_node.bumpfee(rbfid, {"fee_rate": 0.0035}) + # The DER formatting used by Bitcoin to serialize ECDSA signatures means that signatures can have a + # variable size of 70-72 bytes (or possibly even less), with most being 71 or 72 bytes. The signature + # in the witness is divided by 4 for the vsize, so this variance can take the weight across a 4-byte + # boundary. Thus expected transaction size (p2wpkh, 1 input, 2 outputs) is 140-141 vbytes, usually 141. + if not 140 <= fulltx["vsize"] <= 141: + raise AssertionError("Invalid tx vsize of {} (140-141 expected), full tx: {}".format(fulltx["vsize"], fulltx)) + # Bump with fee_rate of 0.00350250 BTC per 1000 vbytes to create dust. + # Expected fee is 141 vbytes * fee_rate 0.00350250 BTC / 1000 vbytes = 0.00049385 BTC. + # or occasionally 140 vbytes * fee_rate 0.00350250 BTC / 1000 vbytes = 0.00049035 BTC. + # Dust should be dropped to the fee, so actual bump fee is 0.00050000 BTC. + bumped_tx = rbf_node.bumpfee(rbfid, {"fee_rate": 0.00350250}) full_bumped_tx = rbf_node.getrawtransaction(bumped_tx["txid"], 1) assert_equal(bumped_tx["fee"], Decimal("0.00050000")) assert_equal(len(fulltx["vout"]), 2) |