Changeset View
Changeset View
Standalone View
Standalone View
test/functional/feature_dbcrash.py
#!/usr/bin/env python3 | #!/usr/bin/env python3 | ||||
# Copyright (c) 2017 The Bitcoin Core developers | # Copyright (c) 2017-2019 The Bitcoin Core developers | ||||
# Distributed under the MIT software license, see the accompanying | # Distributed under the MIT software license, see the accompanying | ||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php. | # file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
"""Test recovery from a crash during chainstate writing. | """Test recovery from a crash during chainstate writing. | ||||
- 4 nodes | - 4 nodes | ||||
* node0, node1, and node2 will have different dbcrash ratios, and different | * node0, node1, and node2 will have different dbcrash ratios, and different | ||||
dbcache sizes | dbcache sizes | ||||
* node3 will be a regular node, with no crashing. | * node3 will be a regular node, with no crashing. | ||||
Show All 12 Lines | - for each mined block: | ||||
* submit block to node | * submit block to node | ||||
* if node crashed on/after submitting: | * if node crashed on/after submitting: | ||||
- restart until recovery succeeds | - restart until recovery succeeds | ||||
- check that utxo matches node3 using gettxoutsetinfo""" | - check that utxo matches node3 using gettxoutsetinfo""" | ||||
import errno | import errno | ||||
import http.client | import http.client | ||||
import random | import random | ||||
import sys | |||||
import time | import time | ||||
from test_framework.blocktools import create_confirmed_utxos | from test_framework.blocktools import create_confirmed_utxos | ||||
from test_framework.messages import ( | from test_framework.messages import ( | ||||
COIN, | COIN, | ||||
COutPoint, | COutPoint, | ||||
CTransaction, | CTransaction, | ||||
CTxIn, | CTxIn, | ||||
CTxOut, | CTxOut, | ||||
ToHex, | ToHex, | ||||
) | ) | ||||
from test_framework.test_framework import BitcoinTestFramework | from test_framework.test_framework import BitcoinTestFramework | ||||
from test_framework.util import assert_equal, hex_str_to_bytes | from test_framework.util import assert_equal, hex_str_to_bytes | ||||
HTTP_DISCONNECT_ERRORS = [http.client.CannotSendRequest] | |||||
try: | |||||
HTTP_DISCONNECT_ERRORS.append(http.client.RemoteDisconnected) | |||||
except AttributeError: | |||||
pass | |||||
class ChainstateWriteCrashTest(BitcoinTestFramework): | class ChainstateWriteCrashTest(BitcoinTestFramework): | ||||
def set_test_params(self): | def set_test_params(self): | ||||
self.num_nodes = 4 | self.num_nodes = 4 | ||||
self.setup_clean_chain = False | self.setup_clean_chain = False | ||||
# Set -maxmempool=0 to turn off mempool memory sharing with dbcache | # Set -maxmempool=0 to turn off mempool memory sharing with dbcache | ||||
# Set -rpcservertimeout=900 to reduce socket disconnects in this | # Set -rpcservertimeout=900 to reduce socket disconnects in this | ||||
▲ Show 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | def submit_block_catch_error(self, node_index, block): | ||||
"""Try submitting a block to the given node. | """Try submitting a block to the given node. | ||||
Catch any exceptions that indicate the node has crashed. | Catch any exceptions that indicate the node has crashed. | ||||
Returns true if the block was submitted successfully; false otherwise.""" | Returns true if the block was submitted successfully; false otherwise.""" | ||||
try: | try: | ||||
self.nodes[node_index].submitblock(block) | self.nodes[node_index].submitblock(block) | ||||
return True | return True | ||||
except http.client.BadStatusLine as e: | except (http.client.CannotSendRequest, http.client.RemoteDisconnected) as e: | ||||
# Prior to 3.5 BadStatusLine('') was raised for a remote disconnect error. | |||||
if sys.version_info[0] == 3 and sys.version_info[1] < 5 and e.line == "''": | |||||
self.log.debug( | |||||
"node {} submitblock raised exception: {}".format(node_index, e)) | |||||
return False | |||||
else: | |||||
raise | |||||
except tuple(HTTP_DISCONNECT_ERRORS) as e: | |||||
self.log.debug( | self.log.debug( | ||||
"node {} submitblock raised exception: {}".format(node_index, e)) | "node {} submitblock raised exception: {}".format(node_index, e)) | ||||
return False | return False | ||||
except OSError as e: | except OSError as e: | ||||
self.log.debug( | self.log.debug( | ||||
"node {} submitblock raised OSError exception: errno={}".format(node_index, e.errno)) | "node {} submitblock raised OSError exception: errno={}".format(node_index, e.errno)) | ||||
if e.errno in [errno.EPIPE, errno.ECONNREFUSED, errno.ECONNRESET]: | if e.errno in [errno.EPIPE, errno.ECONNREFUSED, errno.ECONNRESET]: | ||||
# The node has likely crashed | # The node has likely crashed | ||||
▲ Show 20 Lines • Show All 178 Lines • Show Last 20 Lines |