aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rwxr-xr-xtest/functional/interface_bitcoin_cli.py19
-rwxr-xr-xtest/functional/p2p_filter.py14
-rwxr-xr-xtest/functional/p2p_invalid_locator.py2
-rwxr-xr-xtest/functional/p2p_leak.py6
-rwxr-xr-xtest/functional/rpc_generateblock.py105
-rwxr-xr-xtest/functional/test_framework/messages.py15
-rwxr-xr-xtest/functional/test_framework/mininode.py8
-rwxr-xr-xtest/functional/test_runner.py1
8 files changed, 143 insertions, 27 deletions
diff --git a/test/functional/interface_bitcoin_cli.py b/test/functional/interface_bitcoin_cli.py
index f04a58cd19..2e1e84b707 100755
--- a/test/functional/interface_bitcoin_cli.py
+++ b/test/functional/interface_bitcoin_cli.py
@@ -6,6 +6,12 @@
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, assert_raises_process_error, get_auth_cookie
+# The block reward of coinbaseoutput.nValue (50) BTC/block matures after
+# COINBASE_MATURITY (100) blocks. Therefore, after mining 101 blocks we expect
+# node 0 to have a balance of (BLOCKS - COINBASE_MATURITY) * 50 BTC/block.
+BLOCKS = 101
+BALANCE = (BLOCKS - 100) * 50
+
class TestBitcoinCli(BitcoinTestFramework):
def set_test_params(self):
@@ -17,6 +23,7 @@ class TestBitcoinCli(BitcoinTestFramework):
def run_test(self):
"""Main test logic"""
+ self.nodes[0].generate(BLOCKS)
cli_response = self.nodes[0].cli("-version").send_cli()
assert "{} RPC client version".format(self.config['environment']['PACKAGE_NAME']) in cli_response
@@ -35,7 +42,7 @@ class TestBitcoinCli(BitcoinTestFramework):
user, password = get_auth_cookie(self.nodes[0].datadir, self.chain)
self.log.info("Test -stdinrpcpass option")
- assert_equal(0, self.nodes[0].cli('-rpcuser=%s' % user, '-stdinrpcpass', input=password).getblockcount())
+ assert_equal(BLOCKS, self.nodes[0].cli('-rpcuser=%s' % user, '-stdinrpcpass', input=password).getblockcount())
assert_raises_process_error(1, "Incorrect rpcuser or rpcpassword", self.nodes[0].cli('-rpcuser=%s' % user, '-stdinrpcpass', input="foo").echo)
self.log.info("Test -stdin and -stdinrpcpass")
@@ -51,10 +58,8 @@ class TestBitcoinCli(BitcoinTestFramework):
self.log.info("Make sure that -getinfo with arguments fails")
assert_raises_process_error(1, "-getinfo takes no arguments", self.nodes[0].cli('-getinfo').help)
- self.log.info("Compare responses from `bitcoin-cli -getinfo` and the RPCs data is retrieved from.")
+ self.log.info("Test that -getinfo returns the expected network and blockchain info")
cli_get_info = self.nodes[0].cli('-getinfo').send_cli()
- if self.is_wallet_compiled():
- wallet_info = self.nodes[0].getwalletinfo()
network_info = self.nodes[0].getnetworkinfo()
blockchain_info = self.nodes[0].getblockchaininfo()
@@ -66,11 +71,15 @@ class TestBitcoinCli(BitcoinTestFramework):
assert_equal(cli_get_info['difficulty'], blockchain_info['difficulty'])
assert_equal(cli_get_info['chain'], blockchain_info['chain'])
if self.is_wallet_compiled():
- assert_equal(cli_get_info['balance'], wallet_info['balance'])
+ self.log.info("Test that -getinfo returns the expected wallet info")
+ assert_equal(cli_get_info['balance'], BALANCE)
+ wallet_info = self.nodes[0].getwalletinfo()
assert_equal(cli_get_info['keypoolsize'], wallet_info['keypoolsize'])
assert_equal(cli_get_info['paytxfee'], wallet_info['paytxfee'])
assert_equal(cli_get_info['relayfee'], network_info['relayfee'])
# unlocked_until is not tested because the wallet is not encrypted
+ else:
+ self.log.info("*** Wallet not compiled; -getinfo wallet tests skipped")
if __name__ == '__main__':
diff --git a/test/functional/p2p_filter.py b/test/functional/p2p_filter.py
index 188b130a57..b73d5784aa 100755
--- a/test/functional/p2p_filter.py
+++ b/test/functional/p2p_filter.py
@@ -14,10 +14,7 @@ from test_framework.messages import (
msg_filteradd,
msg_filterclear,
)
-from test_framework.mininode import (
- P2PInterface,
- mininode_lock,
-)
+from test_framework.mininode import P2PInterface
from test_framework.test_framework import BitcoinTestFramework
@@ -69,18 +66,15 @@ class FilterTest(BitcoinTestFramework):
filter_address = self.nodes[0].decodescript(filter_node.watch_script_pubkey)['addresses'][0]
self.log.info('Check that we receive merkleblock and tx if the filter matches a tx in a block')
- filter_node.merkleblock_received = False
block_hash = self.nodes[0].generatetoaddress(1, filter_address)[0]
txid = self.nodes[0].getblock(block_hash)['tx'][0]
+ filter_node.wait_for_merkleblock(block_hash)
filter_node.wait_for_tx(txid)
- assert filter_node.merkleblock_received
self.log.info('Check that we only receive a merkleblock if the filter does not match a tx in a block')
- with mininode_lock:
- filter_node.last_message.pop("merkleblock", None)
filter_node.tx_received = False
- self.nodes[0].generatetoaddress(1, self.nodes[0].getnewaddress())
- filter_node.wait_for_merkleblock()
+ block_hash = self.nodes[0].generatetoaddress(1, self.nodes[0].getnewaddress())[0]
+ filter_node.wait_for_merkleblock(block_hash)
assert not filter_node.tx_received
self.log.info('Check that we not receive a tx if the filter does not match a mempool tx')
diff --git a/test/functional/p2p_invalid_locator.py b/test/functional/p2p_invalid_locator.py
index 33b7060060..58be703bf6 100755
--- a/test/functional/p2p_invalid_locator.py
+++ b/test/functional/p2p_invalid_locator.py
@@ -34,7 +34,7 @@ class InvalidLocatorTest(BitcoinTestFramework):
msg.locator.vHave = [int(node.getblockhash(i - 1), 16) for i in range(block_count, block_count - (MAX_LOCATOR_SZ), -1)]
node.p2p.send_message(msg)
if type(msg) == msg_getheaders:
- node.p2p.wait_for_header(int(node.getbestblockhash(), 16))
+ node.p2p.wait_for_header(node.getbestblockhash())
else:
node.p2p.wait_for_block(int(node.getbestblockhash(), 16))
diff --git a/test/functional/p2p_leak.py b/test/functional/p2p_leak.py
index 08e1f0bcd4..c574c1ab9f 100755
--- a/test/functional/p2p_leak.py
+++ b/test/functional/p2p_leak.py
@@ -4,7 +4,7 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test message sending before handshake completion.
-A node should never send anything other than VERSION/VERACK/REJECT until it's
+A node should never send anything other than VERSION/VERACK until it's
received a VERACK.
This test connects to a node and sends it a few messages, trying to entice it
@@ -39,7 +39,6 @@ class CLazyNode(P2PInterface):
def on_version(self, message): self.bad_message(message)
def on_verack(self, message): self.bad_message(message)
- def on_reject(self, message): self.bad_message(message)
def on_inv(self, message): self.bad_message(message)
def on_addr(self, message): self.bad_message(message)
def on_getdata(self, message): self.bad_message(message)
@@ -69,8 +68,6 @@ class CNodeNoVersionBan(CLazyNode):
for i in range(banscore):
self.send_message(msg_verack())
- def on_reject(self, message): pass
-
# Node that never sends a version. This one just sits idle and hopes to receive
# any message (it shouldn't!)
class CNodeNoVersionIdle(CLazyNode):
@@ -83,7 +80,6 @@ class CNodeNoVerackIdle(CLazyNode):
self.version_received = False
super().__init__()
- def on_reject(self, message): pass
def on_verack(self, message): pass
# When version is received, don't reply with a verack. Instead, see if the
# node will give us a message that it shouldn't. This is not an exhaustive
diff --git a/test/functional/rpc_generateblock.py b/test/functional/rpc_generateblock.py
new file mode 100755
index 0000000000..f23d9ec556
--- /dev/null
+++ b/test/functional/rpc_generateblock.py
@@ -0,0 +1,105 @@
+#!/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 generateblock rpc.
+'''
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (
+ assert_equal,
+ assert_raises_rpc_error,
+)
+
+class GenerateBlockTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.num_nodes = 1
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
+ def run_test(self):
+ node = self.nodes[0]
+
+ self.log.info('Generate an empty block to address')
+ address = node.getnewaddress()
+ hash = node.generateblock(address, [])['hash']
+ block = node.getblock(hash, 2)
+ assert_equal(len(block['tx']), 1)
+ assert_equal(block['tx'][0]['vout'][0]['scriptPubKey']['addresses'][0], address)
+
+ self.log.info('Generate an empty block to a descriptor')
+ hash = node.generateblock('addr(' + address + ')', [])['hash']
+ block = node.getblock(hash, 2)
+ assert_equal(len(block['tx']), 1)
+ assert_equal(block['tx'][0]['vout'][0]['scriptPubKey']['addresses'][0], address)
+
+ self.log.info('Generate an empty block to a combo descriptor with compressed pubkey')
+ combo_key = '0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798'
+ combo_address = 'bcrt1qw508d6qejxtdg4y5r3zarvary0c5xw7kygt080'
+ hash = node.generateblock('combo(' + combo_key + ')', [])['hash']
+ block = node.getblock(hash, 2)
+ assert_equal(len(block['tx']), 1)
+ assert_equal(block['tx'][0]['vout'][0]['scriptPubKey']['addresses'][0], combo_address)
+
+ self.log.info('Generate an empty block to a combo descriptor with uncompressed pubkey')
+ combo_key = '0408ef68c46d20596cc3f6ddf7c8794f71913add807f1dc55949fa805d764d191c0b7ce6894c126fce0babc6663042f3dde9b0cf76467ea315514e5a6731149c67'
+ combo_address = 'mkc9STceoCcjoXEXe6cm66iJbmjM6zR9B2'
+ hash = node.generateblock('combo(' + combo_key + ')', [])['hash']
+ block = node.getblock(hash, 2)
+ assert_equal(len(block['tx']), 1)
+ assert_equal(block['tx'][0]['vout'][0]['scriptPubKey']['addresses'][0], combo_address)
+
+ # Generate 110 blocks to spend
+ node.generatetoaddress(110, address)
+
+ # Generate some extra mempool transactions to verify they don't get mined
+ for i in range(10):
+ node.sendtoaddress(address, 0.001)
+
+ self.log.info('Generate block with txid')
+ txid = node.sendtoaddress(address, 1)
+ hash = node.generateblock(address, [txid])['hash']
+ block = node.getblock(hash, 1)
+ assert_equal(len(block['tx']), 2)
+ assert_equal(block['tx'][1], txid)
+
+ self.log.info('Generate block with raw tx')
+ utxos = node.listunspent(addresses=[address])
+ raw = node.createrawtransaction([{'txid':utxos[0]['txid'], 'vout':utxos[0]['vout']}],[{address:1}])
+ signed_raw = node.signrawtransactionwithwallet(raw)['hex']
+ hash = node.generateblock(address, [signed_raw])['hash']
+ block = node.getblock(hash, 1)
+ assert_equal(len(block['tx']), 2)
+ txid = block['tx'][1]
+ assert_equal(node.gettransaction(txid)['hex'], signed_raw)
+
+ self.log.info('Fail to generate block with out of order txs')
+ raw1 = node.createrawtransaction([{'txid':txid, 'vout':0}],[{address:0.9999}])
+ signed_raw1 = node.signrawtransactionwithwallet(raw1)['hex']
+ txid1 = node.sendrawtransaction(signed_raw1)
+ raw2 = node.createrawtransaction([{'txid':txid1, 'vout':0}],[{address:0.999}])
+ signed_raw2 = node.signrawtransactionwithwallet(raw2)['hex']
+ assert_raises_rpc_error(-25, 'TestBlockValidity failed: bad-txns-inputs-missingorspent', node.generateblock, address, [signed_raw2, txid1])
+
+ self.log.info('Fail to generate block with txid not in mempool')
+ missing_txid = '0000000000000000000000000000000000000000000000000000000000000000'
+ assert_raises_rpc_error(-5, 'Transaction ' + missing_txid + ' not in mempool.', node.generateblock, address, [missing_txid])
+
+ self.log.info('Fail to generate block with invalid raw tx')
+ invalid_raw_tx = '0000'
+ assert_raises_rpc_error(-22, 'Transaction decode failed for ' + invalid_raw_tx, node.generateblock, address, [invalid_raw_tx])
+
+ self.log.info('Fail to generate block with invalid address/descriptor')
+ assert_raises_rpc_error(-5, 'Invalid address or descriptor', node.generateblock, '1234', [])
+
+ self.log.info('Fail to generate block with a ranged descriptor')
+ ranged_descriptor = 'pkh(tpubD6NzVbkrYhZ4XgiXtGrdW5XDAPFCL9h7we1vwNCpn8tGbBcgfVYjXyhWo4E1xkh56hjod1RhGjxbaTLV3X4FyWuejifB9jusQ46QzG87VKp/0/*)'
+ assert_raises_rpc_error(-8, 'Ranged descriptor not accepted. Maybe pass through deriveaddresses first?', node.generateblock, ranged_descriptor, [])
+
+ self.log.info('Fail to generate block with a descriptor missing a private key')
+ child_descriptor = 'pkh(tpubD6NzVbkrYhZ4XgiXtGrdW5XDAPFCL9h7we1vwNCpn8tGbBcgfVYjXyhWo4E1xkh56hjod1RhGjxbaTLV3X4FyWuejifB9jusQ46QzG87VKp/0\'/0)'
+ assert_raises_rpc_error(-5, 'Cannot derive script without private keys', node.generateblock, child_descriptor, [])
+
+if __name__ == '__main__':
+ GenerateBlockTest().main()
diff --git a/test/functional/test_framework/messages.py b/test/functional/test_framework/messages.py
index 5f8fcc6fd8..45b49bcf9e 100755
--- a/test/functional/test_framework/messages.py
+++ b/test/functional/test_framework/messages.py
@@ -1321,10 +1321,23 @@ class msg_headers:
class msg_merkleblock:
+ __slots__ = ("merkleblock",)
command = b"merkleblock"
+ def __init__(self, merkleblock=None):
+ if merkleblock is None:
+ self.merkleblock = CMerkleBlock()
+ else:
+ self.merkleblock = merkleblock
+
def deserialize(self, f):
- pass # Placeholder for now
+ self.merkleblock.deserialize(f)
+
+ def serialize(self):
+ return self.merkleblock.serialize()
+
+ def __repr__(self):
+ return "msg_merkleblock(merkleblock=%s)" % (repr(self.merkleblock))
class msg_filterload:
diff --git a/test/functional/test_framework/mininode.py b/test/functional/test_framework/mininode.py
index ad330f2a93..9f51bef946 100755
--- a/test/functional/test_framework/mininode.py
+++ b/test/functional/test_framework/mininode.py
@@ -339,7 +339,6 @@ class P2PInterface(P2PConnection):
def on_merkleblock(self, message): pass
def on_notfound(self, message): pass
def on_pong(self, message): pass
- def on_reject(self, message): pass
def on_sendcmpct(self, message): pass
def on_sendheaders(self, message): pass
def on_tx(self, message): pass
@@ -393,18 +392,17 @@ class P2PInterface(P2PConnection):
last_headers = self.last_message.get('headers')
if not last_headers:
return False
- return last_headers.headers[0].rehash() == blockhash
+ return last_headers.headers[0].rehash() == int(blockhash, 16)
wait_until(test_function, timeout=timeout, lock=mininode_lock)
- def wait_for_merkleblock(self, timeout=60):
+ def wait_for_merkleblock(self, blockhash, timeout=60):
def test_function():
assert self.is_connected
last_filtered_block = self.last_message.get('merkleblock')
if not last_filtered_block:
return False
- # TODO change this method to take a hash value and only return true if the correct block has been received
- return True
+ return last_filtered_block.merkleblock.header.rehash() == int(blockhash, 16)
wait_until(test_function, timeout=timeout, lock=mininode_lock)
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index faa2dee4ed..ee71de3310 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -173,6 +173,7 @@ BASE_SCRIPTS = [
'wallet_importprunedfunds.py',
'p2p_leak_tx.py',
'rpc_signmessage.py',
+ 'rpc_generateblock.py',
'wallet_balance.py',
'feature_nulldummy.py',
'mempool_accept.py',