Skip to content

Commit

Permalink
Port python tests part 1
Browse files Browse the repository at this point in the history
  • Loading branch information
timemarkovqtum committed Mar 25, 2024
1 parent 61726bf commit 5624032
Show file tree
Hide file tree
Showing 56 changed files with 481 additions and 238 deletions.
59 changes: 46 additions & 13 deletions test/functional/feature_assumevalid.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
block 200. node2 will reject block 102 since it's assumed valid, but it
isn't buried by at least two weeks' work.
"""
import time

from test_framework.blocktools import (
COINBASE_MATURITY,
Expand All @@ -52,6 +53,7 @@
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
from test_framework.wallet_util import generate_keypair
import inspect


class BaseNode(P2PInterface):
Expand Down Expand Up @@ -85,6 +87,25 @@ def send_blocks_until_disconnected(self, p2p_conn):
assert not p2p_conn.is_connected
break

def assert_blockchain_height(self, node, height):
"""Wait until the blockchain is no longer advancing and verify it's reached the expected height."""
last_height = node.getblock(node.getbestblockhash())['height']
timeout = 10
while True:
if timeout < 0:
assert False, "blockchain too short after timeout: %d" % current_height

time.sleep(0.25)
current_height = node.getblock(node.getbestblockhash())['height']
if current_height > height:
assert False, "blockchain too long: %d" % current_height
elif current_height != last_height:
last_height = current_height
timeout = 10 # reset the timeout
elif current_height == height:
break
timeout = timeout - 0.25

def run_test(self):
# Build the blockchain
self.tip = int(self.nodes[0].getbestblockhash(), 16)
Expand All @@ -107,7 +128,7 @@ def run_test(self):
height += 1

# Bury the block 100 deep so the coinbase output is spendable
for _ in range(100):
for _ in range(COINBASE_MATURITY):
block = create_block(self.tip, create_coinbase(height), self.block_time)
block.solve()
self.blocks.append(block)
Expand All @@ -130,7 +151,7 @@ def run_test(self):
height += 1

# Bury the assumed valid block 2100 deep
for _ in range(2100):
for _ in range(10000):
block = create_block(self.tip, create_coinbase(height), self.block_time)
block.solve()
self.blocks.append(block)
Expand All @@ -139,36 +160,48 @@ def run_test(self):
height += 1

# Start node1 and node2 with assumevalid so they accept a block with a bad signature.
self.start_node(1, extra_args=["-assumevalid=" + hex(block102.sha256)])
self.start_node(2, extra_args=["-assumevalid=" + hex(block102.sha256)])
self.start_node(1, extra_args=["-assumevalid=" + hex(block102.sha256)[2:]])
self.start_node(2, extra_args=["-assumevalid=" + hex(block102.sha256)[2:]])

p2p0 = self.nodes[0].add_p2p_connection(BaseNode())
p2p0.send_header_for_blocks(self.blocks[0:2000])
p2p0.send_header_for_blocks(self.blocks[2000:])
p2p0.send_header_for_blocks(self.blocks[2000:4000])
p2p0.send_header_for_blocks(self.blocks[4000:6000])
p2p0.send_header_for_blocks(self.blocks[6000:8000])
p2p0.send_header_for_blocks(self.blocks[8000:10000])
p2p0.send_header_for_blocks(self.blocks[10000:])

# Send blocks to node0. Block 102 will be rejected.
self.send_blocks_until_disconnected(p2p0)
self.wait_until(lambda: self.nodes[0].getblockcount() >= COINBASE_MATURITY + 1)
assert_equal(self.nodes[0].getblockcount(), COINBASE_MATURITY + 1)
self.assert_blockchain_height(self.nodes[0], COINBASE_MATURITY+1)

p2p1 = self.nodes[1].add_p2p_connection(BaseNode())
p2p1.send_header_for_blocks(self.blocks[0:2000])
p2p1.send_header_for_blocks(self.blocks[2000:])
p2p1.send_header_for_blocks(self.blocks[2000:4000])
p2p1.send_header_for_blocks(self.blocks[4000:6000])
p2p1.send_header_for_blocks(self.blocks[6000:8000])
p2p1.send_header_for_blocks(self.blocks[8000:10000])
p2p1.send_header_for_blocks(self.blocks[10000:])

# Send all blocks to node1. All blocks will be accepted.
for i in range(2202):
# Send only a subset to speed this up
p2p1 = self.nodes[1].add_p2p_connection(BaseNode())
for i in range(1000):
p2p1.send_message(msg_block(self.blocks[i]))

# Syncing 2200 blocks can take a while on slow systems. Give it plenty of time to sync.
p2p1.sync_with_ping(960)
assert_equal(self.nodes[1].getblock(self.nodes[1].getbestblockhash())['height'], 2202)
timeout = time.time() + 200
while time.time() < timeout:
if self.nodes[1].getblock(self.nodes[1].getbestblockhash())['height'] == 1000:
break
assert_equal(self.nodes[1].getblock(self.nodes[1].getbestblockhash())['height'], 1000)

p2p2 = self.nodes[2].add_p2p_connection(BaseNode())
p2p2.send_header_for_blocks(self.blocks[0:200])

# Send blocks to node2. Block 102 will be rejected.
self.send_blocks_until_disconnected(p2p2)
self.wait_until(lambda: self.nodes[2].getblockcount() >= COINBASE_MATURITY + 1)
assert_equal(self.nodes[2].getblockcount(), COINBASE_MATURITY + 1)
self.assert_blockchain_height(self.nodes[2], COINBASE_MATURITY+1)


if __name__ == '__main__':
Expand Down
10 changes: 6 additions & 4 deletions test/functional/feature_bip68_sequence.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
"""Test BIP68 implementation."""

import time
import random

from test_framework.blocktools import (
COINBASE_MATURITY,
NORMAL_GBT_REQUEST_PARAMS,
add_witness_commitment,
create_block,
Expand Down Expand Up @@ -72,11 +74,11 @@ def run_test(self):
self.log.info("Running test sequence-lock-unconfirmed-inputs")
self.test_sequence_lock_unconfirmed_inputs()

self.log.info("Running test BIP68 not consensus before activation")
self.test_bip68_not_consensus()
#self.log.info("Running test BIP68 not consensus before activation")
#self.test_bip68_not_consensus()

self.log.info("Activating BIP68 (and 112/113)")
self.activateCSV()
#self.log.info("Activating BIP68 (and 112/113)")
#self.activateCSV()

self.log.info("Verifying nVersion=2 transactions are standard.")
self.log.info("Note that nVersion=2 transactions are always standard (independent of BIP68 activation status).")
Expand Down
6 changes: 3 additions & 3 deletions test/functional/feature_config_args.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def test_config_file_parser(self):
expected_msg=conf_in_config_file_err,
)
inc_conf_file_path = self.nodes[0].datadir_path / 'include.conf'
with open(self.nodes[0].datadir_path / 'bitcoin.conf', 'a', encoding='utf-8') as conf:
with open(self.nodes[0].datadir_path / 'qtum.conf', 'a', encoding='utf-8') as conf:
conf.write(f'includeconf={inc_conf_file_path}\n')
with open(inc_conf_file_path, 'w', encoding='utf-8') as conf:
conf.write('conf=some.conf\n')
Expand Down Expand Up @@ -98,7 +98,7 @@ def test_config_file_parser(self):
self.nodes[0].assert_start_raises_init_error(expected_msg='Error: Error reading configuration file: parse error on line 4, using # in rpcpassword can be ambiguous and should be avoided')

inc_conf_file2_path = self.nodes[0].datadir_path / 'include2.conf'
with open(self.nodes[0].datadir_path / 'bitcoin.conf', 'a', encoding='utf-8') as conf:
with open(self.nodes[0].datadir_path / 'qtum.conf', 'a', encoding='utf-8') as conf:
conf.write(f'includeconf={inc_conf_file2_path}\n')

with open(inc_conf_file_path, 'w', encoding='utf-8') as conf:
Expand Down Expand Up @@ -402,7 +402,7 @@ def run_test(self):
self.nodes[0].assert_start_raises_init_error([f'-datadir={new_data_dir}'], f'Error: Specified data directory "{new_data_dir}" does not exist.')

# Check that using non-existent datadir in conf file fails
conf_file = default_data_dir / "bitcoin.conf"
conf_file = default_data_dir / "qtum.conf"

# datadir needs to be set before [chain] section
with open(conf_file, encoding='utf8') as f:
Expand Down
11 changes: 6 additions & 5 deletions test/functional/feature_dbcrash.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,15 @@
class ChainstateWriteCrashTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 4
self.rpc_timeout = 480
self.rpc_timeout = 960
self.supports_cli = False

# Set -maxmempool=0 to turn off mempool memory sharing with dbcache
self.base_args = [
"-limitdescendantsize=0",
"-maxmempool=0",
"-dbbatchsize=200000",
"-rpcservertimeout=1800",
]

# Set different crash ratios and cache sizes. Note that not all of
Expand All @@ -80,7 +81,7 @@ def restart_node(self, node_index, expected_tip):
after 60 seconds. Returns the utxo hash of the given node."""

time_start = time.time()
while time.time() - time_start < 120:
while time.time() - time_start < 720:
try:
# Any of these RPC calls could throw due to node crash
self.start_node(node_index)
Expand Down Expand Up @@ -147,7 +148,7 @@ def sync_node3blocks(self, block_hashes):
if not self.submit_block_catch_error(i, block):
# TODO: more carefully check that the crash is due to -dbcrashratio
# (change the exit code perhaps, and check that here?)
self.wait_for_node_exit(i, timeout=30)
self.wait_for_node_exit(i, timeout=120)
self.log.debug(f"Restarting node {i} after block hash {block_hash}")
nodei_utxo_hash = self.restart_node(i, block_hash)
assert nodei_utxo_hash is not None
Expand Down Expand Up @@ -184,7 +185,7 @@ def verify_utxo_hash(self):
assert_equal(nodei_utxo_hash, node3_utxo_hash)

def generate_small_transactions(self, node, count, utxo_list):
FEE = 1000 # TODO: replace this with node relay fee based calculation
FEE = 400000 # TODO: replace this with node relay fee based calculation
num_transactions = 0
random.shuffle(utxo_list)
while len(utxo_list) >= 2 and num_transactions < count:
Expand Down Expand Up @@ -254,7 +255,7 @@ def run_test(self):
while current_height + 1 > self.nodes[3].getblockcount():
block_hashes.extend(self.generatetoaddress(
self.nodes[3],
nblocks=min(10, current_height + 1 - self.nodes[3].getblockcount()),
nblocks=10,
# new address to avoid mining a block that has just been invalidated
address=getnewdestination()[2],
sync_fun=self.no_op,
Expand Down
14 changes: 7 additions & 7 deletions test/functional/feature_fee_estimation.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,9 @@ def set_test_params(self):
self.num_nodes = 3
# Force fSendTrickle to true (via whitelist.noban)
self.extra_args = [
["[email protected]"],
["[email protected]", "-blockmaxweight=68000"],
["[email protected]", "-blockmaxweight=32000"],
["[email protected]", "-dustrelayfee=0"],
["[email protected]", "-blockmaxweight=68000", "-dustrelayfee=0"],
["[email protected]", "-blockmaxweight=32000", "-dustrelayfee=0"],
]

def setup_network(self):
Expand All @@ -154,7 +154,7 @@ def setup_network(self):
# produces too small blocks (room for only 55 or so transactions)

def transact_and_mine(self, numblocks, mining_node):
min_fee = Decimal("0.00001")
min_fee = Decimal("0.0009")
# We will now mine numblocks blocks generating on average 100 transactions between each block
# We shuffle our confirmed txout set before each set of transactions
# small_txpuzzle_randfee will use the transactions that have inputs already in the chain when possible
Expand All @@ -169,7 +169,7 @@ def transact_and_mine(self, numblocks, mining_node):
self.nodes[from_index],
self.confutxo,
self.memutxo,
Decimal("0.005"),
Decimal("0.5"),
min_fee,
min_fee,
batch_sendtx_reqs,
Expand Down Expand Up @@ -244,8 +244,8 @@ def sanity_check_rbf_estimates(self, utxos):
node = self.nodes[0]
miner = self.nodes[1]
# In sat/vb
low_feerate = 1
high_feerate = 10
low_feerate = 1200
high_feerate = 10000
# Cache the utxos of which to replace the spender after it failed to get
# confirmed
utxos_to_respend = []
Expand Down
4 changes: 2 additions & 2 deletions test/functional/feature_includeconf.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def run_test(self):
# - tmpdir/node0/relative2.conf
with open(self.nodes[0].datadir_path / "relative2.conf", "w", encoding="utf8") as f:
f.write("uacomment=relative2\n")
with open(self.nodes[0].datadir_path / "bitcoin.conf", "a", encoding="utf8") as f:
with open(self.nodes[0].datadir_path / "qtum.conf", "a", encoding="utf8") as f:
f.write("uacomment=main\nincludeconf=relative.conf\n")
self.restart_node(0)

Expand Down Expand Up @@ -74,7 +74,7 @@ def run_test(self):
# Restore initial file contents
f.write("uacomment=relative\n")

with open(self.nodes[0].datadir_path / "bitcoin.conf", "a", encoding="utf8") as f:
with open(self.nodes[0].datadir_path / "qtum.conf", "a", encoding="utf8") as f:
f.write("includeconf=relative2.conf\n")

self.start_node(0)
Expand Down
2 changes: 1 addition & 1 deletion test/functional/feature_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def check_clean_start():
"""Ensure that node restarts successfully after various interrupts."""
node.start()
node.wait_for_rpc_connection()
assert_equal(200, node.getblockcount())
assert_equal(2100, node.getblockcount())

lines_to_terminate_after = [
b'Validating signatures for all blocks',
Expand Down
8 changes: 4 additions & 4 deletions test/functional/feature_loadblock.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ def run_test(self):
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("max_height="+str(COINBASE_MATURITY)+"\n")
cfg.write("netmagic=fdddc6e1\n")
cfg.write(f"input={blocks_dir}\n")
cfg.write(f"genesis={genesis_block}\n")
cfg.write(f"hashlist={hash_list.name}\n")
Expand All @@ -73,9 +73,9 @@ def run_test(self):

self.log.info("Restart second, unsynced node with 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].getblockcount(), COINBASE_MATURITY) # start_node is blocking on all block files being imported

assert_equal(self.nodes[1].getblockchaininfo()['blocks'], 100)
assert_equal(self.nodes[1].getblockchaininfo()['blocks'], COINBASE_MATURITY)
assert_equal(self.nodes[0].getbestblockhash(), self.nodes[1].getbestblockhash())


Expand Down
6 changes: 3 additions & 3 deletions test/functional/feature_maxtipage.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from test_framework.util import assert_equal


DEFAULT_MAX_TIP_AGE = 24 * 60 * 60
DEFAULT_MAX_TIP_AGE = 12 * 60 * 60


class MaxTipAgeTest(BitcoinTestFramework):
Expand Down Expand Up @@ -44,10 +44,10 @@ def test_maxtipage(self, maxtipage, set_parameter=True, test_deltas=True):
assert_equal(node_ibd.getblockchaininfo()['initialblockdownload'], False)

def run_test(self):
self.log.info("Test IBD with maximum tip age of 24 hours (default).")
self.log.info("Test IBD with maximum tip age of 12 hours (default).")
self.test_maxtipage(DEFAULT_MAX_TIP_AGE, set_parameter=False)

for hours in [20, 10, 5, 2, 1]:
for hours in [10, 5, 2, 1]:
maxtipage = hours * 60 * 60
self.log.info(f"Test IBD with maximum tip age of {hours} hours (-maxtipage={maxtipage}).")
self.test_maxtipage(maxtipage)
Expand Down
10 changes: 5 additions & 5 deletions test/functional/feature_maxuploadtarget.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 1
self.extra_args = [[
"-maxuploadtarget=800M",
"-maxuploadtarget=1350M",
"-datacarriersize=100000",
]]
self.supports_cli = False
Expand All @@ -59,7 +59,7 @@ def run_test(self):

# Generate some old blocks
self.wallet = MiniWallet(self.nodes[0])
self.generate(self.wallet, 130)
self.generate(self.wallet, 2030)

# p2p_conns[0] will only request old blocks
# p2p_conns[1] will only request new blocks
Expand Down Expand Up @@ -93,8 +93,8 @@ def run_test(self):
getdata_request = msg_getdata()
getdata_request.inv.append(CInv(MSG_BLOCK, big_old_block))

max_bytes_per_day = 800*1024*1024
daily_buffer = 144 * 4000000
max_bytes_per_day = 1350*1024*1024
daily_buffer = 2700 * 512000
max_bytes_available = max_bytes_per_day - daily_buffer
success_count = max_bytes_available // old_block_size

Expand All @@ -107,7 +107,7 @@ def run_test(self):
assert_equal(len(self.nodes[0].getpeerinfo()), 3)
# At most a couple more tries should succeed (depending on how long
# the test has been running so far).
for _ in range(3):
for _ in range(4000):
p2p_conns[0].send_message(getdata_request)
p2p_conns[0].wait_for_disconnect()
assert_equal(len(self.nodes[0].getpeerinfo()), 2)
Expand Down
4 changes: 3 additions & 1 deletion test/functional/feature_notifications.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
from test_framework.util import (
assert_equal,
)
from test_framework.qtumconfig import *
from test_framework.qtum import generatesynchronized

# Linux allow all characters other than \x00
# Windows disallow control characters (0-31) and /\?%:|"<>
Expand Down Expand Up @@ -115,7 +117,7 @@ def run_test(self):
# triggered by node 1
self.log.info("test -walletnotify with conflicting transactions")
self.nodes[0].rescanblockchain()
self.generatetoaddress(self.nodes[0], 100, ADDRESS_BCRT1_UNSPENDABLE)
generatesynchronized(self.nodes[0], COINBASE_MATURITY, ADDRESS_BCRT1_UNSPENDABLE, self.nodes)

# Generate transaction on node 0, sync mempools, and check for
# notification on node 1.
Expand Down
Loading

0 comments on commit 5624032

Please sign in to comment.