Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Functional tests: stabilizing results and a few test fixes. #63

Closed
wants to merge 15 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 20 additions & 10 deletions test/functional/feature_config_args.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ def set_test_params(self):
self.num_nodes = 1
self.supports_cli = False
self.wallet_names = []
self.disable_autoconnect = False

def test_config_file_parser(self):
self.stop_node(0)
Expand Down Expand Up @@ -157,14 +158,19 @@ def test_seed_peers(self):
self.stop_node(0)

# No peers.dat exists and -dnsseed=1
# We expect the node will use DNS Seeds, but Regtest mode has 0 DNS seeds
# So after 60 seconds, the node should fallback to fixed seeds (this is a slow test)
# We expect the node will use DNS Seeds, but Regtest mode does not have
# any valid DNS seeds. So after 60 seconds, the node should fallback to
# fixed seeds
assert not os.path.exists(os.path.join(default_data_dir, "peers.dat"))
start = int(time.time())
with self.nodes[0].assert_debug_log(expected_msgs=[
"Loaded 0 addresses from peers.dat",
"0 addresses found from DNS seeds",
]):
with self.nodes[0].assert_debug_log(
expected_msgs=[
"Loaded 0 addresses from peers.dat",
"0 addresses found from DNS seeds",
"opencon thread start", # Ensure ThreadOpenConnections::start time is properly set
],
timeout=10,
):
self.start_node(0, extra_args=['-dnsseed=1', '-fixedseeds=1', f'-mocktime={start}'])
with self.nodes[0].assert_debug_log(expected_msgs=[
"Adding fixed seeds as 60 seconds have passed and addrman is empty",
Expand Down Expand Up @@ -202,10 +208,14 @@ def test_seed_peers(self):
# We expect the node will allow 60 seconds prior to using fixed seeds
assert not os.path.exists(os.path.join(default_data_dir, "peers.dat"))
start = int(time.time())
with self.nodes[0].assert_debug_log(expected_msgs=[
"Loaded 0 addresses from peers.dat",
"DNS seeding disabled",
]):
with self.nodes[0].assert_debug_log(
expected_msgs=[
"Loaded 0 addresses from peers.dat",
"DNS seeding disabled",
"opencon thread start", # Ensure ThreadOpenConnections::start time is properly set
],
timeout=10,
):
self.start_node(0, extra_args=['-dnsseed=0', '-fixedseeds=1', '-addnode=fakenodeaddr', f'-mocktime={start}'])
with self.nodes[0].assert_debug_log(expected_msgs=[
"Adding fixed seeds as 60 seconds have passed and addrman is empty",
Expand Down
30 changes: 15 additions & 15 deletions test/functional/feature_loadblock.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import tempfile
import urllib

from test_framework.blocktools import COINBASE_MATURITY
from test_framework.test_framework import (
BGLTestFramework,
)
Expand All @@ -30,33 +31,32 @@ def set_test_params(self):

def run_test(self):
self.nodes[1].setnetworkactive(state=False)
self.nodes[0].generate(100)

self.nodes[0].generate(1, COINBASE_MATURITY)[0]
# Parsing the url of our node to get settings for config file
data_dir = self.nodes[0].datadir
node_url = urllib.parse.urlparse(self.nodes[0].url)
cfg_file = os.path.join(data_dir, "linearize.cfg")
bootstrap_file = os.path.join(self.options.tmpdir, "bootstrap.dat")
genesis_block = self.nodes[0].getblockhash(0)
blocks_dir = os.path.join(data_dir, "regtest", "blocks")
blocks_dir = os.path.join(data_dir, self.chain, "blocks")
hash_list = tempfile.NamedTemporaryFile(dir=data_dir,
mode='w',
delete=False,
encoding="utf-8")

self.log.info("Create linearization config file")
with open(cfg_file, "a", encoding="utf-8") as cfg:
cfg.write("datadir={}\n".format(data_dir))
cfg.write("rpcuser={}\n".format(node_url.username))
cfg.write("rpcpassword={}\n".format(node_url.password))
cfg.write("port={}\n".format(node_url.port))
cfg.write("host={}\n".format(node_url.hostname))
cfg.write("output_file={}\n".format(bootstrap_file))
cfg.write("max_height=100\n")
cfg.write("netmagic=fabfb5da\n")
cfg.write("input={}\n".format(blocks_dir))
cfg.write("genesis={}\n".format(genesis_block))
cfg.write("hashlist={}\n".format(hash_list.name))
cfg.write(f"datadir={data_dir}\n")
cfg.write(f"rpcuser={node_url.username}\n")
cfg.write(f"rpcpassword={node_url.password}\n")
cfg.write(f"port={node_url.port}\n")
cfg.write(f"host={node_url.hostname}\n")
cfg.write(f"output_file={bootstrap_file}\n")
cfg.write(f"max_height=100\n")
cfg.write(f"netmagic=fabfb5da\n")
cfg.write(f"input={blocks_dir}\n")
cfg.write(f"genesis={genesis_block}\n")
cfg.write(f"hashlist={hash_list.name}\n")

base_dir = self.config["environment"]["SRCDIR"]
linearize_dir = os.path.join(base_dir, "contrib", "linearize")
Expand All @@ -73,7 +73,7 @@ def run_test(self):
check=True)

self.log.info("Restart second, unsynced node with bootstrap file")
self.restart_node(1, extra_args=["-loadblock=" + bootstrap_file])
self.restart_node(1, extra_args=[f"-loadblock={bootstrap_file}"])
assert_equal(self.nodes[1].getblockcount(), 100) # start_node is blocking on all block files being imported

assert_equal(self.nodes[1].getblockchaininfo()['blocks'], 100)
Expand Down
8 changes: 7 additions & 1 deletion test/functional/feature_segwit.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from test_framework.blocktools import witness_script, send_to_witness
from test_framework.messages import COIN, COutPoint, CTransaction, CTxIn, CTxOut, FromHex, sha256, ToHex
from test_framework.script import CScript, OP_HASH160, OP_CHECKSIG, OP_0, hash160, OP_EQUAL, OP_DUP, OP_EQUALVERIFY, OP_1, OP_2, OP_CHECKMULTISIG, OP_TRUE, OP_DROP
from test_framework.test_framework import BGLTestFramework
from test_framework.test_framework import BGLTestFramework, SkipTest
from test_framework.util import (
assert_equal,
assert_is_hex_string,
Expand All @@ -26,6 +26,7 @@
try_rpc,
)


NODE_0 = 0
NODE_2 = 2
P2WPKH = 0
Expand Down Expand Up @@ -95,7 +96,12 @@ def skip_mine(self, node, txid, sign, redeem_script=""):
def fail_accept(self, node, error_msg, txid, sign, redeem_script=""):
assert_raises_rpc_error(-26, error_msg, send_to_witness, use_p2wsh=1, node=node, utxo=getutxo(txid), pubkey=self.pubkey[0], encode_p2sh=False, amount=Decimal("49.998"), sign=sign, insert_redeem_script=redeem_script)

def skip_test_bgl_fork(self):
raise SkipTest("Forked after segwit.")

def run_test(self):
self.skip_test_bgl_fork()

self.nodes[0].generate(161) # block 161

self.log.info("Verify sigops are counted in GBT with pre-BIP141 rules before the fork")
Expand Down
1 change: 1 addition & 0 deletions test/functional/interface_zmq.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ def caused_notification(self, notification):

class ZMQTest (BGLTestFramework):
def set_test_params(self):
self.setup()
self.num_nodes = 2
if self.is_wallet_compiled():
self.requires_wallet = True
Expand Down
6 changes: 1 addition & 5 deletions test/functional/p2p_segwit.py
Original file line number Diff line number Diff line change
Expand Up @@ -276,11 +276,7 @@ def run_test(self):
self.test_non_witness_transaction()
self.test_v0_outputs_arent_spendable()
self.test_block_relay()
self.test_getblocktemplate_before_lockin()
self.test_unnecessary_witness_before_segwit_activation()
self.test_witness_tx_relay_before_segwit_activation()
self.test_standardness_v0()


self.log.info("Advancing to segwit activation")
self.advance_to_segwit_active()

Expand Down
2 changes: 1 addition & 1 deletion test/functional/rpc_addresses_deprecation.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def test_addresses_deprecation(self):

self.log.info("Test RPCResult scriptPubKey returns the addresses field with -deprecatedrpc=addresses")
script_pub_key = self.nodes[1].getblock(blockhash=hash, verbose=2)['tx'][-1]['vout'][0]['scriptPubKey']
assert_equal(script_pub_key['addresses'], ['mvKDK6D54HU8wQumJBLHY95eq5iHFqXSBz', 'mv3rHCQSwKp2BLSuMHD8uCS32LW5xiNAA5', 'mirrsyhAQYzo5CwVhcaYJKwUJu1WJRCRJe'])
assert_equal(script_pub_key['addresses'], ['EwHmVjFtPPnfy3B6QsgkCV85NEseUTVLvx', 'Ew2QTqTGGS8ZCxiETyZbZYUTZVfTG44d9U', 'EjqR4cjyjfKL6qCppJvzxfytr4AsU4WonJ'])
assert_equal(script_pub_key['reqSigs'], 2)


Expand Down
3 changes: 3 additions & 0 deletions test/functional/test_framework/p2p.py
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,7 @@ def on_version(self, message):
self.send_message(msg_sendaddrv2())
self.send_message(msg_verack())
self.nServices = message.nServices
self.send_message(msg_getaddr())

# Connection helper methods

Expand Down Expand Up @@ -575,6 +576,8 @@ def __init__(self):

NetworkThread.listeners = {}
NetworkThread.protos = {}
if sys.platform == 'win32':
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
NetworkThread.network_event_loop = asyncio.new_event_loop()

def run(self):
Expand Down
57 changes: 42 additions & 15 deletions test/functional/test_framework/test_framework.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ def __init__(self):
# By default the wallet is not required. Set to true by skip_if_no_wallet().
# When False, we ignore wallet_names regardless of what it is.
self.requires_wallet = False
# Disable ThreadOpenConnections by default, so that adding entries to
# addrman will not result in automatic connections to them.
self.disable_autoconnect = True
self.set_test_params()
assert self.wallet_names is None or len(self.wallet_names) <= self.num_nodes
if self.options.timeout_factor == 0 :
Expand Down Expand Up @@ -554,18 +557,19 @@ def wait_for_node_exit(self, i, timeout):
self.nodes[i].process.wait(timeout)

def connect_nodes(self, a, b):
def connect_nodes_helper(from_connection, node_num):
ip_port = "127.0.0.1:" + str(p2p_port(node_num))
from_connection.addnode(ip_port, "onetry")
# poll until version handshake complete to avoid race conditions
# with transaction relaying
# See comments in net_processing:
# * Must have a version message before anything else
# * Must have a verack message before anything else
wait_until_helper(lambda: all(peer['version'] != 0 for peer in from_connection.getpeerinfo()))
wait_until_helper(lambda: all(peer['bytesrecv_per_msg'].pop('verack', 0) == 24 for peer in from_connection.getpeerinfo()))

connect_nodes_helper(self.nodes[a], b)
from_connection = self.nodes[a]
to_connection = self.nodes[b]
ip_port = "127.0.0.1:" + str(p2p_port(b))
from_connection.addnode(ip_port, "onetry")
# poll until version handshake complete to avoid race conditions
# with transaction relaying
# See comments in net_processing:
# * Must have a version message before anything else
# * Must have a verack message before anything else
wait_until_helper(lambda: all(peer['version'] != 0 for peer in from_connection.getpeerinfo()))
wait_until_helper(lambda: all(peer['version'] != 0 for peer in to_connection.getpeerinfo()))
wait_until_helper(lambda: all(peer['bytesrecv_per_msg'].pop('verack', 0) == 24 for peer in from_connection.getpeerinfo()))
wait_until_helper(lambda: all(peer['bytesrecv_per_msg'].pop('verack', 0) == 24 for peer in to_connection.getpeerinfo()))

def disconnect_nodes(self, a, b):
def disconnect_nodes_helper(from_connection, node_num):
Expand Down Expand Up @@ -613,6 +617,29 @@ def join_network(self):
self.connect_nodes(1, 2)
self.sync_all()

def no_op(self):
pass

def generate(self, generator, *args, sync_fun=None, **kwargs):
blocks = generator.generate(*args, invalid_call=False, **kwargs)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You wrote a lot of new functions. That's a bit unusual.

sync_fun() if sync_fun else self.sync_all()
return blocks

def generateblock(self, generator, *args, sync_fun=None, **kwargs):
blocks = generator.generateblock(*args, invalid_call=False, **kwargs)
sync_fun() if sync_fun else self.sync_all()
return blocks

def generatetoaddress(self, generator, *args, sync_fun=None, **kwargs):
blocks = generator.generatetoaddress(*args, invalid_call=False, **kwargs)
sync_fun() if sync_fun else self.sync_all()
return blocks

def generatetodescriptor(self, generator, *args, sync_fun=None, **kwargs):
blocks = generator.generatetodescriptor(*args, invalid_call=False, **kwargs)
sync_fun() if sync_fun else self.sync_all()
return blocks

def sync_blocks(self, nodes=None, wait=1, timeout=60):
"""
Wait until everybody has the same tip.
Expand Down Expand Up @@ -708,7 +735,7 @@ def _initialize_chain(self):
if not os.path.isdir(cache_node_dir):
self.log.debug("Creating cache directory {}".format(cache_node_dir))

initialize_datadir(self.options.cachedir, CACHE_NODE_ID, self.chain)
initialize_datadir(self.options.cachedir, CACHE_NODE_ID, self.chain, self.disable_autoconnect)
self.nodes.append(
TestNode(
CACHE_NODE_ID,
Expand Down Expand Up @@ -765,15 +792,15 @@ def cache_path(*paths):
self.log.debug("Copy cache directory {} to node {}".format(cache_node_dir, i))
to_dir = get_datadir_path(self.options.tmpdir, i)
shutil.copytree(cache_node_dir, to_dir)
initialize_datadir(self.options.tmpdir, i, self.chain) # Overwrite port/rpcport in BGL.conf
initialize_datadir(self.options.tmpdir, i, self.chain, self.disable_autoconnect) # Overwrite port/rpcport in bitcoin.conf

def _initialize_chain_clean(self):
"""Initialize empty blockchain for use by the test.

Create an empty blockchain and num_nodes wallets.
Useful if a test case wants complete control over initialization."""
for i in range(self.num_nodes):
initialize_datadir(self.options.tmpdir, i, self.chain)
initialize_datadir(self.options.tmpdir, i, self.chain, self.disable_autoconnect)

def skip_if_no_py3_zmq(self):
"""Attempt to import the zmq package and skip the test if the import fails."""
Expand Down
13 changes: 10 additions & 3 deletions test/functional/test_framework/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -339,17 +339,17 @@ def rpc_url(datadir, i, chain, rpchost):
################


def initialize_datadir(dirname, n, chain):
def initialize_datadir(dirname, n, chain, disable_autoconnect=True):
datadir = get_datadir_path(dirname, n)
if not os.path.isdir(datadir):
os.makedirs(datadir)
write_config(os.path.join(datadir, "BGL.conf"), n=n, chain=chain)
write_config(os.path.join(datadir, "BGL.conf"), n=n, chain=chain, disable_autoconnect=disable_autoconnect)
os.makedirs(os.path.join(datadir, 'stderr'), exist_ok=True)
os.makedirs(os.path.join(datadir, 'stdout'), exist_ok=True)
return datadir


def write_config(config_path, *, n, chain, extra_config=""):
def write_config(config_path, *, n, chain, extra_config="", disable_autoconnect=True):
# Translate chain subdirectory name to config name
if chain == 'testnet3':
chain_name_conf_arg = 'testnet'
Expand All @@ -371,12 +371,19 @@ def write_config(config_path, *, n, chain, extra_config=""):
f.write("dnsseed=0\n")
f.write("fixedseeds=0\n")
f.write("listenonion=0\n")
# Increase peertimeout to avoid disconnects while using mocktime.
# peertimeout is measured in wall clock time, so setting it to the
# duration of the longest test is sufficient. It can be overridden in
# tests.
f.write("peertimeout=999999\n")
f.write("printtoconsole=0\n")
f.write("upnp=0\n")
f.write("natpmp=0\n")
f.write("shrinkdebugfile=0\n")
# To improve SQLite wallet performance so that the tests don't timeout, use -unsafesqlitesync
f.write("unsafesqlitesync=1\n")
if disable_autoconnect:
f.write("connect=0\n")
f.write(extra_config)


Expand Down
2 changes: 0 additions & 2 deletions test/functional/test_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,6 @@
'wallet_txn_doublespend.py --mineblock',
'tool_wallet.py --legacy-wallet',
'tool_wallet.py --descriptors',
'wallet_txn_clone.py',
'wallet_txn_clone.py --segwit',
'rpc_getchaintips.py',
'rpc_misc.py',
Expand Down Expand Up @@ -247,7 +246,6 @@
'p2p_leak.py',
'wallet_encryption.py --legacy-wallet',
'wallet_encryption.py --descriptors',
'feature_dersig.py',
'feature_cltv.py',
'rpc_uptime.py',
'wallet_resendwallettransactions.py --legacy-wallet',
Expand Down
6 changes: 3 additions & 3 deletions test/functional/wallet_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -593,9 +593,9 @@ def run_test(self):

# Test getaddressinfo on external address. Note that these addresses are taken from disablewallet.py
assert_raises_rpc_error(-5, "Invalid prefix for Base58-encoded address", self.nodes[0].getaddressinfo, "3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy")
address_info = self.nodes[0].getaddressinfo("mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ")
assert_equal(address_info['address'], "mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ")
assert_equal(address_info["scriptPubKey"], "76a9144e3854046c7bd1594ac904e4793b6a45b36dea0988ac")
address_info = self.nodes[0].getaddressinfo("rbgl1qmevj8zfx0wdvp05cqwkmr6mxkfx60yezhdmczp")
assert_equal(address_info['address'], "rbgl1qmevj8zfx0wdvp05cqwkmr6mxkfx60yezhdmczp")
assert_equal(address_info["scriptPubKey"], "0014de592389267b9ac0be9803adb1eb66b24da79322")
assert not address_info["ismine"]
assert not address_info["iswatchonly"]
assert not address_info["isscript"]
Expand Down
4 changes: 2 additions & 2 deletions test/functional/wallet_txn_clone.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ def run_test(self):
else:
output_type = "legacy"

# All nodes should start with 1,250 BTC:
starting_balance = 1250
# All nodes should start with 5000 BGL:
starting_balance = 5000
for i in range(3):
assert_equal(self.nodes[i].getbalance(), starting_balance)

Expand Down
8 changes: 4 additions & 4 deletions test/functional/wallet_txn_doublespend.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ def setup_network(self):
self.disconnect_nodes(1, 2)

def run_test(self):
# All nodes should start with 1,250 BTC:
starting_balance = 1250
# All nodes should start with 5000 BGL:
starting_balance = 5000

# All nodes should be out of IBD.
# If the nodes are not all out of IBD, that can interfere with
Expand Down Expand Up @@ -132,8 +132,8 @@ def run_test(self):
expected = starting_balance + 100 - 1240 + fund_foo_tx["fee"] + fund_bar_tx["fee"] + doublespend_fee
assert_equal(self.nodes[0].getbalance(), expected)

# Node1's balance should be its initial balance (1250 for 25 block rewards) plus the doublespend:
assert_equal(self.nodes[1].getbalance(), 1250 + 1240)
# Node1's balance should be its initial balance (5000 for 25 block rewards) plus the doublespend:
assert_equal(self.nodes[1].getbalance(), 5000 + 1240)


if __name__ == '__main__':
Expand Down
Loading