|
|
@ -8,24 +8,35 @@ from collections import deque |
|
|
|
import logging |
|
|
|
import logging |
|
|
|
import optparse |
|
|
|
import optparse |
|
|
|
import os |
|
|
|
import os |
|
|
|
import sys |
|
|
|
|
|
|
|
import shutil |
|
|
|
import shutil |
|
|
|
|
|
|
|
import subprocess |
|
|
|
|
|
|
|
import sys |
|
|
|
import tempfile |
|
|
|
import tempfile |
|
|
|
import time |
|
|
|
import time |
|
|
|
|
|
|
|
|
|
|
|
from .util import ( |
|
|
|
from .util import ( |
|
|
|
initialize_chain, |
|
|
|
PortSeed, |
|
|
|
start_nodes, |
|
|
|
MAX_NODES, |
|
|
|
|
|
|
|
bitcoind_processes, |
|
|
|
|
|
|
|
check_json_precision, |
|
|
|
connect_nodes_bi, |
|
|
|
connect_nodes_bi, |
|
|
|
|
|
|
|
disable_mocktime, |
|
|
|
disconnect_nodes, |
|
|
|
disconnect_nodes, |
|
|
|
|
|
|
|
enable_coverage, |
|
|
|
|
|
|
|
enable_mocktime, |
|
|
|
|
|
|
|
get_mocktime, |
|
|
|
|
|
|
|
get_rpc_proxy, |
|
|
|
|
|
|
|
initialize_datadir, |
|
|
|
|
|
|
|
log_filename, |
|
|
|
|
|
|
|
p2p_port, |
|
|
|
|
|
|
|
rpc_url, |
|
|
|
|
|
|
|
set_node_times, |
|
|
|
|
|
|
|
start_nodes, |
|
|
|
|
|
|
|
stop_node, |
|
|
|
|
|
|
|
stop_nodes, |
|
|
|
sync_blocks, |
|
|
|
sync_blocks, |
|
|
|
sync_mempools, |
|
|
|
sync_mempools, |
|
|
|
stop_nodes, |
|
|
|
wait_for_bitcoind_start, |
|
|
|
stop_node, |
|
|
|
|
|
|
|
enable_coverage, |
|
|
|
|
|
|
|
check_json_precision, |
|
|
|
|
|
|
|
initialize_chain_clean, |
|
|
|
|
|
|
|
PortSeed, |
|
|
|
|
|
|
|
) |
|
|
|
) |
|
|
|
from .authproxy import JSONRPCException |
|
|
|
from .authproxy import JSONRPCException |
|
|
|
|
|
|
|
|
|
|
@ -49,9 +60,9 @@ class BitcoinTestFramework(object): |
|
|
|
def setup_chain(self): |
|
|
|
def setup_chain(self): |
|
|
|
self.log.info("Initializing test directory "+self.options.tmpdir) |
|
|
|
self.log.info("Initializing test directory "+self.options.tmpdir) |
|
|
|
if self.setup_clean_chain: |
|
|
|
if self.setup_clean_chain: |
|
|
|
initialize_chain_clean(self.options.tmpdir, self.num_nodes) |
|
|
|
self._initialize_chain_clean(self.options.tmpdir, self.num_nodes) |
|
|
|
else: |
|
|
|
else: |
|
|
|
initialize_chain(self.options.tmpdir, self.num_nodes, self.options.cachedir) |
|
|
|
self._initialize_chain(self.options.tmpdir, self.num_nodes, self.options.cachedir) |
|
|
|
|
|
|
|
|
|
|
|
def stop_node(self, num_node): |
|
|
|
def stop_node(self, num_node): |
|
|
|
stop_node(self.nodes[num_node], num_node) |
|
|
|
stop_node(self.nodes[num_node], num_node) |
|
|
@ -216,6 +227,87 @@ class BitcoinTestFramework(object): |
|
|
|
rpc_handler.setLevel(logging.DEBUG) |
|
|
|
rpc_handler.setLevel(logging.DEBUG) |
|
|
|
rpc_logger.addHandler(rpc_handler) |
|
|
|
rpc_logger.addHandler(rpc_handler) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _initialize_chain(self, test_dir, num_nodes, cachedir): |
|
|
|
|
|
|
|
"""Initialize a pre-mined blockchain for use by the test. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Create a cache of a 200-block-long chain (with wallet) for MAX_NODES |
|
|
|
|
|
|
|
Afterward, create num_nodes copies from the cache.""" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assert num_nodes <= MAX_NODES |
|
|
|
|
|
|
|
create_cache = False |
|
|
|
|
|
|
|
for i in range(MAX_NODES): |
|
|
|
|
|
|
|
if not os.path.isdir(os.path.join(cachedir, 'node' + str(i))): |
|
|
|
|
|
|
|
create_cache = True |
|
|
|
|
|
|
|
break |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if create_cache: |
|
|
|
|
|
|
|
self.log.debug("Creating data directories from cached datadir") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# find and delete old cache directories if any exist |
|
|
|
|
|
|
|
for i in range(MAX_NODES): |
|
|
|
|
|
|
|
if os.path.isdir(os.path.join(cachedir, "node" + str(i))): |
|
|
|
|
|
|
|
shutil.rmtree(os.path.join(cachedir, "node" + str(i))) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Create cache directories, run bitcoinds: |
|
|
|
|
|
|
|
for i in range(MAX_NODES): |
|
|
|
|
|
|
|
datadir = initialize_datadir(cachedir, i) |
|
|
|
|
|
|
|
args = [os.getenv("BITCOIND", "bitcoind"), "-server", "-keypool=1", "-datadir=" + datadir, "-discover=0"] |
|
|
|
|
|
|
|
if i > 0: |
|
|
|
|
|
|
|
args.append("-connect=127.0.0.1:" + str(p2p_port(0))) |
|
|
|
|
|
|
|
bitcoind_processes[i] = subprocess.Popen(args) |
|
|
|
|
|
|
|
self.log.debug("initialize_chain: bitcoind started, waiting for RPC to come up") |
|
|
|
|
|
|
|
wait_for_bitcoind_start(bitcoind_processes[i], rpc_url(i), i) |
|
|
|
|
|
|
|
self.log.debug("initialize_chain: RPC successfully started") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
rpcs = [] |
|
|
|
|
|
|
|
for i in range(MAX_NODES): |
|
|
|
|
|
|
|
try: |
|
|
|
|
|
|
|
rpcs.append(get_rpc_proxy(rpc_url(i), i)) |
|
|
|
|
|
|
|
except: |
|
|
|
|
|
|
|
self.log.exception("Error connecting to node %d" % i) |
|
|
|
|
|
|
|
sys.exit(1) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Create a 200-block-long chain; each of the 4 first nodes |
|
|
|
|
|
|
|
# gets 25 mature blocks and 25 immature. |
|
|
|
|
|
|
|
# Note: To preserve compatibility with older versions of |
|
|
|
|
|
|
|
# initialize_chain, only 4 nodes will generate coins. |
|
|
|
|
|
|
|
# |
|
|
|
|
|
|
|
# blocks are created with timestamps 10 minutes apart |
|
|
|
|
|
|
|
# starting from 2010 minutes in the past |
|
|
|
|
|
|
|
enable_mocktime() |
|
|
|
|
|
|
|
block_time = get_mocktime() - (201 * 10 * 60) |
|
|
|
|
|
|
|
for i in range(2): |
|
|
|
|
|
|
|
for peer in range(4): |
|
|
|
|
|
|
|
for j in range(25): |
|
|
|
|
|
|
|
set_node_times(rpcs, block_time) |
|
|
|
|
|
|
|
rpcs[peer].generate(1) |
|
|
|
|
|
|
|
block_time += 10 * 60 |
|
|
|
|
|
|
|
# Must sync before next peer starts generating blocks |
|
|
|
|
|
|
|
sync_blocks(rpcs) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Shut them down, and clean up cache directories: |
|
|
|
|
|
|
|
stop_nodes(rpcs) |
|
|
|
|
|
|
|
disable_mocktime() |
|
|
|
|
|
|
|
for i in range(MAX_NODES): |
|
|
|
|
|
|
|
os.remove(log_filename(cachedir, i, "debug.log")) |
|
|
|
|
|
|
|
os.remove(log_filename(cachedir, i, "db.log")) |
|
|
|
|
|
|
|
os.remove(log_filename(cachedir, i, "peers.dat")) |
|
|
|
|
|
|
|
os.remove(log_filename(cachedir, i, "fee_estimates.dat")) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for i in range(num_nodes): |
|
|
|
|
|
|
|
from_dir = os.path.join(cachedir, "node" + str(i)) |
|
|
|
|
|
|
|
to_dir = os.path.join(test_dir, "node" + str(i)) |
|
|
|
|
|
|
|
shutil.copytree(from_dir, to_dir) |
|
|
|
|
|
|
|
initialize_datadir(test_dir, i) # Overwrite port/rpcport in bitcoin.conf |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _initialize_chain_clean(self, test_dir, num_nodes): |
|
|
|
|
|
|
|
"""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(num_nodes): |
|
|
|
|
|
|
|
initialize_datadir(test_dir, i) |
|
|
|
|
|
|
|
|
|
|
|
# Test framework for doing p2p comparison testing, which sets up some bitcoind |
|
|
|
# Test framework for doing p2p comparison testing, which sets up some bitcoind |
|
|
|
# binaries: |
|
|
|
# binaries: |
|
|
|
# 1 binary: test binary |
|
|
|
# 1 binary: test binary |
|
|
|