aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml2
-rw-r--r--README.md3
-rw-r--r--doc/README.md10
-rw-r--r--doc/developer-notes.md4
-rw-r--r--qa/README.md3
-rwxr-xr-xqa/pull-tester/rpc-tests.py93
-rwxr-xr-xqa/rpc-tests/abandonconflict.py4
-rwxr-xr-xqa/rpc-tests/bip65-cltv-p2p.py3
-rwxr-xr-xqa/rpc-tests/bip65-cltv.py4
-rwxr-xr-xqa/rpc-tests/bip68-112-113-p2p.py3
-rwxr-xr-xqa/rpc-tests/bip68-sequence.py4
-rwxr-xr-xqa/rpc-tests/bip9-softforks.py6
-rwxr-xr-xqa/rpc-tests/bipdersig-p2p.py3
-rwxr-xr-xqa/rpc-tests/bipdersig.py4
-rwxr-xr-xqa/rpc-tests/blockchain.py10
-rwxr-xr-xqa/rpc-tests/create_cache.py23
-rwxr-xr-xqa/rpc-tests/decodescript.py9
-rwxr-xr-xqa/rpc-tests/disablewallet.py9
-rwxr-xr-xqa/rpc-tests/forknotify.py5
-rwxr-xr-xqa/rpc-tests/fundrawtransaction.py11
-rwxr-xr-xqa/rpc-tests/getblocktemplate_longpoll.py5
-rwxr-xr-xqa/rpc-tests/getblocktemplate_proposals.py9
-rwxr-xr-xqa/rpc-tests/getchaintips.py5
-rwxr-xr-xqa/rpc-tests/httpbasics.py9
-rwxr-xr-xqa/rpc-tests/importprunedfunds.py9
-rwxr-xr-xqa/rpc-tests/invalidateblock.py9
-rwxr-xr-xqa/rpc-tests/invalidblockrequest.py1
-rwxr-xr-xqa/rpc-tests/invalidtxrequest.py1
-rwxr-xr-xqa/rpc-tests/keypool.py11
-rwxr-xr-xqa/rpc-tests/listtransactions.py6
-rwxr-xr-xqa/rpc-tests/maxblocksinflight.py9
-rwxr-xr-xqa/rpc-tests/maxuploadtarget.py12
-rwxr-xr-xqa/rpc-tests/mempool_limit.py12
-rwxr-xr-xqa/rpc-tests/mempool_packages.py4
-rwxr-xr-xqa/rpc-tests/mempool_reorg.py4
-rwxr-xr-xqa/rpc-tests/mempool_resurrect_test.py5
-rwxr-xr-xqa/rpc-tests/mempool_spendcoinbase.py5
-rwxr-xr-xqa/rpc-tests/merkle_blocks.py7
-rwxr-xr-xqa/rpc-tests/multi_rpc.py16
-rwxr-xr-xqa/rpc-tests/nodehandling.py6
-rwxr-xr-xqa/rpc-tests/p2p-acceptblock.py6
-rwxr-xr-xqa/rpc-tests/p2p-feefilter.py6
-rwxr-xr-xqa/rpc-tests/p2p-fullblocktest.py1
-rwxr-xr-xqa/rpc-tests/p2p-versionbits-warning.py6
-rwxr-xr-xqa/rpc-tests/prioritise_transaction.py8
-rwxr-xr-xqa/rpc-tests/proxy_test.py6
-rwxr-xr-xqa/rpc-tests/pruning.py10
-rwxr-xr-xqa/rpc-tests/rawtransactions.py9
-rwxr-xr-xqa/rpc-tests/receivedby.py7
-rwxr-xr-xqa/rpc-tests/reindex.py25
-rwxr-xr-xqa/rpc-tests/replace-by-fee.py5
-rwxr-xr-xqa/rpc-tests/rest.py9
-rwxr-xr-xqa/rpc-tests/rpcbind_test.py4
-rwxr-xr-xqa/rpc-tests/sendheaders.py8
-rwxr-xr-xqa/rpc-tests/signmessages.py9
-rwxr-xr-xqa/rpc-tests/signrawtransactions.py9
-rwxr-xr-xqa/rpc-tests/smartfees.py5
-rwxr-xr-xqa/rpc-tests/test_framework/test_framework.py42
-rw-r--r--qa/rpc-tests/test_framework/util.py49
-rwxr-xr-xqa/rpc-tests/txn_clone.py5
-rwxr-xr-xqa/rpc-tests/txn_doublespend.py5
-rwxr-xr-xqa/rpc-tests/wallet.py14
-rwxr-xr-xqa/rpc-tests/walletbackup.py9
-rwxr-xr-xqa/rpc-tests/zapwallettxes.py9
-rwxr-xr-xqa/rpc-tests/zmq_test.py6
-rwxr-xr-xshare/qt/extract_strings_qt.py4
-rw-r--r--src/Makefile.bench.include3
-rw-r--r--src/Makefile.test.include1
-rw-r--r--src/addrman.h8
-rw-r--r--src/bench/crypto_hash.cpp53
-rw-r--r--src/coins.cpp6
-rw-r--r--src/coins.h14
-rw-r--r--src/hash.cpp94
-rw-r--r--src/hash.h15
-rw-r--r--src/init.cpp53
-rw-r--r--src/main.cpp152
-rw-r--r--src/main.h8
-rw-r--r--src/net.cpp255
-rw-r--r--src/net.h6
-rw-r--r--src/netbase.cpp37
-rw-r--r--src/qt/askpassphrasedialog.cpp21
-rw-r--r--src/qt/askpassphrasedialog.h1
-rw-r--r--src/qt/bitcoin.cpp1
-rw-r--r--src/qt/bitcoingui.cpp50
-rw-r--r--src/qt/bitcoingui.h6
-rw-r--r--src/qt/clientmodel.cpp18
-rw-r--r--src/qt/clientmodel.h2
-rw-r--r--src/qt/forms/optionsdialog.ui10
-rw-r--r--src/qt/optionsdialog.cpp14
-rw-r--r--src/qt/optionsdialog.h2
-rw-r--r--src/qt/optionsmodel.cpp14
-rw-r--r--src/qt/optionsmodel.h4
-rw-r--r--src/qt/overviewpage.cpp2
-rw-r--r--src/qt/rpcconsole.cpp17
-rw-r--r--src/qt/rpcconsole.h2
-rw-r--r--src/qt/sendcoinsdialog.cpp55
-rw-r--r--src/qt/sendcoinsdialog.h22
-rw-r--r--src/qt/transactionview.cpp2
-rw-r--r--src/qt/walletmodel.cpp2
-rw-r--r--src/rpc/blockchain.cpp8
-rw-r--r--src/rpc/net.cpp10
-rw-r--r--src/rpc/rawtransaction.cpp5
-rw-r--r--src/scheduler.cpp1
-rw-r--r--src/test/data/script_tests.json11
-rw-r--r--src/test/hash_tests.cpp20
-rw-r--r--src/test/net_tests.cpp145
-rw-r--r--src/test/scheduler_tests.cpp2
-rw-r--r--src/test/txvalidationcache_tests.cpp2
-rw-r--r--src/txmempool.h3
-rw-r--r--src/ui_interface.h3
-rw-r--r--src/uint256.cpp64
-rw-r--r--src/uint256.h18
-rw-r--r--src/util.cpp2
-rw-r--r--src/util.h6
-rw-r--r--src/wallet/rpcwallet.cpp44
-rw-r--r--src/wallet/wallet.cpp92
-rw-r--r--src/wallet/wallet.h6
-rw-r--r--src/wallet/walletdb.cpp50
-rw-r--r--src/wallet/walletdb.h3
119 files changed, 1431 insertions, 648 deletions
diff --git a/.travis.yml b/.travis.yml
index fd70d3ab52..bc2c7faf7e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -78,7 +78,7 @@ script:
- ./configure --cache-file=../config.cache $BITCOIN_CONFIG_ALL $BITCOIN_CONFIG || ( cat config.log && false)
- make $MAKEJOBS $GOAL || ( echo "Build failure. Verbose build follows." && make $GOAL V=1 ; false )
- export LD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/depends/$HOST/lib
- - if [ "$RUN_TESTS" = "true" ]; then make check; fi
+ - if [ "$RUN_TESTS" = "true" ]; then make $MAKEJOBS check VERBOSE=1; fi
- if [ "$RUN_TESTS" = "true" ]; then qa/pull-tester/rpc-tests.py --coverage; fi
after_script:
- echo $TRAVIS_COMMIT_RANGE
diff --git a/README.md b/README.md
index 85b1985560..8e816e7a43 100644
--- a/README.md
+++ b/README.md
@@ -57,8 +57,7 @@ There are also [regression and integration tests](/qa) of the RPC interface, wri
in Python, that are run automatically on the build server.
These tests can be run (if the [test dependencies](/qa) are installed) with: `qa/pull-tester/rpc-tests.py`
-The Travis CI system makes sure that every pull request is built for Windows
-and Linux, OS X, and that unit and sanity tests are automatically run.
+The Travis CI system makes sure that every pull request is built for Windows, Linux, and OS X, and that unit/sanity tests are run automatically.
### Manual Quality Assurance (QA) Testing
diff --git a/doc/README.md b/doc/README.md
index cf475ef18e..357334dfb2 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -11,16 +11,10 @@ The following are some helpful notes on how to run Bitcoin on your native platfo
### Unix
-You need the Qt4 run-time libraries to run Bitcoin-Qt. On Debian or Ubuntu:
-
- sudo apt-get install libqtgui4
-
Unpack the files into a directory and run:
-- bin/32/bitcoin-qt (GUI, 32-bit) or bin/32/bitcoind (headless, 32-bit)
-- bin/64/bitcoin-qt (GUI, 64-bit) or bin/64/bitcoind (headless, 64-bit)
-
-
+- `bin/bitcoin-qt` (GUI) or
+- `bin/bitcoind` (headless)
### Windows
diff --git a/doc/developer-notes.md b/doc/developer-notes.md
index 8affb2158a..add2fb5004 100644
--- a/doc/developer-notes.md
+++ b/doc/developer-notes.md
@@ -5,7 +5,9 @@ Various coding styles have been used during the history of the codebase,
and the result is not very consistent. However, we're now trying to converge to
a single style, so please use it in new code. Old code will be converted
gradually.
-- Basic rules specified in src/.clang-format. Use a recent clang-format-3.5 to format automatically.
+- Basic rules specified in [src/.clang-format](/src/.clang-format).
+ Use a recent clang-format to format automatically using one of the [dev scripts]
+ (/contrib/devtools/README.md#clang-formatpy).
- Braces on new lines for namespaces, classes, functions, methods.
- Braces on the same line for everything else.
- 4 space indentation (no tabs) for every block except namespaces.
diff --git a/qa/README.md b/qa/README.md
index c7e574ff70..7489eb5130 100644
--- a/qa/README.md
+++ b/qa/README.md
@@ -35,6 +35,9 @@ Run all possible tests with
qa/pull-tester/rpc-tests.py -extended
+By default, tests will be run in parallel if you want to specify how many
+tests should be run in parallel, append `-paralell=n` (default n=4).
+
If you want to create a basic coverage report for the rpc test suite, append `--coverage`.
Possible options, which apply to each individual test run:
diff --git a/qa/pull-tester/rpc-tests.py b/qa/pull-tester/rpc-tests.py
index 10c3799b86..f810f89a59 100755
--- a/qa/pull-tester/rpc-tests.py
+++ b/qa/pull-tester/rpc-tests.py
@@ -53,10 +53,12 @@ ENABLE_COVERAGE=0
#Create a set to store arguments and create the passon string
opts = set()
-passon_args = ""
+passon_args = []
PASSON_REGEX = re.compile("^--")
+PARALLEL_REGEX = re.compile('^-parallel=')
print_help = False
+run_parallel = 4
for arg in sys.argv[1:]:
if arg == "--help" or arg == "-h" or arg == "-?":
@@ -65,7 +67,9 @@ for arg in sys.argv[1:]:
if arg == '--coverage':
ENABLE_COVERAGE = 1
elif PASSON_REGEX.match(arg):
- passon_args += " " + arg
+ passon_args.append(arg)
+ elif PARALLEL_REGEX.match(arg):
+ run_parallel = int(arg.split(sep='=', maxsplit=1)[1])
else:
opts.add(arg)
@@ -96,6 +100,7 @@ if ENABLE_ZMQ:
#Tests
testScripts = [
+ 'walletbackup.py',
'bip68-112-113-p2p.py',
'wallet.py',
'listtransactions.py',
@@ -116,7 +121,6 @@ testScripts = [
'merkle_blocks.py',
'fundrawtransaction.py',
'signrawtransactions.py',
- 'walletbackup.py',
'nodehandling.py',
'reindex.py',
'decodescript.py',
@@ -131,7 +135,7 @@ testScripts = [
'abandonconflict.py',
'p2p-versionbits-warning.py',
'importprunedfunds.py',
- 'signmessages.py'
+ 'signmessages.py',
]
if ENABLE_ZMQ:
testScripts.append('zmq_test.py')
@@ -160,6 +164,7 @@ testScriptsExt = [
'pruning.py', # leave pruning last as it takes a REALLY long time
]
+
def runtests():
test_list = []
if '-extended' in opts:
@@ -173,7 +178,7 @@ def runtests():
if print_help:
# Only print help of the first script and exit
- subprocess.check_call(RPC_TESTS_DIR + test_list[0] + ' -h', shell=True)
+ subprocess.check_call((RPC_TESTS_DIR + test_list[0]).split() + ['-h'])
sys.exit(0)
coverage = None
@@ -181,15 +186,34 @@ def runtests():
if ENABLE_COVERAGE:
coverage = RPCCoverage()
print("Initializing coverage directory at %s\n" % coverage.dir)
- flags = " --srcdir %s/src %s %s" % (BUILDDIR, coverage.flag if coverage else '', passon_args)
+ flags = ["--srcdir=%s/src" % BUILDDIR] + passon_args
+ if coverage:
+ flags.append(coverage.flag)
+
+ if len(test_list) > 1:
+ # Populate cache
+ subprocess.check_output([RPC_TESTS_DIR + 'create_cache.py'] + flags)
#Run Tests
- for t in test_list:
- print("Running testscript %s%s%s ..." % (BOLD[1], t, BOLD[0]))
- time0 = time.time()
- subprocess.check_call(
- RPC_TESTS_DIR + t + flags, shell=True)
- print("Duration: %s s\n" % (int(time.time() - time0)))
+ max_len_name = len(max(test_list, key=len))
+ time_sum = 0
+ time0 = time.time()
+ job_queue = RPCTestHandler(run_parallel, test_list, flags)
+ results = BOLD[1] + "%s | %s | %s\n\n" % ("TEST".ljust(max_len_name), "PASSED", "DURATION") + BOLD[0]
+ all_passed = True
+ for _ in range(len(test_list)):
+ (name, stdout, stderr, passed, duration) = job_queue.get_next()
+ all_passed = all_passed and passed
+ time_sum += duration
+
+ print('\n' + BOLD[1] + name + BOLD[0] + ":")
+ print(stdout)
+ print('stderr:\n' if not stderr == '' else '', stderr)
+ results += "%s | %s | %s s\n" % (name.ljust(max_len_name), str(passed).ljust(6), duration)
+ print("Pass: %s%s%s, Duration: %s s\n" % (BOLD[1], passed, BOLD[0], duration))
+ results += BOLD[1] + "\n%s | %s | %s s (accumulated)" % ("ALL".ljust(max_len_name), str(all_passed).ljust(6), time_sum) + BOLD[0]
+ print(results)
+ print("\nRuntime: %s s" % (int(time.time() - time0)))
if coverage:
coverage.report_rpc_coverage()
@@ -197,6 +221,49 @@ def runtests():
print("Cleaning up coverage data")
coverage.cleanup()
+ sys.exit(not all_passed)
+
+
+class RPCTestHandler:
+ """
+ Trigger the testscrips passed in via the list.
+ """
+
+ def __init__(self, num_tests_parallel, test_list=None, flags=None):
+ assert(num_tests_parallel >= 1)
+ self.num_jobs = num_tests_parallel
+ self.test_list = test_list
+ self.flags = flags
+ self.num_running = 0
+ self.jobs = []
+
+ def get_next(self):
+ while self.num_running < self.num_jobs and self.test_list:
+ # Add tests
+ self.num_running += 1
+ t = self.test_list.pop(0)
+ port_seed = ["--portseed=%s" % len(self.test_list)]
+ self.jobs.append((t,
+ time.time(),
+ subprocess.Popen((RPC_TESTS_DIR + t).split() + self.flags + port_seed,
+ universal_newlines=True,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)))
+ if not self.jobs:
+ raise IndexError('%s from empty list' % __name__)
+ while True:
+ # Return first proc that finishes
+ time.sleep(.5)
+ for j in self.jobs:
+ (name, time0, proc) = j
+ if proc.poll() is not None:
+ (stdout, stderr) = proc.communicate(timeout=3)
+ passed = stderr == "" and proc.returncode == 0
+ self.num_running -= 1
+ self.jobs.remove(j)
+ return name, stdout, stderr, passed, int(time.time() - time0)
+ print('.', end='', flush=True)
+
class RPCCoverage(object):
"""
@@ -215,7 +282,7 @@ class RPCCoverage(object):
"""
def __init__(self):
self.dir = tempfile.mkdtemp(prefix="coverage")
- self.flag = '--coveragedir %s' % self.dir
+ self.flag = '--coveragedir=%s' % self.dir
def report_rpc_coverage(self):
"""
diff --git a/qa/rpc-tests/abandonconflict.py b/qa/rpc-tests/abandonconflict.py
index b6c4b9db48..c50c3cc562 100755
--- a/qa/rpc-tests/abandonconflict.py
+++ b/qa/rpc-tests/abandonconflict.py
@@ -9,6 +9,10 @@ from test_framework.util import *
import urllib.parse
class AbandonConflictTest(BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 2
+ self.setup_clean_chain = False
def setup_network(self):
self.nodes = []
diff --git a/qa/rpc-tests/bip65-cltv-p2p.py b/qa/rpc-tests/bip65-cltv-p2p.py
index 60923b9dda..754b6873b7 100755
--- a/qa/rpc-tests/bip65-cltv-p2p.py
+++ b/qa/rpc-tests/bip65-cltv-p2p.py
@@ -37,11 +37,12 @@ Mine 1 old version block, see that the node rejects.
class BIP65Test(ComparisonTestFramework):
def __init__(self):
+ super().__init__()
self.num_nodes = 1
def setup_network(self):
# Must set the blockversion for this test
- self.nodes = start_nodes(1, self.options.tmpdir,
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir,
extra_args=[['-debug', '-whitelist=127.0.0.1', '-blockversion=3']],
binary=[self.options.testbinary])
diff --git a/qa/rpc-tests/bip65-cltv.py b/qa/rpc-tests/bip65-cltv.py
index 9d83fc947b..abba7fc20e 100755
--- a/qa/rpc-tests/bip65-cltv.py
+++ b/qa/rpc-tests/bip65-cltv.py
@@ -11,6 +11,10 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
class BIP65Test(BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 3
+ self.setup_clean_chain = False
def setup_network(self):
self.nodes = []
diff --git a/qa/rpc-tests/bip68-112-113-p2p.py b/qa/rpc-tests/bip68-112-113-p2p.py
index eedb60e3a0..8ba0704384 100755
--- a/qa/rpc-tests/bip68-112-113-p2p.py
+++ b/qa/rpc-tests/bip68-112-113-p2p.py
@@ -94,11 +94,12 @@ def all_rlt_txs(txarray):
class BIP68_112_113Test(ComparisonTestFramework):
def __init__(self):
+ super().__init__()
self.num_nodes = 1
def setup_network(self):
# Must set the blockversion for this test
- self.nodes = start_nodes(1, self.options.tmpdir,
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir,
extra_args=[['-debug', '-whitelist=127.0.0.1', '-blockversion=4']],
binary=[self.options.testbinary])
diff --git a/qa/rpc-tests/bip68-sequence.py b/qa/rpc-tests/bip68-sequence.py
index 717f7562cd..a12bf10ebd 100755
--- a/qa/rpc-tests/bip68-sequence.py
+++ b/qa/rpc-tests/bip68-sequence.py
@@ -22,6 +22,10 @@ SEQUENCE_LOCKTIME_MASK = 0x0000ffff
NOT_FINAL_ERROR = "64: non-BIP68-final"
class BIP68Test(BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 2
+ self.setup_clean_chain = False
def setup_network(self):
self.nodes = []
diff --git a/qa/rpc-tests/bip9-softforks.py b/qa/rpc-tests/bip9-softforks.py
index e9b659d508..aae258315e 100755
--- a/qa/rpc-tests/bip9-softforks.py
+++ b/qa/rpc-tests/bip9-softforks.py
@@ -3,6 +3,7 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+from test_framework.blockstore import BlockStore
from test_framework.test_framework import ComparisonTestFramework
from test_framework.util import *
from test_framework.mininode import CTransaction, NetworkThread
@@ -31,10 +32,11 @@ test that enforcement has triggered
class BIP9SoftForksTest(ComparisonTestFramework):
def __init__(self):
+ super().__init__()
self.num_nodes = 1
def setup_network(self):
- self.nodes = start_nodes(1, self.options.tmpdir,
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir,
extra_args=[['-debug', '-whitelist=127.0.0.1']],
binary=[self.options.testbinary])
@@ -167,11 +169,13 @@ class BIP9SoftForksTest(ComparisonTestFramework):
yield TestInstance([[block, False]])
# Restart all
+ self.test.block_store.close()
stop_nodes(self.nodes)
wait_bitcoinds()
shutil.rmtree(self.options.tmpdir)
self.setup_chain()
self.setup_network()
+ self.test.block_store = BlockStore(self.options.tmpdir)
self.test.clear_all_connections()
self.test.add_all_connections(self.nodes)
NetworkThread().start() # Start up network handling in another thread
diff --git a/qa/rpc-tests/bipdersig-p2p.py b/qa/rpc-tests/bipdersig-p2p.py
index c462730840..4e4936a4ae 100755
--- a/qa/rpc-tests/bipdersig-p2p.py
+++ b/qa/rpc-tests/bipdersig-p2p.py
@@ -45,11 +45,12 @@ Mine 1 old version block, see that the node rejects.
class BIP66Test(ComparisonTestFramework):
def __init__(self):
+ super().__init__()
self.num_nodes = 1
def setup_network(self):
# Must set the blockversion for this test
- self.nodes = start_nodes(1, self.options.tmpdir,
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir,
extra_args=[['-debug', '-whitelist=127.0.0.1', '-blockversion=2']],
binary=[self.options.testbinary])
diff --git a/qa/rpc-tests/bipdersig.py b/qa/rpc-tests/bipdersig.py
index f2d2c14a72..17c2ced79a 100755
--- a/qa/rpc-tests/bipdersig.py
+++ b/qa/rpc-tests/bipdersig.py
@@ -11,6 +11,10 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
class BIP66Test(BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 3
+ self.setup_clean_chain = False
def setup_network(self):
self.nodes = []
diff --git a/qa/rpc-tests/blockchain.py b/qa/rpc-tests/blockchain.py
index c84047b5dd..410b85d15e 100755
--- a/qa/rpc-tests/blockchain.py
+++ b/qa/rpc-tests/blockchain.py
@@ -13,7 +13,6 @@ from decimal import Decimal
from test_framework.test_framework import BitcoinTestFramework
from test_framework.authproxy import JSONRPCException
from test_framework.util import (
- initialize_chain,
assert_equal,
assert_raises,
assert_is_hex_string,
@@ -32,12 +31,13 @@ class BlockchainTest(BitcoinTestFramework):
"""
- def setup_chain(self):
- print("Initializing test directory " + self.options.tmpdir)
- initialize_chain(self.options.tmpdir)
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = False
+ self.num_nodes = 2
def setup_network(self, split=False):
- self.nodes = start_nodes(2, self.options.tmpdir)
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
connect_nodes_bi(self.nodes, 0, 1)
self.is_network_split = False
self.sync_all()
diff --git a/qa/rpc-tests/create_cache.py b/qa/rpc-tests/create_cache.py
new file mode 100755
index 0000000000..b6161e0917
--- /dev/null
+++ b/qa/rpc-tests/create_cache.py
@@ -0,0 +1,23 @@
+#!/usr/bin/env python3
+# Copyright (c) 2016 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#
+# Helper script to create the cache
+# (see BitcoinTestFramework.setup_chain)
+#
+
+from test_framework.test_framework import BitcoinTestFramework
+
+class CreateCache(BitcoinTestFramework):
+
+ def setup_network(self):
+ # Don't setup any test nodes
+ self.options.noshutdown = True
+
+ def run_test(self):
+ pass
+
+if __name__ == '__main__':
+ CreateCache().main()
diff --git a/qa/rpc-tests/decodescript.py b/qa/rpc-tests/decodescript.py
index 0037542e62..24768c2655 100755
--- a/qa/rpc-tests/decodescript.py
+++ b/qa/rpc-tests/decodescript.py
@@ -11,12 +11,13 @@ from io import BytesIO
class DecodeScriptTest(BitcoinTestFramework):
"""Tests decoding scripts via RPC command "decodescript"."""
- def setup_chain(self):
- print('Initializing test directory ' + self.options.tmpdir)
- initialize_chain_clean(self.options.tmpdir, 1)
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 1
def setup_network(self, split=False):
- self.nodes = start_nodes(1, self.options.tmpdir)
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
self.is_network_split = False
def decodescript_script_sig(self):
diff --git a/qa/rpc-tests/disablewallet.py b/qa/rpc-tests/disablewallet.py
index b25d2ba335..36c147edad 100755
--- a/qa/rpc-tests/disablewallet.py
+++ b/qa/rpc-tests/disablewallet.py
@@ -13,12 +13,13 @@ from test_framework.util import *
class DisableWalletTest (BitcoinTestFramework):
- def setup_chain(self):
- print("Initializing test directory "+self.options.tmpdir)
- initialize_chain_clean(self.options.tmpdir, 1)
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 1
def setup_network(self, split=False):
- self.nodes = start_nodes(1, self.options.tmpdir, [['-disablewallet']])
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, [['-disablewallet']])
self.is_network_split = False
self.sync_all()
diff --git a/qa/rpc-tests/forknotify.py b/qa/rpc-tests/forknotify.py
index 421f3dd872..5a3f75c808 100755
--- a/qa/rpc-tests/forknotify.py
+++ b/qa/rpc-tests/forknotify.py
@@ -12,6 +12,11 @@ from test_framework.util import *
class ForkNotifyTest(BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 2
+ self.setup_clean_chain = False
+
alert_filename = None # Set by setup_network
def setup_network(self):
diff --git a/qa/rpc-tests/fundrawtransaction.py b/qa/rpc-tests/fundrawtransaction.py
index 74849603f7..57b850a6a9 100755
--- a/qa/rpc-tests/fundrawtransaction.py
+++ b/qa/rpc-tests/fundrawtransaction.py
@@ -9,12 +9,13 @@ from test_framework.util import *
# Create one-input, one-output, no-fee transaction:
class RawTransactionsTest(BitcoinTestFramework):
- def setup_chain(self):
- print(("Initializing test directory "+self.options.tmpdir))
- initialize_chain_clean(self.options.tmpdir, 4)
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 4
def setup_network(self, split=False):
- self.nodes = start_nodes(4, self.options.tmpdir)
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
connect_nodes_bi(self.nodes,0,1)
connect_nodes_bi(self.nodes,1,2)
@@ -521,7 +522,7 @@ class RawTransactionsTest(BitcoinTestFramework):
stop_nodes(self.nodes)
wait_bitcoinds()
- self.nodes = start_nodes(4, self.options.tmpdir)
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
# This test is not meant to test fee estimation and we'd like
# to be sure all txs are sent at a consistent desired feerate
for node in self.nodes:
diff --git a/qa/rpc-tests/getblocktemplate_longpoll.py b/qa/rpc-tests/getblocktemplate_longpoll.py
index e443347077..3cddf4046a 100755
--- a/qa/rpc-tests/getblocktemplate_longpoll.py
+++ b/qa/rpc-tests/getblocktemplate_longpoll.py
@@ -26,6 +26,11 @@ class GetBlockTemplateLPTest(BitcoinTestFramework):
Test longpolling with getblocktemplate.
'''
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 4
+ self.setup_clean_chain = False
+
def run_test(self):
print("Warning: this test will take about 70 seconds in the best case. Be patient.")
self.nodes[0].generate(10)
diff --git a/qa/rpc-tests/getblocktemplate_proposals.py b/qa/rpc-tests/getblocktemplate_proposals.py
index 1ad2af4c2e..7a4f8f8fdc 100755
--- a/qa/rpc-tests/getblocktemplate_proposals.py
+++ b/qa/rpc-tests/getblocktemplate_proposals.py
@@ -70,6 +70,15 @@ class GetBlockTemplateProposalTest(BitcoinTestFramework):
Test block proposals with getblocktemplate.
'''
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 2
+ self.setup_clean_chain = False
+
+ def setup_network(self):
+ self.nodes = self.setup_nodes()
+ connect_nodes_bi(self.nodes, 0, 1)
+
def run_test(self):
node = self.nodes[0]
node.generate(1) # Mine a block to leave initial block download
diff --git a/qa/rpc-tests/getchaintips.py b/qa/rpc-tests/getchaintips.py
index da354b0c97..1c66b8c289 100755
--- a/qa/rpc-tests/getchaintips.py
+++ b/qa/rpc-tests/getchaintips.py
@@ -11,9 +11,12 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
class GetChainTipsTest (BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 4
+ self.setup_clean_chain = False
def run_test (self):
- BitcoinTestFramework.run_test (self)
tips = self.nodes[0].getchaintips ()
assert_equal (len (tips), 1)
diff --git a/qa/rpc-tests/httpbasics.py b/qa/rpc-tests/httpbasics.py
index c62edc8e13..10bc927e1a 100755
--- a/qa/rpc-tests/httpbasics.py
+++ b/qa/rpc-tests/httpbasics.py
@@ -14,8 +14,13 @@ import http.client
import urllib.parse
class HTTPBasicsTest (BitcoinTestFramework):
- def setup_nodes(self):
- return start_nodes(4, self.options.tmpdir)
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 3
+ self.setup_clean_chain = False
+
+ def setup_network(self):
+ self.nodes = self.setup_nodes()
def run_test(self):
diff --git a/qa/rpc-tests/importprunedfunds.py b/qa/rpc-tests/importprunedfunds.py
index def1d891c3..d86f51b7f3 100755
--- a/qa/rpc-tests/importprunedfunds.py
+++ b/qa/rpc-tests/importprunedfunds.py
@@ -9,12 +9,13 @@ import decimal
class ImportPrunedFundsTest(BitcoinTestFramework):
- def setup_chain(self):
- print("Initializing test directory "+self.options.tmpdir)
- initialize_chain_clean(self.options.tmpdir, 4)
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 2
def setup_network(self, split=False):
- self.nodes = start_nodes(2, self.options.tmpdir)
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
connect_nodes_bi(self.nodes,0,1)
self.is_network_split=False
self.sync_all()
diff --git a/qa/rpc-tests/invalidateblock.py b/qa/rpc-tests/invalidateblock.py
index 2e3a449f5e..0faadd33ab 100755
--- a/qa/rpc-tests/invalidateblock.py
+++ b/qa/rpc-tests/invalidateblock.py
@@ -13,10 +13,11 @@ from test_framework.util import *
class InvalidateTest(BitcoinTestFramework):
- def setup_chain(self):
- print("Initializing test directory "+self.options.tmpdir)
- initialize_chain_clean(self.options.tmpdir, 3)
-
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 3
+
def setup_network(self):
self.nodes = []
self.is_network_split = False
diff --git a/qa/rpc-tests/invalidblockrequest.py b/qa/rpc-tests/invalidblockrequest.py
index 78dc7199da..3d8107a76c 100755
--- a/qa/rpc-tests/invalidblockrequest.py
+++ b/qa/rpc-tests/invalidblockrequest.py
@@ -25,6 +25,7 @@ class InvalidBlockRequestTest(ComparisonTestFramework):
''' Can either run this test as 1 node with expected answers, or two and compare them.
Change the "outcome" variable from each TestInstance object to only do the comparison. '''
def __init__(self):
+ super().__init__()
self.num_nodes = 1
def run_test(self):
diff --git a/qa/rpc-tests/invalidtxrequest.py b/qa/rpc-tests/invalidtxrequest.py
index d4200b0e88..93205d79de 100755
--- a/qa/rpc-tests/invalidtxrequest.py
+++ b/qa/rpc-tests/invalidtxrequest.py
@@ -19,6 +19,7 @@ class InvalidTxRequestTest(ComparisonTestFramework):
''' Can either run this test as 1 node with expected answers, or two and compare them.
Change the "outcome" variable from each TestInstance object to only do the comparison. '''
def __init__(self):
+ super().__init__()
self.num_nodes = 1
def run_test(self):
diff --git a/qa/rpc-tests/keypool.py b/qa/rpc-tests/keypool.py
index bdc144bfbc..c75303ecbf 100755
--- a/qa/rpc-tests/keypool.py
+++ b/qa/rpc-tests/keypool.py
@@ -5,8 +5,6 @@
# Exercise the wallet keypool, and interaction with wallet encryption/locking
-# Add python-bitcoinrpc to module search path:
-
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
@@ -65,12 +63,13 @@ class KeyPoolTest(BitcoinTestFramework):
except JSONRPCException as e:
assert(e.error['code']==-12)
- def setup_chain(self):
- print("Initializing test directory "+self.options.tmpdir)
- initialize_chain(self.options.tmpdir)
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = False
+ self.num_nodes = 1
def setup_network(self):
- self.nodes = start_nodes(1, self.options.tmpdir)
+ self.nodes = self.setup_nodes()
if __name__ == '__main__':
KeyPoolTest().main()
diff --git a/qa/rpc-tests/listtransactions.py b/qa/rpc-tests/listtransactions.py
index 8dad687edd..5ec6ce17e0 100755
--- a/qa/rpc-tests/listtransactions.py
+++ b/qa/rpc-tests/listtransactions.py
@@ -17,11 +17,15 @@ def txFromHex(hexstring):
return tx
class ListTransactionsTest(BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 4
+ self.setup_clean_chain = False
def setup_nodes(self):
#This test requires mocktime
enable_mocktime()
- return start_nodes(4, self.options.tmpdir)
+ return start_nodes(self.num_nodes, self.options.tmpdir)
def run_test(self):
# Simple send, 0 to 1:
diff --git a/qa/rpc-tests/maxblocksinflight.py b/qa/rpc-tests/maxblocksinflight.py
index 6f105a77e3..1df1c484be 100755
--- a/qa/rpc-tests/maxblocksinflight.py
+++ b/qa/rpc-tests/maxblocksinflight.py
@@ -76,12 +76,13 @@ class MaxBlocksInFlightTest(BitcoinTestFramework):
default=os.getenv("BITCOIND", "bitcoind"),
help="Binary to test max block requests behavior")
- def setup_chain(self):
- print("Initializing test directory "+self.options.tmpdir)
- initialize_chain_clean(self.options.tmpdir, 1)
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 1
def setup_network(self):
- self.nodes = start_nodes(1, self.options.tmpdir,
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir,
extra_args=[['-debug', '-whitelist=127.0.0.1']],
binary=[self.options.testbinary])
diff --git a/qa/rpc-tests/maxuploadtarget.py b/qa/rpc-tests/maxuploadtarget.py
index ec802d8155..5087f07620 100755
--- a/qa/rpc-tests/maxuploadtarget.py
+++ b/qa/rpc-tests/maxuploadtarget.py
@@ -80,17 +80,19 @@ class TestNode(NodeConnCB):
return success
class MaxUploadTest(BitcoinTestFramework):
- def __init__(self):
- self.utxo = []
- self.txouts = gen_return_txouts()
def add_options(self, parser):
parser.add_option("--testbinary", dest="testbinary",
default=os.getenv("BITCOIND", "bitcoind"),
help="bitcoind binary to test")
- def setup_chain(self):
- initialize_chain_clean(self.options.tmpdir, 2)
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 1
+
+ self.utxo = []
+ self.txouts = gen_return_txouts()
def setup_network(self):
# Start a node with maxuploadtarget of 200 MB (/24h)
diff --git a/qa/rpc-tests/mempool_limit.py b/qa/rpc-tests/mempool_limit.py
index bc208709e9..4438c152df 100755
--- a/qa/rpc-tests/mempool_limit.py
+++ b/qa/rpc-tests/mempool_limit.py
@@ -10,9 +10,6 @@ from test_framework.util import *
class MempoolLimitTest(BitcoinTestFramework):
- def __init__(self):
- self.txouts = gen_return_txouts()
-
def setup_network(self):
self.nodes = []
self.nodes.append(start_node(0, self.options.tmpdir, ["-maxmempool=5", "-spendzeroconfchange=0", "-debug"]))
@@ -20,9 +17,12 @@ class MempoolLimitTest(BitcoinTestFramework):
self.sync_all()
self.relayfee = self.nodes[0].getnetworkinfo()['relayfee']
- def setup_chain(self):
- print("Initializing test directory "+self.options.tmpdir)
- initialize_chain_clean(self.options.tmpdir, 2)
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 1
+
+ self.txouts = gen_return_txouts()
def run_test(self):
txids = []
diff --git a/qa/rpc-tests/mempool_packages.py b/qa/rpc-tests/mempool_packages.py
index 7ac85c1b6d..693ff593b3 100755
--- a/qa/rpc-tests/mempool_packages.py
+++ b/qa/rpc-tests/mempool_packages.py
@@ -13,6 +13,10 @@ MAX_ANCESTORS = 25
MAX_DESCENDANTS = 25
class MempoolPackagesTest(BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 2
+ self.setup_clean_chain = False
def setup_network(self):
self.nodes = []
diff --git a/qa/rpc-tests/mempool_reorg.py b/qa/rpc-tests/mempool_reorg.py
index 608e9d0a06..301b094eb0 100755
--- a/qa/rpc-tests/mempool_reorg.py
+++ b/qa/rpc-tests/mempool_reorg.py
@@ -13,6 +13,10 @@ from test_framework.util import *
# Create one-input, one-output, no-fee transaction:
class MempoolCoinbaseTest(BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 2
+ self.setup_clean_chain = False
alert_filename = None # Set by setup_network
diff --git a/qa/rpc-tests/mempool_resurrect_test.py b/qa/rpc-tests/mempool_resurrect_test.py
index b4d9f0a1a2..3db12cbf76 100755
--- a/qa/rpc-tests/mempool_resurrect_test.py
+++ b/qa/rpc-tests/mempool_resurrect_test.py
@@ -14,6 +14,11 @@ from test_framework.util import *
# Create one-input, one-output, no-fee transaction:
class MempoolCoinbaseTest(BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 1
+ self.setup_clean_chain = False
+
def setup_network(self):
# Just need one node for this test
args = ["-checkmempool", "-debug=mempool"]
diff --git a/qa/rpc-tests/mempool_spendcoinbase.py b/qa/rpc-tests/mempool_spendcoinbase.py
index c23f5ef10a..d5e4bf52d2 100755
--- a/qa/rpc-tests/mempool_spendcoinbase.py
+++ b/qa/rpc-tests/mempool_spendcoinbase.py
@@ -19,6 +19,11 @@ from test_framework.util import *
# Create one-input, one-output, no-fee transaction:
class MempoolSpendCoinbaseTest(BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 1
+ self.setup_clean_chain = False
+
def setup_network(self):
# Just need one node for this test
args = ["-checkmempool", "-debug=mempool"]
diff --git a/qa/rpc-tests/merkle_blocks.py b/qa/rpc-tests/merkle_blocks.py
index 9419d9a714..b2155d7fc3 100755
--- a/qa/rpc-tests/merkle_blocks.py
+++ b/qa/rpc-tests/merkle_blocks.py
@@ -12,9 +12,10 @@ from test_framework.util import *
class MerkleBlockTest(BitcoinTestFramework):
- def setup_chain(self):
- print("Initializing test directory "+self.options.tmpdir)
- initialize_chain_clean(self.options.tmpdir, 4)
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 4
def setup_network(self):
self.nodes = []
diff --git a/qa/rpc-tests/multi_rpc.py b/qa/rpc-tests/multi_rpc.py
index 577d80949d..24373b257d 100755
--- a/qa/rpc-tests/multi_rpc.py
+++ b/qa/rpc-tests/multi_rpc.py
@@ -8,18 +8,21 @@
#
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
+from test_framework.util import str_to_b64str, assert_equal
+import os
import http.client
import urllib.parse
class HTTPBasicsTest (BitcoinTestFramework):
- def setup_nodes(self):
- return start_nodes(4, self.options.tmpdir)
+
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = False
+ self.num_nodes = 1
def setup_chain(self):
- print("Initializing test directory "+self.options.tmpdir)
- initialize_chain(self.options.tmpdir)
+ super().setup_chain()
#Append rpcauth to bitcoin.conf before initialization
rpcauth = "rpcauth=rt:93648e835a54c573682c2eb19f882535$7681e9c5b74bdd85e78166031d2058e1069b3ed7ed967c93fc63abba06f31144"
rpcauth2 = "rpcauth=rt2:f8607b1a88861fac29dfccf9b52ff9f$ff36a0c23c8c62b4846112e50fa888416e94c17bfd4c42f88fd8f55ec6a3137e"
@@ -27,6 +30,9 @@ class HTTPBasicsTest (BitcoinTestFramework):
f.write(rpcauth+"\n")
f.write(rpcauth2+"\n")
+ def setup_network(self):
+ self.nodes = self.setup_nodes()
+
def run_test(self):
##################################################
diff --git a/qa/rpc-tests/nodehandling.py b/qa/rpc-tests/nodehandling.py
index 1b6ba021a0..e9682c4908 100755
--- a/qa/rpc-tests/nodehandling.py
+++ b/qa/rpc-tests/nodehandling.py
@@ -14,6 +14,12 @@ import http.client
import urllib.parse
class NodeHandlingTest (BitcoinTestFramework):
+
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 4
+ self.setup_clean_chain = False
+
def run_test(self):
###########################
# setban/listbanned tests #
diff --git a/qa/rpc-tests/p2p-acceptblock.py b/qa/rpc-tests/p2p-acceptblock.py
index 21e4c2f468..015ec34eff 100755
--- a/qa/rpc-tests/p2p-acceptblock.py
+++ b/qa/rpc-tests/p2p-acceptblock.py
@@ -111,8 +111,10 @@ class AcceptBlockTest(BitcoinTestFramework):
default=os.getenv("BITCOIND", "bitcoind"),
help="bitcoind binary to test")
- def setup_chain(self):
- initialize_chain_clean(self.options.tmpdir, 2)
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 2
def setup_network(self):
# Node0 will be used to test behavior of processing unrequested blocks
diff --git a/qa/rpc-tests/p2p-feefilter.py b/qa/rpc-tests/p2p-feefilter.py
index 5fb51ed0fe..cd0501a314 100755
--- a/qa/rpc-tests/p2p-feefilter.py
+++ b/qa/rpc-tests/p2p-feefilter.py
@@ -46,6 +46,12 @@ class TestNode(SingleNodeConnCB):
self.sync_with_ping()
class FeeFilterTest(BitcoinTestFramework):
+
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 2
+ self.setup_clean_chain = False
+
def setup_network(self):
# Node1 will be used to generate txs which should be relayed from Node0
# to our test node
diff --git a/qa/rpc-tests/p2p-fullblocktest.py b/qa/rpc-tests/p2p-fullblocktest.py
index 56df8ffd01..aa0501c5e9 100755
--- a/qa/rpc-tests/p2p-fullblocktest.py
+++ b/qa/rpc-tests/p2p-fullblocktest.py
@@ -29,6 +29,7 @@ class FullBlockTest(ComparisonTestFramework):
''' Can either run this test as 1 node with expected answers, or two and compare them.
Change the "outcome" variable from each TestInstance object to only do the comparison. '''
def __init__(self):
+ super().__init__()
self.num_nodes = 1
self.block_heights = {}
self.coinbase_key = CECKey()
diff --git a/qa/rpc-tests/p2p-versionbits-warning.py b/qa/rpc-tests/p2p-versionbits-warning.py
index 8c8c2358f7..962cafef0b 100755
--- a/qa/rpc-tests/p2p-versionbits-warning.py
+++ b/qa/rpc-tests/p2p-versionbits-warning.py
@@ -59,8 +59,10 @@ class TestNode(NodeConnCB):
class VersionBitsWarningTest(BitcoinTestFramework):
- def setup_chain(self):
- initialize_chain_clean(self.options.tmpdir, 1)
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 1
def setup_network(self):
self.nodes = []
diff --git a/qa/rpc-tests/prioritise_transaction.py b/qa/rpc-tests/prioritise_transaction.py
index 6ab88602b5..e1771231c0 100755
--- a/qa/rpc-tests/prioritise_transaction.py
+++ b/qa/rpc-tests/prioritise_transaction.py
@@ -14,11 +14,11 @@ from test_framework.mininode import COIN, MAX_BLOCK_SIZE
class PrioritiseTransactionTest(BitcoinTestFramework):
def __init__(self):
- self.txouts = gen_return_txouts()
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 1
- def setup_chain(self):
- print("Initializing test directory "+self.options.tmpdir)
- initialize_chain_clean(self.options.tmpdir, 1)
+ self.txouts = gen_return_txouts()
def setup_network(self):
self.nodes = []
diff --git a/qa/rpc-tests/proxy_test.py b/qa/rpc-tests/proxy_test.py
index 6c7b201d56..27160cae07 100755
--- a/qa/rpc-tests/proxy_test.py
+++ b/qa/rpc-tests/proxy_test.py
@@ -36,6 +36,10 @@ addnode connect to generic DNS name
class ProxyTest(BitcoinTestFramework):
def __init__(self):
+ super().__init__()
+ self.num_nodes = 4
+ self.setup_clean_chain = False
+
self.have_ipv6 = test_ipv6_local()
# Create two proxies on different ports
# ... one unauthenticated
@@ -77,7 +81,7 @@ class ProxyTest(BitcoinTestFramework):
]
if self.have_ipv6:
args[3] = ['-listen', '-debug=net', '-debug=proxy', '-proxy=[%s]:%i' % (self.conf3.addr),'-proxyrandomize=0', '-noonion']
- return start_nodes(4, self.options.tmpdir, extra_args=args)
+ return start_nodes(self.num_nodes, self.options.tmpdir, extra_args=args)
def node_test(self, node, proxies, auth, test_onion=True):
rv = []
diff --git a/qa/rpc-tests/pruning.py b/qa/rpc-tests/pruning.py
index 92d33bd20e..d225e29b50 100755
--- a/qa/rpc-tests/pruning.py
+++ b/qa/rpc-tests/pruning.py
@@ -20,14 +20,14 @@ def calc_usage(blockdir):
class PruneTest(BitcoinTestFramework):
def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 3
+
self.utxo = []
self.address = ["",""]
self.txouts = gen_return_txouts()
- def setup_chain(self):
- print("Initializing test directory "+self.options.tmpdir)
- initialize_chain_clean(self.options.tmpdir, 3)
-
def setup_network(self):
self.nodes = []
self.is_network_split = False
@@ -75,7 +75,7 @@ class PruneTest(BitcoinTestFramework):
waitstart = time.time()
while os.path.isfile(self.prunedir+"blk00000.dat"):
time.sleep(0.1)
- if time.time() - waitstart > 10:
+ if time.time() - waitstart > 30:
raise AssertionError("blk00000.dat not pruned when it should be")
print("Success")
diff --git a/qa/rpc-tests/rawtransactions.py b/qa/rpc-tests/rawtransactions.py
index 7f7b6887a8..df02c1697f 100755
--- a/qa/rpc-tests/rawtransactions.py
+++ b/qa/rpc-tests/rawtransactions.py
@@ -14,12 +14,13 @@ from test_framework.util import *
# Create one-input, one-output, no-fee transaction:
class RawTransactionsTest(BitcoinTestFramework):
- def setup_chain(self):
- print("Initializing test directory "+self.options.tmpdir)
- initialize_chain_clean(self.options.tmpdir, 3)
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 3
def setup_network(self, split=False):
- self.nodes = start_nodes(3, self.options.tmpdir)
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
#connect to a local machine for debugging
#url = "http://bitcoinrpc:DP6DvqZtqXarpeNWyN3LZTFchCCyCUuHwNF7E8pX99x1@%s:%d" % ('127.0.0.1', 18332)
diff --git a/qa/rpc-tests/receivedby.py b/qa/rpc-tests/receivedby.py
index a3f97669ea..4f17b661cb 100755
--- a/qa/rpc-tests/receivedby.py
+++ b/qa/rpc-tests/receivedby.py
@@ -27,10 +27,15 @@ def get_sub_array_from_array(object_array, to_match):
class ReceivedByTest(BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 4
+ self.setup_clean_chain = False
+
def setup_nodes(self):
#This test requires mocktime
enable_mocktime()
- return start_nodes(4, self.options.tmpdir)
+ return start_nodes(self.num_nodes, self.options.tmpdir)
def run_test(self):
'''
diff --git a/qa/rpc-tests/reindex.py b/qa/rpc-tests/reindex.py
index 39564b32ba..abbbb10336 100755
--- a/qa/rpc-tests/reindex.py
+++ b/qa/rpc-tests/reindex.py
@@ -4,29 +4,40 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
#
-# Test -reindex with CheckBlockIndex
+# Test -reindex and -reindex-chainstate with CheckBlockIndex
#
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
+import time
class ReindexTest(BitcoinTestFramework):
- def setup_chain(self):
- print("Initializing test directory "+self.options.tmpdir)
- initialize_chain_clean(self.options.tmpdir, 1)
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 1
def setup_network(self):
self.nodes = []
self.is_network_split = False
self.nodes.append(start_node(0, self.options.tmpdir))
- def run_test(self):
+ def reindex(self, justchainstate=False):
self.nodes[0].generate(3)
+ blockcount = self.nodes[0].getblockcount()
stop_node(self.nodes[0], 0)
wait_bitcoinds()
- self.nodes[0]=start_node(0, self.options.tmpdir, ["-debug", "-reindex", "-checkblockindex=1"])
- assert_equal(self.nodes[0].getblockcount(), 3)
+ self.nodes[0]=start_node(0, self.options.tmpdir, ["-debug", "-reindex-chainstate" if justchainstate else "-reindex", "-checkblockindex=1"])
+ while self.nodes[0].getblockcount() < blockcount:
+ time.sleep(0.1)
+ assert_equal(self.nodes[0].getblockcount(), blockcount)
print("Success")
+ def run_test(self):
+ self.reindex(False)
+ self.reindex(True)
+ self.reindex(False)
+ self.reindex(True)
+
if __name__ == '__main__':
ReindexTest().main()
diff --git a/qa/rpc-tests/replace-by-fee.py b/qa/rpc-tests/replace-by-fee.py
index 4afc3981da..34c0f9d795 100755
--- a/qa/rpc-tests/replace-by-fee.py
+++ b/qa/rpc-tests/replace-by-fee.py
@@ -68,6 +68,11 @@ def make_utxo(node, amount, confirmed=True, scriptPubKey=CScript([1])):
class ReplaceByFeeTest(BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 1
+ self.setup_clean_chain = False
+
def setup_network(self):
self.nodes = []
self.nodes.append(start_node(0, self.options.tmpdir, ["-maxorphantx=1000", "-debug",
diff --git a/qa/rpc-tests/rest.py b/qa/rpc-tests/rest.py
index ec9515528e..c9c2eaf7f3 100755
--- a/qa/rpc-tests/rest.py
+++ b/qa/rpc-tests/rest.py
@@ -47,12 +47,13 @@ def http_post_call(host, port, path, requestdata = '', response_object = 0):
class RESTTest (BitcoinTestFramework):
FORMAT_SEPARATOR = "."
- def setup_chain(self):
- print("Initializing test directory "+self.options.tmpdir)
- initialize_chain_clean(self.options.tmpdir, 3)
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 3
def setup_network(self, split=False):
- self.nodes = start_nodes(3, self.options.tmpdir)
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
connect_nodes_bi(self.nodes,0,1)
connect_nodes_bi(self.nodes,1,2)
connect_nodes_bi(self.nodes,0,2)
diff --git a/qa/rpc-tests/rpcbind_test.py b/qa/rpc-tests/rpcbind_test.py
index 7b7c01f993..572273566b 100755
--- a/qa/rpc-tests/rpcbind_test.py
+++ b/qa/rpc-tests/rpcbind_test.py
@@ -24,7 +24,7 @@ def run_bind_test(tmpdir, allow_ips, connect_to, addresses, expected):
if allow_ips:
base_args += ['-rpcallowip=' + x for x in allow_ips]
binds = ['-rpcbind='+addr for addr in addresses]
- nodes = start_nodes(1, tmpdir, [base_args + binds], connect_to)
+ nodes = start_nodes(self.num_nodes, tmpdir, [base_args + binds], connect_to)
try:
pid = bitcoind_processes[0].pid
assert_equal(set(get_bind_addrs(pid)), set(expected))
@@ -38,7 +38,7 @@ def run_allowip_test(tmpdir, allow_ips, rpchost, rpcport):
at a non-localhost IP.
'''
base_args = ['-disablewallet', '-nolisten'] + ['-rpcallowip='+x for x in allow_ips]
- nodes = start_nodes(1, tmpdir, [base_args])
+ nodes = start_nodes(self.num_nodes, tmpdir, [base_args])
try:
# connect to node through non-loopback interface
url = "http://rt:rt@%s:%d" % (rpchost, rpcport,)
diff --git a/qa/rpc-tests/sendheaders.py b/qa/rpc-tests/sendheaders.py
index 96d1da729b..6ab17d59b3 100755
--- a/qa/rpc-tests/sendheaders.py
+++ b/qa/rpc-tests/sendheaders.py
@@ -208,12 +208,14 @@ class TestNode(BaseNode):
BaseNode.__init__(self)
class SendHeadersTest(BitcoinTestFramework):
- def setup_chain(self):
- initialize_chain_clean(self.options.tmpdir, 2)
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 2
def setup_network(self):
self.nodes = []
- self.nodes = start_nodes(2, self.options.tmpdir, [["-debug", "-logtimemicros=1"]]*2)
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, [["-debug", "-logtimemicros=1"]]*2)
connect_nodes(self.nodes[0], 1)
# mine count blocks and return the new tip
diff --git a/qa/rpc-tests/signmessages.py b/qa/rpc-tests/signmessages.py
index 4a47c0ca1e..31b6f14a26 100755
--- a/qa/rpc-tests/signmessages.py
+++ b/qa/rpc-tests/signmessages.py
@@ -10,12 +10,13 @@ from test_framework.util import *
class SignMessagesTest(BitcoinTestFramework):
"""Tests RPC commands for signing and verifying messages."""
- def setup_chain(self):
- print('Initializing test directory ' + self.options.tmpdir)
- initialize_chain_clean(self.options.tmpdir, 1)
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 1
def setup_network(self, split=False):
- self.nodes = start_nodes(1, self.options.tmpdir)
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
self.is_network_split = False
def run_test(self):
diff --git a/qa/rpc-tests/signrawtransactions.py b/qa/rpc-tests/signrawtransactions.py
index a06ac53191..c61a280616 100755
--- a/qa/rpc-tests/signrawtransactions.py
+++ b/qa/rpc-tests/signrawtransactions.py
@@ -10,12 +10,13 @@ from test_framework.util import *
class SignRawTransactionsTest(BitcoinTestFramework):
"""Tests transaction signing via RPC command "signrawtransaction"."""
- def setup_chain(self):
- print('Initializing test directory ' + self.options.tmpdir)
- initialize_chain_clean(self.options.tmpdir, 1)
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 1
def setup_network(self, split=False):
- self.nodes = start_nodes(1, self.options.tmpdir)
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
self.is_network_split = False
def successful_signing_test(self):
diff --git a/qa/rpc-tests/smartfees.py b/qa/rpc-tests/smartfees.py
index 8fcb99c1b7..d76fba4b07 100755
--- a/qa/rpc-tests/smartfees.py
+++ b/qa/rpc-tests/smartfees.py
@@ -145,6 +145,11 @@ def check_estimates(node, fees_seen, max_invalid, print_estimates = True):
class EstimateFeeTest(BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 3
+ self.setup_clean_chain = False
+
def setup_network(self):
'''
We'll setup the network to have 3 nodes that all mine with different parameters.
diff --git a/qa/rpc-tests/test_framework/test_framework.py b/qa/rpc-tests/test_framework/test_framework.py
index 4e72463096..49f4192269 100755
--- a/qa/rpc-tests/test_framework/test_framework.py
+++ b/qa/rpc-tests/test_framework/test_framework.py
@@ -5,17 +5,16 @@
# Base class for RPC testing
-# Add python-bitcoinrpc to module search path:
+import logging
+import optparse
import os
import sys
-
import shutil
import tempfile
import traceback
from .util import (
initialize_chain,
- assert_equal,
start_nodes,
connect_nodes_bi,
sync_blocks,
@@ -25,27 +24,33 @@ from .util import (
enable_coverage,
check_json_precision,
initialize_chain_clean,
+ PortSeed,
)
-from .authproxy import AuthServiceProxy, JSONRPCException
+from .authproxy import JSONRPCException
class BitcoinTestFramework(object):
- # These may be over-ridden by subclasses:
+ def __init__(self):
+ self.num_nodes = 4
+ self.setup_clean_chain = False
+ self.nodes = None
+
def run_test(self):
- for node in self.nodes:
- assert_equal(node.getblockcount(), 200)
- assert_equal(node.getbalance(), 25*50)
+ raise NotImplementedError
def add_options(self, parser):
pass
def setup_chain(self):
print("Initializing test directory "+self.options.tmpdir)
- initialize_chain(self.options.tmpdir)
+ if self.setup_clean_chain:
+ initialize_chain_clean(self.options.tmpdir, self.num_nodes)
+ else:
+ initialize_chain(self.options.tmpdir, self.num_nodes)
def setup_nodes(self):
- return start_nodes(4, self.options.tmpdir)
+ return start_nodes(self.num_nodes, self.options.tmpdir)
def setup_network(self, split = False):
self.nodes = self.setup_nodes()
@@ -95,7 +100,6 @@ class BitcoinTestFramework(object):
self.setup_network(False)
def main(self):
- import optparse
parser = optparse.OptionParser(usage="%prog [options]")
parser.add_option("--nocleanup", dest="nocleanup", default=False, action="store_true",
@@ -108,18 +112,21 @@ class BitcoinTestFramework(object):
help="Root directory for datadirs")
parser.add_option("--tracerpc", dest="trace_rpc", default=False, action="store_true",
help="Print out all RPC calls as they are made")
+ parser.add_option("--portseed", dest="port_seed", default=os.getpid(), type='int',
+ help="The seed to use for assigning port numbers (default: current process id)")
parser.add_option("--coveragedir", dest="coveragedir",
help="Write tested RPC commands into this directory")
self.add_options(parser)
(self.options, self.args) = parser.parse_args()
if self.options.trace_rpc:
- import logging
logging.basicConfig(level=logging.DEBUG, stream=sys.stdout)
if self.options.coveragedir:
enable_coverage(self.options.coveragedir)
+ PortSeed.n = self.options.port_seed
+
os.environ['PATH'] = self.options.srcdir+":"+self.options.srcdir+"/qt:"+os.environ['PATH']
check_json_precision()
@@ -158,9 +165,11 @@ class BitcoinTestFramework(object):
else:
print("Note: bitcoinds were not stopped and may still be running")
- if not self.options.nocleanup and not self.options.noshutdown:
+ if not self.options.nocleanup and not self.options.noshutdown and success:
print("Cleaning up")
shutil.rmtree(self.options.tmpdir)
+ else:
+ print("Not cleaning up dir %s" % self.options.tmpdir)
if success:
print("Tests successful")
@@ -178,9 +187,10 @@ class BitcoinTestFramework(object):
class ComparisonTestFramework(BitcoinTestFramework):
- # Can override the num_nodes variable to indicate how many nodes to run.
def __init__(self):
+ super().__init__()
self.num_nodes = 2
+ self.setup_clean_chain = True
def add_options(self, parser):
parser.add_option("--testbinary", dest="testbinary",
@@ -190,10 +200,6 @@ class ComparisonTestFramework(BitcoinTestFramework):
default=os.getenv("BITCOIND", "bitcoind"),
help="bitcoind binary to use for reference nodes (if any)")
- def setup_chain(self):
- print("Initializing test directory "+self.options.tmpdir)
- initialize_chain_clean(self.options.tmpdir, self.num_nodes)
-
def setup_network(self):
self.nodes = start_nodes(
self.num_nodes, self.options.tmpdir,
diff --git a/qa/rpc-tests/test_framework/util.py b/qa/rpc-tests/test_framework/util.py
index 6dc685ea1b..3948b664e3 100644
--- a/qa/rpc-tests/test_framework/util.py
+++ b/qa/rpc-tests/test_framework/util.py
@@ -8,7 +8,6 @@
# Helpful routines for regression testing
#
-# Add python-bitcoinrpc to module search path:
import os
import sys
@@ -36,6 +35,13 @@ PORT_MIN = 11000
# The number of ports to "reserve" for p2p and rpc, each
PORT_RANGE = 5000
+BITCOIND_PROC_WAIT_TIMEOUT = 60
+
+
+class PortSeed:
+ # Must be initialized with a unique integer for each process
+ n = None
+
#Set Mocktime default to OFF.
#MOCKTIME is only needed for scripts that use the
#cached version of the blockchain. If the cached
@@ -91,10 +97,10 @@ def get_rpc_proxy(url, node_number, timeout=None):
def p2p_port(n):
assert(n <= MAX_NODES)
- return PORT_MIN + n + (MAX_NODES * os.getpid()) % (PORT_RANGE - 1 - MAX_NODES)
+ return PORT_MIN + n + (MAX_NODES * PortSeed.n) % (PORT_RANGE - 1 - MAX_NODES)
def rpc_port(n):
- return PORT_MIN + PORT_RANGE + n + (MAX_NODES * os.getpid()) % (PORT_RANGE -1 - MAX_NODES)
+ return PORT_MIN + PORT_RANGE + n + (MAX_NODES * PortSeed.n) % (PORT_RANGE - 1 - MAX_NODES)
def check_json_precision():
"""Make sure json library being used does not lose precision converting BTC values"""
@@ -178,24 +184,28 @@ def wait_for_bitcoind_start(process, url, i):
raise # unkown JSON RPC exception
time.sleep(0.25)
-def initialize_chain(test_dir):
+def initialize_chain(test_dir, num_nodes):
"""
- Create (or copy from cache) a 200-block-long chain and
- 4 wallets.
+ Create a cache of a 200-block-long chain (with wallet) for MAX_NODES
+ Afterward, create num_nodes copies from the cache
"""
- if (not os.path.isdir(os.path.join("cache","node0"))
- or not os.path.isdir(os.path.join("cache","node1"))
- or not os.path.isdir(os.path.join("cache","node2"))
- or not os.path.isdir(os.path.join("cache","node3"))):
+ assert num_nodes <= MAX_NODES
+ create_cache = False
+ for i in range(MAX_NODES):
+ if not os.path.isdir(os.path.join('cache', 'node'+str(i))):
+ create_cache = True
+ break
+
+ if create_cache:
#find and delete old cache directories if any exist
- for i in range(4):
+ for i in range(MAX_NODES):
if os.path.isdir(os.path.join("cache","node"+str(i))):
shutil.rmtree(os.path.join("cache","node"+str(i)))
# Create cache directories, run bitcoinds:
- for i in range(4):
+ for i in range(MAX_NODES):
datadir=initialize_datadir("cache", i)
args = [ os.getenv("BITCOIND", "bitcoind"), "-server", "-keypool=1", "-datadir="+datadir, "-discover=0" ]
if i > 0:
@@ -208,15 +218,18 @@ def initialize_chain(test_dir):
print("initialize_chain: RPC succesfully started")
rpcs = []
- for i in range(4):
+ for i in range(MAX_NODES):
try:
rpcs.append(get_rpc_proxy(rpc_url(i), i))
except:
sys.stderr.write("Error connecting to "+url+"\n")
sys.exit(1)
- # Create a 200-block-long chain; each of the 4 nodes
+ # 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()
@@ -234,13 +247,13 @@ def initialize_chain(test_dir):
stop_nodes(rpcs)
wait_bitcoinds()
disable_mocktime()
- for i in range(4):
+ for i in range(MAX_NODES):
os.remove(log_filename("cache", i, "debug.log"))
os.remove(log_filename("cache", i, "db.log"))
os.remove(log_filename("cache", i, "peers.dat"))
os.remove(log_filename("cache", i, "fee_estimates.dat"))
- for i in range(4):
+ for i in range(num_nodes):
from_dir = os.path.join("cache", "node"+str(i))
to_dir = os.path.join(test_dir, "node"+str(i))
shutil.copytree(from_dir, to_dir)
@@ -321,7 +334,7 @@ def stop_node(node, i):
node.stop()
except http.client.CannotSendRequest as e:
print("WARN: Unable to stop node: " + repr(e))
- bitcoind_processes[i].wait()
+ bitcoind_processes[i].wait(timeout=BITCOIND_PROC_WAIT_TIMEOUT)
del bitcoind_processes[i]
def stop_nodes(nodes):
@@ -339,7 +352,7 @@ def set_node_times(nodes, t):
def wait_bitcoinds():
# Wait for all bitcoinds to cleanly exit
for bitcoind in bitcoind_processes.values():
- bitcoind.wait()
+ bitcoind.wait(timeout=BITCOIND_PROC_WAIT_TIMEOUT)
bitcoind_processes.clear()
def connect_nodes(from_connection, node_num):
diff --git a/qa/rpc-tests/txn_clone.py b/qa/rpc-tests/txn_clone.py
index 5710c29aa6..22f850ece6 100755
--- a/qa/rpc-tests/txn_clone.py
+++ b/qa/rpc-tests/txn_clone.py
@@ -12,6 +12,11 @@ from test_framework.util import *
class TxnMallTest(BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 4
+ self.setup_clean_chain = False
+
def add_options(self, parser):
parser.add_option("--mineblock", dest="mine_block", default=False, action="store_true",
help="Test double-spend of 1-confirmed transaction")
diff --git a/qa/rpc-tests/txn_doublespend.py b/qa/rpc-tests/txn_doublespend.py
index 1fbb207e22..84944c3c19 100755
--- a/qa/rpc-tests/txn_doublespend.py
+++ b/qa/rpc-tests/txn_doublespend.py
@@ -12,6 +12,11 @@ from test_framework.util import *
class TxnMallTest(BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 4
+ self.setup_clean_chain = False
+
def add_options(self, parser):
parser.add_option("--mineblock", dest="mine_block", default=False, action="store_true",
help="Test double-spend of 1-confirmed transaction")
diff --git a/qa/rpc-tests/wallet.py b/qa/rpc-tests/wallet.py
index 42ce0a7260..9dda712f4f 100755
--- a/qa/rpc-tests/wallet.py
+++ b/qa/rpc-tests/wallet.py
@@ -19,9 +19,10 @@ class WalletTest (BitcoinTestFramework):
raise AssertionError("Fee of %s BTC too high! (Should be %s BTC)"%(str(fee), str(target_fee)))
return curr_balance
- def setup_chain(self):
- print("Initializing test directory "+self.options.tmpdir)
- initialize_chain_clean(self.options.tmpdir, 4)
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 4
def setup_network(self, split=False):
self.nodes = start_nodes(3, self.options.tmpdir)
@@ -306,7 +307,7 @@ class WalletTest (BitcoinTestFramework):
# Check that the txid and balance is found by node1
self.nodes[1].gettransaction(cbTxId)
- #check if wallet or blochchain maintenance changes the balance
+ # check if wallet or blockchain maintenance changes the balance
self.sync_all()
blocks = self.nodes[0].generate(2)
self.sync_all()
@@ -318,7 +319,8 @@ class WalletTest (BitcoinTestFramework):
'-reindex',
'-zapwallettxes=1',
'-zapwallettxes=2',
- '-salvagewallet',
+ # disabled until issue is fixed: https://github.com/bitcoin/bitcoin/issues/7463
+ # '-salvagewallet',
]
for m in maintenance:
print("check " + m)
@@ -338,4 +340,4 @@ class WalletTest (BitcoinTestFramework):
assert_equal(len(self.nodes[0].listsinceblock(blocks[1])["transactions"]), 0)
if __name__ == '__main__':
- WalletTest ().main ()
+ WalletTest().main()
diff --git a/qa/rpc-tests/walletbackup.py b/qa/rpc-tests/walletbackup.py
index c3d53669c9..b991d5c761 100755
--- a/qa/rpc-tests/walletbackup.py
+++ b/qa/rpc-tests/walletbackup.py
@@ -41,15 +41,16 @@ logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO, str
class WalletBackupTest(BitcoinTestFramework):
- def setup_chain(self):
- logging.info("Initializing test directory "+self.options.tmpdir)
- initialize_chain_clean(self.options.tmpdir, 4)
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 4
# This mirrors how the network was setup in the bash test
def setup_network(self, split=False):
# nodes 1, 2,3 are spenders, let's give them a keypool=100
extra_args = [["-keypool=100"], ["-keypool=100"], ["-keypool=100"], []]
- self.nodes = start_nodes(4, self.options.tmpdir, extra_args)
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, extra_args)
connect_nodes(self.nodes[0], 3)
connect_nodes(self.nodes[1], 3)
connect_nodes(self.nodes[2], 3)
diff --git a/qa/rpc-tests/zapwallettxes.py b/qa/rpc-tests/zapwallettxes.py
index 2f8214f87c..17ba53a844 100755
--- a/qa/rpc-tests/zapwallettxes.py
+++ b/qa/rpc-tests/zapwallettxes.py
@@ -9,12 +9,13 @@ from test_framework.util import *
class ZapWalletTXesTest (BitcoinTestFramework):
- def setup_chain(self):
- print("Initializing test directory "+self.options.tmpdir)
- initialize_chain_clean(self.options.tmpdir, 3)
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 3
def setup_network(self, split=False):
- self.nodes = start_nodes(3, self.options.tmpdir)
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
connect_nodes_bi(self.nodes,0,1)
connect_nodes_bi(self.nodes,1,2)
connect_nodes_bi(self.nodes,0,2)
diff --git a/qa/rpc-tests/zmq_test.py b/qa/rpc-tests/zmq_test.py
index f5617a084d..3a116317fe 100755
--- a/qa/rpc-tests/zmq_test.py
+++ b/qa/rpc-tests/zmq_test.py
@@ -17,6 +17,10 @@ import urllib.parse
class ZMQTest (BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 4
+
port = 28332
def setup_nodes(self):
@@ -25,7 +29,7 @@ class ZMQTest (BitcoinTestFramework):
self.zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"hashblock")
self.zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"hashtx")
self.zmqSubSocket.connect("tcp://127.0.0.1:%i" % self.port)
- return start_nodes(4, self.options.tmpdir, extra_args=[
+ return start_nodes(self.num_nodes, self.options.tmpdir, extra_args=[
['-zmqpubhashtx=tcp://127.0.0.1:'+str(self.port), '-zmqpubhashblock=tcp://127.0.0.1:'+str(self.port)],
[],
[],
diff --git a/share/qt/extract_strings_qt.py b/share/qt/extract_strings_qt.py
index 7728a43775..2ba8bb9b3a 100755
--- a/share/qt/extract_strings_qt.py
+++ b/share/qt/extract_strings_qt.py
@@ -32,7 +32,7 @@ def parse_po(text):
in_msgstr = False
# message start
in_msgid = True
-
+
msgid = [line[6:]]
elif line.startswith('msgstr '):
in_msgid = False
@@ -67,7 +67,7 @@ f.write("""
#include <QtGlobal>
-// Automatically generated by extract_strings.py
+// Automatically generated by extract_strings_qt.py
#ifdef __GNUC__
#define UNUSED __attribute__((unused))
#else
diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include
index 24e2b3e0c8..65fd24e051 100644
--- a/src/Makefile.bench.include
+++ b/src/Makefile.bench.include
@@ -8,7 +8,8 @@ bench_bench_bitcoin_SOURCES = \
bench/bench.cpp \
bench/bench.h \
bench/Examples.cpp \
- bench/rollingbloom.cpp
+ bench/rollingbloom.cpp \
+ bench/crypto_hash.cpp
bench_bench_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(EVENT_CLFAGS) $(EVENT_PTHREADS_CFLAGS) -I$(builddir)/bench/
bench_bench_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 08e2f6af4d..897a7dd4a2 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -59,6 +59,7 @@ BITCOIN_TESTS =\
test/merkle_tests.cpp \
test/miner_tests.cpp \
test/multisig_tests.cpp \
+ test/net_tests.cpp \
test/netbase_tests.cpp \
test/pmt_tests.cpp \
test/policyestimator_tests.cpp \
diff --git a/src/addrman.h b/src/addrman.h
index 4f3de8d7c5..3085450450 100644
--- a/src/addrman.h
+++ b/src/addrman.h
@@ -350,6 +350,14 @@ public:
nUBuckets ^= (1 << 30);
}
+ if (nNew > ADDRMAN_NEW_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE) {
+ throw std::ios_base::failure("Corrupt CAddrMan serialization, nNew exceeds limit.");
+ }
+
+ if (nTried > ADDRMAN_TRIED_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE) {
+ throw std::ios_base::failure("Corrupt CAddrMan serialization, nTried exceeds limit.");
+ }
+
// Deserialize entries from the new table.
for (int n = 0; n < nNew; n++) {
CAddrInfo &info = mapInfo[n];
diff --git a/src/bench/crypto_hash.cpp b/src/bench/crypto_hash.cpp
new file mode 100644
index 0000000000..6b753f6308
--- /dev/null
+++ b/src/bench/crypto_hash.cpp
@@ -0,0 +1,53 @@
+// Copyright (c) 2016 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <iostream>
+
+#include "bench.h"
+#include "bloom.h"
+#include "utiltime.h"
+#include "crypto/ripemd160.h"
+#include "crypto/sha1.h"
+#include "crypto/sha256.h"
+#include "crypto/sha512.h"
+
+/* Number of bytes to hash per iteration */
+static const uint64_t BUFFER_SIZE = 1000*1000;
+
+static void RIPEMD160(benchmark::State& state)
+{
+ uint8_t hash[CRIPEMD160::OUTPUT_SIZE];
+ std::vector<uint8_t> in(BUFFER_SIZE,0);
+ while (state.KeepRunning())
+ CRIPEMD160().Write(begin_ptr(in), in.size()).Finalize(hash);
+}
+
+static void SHA1(benchmark::State& state)
+{
+ uint8_t hash[CSHA1::OUTPUT_SIZE];
+ std::vector<uint8_t> in(BUFFER_SIZE,0);
+ while (state.KeepRunning())
+ CSHA1().Write(begin_ptr(in), in.size()).Finalize(hash);
+}
+
+static void SHA256(benchmark::State& state)
+{
+ uint8_t hash[CSHA256::OUTPUT_SIZE];
+ std::vector<uint8_t> in(BUFFER_SIZE,0);
+ while (state.KeepRunning())
+ CSHA256().Write(begin_ptr(in), in.size()).Finalize(hash);
+}
+
+static void SHA512(benchmark::State& state)
+{
+ uint8_t hash[CSHA512::OUTPUT_SIZE];
+ std::vector<uint8_t> in(BUFFER_SIZE,0);
+ while (state.KeepRunning())
+ CSHA512().Write(begin_ptr(in), in.size()).Finalize(hash);
+}
+
+BENCHMARK(RIPEMD160);
+BENCHMARK(SHA1);
+BENCHMARK(SHA256);
+BENCHMARK(SHA512);
diff --git a/src/coins.cpp b/src/coins.cpp
index 1c329740b4..b7dd293d69 100644
--- a/src/coins.cpp
+++ b/src/coins.cpp
@@ -56,7 +56,11 @@ void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; }
bool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return base->BatchWrite(mapCoins, hashBlock); }
CCoinsViewCursor *CCoinsViewBacked::Cursor() const { return base->Cursor(); }
-CCoinsKeyHasher::CCoinsKeyHasher() : salt(GetRandHash()) {}
+SaltedTxidHasher::SaltedTxidHasher()
+{
+ GetRandBytes((unsigned char*)&k0, sizeof(k0));
+ GetRandBytes((unsigned char*)&k1, sizeof(k1));
+}
CCoinsViewCache::CCoinsViewCache(CCoinsView *baseIn) : CCoinsViewBacked(baseIn), hasModifier(false), cachedCoinsUsage(0) { }
diff --git a/src/coins.h b/src/coins.h
index d72f885473..1dd908700b 100644
--- a/src/coins.h
+++ b/src/coins.h
@@ -8,6 +8,7 @@
#include "compressor.h"
#include "core_memusage.h"
+#include "hash.h"
#include "memusage.h"
#include "serialize.h"
#include "uint256.h"
@@ -264,21 +265,22 @@ public:
}
};
-class CCoinsKeyHasher
+class SaltedTxidHasher
{
private:
- uint256 salt;
+ /** Salt */
+ uint64_t k0, k1;
public:
- CCoinsKeyHasher();
+ SaltedTxidHasher();
/**
* This *must* return size_t. With Boost 1.46 on 32-bit systems the
* unordered_map will behave unpredictably if the custom hasher returns a
* uint64_t, resulting in failures when syncing the chain (#4634).
*/
- size_t operator()(const uint256& key) const {
- return key.GetHash(salt);
+ size_t operator()(const uint256& txid) const {
+ return SipHashUint256(k0, k1, txid);
}
};
@@ -295,7 +297,7 @@ struct CCoinsCacheEntry
CCoinsCacheEntry() : coins(), flags(0) {}
};
-typedef boost::unordered_map<uint256, CCoinsCacheEntry, CCoinsKeyHasher> CCoinsMap;
+typedef boost::unordered_map<uint256, CCoinsCacheEntry, SaltedTxidHasher> CCoinsMap;
/** Cursor for iterating over CoinsView state */
class CCoinsViewCursor
diff --git a/src/hash.cpp b/src/hash.cpp
index 7f3cf1a1fa..a518314a53 100644
--- a/src/hash.cpp
+++ b/src/hash.cpp
@@ -81,3 +81,97 @@ void BIP32Hash(const ChainCode &chainCode, unsigned int nChild, unsigned char he
num[3] = (nChild >> 0) & 0xFF;
CHMAC_SHA512(chainCode.begin(), chainCode.size()).Write(&header, 1).Write(data, 32).Write(num, 4).Finalize(output);
}
+
+#define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b))))
+
+#define SIPROUND do { \
+ v0 += v1; v1 = ROTL(v1, 13); v1 ^= v0; \
+ v0 = ROTL(v0, 32); \
+ v2 += v3; v3 = ROTL(v3, 16); v3 ^= v2; \
+ v0 += v3; v3 = ROTL(v3, 21); v3 ^= v0; \
+ v2 += v1; v1 = ROTL(v1, 17); v1 ^= v2; \
+ v2 = ROTL(v2, 32); \
+} while (0)
+
+CSipHasher::CSipHasher(uint64_t k0, uint64_t k1)
+{
+ v[0] = 0x736f6d6570736575ULL ^ k0;
+ v[1] = 0x646f72616e646f6dULL ^ k1;
+ v[2] = 0x6c7967656e657261ULL ^ k0;
+ v[3] = 0x7465646279746573ULL ^ k1;
+ count = 0;
+}
+
+CSipHasher& CSipHasher::Write(uint64_t data)
+{
+ uint64_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3];
+
+ v3 ^= data;
+ SIPROUND;
+ SIPROUND;
+ v0 ^= data;
+
+ v[0] = v0;
+ v[1] = v1;
+ v[2] = v2;
+ v[3] = v3;
+
+ count++;
+ return *this;
+}
+
+uint64_t CSipHasher::Finalize() const
+{
+ uint64_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3];
+
+ v3 ^= ((uint64_t)count) << 59;
+ SIPROUND;
+ SIPROUND;
+ v0 ^= ((uint64_t)count) << 59;
+ v2 ^= 0xFF;
+ SIPROUND;
+ SIPROUND;
+ SIPROUND;
+ SIPROUND;
+ return v0 ^ v1 ^ v2 ^ v3;
+}
+
+uint64_t SipHashUint256(uint64_t k0, uint64_t k1, const uint256& val)
+{
+ /* Specialized implementation for efficiency */
+ uint64_t d = val.GetUint64(0);
+
+ uint64_t v0 = 0x736f6d6570736575ULL ^ k0;
+ uint64_t v1 = 0x646f72616e646f6dULL ^ k1;
+ uint64_t v2 = 0x6c7967656e657261ULL ^ k0;
+ uint64_t v3 = 0x7465646279746573ULL ^ k1 ^ d;
+
+ SIPROUND;
+ SIPROUND;
+ v0 ^= d;
+ d = val.GetUint64(1);
+ v3 ^= d;
+ SIPROUND;
+ SIPROUND;
+ v0 ^= d;
+ d = val.GetUint64(2);
+ v3 ^= d;
+ SIPROUND;
+ SIPROUND;
+ v0 ^= d;
+ d = val.GetUint64(3);
+ v3 ^= d;
+ SIPROUND;
+ SIPROUND;
+ v0 ^= d;
+ v3 ^= ((uint64_t)4) << 59;
+ SIPROUND;
+ SIPROUND;
+ v0 ^= ((uint64_t)4) << 59;
+ v2 ^= 0xFF;
+ SIPROUND;
+ SIPROUND;
+ SIPROUND;
+ SIPROUND;
+ return v0 ^ v1 ^ v2 ^ v3;
+}
diff --git a/src/hash.h b/src/hash.h
index 97955c8d5a..600dabec56 100644
--- a/src/hash.h
+++ b/src/hash.h
@@ -171,4 +171,19 @@ unsigned int MurmurHash3(unsigned int nHashSeed, const std::vector<unsigned char
void BIP32Hash(const ChainCode &chainCode, unsigned int nChild, unsigned char header, const unsigned char data[32], unsigned char output[64]);
+/** SipHash-2-4, using a uint64_t-based (rather than byte-based) interface */
+class CSipHasher
+{
+private:
+ uint64_t v[4];
+ int count;
+
+public:
+ CSipHasher(uint64_t k0, uint64_t k1);
+ CSipHasher& Write(uint64_t data);
+ uint64_t Finalize() const;
+};
+
+uint64_t SipHashUint256(uint64_t k0, uint64_t k1, const uint256& val);
+
#endif // BITCOIN_HASH_H
diff --git a/src/init.cpp b/src/init.cpp
index b06f448a00..a6d14996bd 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -37,9 +37,7 @@
#include "utilmoneystr.h"
#include "validationinterface.h"
#ifdef ENABLE_WALLET
-#include "wallet/db.h"
#include "wallet/wallet.h"
-#include "wallet/walletdb.h"
#endif
#include <stdint.h>
#include <stdio.h>
@@ -125,7 +123,7 @@ static const char* FEE_ESTIMATES_FILENAME="fee_estimates.dat";
// shutdown thing.
//
-volatile bool fRequestShutdown = false;
+volatile sig_atomic_t fRequestShutdown = false;
void StartShutdown()
{
@@ -329,7 +327,8 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-prune=<n>", strprintf(_("Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. "
"Warning: Reverting this setting requires re-downloading the entire blockchain. "
"(default: 0 = disable pruning blocks, >%u = target size in MiB to use for block files)"), MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024));
- strUsage += HelpMessageOpt("-reindex", _("Rebuild block chain index from current blk000??.dat files on startup"));
+ strUsage += HelpMessageOpt("-reindex-chainstate", _("Rebuild chain state from the currently indexed blocks"));
+ strUsage += HelpMessageOpt("-reindex", _("Rebuild chain state and block index from the blk*.dat files on disk"));
#ifndef WIN32
strUsage += HelpMessageOpt("-sysperms", _("Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality)"));
#endif
@@ -406,7 +405,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-limitdescendantcount=<n>", strprintf("Do not accept transactions if any ancestor would have <n> or more in-mempool descendants (default: %u)", DEFAULT_DESCENDANT_LIMIT));
strUsage += HelpMessageOpt("-limitdescendantsize=<n>", strprintf("Do not accept transactions if any ancestor would have more than <n> kilobytes of in-mempool descendants (default: %u).", DEFAULT_DESCENDANT_SIZE_LIMIT));
}
- string debugCategories = "addrman, alert, bench, coindb, db, lock, rand, rpc, selectcoins, mempool, mempoolrej, net, proxy, prune, http, libevent, tor, zmq"; // Don't translate these and qt below
+ string debugCategories = "addrman, alert, bench, coindb, db, http, libevent, lock, mempool, mempoolrej, net, proxy, prune, rand, reindex, rpc, selectcoins, tor, zmq"; // Don't translate these and qt below
if (mode == HMM_BITCOIN_QT)
debugCategories += ", qt";
strUsage += HelpMessageOpt("-debug=<category>", strprintf(_("Output debugging information (default: %u, supplying <category> is optional)"), 0) + ". " +
@@ -556,9 +555,10 @@ void ThreadImport(std::vector<boost::filesystem::path> vImportFiles)
{
const CChainParams& chainparams = Params();
RenameThread("bitcoin-loadblk");
+ CImportingNow imp;
+
// -reindex
if (fReindex) {
- CImportingNow imp;
int nFile = 0;
while (true) {
CDiskBlockPos pos(nFile, 0);
@@ -583,7 +583,6 @@ void ThreadImport(std::vector<boost::filesystem::path> vImportFiles)
if (boost::filesystem::exists(pathBootstrap)) {
FILE *file = fopen(pathBootstrap.string().c_str(), "rb");
if (file) {
- CImportingNow imp;
boost::filesystem::path pathBootstrapOld = GetDataDir() / "bootstrap.dat.old";
LogPrintf("Importing bootstrap.dat...\n");
LoadExternalBlockFile(chainparams, file);
@@ -597,7 +596,6 @@ void ThreadImport(std::vector<boost::filesystem::path> vImportFiles)
BOOST_FOREACH(const boost::filesystem::path& path, vImportFiles) {
FILE *file = fopen(path.string().c_str(), "rb");
if (file) {
- CImportingNow imp;
LogPrintf("Importing blocks file %s...\n", path.string());
LoadExternalBlockFile(chainparams, file);
} else {
@@ -605,6 +603,13 @@ void ThreadImport(std::vector<boost::filesystem::path> vImportFiles)
}
}
+ // scan for better chains in the block chain database, that are not yet connected in the active best chain
+ CValidationState state;
+ if (!ActivateBestChain(state, chainparams)) {
+ LogPrintf("Failed to connect best block");
+ StartShutdown();
+ }
+
if (GetBoolArg("-stopafterblockimport", DEFAULT_STOPAFTERBLOCKIMPORT)) {
LogPrintf("Stopping after block import\n");
StartShutdown();
@@ -986,9 +991,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
if (fPrintToDebugLog)
OpenDebugLog();
-#ifdef ENABLE_WALLET
- LogPrintf("Using BerkeleyDB version %s\n", DbEnv::version(0, 0, 0));
-#endif
if (!fLogTimestamps)
LogPrintf("Startup time: %s\n", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime()));
LogPrintf("Default data directory %s\n", GetDefaultDataDir().string());
@@ -1163,6 +1165,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
// ********************************************************* Step 7: load block chain
fReindex = GetBoolArg("-reindex", false);
+ bool fReindexChainState = GetBoolArg("-reindex-chainstate", false);
// Upgrading to 0.8; hard-link the old blknnnn.dat files into /blocks/
boost::filesystem::path blocksDir = GetDataDir() / "blocks";
@@ -1224,7 +1227,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
delete pblocktree;
pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReindex);
- pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex);
+ pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex || fReindexChainState);
pcoinscatcher = new CCoinsViewErrorCatcher(pcoinsdbview);
pcoinsTip = new CCoinsViewCache(pcoinscatcher);
@@ -1253,7 +1256,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
// Check for changed -txindex state
if (fTxIndex != GetBoolArg("-txindex", DEFAULT_TXINDEX)) {
- strLoadError = _("You need to rebuild the database using -reindex to change -txindex");
+ strLoadError = _("You need to rebuild the database using -reindex-chainstate to change -txindex");
break;
}
@@ -1266,8 +1269,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
uiInterface.InitMessage(_("Verifying blocks..."));
if (fHavePruned && GetArg("-checkblocks", DEFAULT_CHECKBLOCKS) > MIN_BLOCKS_TO_KEEP) {
- LogPrintf("Prune: pruned datadir may not have more than %d blocks; -checkblocks=%d may fail\n",
- MIN_BLOCKS_TO_KEEP, GetArg("-checkblocks", DEFAULT_CHECKBLOCKS));
+ LogPrintf("Prune: pruned datadir may not have more than %d blocks; only checking available blocks",
+ MIN_BLOCKS_TO_KEEP);
}
{
@@ -1363,12 +1366,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
if (mapArgs.count("-blocknotify"))
uiInterface.NotifyBlockTip.connect(BlockNotifyCallback);
- uiInterface.InitMessage(_("Activating best chain..."));
- // scan for better chains in the block chain database, that are not yet connected in the active best chain
- CValidationState state;
- if (!ActivateBestChain(state, chainparams))
- strErrors << "Failed to connect best block";
-
std::vector<boost::filesystem::path> vImportFiles;
if (mapArgs.count("-loadblock"))
{
@@ -1376,10 +1373,18 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
vImportFiles.push_back(strFile);
}
threadGroup.create_thread(boost::bind(&ThreadImport, vImportFiles));
- if (chainActive.Tip() == NULL) {
- LogPrintf("Waiting for genesis block to be imported...\n");
- while (!fRequestShutdown && chainActive.Tip() == NULL)
+
+ // Wait for genesis block to be processed
+ bool fHaveGenesis = false;
+ while (!fHaveGenesis && !fRequestShutdown) {
+ {
+ LOCK(cs_main);
+ fHaveGenesis = (chainActive.Tip() != NULL);
+ }
+
+ if (!fHaveGenesis) {
MilliSleep(10);
+ }
}
// ********************************************************* Step 11: start node
diff --git a/src/main.cpp b/src/main.cpp
index ebe91f7fa9..9a2ff8c2bb 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -40,6 +40,7 @@
#include <sstream>
#include <boost/algorithm/string/replace.hpp>
+#include <boost/algorithm/string/join.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/math/distributions/poisson.hpp>
@@ -1005,7 +1006,7 @@ std::string FormatStateMessage(const CValidationState &state)
}
bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const CTransaction& tx, bool fLimitFree,
- bool* pfMissingInputs, CFeeRate* txFeeRate, bool fOverrideMempoolLimit, const CAmount& nAbsurdFee,
+ bool* pfMissingInputs, bool fOverrideMempoolLimit, const CAmount& nAbsurdFee,
std::vector<uint256>& vHashTxnToUncache)
{
const uint256 hash = tx.GetHash();
@@ -1170,9 +1171,6 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), pool.HasNoInputsOf(tx), inChainInputValue, fSpendsCoinbase, nSigOps, lp);
unsigned int nSize = entry.GetTxSize();
- if (txFeeRate) {
- *txFeeRate = CFeeRate(nFees, nSize);
- }
// Check that the transaction doesn't have an excessive number of
// sigops, making it impossible to mine. Since the coinbase transaction
@@ -1421,10 +1419,10 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
}
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,
- bool* pfMissingInputs, CFeeRate* txFeeRate, bool fOverrideMempoolLimit, const CAmount nAbsurdFee)
+ bool* pfMissingInputs, bool fOverrideMempoolLimit, const CAmount nAbsurdFee)
{
std::vector<uint256> vHashTxToUncache;
- bool res = AcceptToMemoryPoolWorker(pool, state, tx, fLimitFree, pfMissingInputs, txFeeRate, fOverrideMempoolLimit, nAbsurdFee, vHashTxToUncache);
+ bool res = AcceptToMemoryPoolWorker(pool, state, tx, fLimitFree, pfMissingInputs, fOverrideMempoolLimit, nAbsurdFee, vHashTxToUncache);
if (!res) {
BOOST_FOREACH(const uint256& hashTx, vHashTxToUncache)
pcoinsTip->Uncache(hashTx);
@@ -2574,16 +2572,10 @@ void static UpdateTip(CBlockIndex *pindexNew, const CChainParams& chainParams) {
nTimeBestReceived = GetTime();
mempool.AddTransactionsUpdated(1);
- LogPrintf("%s: new best=%s height=%d version=0x%08x log2_work=%.8g tx=%lu date='%s' progress=%f cache=%.1fMiB(%utx)\n", __func__,
- chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), chainActive.Tip()->nVersion,
- log(chainActive.Tip()->nChainWork.getdouble())/log(2.0), (unsigned long)chainActive.Tip()->nChainTx,
- DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()),
- Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), chainActive.Tip()), pcoinsTip->DynamicMemoryUsage() * (1.0 / (1<<20)), pcoinsTip->GetCacheSize());
-
cvBlockChange.notify_all();
- // Check the version of the last 100 blocks to see if we need to upgrade:
static bool fWarned = false;
+ std::vector<std::string> warningMessages;
if (!IsInitialBlockDownload())
{
int nUpgraded = 0;
@@ -2599,10 +2591,11 @@ void static UpdateTip(CBlockIndex *pindexNew, const CChainParams& chainParams) {
fWarned = true;
}
} else {
- LogPrintf("%s: unknown new rules are about to activate (versionbit %i)\n", __func__, bit);
+ warningMessages.push_back(strprintf("unknown new rules are about to activate (versionbit %i)", bit));
}
}
}
+ // Check the version of the last 100 blocks to see if we need to upgrade:
for (int i = 0; i < 100 && pindex != NULL; i++)
{
int32_t nExpectedVersion = ComputeBlockVersion(pindex->pprev, chainParams.GetConsensus());
@@ -2611,7 +2604,7 @@ void static UpdateTip(CBlockIndex *pindexNew, const CChainParams& chainParams) {
pindex = pindex->pprev;
}
if (nUpgraded > 0)
- LogPrintf("%s: %d of last 100 blocks have unexpected version\n", __func__, nUpgraded);
+ warningMessages.push_back(strprintf("%d of last 100 blocks have unexpected version", nUpgraded));
if (nUpgraded > 100/2)
{
// strMiscWarning is read by GetWarnings(), called by Qt and the JSON-RPC code to warn the user:
@@ -2622,6 +2615,15 @@ void static UpdateTip(CBlockIndex *pindexNew, const CChainParams& chainParams) {
}
}
}
+ LogPrintf("%s: new best=%s height=%d version=0x%08x log2_work=%.8g tx=%lu date='%s' progress=%f cache=%.1fMiB(%utx)", __func__,
+ chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), chainActive.Tip()->nVersion,
+ log(chainActive.Tip()->nChainWork.getdouble())/log(2.0), (unsigned long)chainActive.Tip()->nChainTx,
+ DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()),
+ Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), chainActive.Tip()), pcoinsTip->DynamicMemoryUsage() * (1.0 / (1<<20)), pcoinsTip->GetCacheSize());
+ if (!warningMessages.empty())
+ LogPrintf(" warning='%s'", boost::algorithm::join(warningMessages, ", "));
+ LogPrintf("\n");
+
}
/** Disconnect chainActive's tip. You probably want to call mempool.removeForReorg and manually re-limit mempool size after this, with cs_main held. */
@@ -2651,7 +2653,7 @@ bool static DisconnectTip(CValidationState& state, const CChainParams& chainpara
// ignore validation errors in resurrected transactions
list<CTransaction> removed;
CValidationState stateDummy;
- if (tx.IsCoinBase() || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL, NULL, true)) {
+ if (tx.IsCoinBase() || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL, true)) {
mempool.removeRecursive(tx, removed);
} else if (mempool.exists(tx.GetHash())) {
vHashUpdate.push_back(tx.GetHash());
@@ -2814,10 +2816,9 @@ static void PruneBlockIndexCandidates() {
* Try to make some progress towards making pindexMostWork the active block.
* pblock is either NULL or a pointer to a CBlock corresponding to pindexMostWork.
*/
-static bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const CBlock* pblock)
+static bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const CBlock* pblock, bool& fInvalidFound)
{
AssertLockHeld(cs_main);
- bool fInvalidFound = false;
const CBlockIndex *pindexOldTip = chainActive.Tip();
const CBlockIndex *pindexFork = chainActive.FindFork(pindexMostWork);
@@ -2887,6 +2888,28 @@ static bool ActivateBestChainStep(CValidationState& state, const CChainParams& c
return true;
}
+static void NotifyHeaderTip() {
+ bool fNotify = false;
+ bool fInitialBlockDownload = false;
+ static CBlockIndex* pindexHeaderOld = NULL;
+ CBlockIndex* pindexHeader = NULL;
+ {
+ LOCK(cs_main);
+ if (!setBlockIndexCandidates.empty()) {
+ pindexHeader = *setBlockIndexCandidates.rbegin();
+ }
+ if (pindexHeader != pindexHeaderOld) {
+ fNotify = true;
+ fInitialBlockDownload = IsInitialBlockDownload();
+ pindexHeaderOld = pindexHeader;
+ }
+ }
+ // Send block tip changed notifications without cs_main
+ if (fNotify) {
+ uiInterface.NotifyHeaderTip(fInitialBlockDownload, pindexHeader);
+ }
+}
+
/**
* Make the best chain active, in multiple steps. The result is either failure
* or an activated best chain. pblock is either NULL or a pointer to a block
@@ -2905,15 +2928,22 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
{
LOCK(cs_main);
CBlockIndex *pindexOldTip = chainActive.Tip();
- pindexMostWork = FindMostWorkChain();
+ if (pindexMostWork == NULL) {
+ pindexMostWork = FindMostWorkChain();
+ }
// Whether we have anything to do at all.
if (pindexMostWork == NULL || pindexMostWork == chainActive.Tip())
return true;
- if (!ActivateBestChainStep(state, chainparams, pindexMostWork, pblock && pblock->GetHash() == pindexMostWork->GetBlockHash() ? pblock : NULL))
+ bool fInvalidFound = false;
+ if (!ActivateBestChainStep(state, chainparams, pindexMostWork, pblock && pblock->GetHash() == pindexMostWork->GetBlockHash() ? pblock : NULL, fInvalidFound))
return false;
+ if (fInvalidFound) {
+ // Wipe cache, we may need another branch now.
+ pindexMostWork = NULL;
+ }
pindexNewTip = chainActive.Tip();
pindexFork = chainActive.FindFork(pindexOldTip);
fInitialDownload = IsInitialBlockDownload();
@@ -3008,7 +3038,7 @@ bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, C
return true;
}
-bool ReconsiderBlock(CValidationState& state, CBlockIndex *pindex) {
+bool ResetBlockFailureFlags(CBlockIndex *pindex) {
AssertLockHeld(cs_main);
int nHeight = pindex->nHeight;
@@ -3401,11 +3431,12 @@ static bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state
}
/** Store block on disk. If dbp is non-NULL, the file is known to already reside on disk */
-static bool AcceptBlock(const CBlock& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, CDiskBlockPos* dbp)
+static bool AcceptBlock(const CBlock& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const CDiskBlockPos* dbp)
{
AssertLockHeld(cs_main);
- CBlockIndex *&pindex = *ppindex;
+ CBlockIndex *pindexDummy = NULL;
+ CBlockIndex *&pindex = ppindex ? *ppindex : pindexDummy;
if (!AcceptBlockHeader(block, state, chainparams, &pindex))
return false;
@@ -3477,7 +3508,7 @@ static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned
}
-bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, const CNode* pfrom, const CBlock* pblock, bool fForceProcessing, CDiskBlockPos* dbp)
+bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, const CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp)
{
{
LOCK(cs_main);
@@ -3495,6 +3526,8 @@ bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, c
return error("%s: AcceptBlock FAILED", __func__);
}
+ NotifyHeaderTip();
+
if (!ActivateBestChain(state, chainparams, pblock))
return error("%s: ActivateBestChain failed", __func__);
@@ -3843,6 +3876,11 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
uiInterface.ShowProgress(_("Verifying blocks..."), std::max(1, std::min(99, (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * (nCheckLevel >= 4 ? 50 : 100)))));
if (pindex->nHeight < chainActive.Height()-nCheckDepth)
break;
+ if (fPruneMode && !(pindex->nStatus & BLOCK_HAVE_DATA)) {
+ // If pruning, only go back as far as we have data.
+ LogPrintf("VerifyDB(): block verification stopping at height %d (pruning, no data)\n", pindex->nHeight);
+ break;
+ }
CBlock block;
// check level 0: read from disk
if (!ReadBlockFromDisk(block, pindex, chainparams.GetConsensus()))
@@ -4040,15 +4078,26 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB
// process in case the block isn't known yet
if (mapBlockIndex.count(hash) == 0 || (mapBlockIndex[hash]->nStatus & BLOCK_HAVE_DATA) == 0) {
+ LOCK(cs_main);
CValidationState state;
- if (ProcessNewBlock(state, chainparams, NULL, &block, true, dbp))
+ if (AcceptBlock(block, state, chainparams, NULL, true, dbp))
nLoaded++;
if (state.IsError())
break;
} else if (hash != chainparams.GetConsensus().hashGenesisBlock && mapBlockIndex[hash]->nHeight % 1000 == 0) {
- LogPrintf("Block Import: already had block %s at height %d\n", hash.ToString(), mapBlockIndex[hash]->nHeight);
+ LogPrint("reindex", "Block Import: already had block %s at height %d\n", hash.ToString(), mapBlockIndex[hash]->nHeight);
}
+ // Activate the genesis block so normal node progress can continue
+ if (hash == chainparams.GetConsensus().hashGenesisBlock) {
+ CValidationState state;
+ if (!ActivateBestChain(state, chainparams)) {
+ break;
+ }
+ }
+
+ NotifyHeaderTip();
+
// Recursively process earlier encountered successors of this block
deque<uint256> queue;
queue.push_back(hash);
@@ -4060,10 +4109,11 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB
std::multimap<uint256, CDiskBlockPos>::iterator it = range.first;
if (ReadBlockFromDisk(block, it->second, chainparams.GetConsensus()))
{
- LogPrintf("%s: Processing out of order child %s of %s\n", __func__, block.GetHash().ToString(),
+ LogPrint("reindex", "%s: Processing out of order child %s of %s\n", __func__, block.GetHash().ToString(),
head.ToString());
+ LOCK(cs_main);
CValidationState dummy;
- if (ProcessNewBlock(dummy, chainparams, NULL, &block, true, &it->second))
+ if (AcceptBlock(block, dummy, chainparams, NULL, true, &it->second))
{
nLoaded++;
queue.push_back(block.GetHash());
@@ -4071,6 +4121,7 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB
}
range.first++;
mapBlocksUnknownParent.erase(it);
+ NotifyHeaderTip();
}
}
} catch (const std::exception& e) {
@@ -4701,25 +4752,23 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
LOCK(cs_vNodes);
// Use deterministic randomness to send to the same nodes for 24 hours
// at a time so the addrKnowns of the chosen nodes prevent repeats
- static uint256 hashSalt;
- if (hashSalt.IsNull())
- hashSalt = GetRandHash();
+ static uint64_t salt0 = 0, salt1 = 0;
+ while (salt0 == 0 && salt1 == 0) {
+ GetRandBytes((unsigned char*)&salt0, sizeof(salt0));
+ GetRandBytes((unsigned char*)&salt1, sizeof(salt1));
+ }
uint64_t hashAddr = addr.GetHash();
- uint256 hashRand = ArithToUint256(UintToArith256(hashSalt) ^ (hashAddr<<32) ^ ((GetTime()+hashAddr)/(24*60*60)));
- hashRand = Hash(BEGIN(hashRand), END(hashRand));
- multimap<uint256, CNode*> mapMix;
+ multimap<uint64_t, CNode*> mapMix;
+ const CSipHasher hasher = CSipHasher(salt0, salt1).Write(hashAddr << 32).Write((GetTime() + hashAddr) / (24*60*60));
BOOST_FOREACH(CNode* pnode, vNodes)
{
if (pnode->nVersion < CADDR_TIME_VERSION)
continue;
- unsigned int nPointer;
- memcpy(&nPointer, &pnode, sizeof(nPointer));
- uint256 hashKey = ArithToUint256(UintToArith256(hashRand) ^ nPointer);
- hashKey = Hash(BEGIN(hashKey), END(hashKey));
+ uint64_t hashKey = CSipHasher(hasher).Write(pnode->id).Finalize();
mapMix.insert(make_pair(hashKey, pnode));
}
int nRelayNodes = fReachable ? 2 : 1; // limited relaying of addresses outside our network(s)
- for (multimap<uint256, CNode*>::iterator mi = mapMix.begin(); mi != mapMix.end() && nRelayNodes-- > 0; ++mi)
+ for (multimap<uint64_t, CNode*>::iterator mi = mapMix.begin(); mi != mapMix.end() && nRelayNodes-- > 0; ++mi)
((*mi).second)->PushAddress(addr);
}
}
@@ -4956,10 +5005,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
pfrom->setAskFor.erase(inv.hash);
mapAlreadyAskedFor.erase(inv.hash);
- CFeeRate txFeeRate = CFeeRate(0);
- if (!AlreadyHave(inv) && AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs, &txFeeRate)) {
+ if (!AlreadyHave(inv) && AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs)) {
mempool.check(pcoinsTip);
- RelayTransaction(tx, txFeeRate);
+ RelayTransaction(tx);
vWorkQueue.push_back(inv.hash);
LogPrint("mempool", "AcceptToMemoryPool: peer=%d: accepted %s (poolsz %u txn, %u kB)\n",
@@ -4990,10 +5038,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (setMisbehaving.count(fromPeer))
continue;
- CFeeRate orphanFeeRate = CFeeRate(0);
- if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2, &orphanFeeRate)) {
+ if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2)) {
LogPrint("mempool", " accepted orphan tx %s\n", orphanHash.ToString());
- RelayTransaction(orphanTx, orphanFeeRate);
+ RelayTransaction(orphanTx);
vWorkQueue.push_back(orphanHash);
vEraseQueue.push_back(orphanHash);
}
@@ -5046,7 +5093,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
int nDoS = 0;
if (!state.IsInvalid(nDoS) || nDoS == 0) {
LogPrintf("Force relaying tx %s from whitelisted peer=%d\n", tx.GetHash().ToString(), pfrom->id);
- RelayTransaction(tx, txFeeRate);
+ RelayTransaction(tx);
} else {
LogPrintf("Not relaying invalid transaction %s from whitelisted peer=%d (%s)\n", tx.GetHash().ToString(), pfrom->id, FormatStateMessage(state));
}
@@ -5084,6 +5131,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
ReadCompactSize(vRecv); // ignore tx count; assume it is 0.
}
+ {
LOCK(cs_main);
if (nCount == 0) {
@@ -5091,6 +5139,13 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
return true;
}
+ // If we already know the last header in the message, then it contains
+ // no new information for us. In this case, we do not request
+ // more headers later. This prevents multiple chains of redundant
+ // getheader requests from running in parallel if triggered by incoming
+ // blocks while the node is still in initial headers sync.
+ const bool hasNewHeaders = (mapBlockIndex.count(headers.back().GetHash()) == 0);
+
CBlockIndex *pindexLast = NULL;
BOOST_FOREACH(const CBlockHeader& header, headers) {
CValidationState state;
@@ -5111,7 +5166,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (pindexLast)
UpdateBlockAvailability(pfrom->GetId(), pindexLast->GetBlockHash());
- if (nCount == MAX_HEADERS_RESULTS && pindexLast) {
+ if (nCount == MAX_HEADERS_RESULTS && pindexLast && hasNewHeaders) {
// Headers message had its maximum size; the peer may have more headers.
// TODO: optimize: if pindexLast is an ancestor of chainActive.Tip or pindexBestHeader, continue
// from there instead.
@@ -5167,6 +5222,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
CheckBlockIndex(chainparams.GetConsensus());
+ }
+
+ NotifyHeaderTip();
}
else if (strCommand == NetMsgType::BLOCK && !fImporting && !fReindex) // Ignore blocks received while importing
diff --git a/src/main.h b/src/main.h
index 3cc16fd8f4..f287171f14 100644
--- a/src/main.h
+++ b/src/main.h
@@ -212,10 +212,10 @@ void UnregisterNodeSignals(CNodeSignals& nodeSignals);
* @param[in] pfrom The node which we are receiving the block from; it is added to mapBlockSource and may be penalised if the block is invalid.
* @param[in] pblock The block we want to process.
* @param[in] fForceProcessing Process this block even if unrequested; used for non-network block sources and whitelisted peers.
- * @param[out] dbp If pblock is stored to disk (or already there), this will be set to its location.
+ * @param[out] dbp The already known disk position of pblock, or NULL if not yet stored.
* @return True if state.IsValid()
*/
-bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, const CNode* pfrom, const CBlock* pblock, bool fForceProcessing, CDiskBlockPos* dbp);
+bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, const CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp);
/** Check whether enough disk space is available for an incoming block */
bool CheckDiskSpace(uint64_t nAdditionalBytes = 0);
/** Open a block file (blk?????.dat) */
@@ -295,7 +295,7 @@ void PruneAndFlush();
/** (try to) add transaction to memory pool **/
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,
- bool* pfMissingInputs, CFeeRate* txFeeRate, bool fOverrideMempoolLimit=false, const CAmount nAbsurdFee=0);
+ bool* pfMissingInputs, bool fOverrideMempoolLimit=false, const CAmount nAbsurdFee=0);
/** Convert CValidationState to a human-readable message for logging */
std::string FormatStateMessage(const CValidationState &state);
@@ -464,7 +464,7 @@ CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& loc
bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex);
/** Remove invalidity status from a block and its descendants. */
-bool ReconsiderBlock(CValidationState& state, CBlockIndex *pindex);
+bool ResetBlockFailureFlags(CBlockIndex *pindex);
/** The currently-connected chain of blocks (protected by cs_main). */
extern CChain chainActive;
diff --git a/src/net.cpp b/src/net.cpp
index 5e810a0f15..bbd23d292a 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -56,7 +56,6 @@
#endif
#endif
-using namespace std;
namespace {
const int MAX_OUTBOUND_CONNECTIONS = 8;
@@ -78,7 +77,7 @@ bool fDiscover = true;
bool fListen = true;
uint64_t nLocalServices = NODE_NETWORK;
CCriticalSection cs_mapLocalHost;
-map<CNetAddr, LocalServiceInfo> mapLocalHost;
+std::map<CNetAddr, LocalServiceInfo> mapLocalHost;
static bool vfLimited[NET_MAX] = {};
static CNode* pnodeLocalHost = NULL;
uint64_t nLocalHostNonce = 0;
@@ -88,20 +87,17 @@ int nMaxConnections = DEFAULT_MAX_PEER_CONNECTIONS;
bool fAddressesInitialized = false;
std::string strSubVersion;
-vector<CNode*> vNodes;
+std::vector<CNode*> vNodes;
CCriticalSection cs_vNodes;
-map<uint256, CTransaction> mapRelay;
-deque<pair<int64_t, uint256> > vRelayExpiration;
+std::map<uint256, CTransaction> mapRelay;
+std::deque<std::pair<int64_t, uint256> > vRelayExpiration;
CCriticalSection cs_mapRelay;
limitedmap<uint256, int64_t> mapAlreadyAskedFor(MAX_INV_SZ);
-static deque<string> vOneShots;
+static std::deque<std::string> vOneShots;
CCriticalSection cs_vOneShots;
-set<CNetAddr> setservAddNodeAddresses;
-CCriticalSection cs_setservAddNodeAddresses;
-
-vector<std::string> vAddedNodes;
+std::vector<std::string> vAddedNodes;
CCriticalSection cs_vAddedNodes;
NodeId nLastNodeId = 0;
@@ -135,7 +131,7 @@ bool GetLocal(CService& addr, const CNetAddr *paddrPeer)
int nBestReachability = -1;
{
LOCK(cs_mapLocalHost);
- for (map<CNetAddr, LocalServiceInfo>::iterator it = mapLocalHost.begin(); it != mapLocalHost.end(); it++)
+ for (std::map<CNetAddr, LocalServiceInfo>::iterator it = mapLocalHost.begin(); it != mapLocalHost.end(); it++)
{
int nScore = (*it).second.nScore;
int nReachability = (*it).first.GetReachabilityFrom(paddrPeer);
@@ -426,6 +422,26 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest)
return NULL;
}
+static void DumpBanlist()
+{
+ CNode::SweepBanned(); // clean unused entries (if bantime has expired)
+
+ if (!CNode::BannedSetIsDirty())
+ return;
+
+ int64_t nStart = GetTimeMillis();
+
+ CBanDB bandb;
+ banmap_t banmap;
+ CNode::SetBannedSetDirty(false);
+ CNode::GetBanned(banmap);
+ if (!bandb.Write(banmap))
+ CNode::SetBannedSetDirty(true);
+
+ LogPrint("net", "Flushed %d banned node ips/subnets to banlist.dat %dms\n",
+ banmap.size(), GetTimeMillis() - nStart);
+}
+
void CNode::CloseSocketDisconnect()
{
fDisconnect = true;
@@ -443,7 +459,7 @@ void CNode::CloseSocketDisconnect()
void CNode::PushVersion()
{
- int nBestHeight = g_signals.GetHeight().get_value_or(0);
+ int nBestHeight = GetNodeSignals().GetHeight().get_value_or(0);
int64_t nTime = (fInbound ? GetAdjustedTime() : GetTime());
CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService("0.0.0.0",0)));
@@ -467,9 +483,13 @@ bool CNode::setBannedIsDirty;
void CNode::ClearBanned()
{
- LOCK(cs_setBanned);
- setBanned.clear();
- setBannedIsDirty = true;
+ {
+ LOCK(cs_setBanned);
+ setBanned.clear();
+ setBannedIsDirty = true;
+ }
+ DumpBanlist(); //store banlist to disk
+ uiInterface.BannedListChanged();
}
bool CNode::IsBanned(CNetAddr ip)
@@ -520,11 +540,25 @@ void CNode::Ban(const CSubNet& subNet, const BanReason &banReason, int64_t banti
}
banEntry.nBanUntil = (sinceUnixEpoch ? 0 : GetTime() )+bantimeoffset;
- LOCK(cs_setBanned);
- if (setBanned[subNet].nBanUntil < banEntry.nBanUntil)
- setBanned[subNet] = banEntry;
-
- setBannedIsDirty = true;
+ {
+ LOCK(cs_setBanned);
+ if (setBanned[subNet].nBanUntil < banEntry.nBanUntil) {
+ setBanned[subNet] = banEntry;
+ setBannedIsDirty = true;
+ }
+ else
+ return;
+ }
+ uiInterface.BannedListChanged();
+ {
+ LOCK(cs_vNodes);
+ BOOST_FOREACH(CNode* pnode, vNodes) {
+ if (subNet.Match((CNetAddr)pnode->addr))
+ pnode->fDisconnect = true;
+ }
+ }
+ if(banReason == BanReasonManuallyAdded)
+ DumpBanlist(); //store banlist to disk immediately if user requested ban
}
bool CNode::Unban(const CNetAddr &addr) {
@@ -533,13 +567,15 @@ bool CNode::Unban(const CNetAddr &addr) {
}
bool CNode::Unban(const CSubNet &subNet) {
- LOCK(cs_setBanned);
- if (setBanned.erase(subNet))
{
+ LOCK(cs_setBanned);
+ if (!setBanned.erase(subNet))
+ return false;
setBannedIsDirty = true;
- return true;
}
- return false;
+ uiInterface.BannedListChanged();
+ DumpBanlist(); //store banlist to disk immediately
+ return true;
}
void CNode::GetBanned(banmap_t &banMap)
@@ -796,53 +832,24 @@ void SocketSendData(CNode *pnode)
pnode->vSendMsg.erase(pnode->vSendMsg.begin(), it);
}
-static list<CNode*> vNodesDisconnected;
-
-class CNodeRef {
-public:
- CNodeRef(CNode *pnode) : _pnode(pnode) {
- LOCK(cs_vNodes);
- _pnode->AddRef();
- }
-
- ~CNodeRef() {
- LOCK(cs_vNodes);
- _pnode->Release();
- }
+static std::list<CNode*> vNodesDisconnected;
- CNode& operator *() const {return *_pnode;};
- CNode* operator ->() const {return _pnode;};
-
- CNodeRef& operator =(const CNodeRef& other)
- {
- if (this != &other) {
- LOCK(cs_vNodes);
-
- _pnode->Release();
- _pnode = other._pnode;
- _pnode->AddRef();
- }
- return *this;
- }
-
- CNodeRef(const CNodeRef& other):
- _pnode(other._pnode)
- {
- LOCK(cs_vNodes);
- _pnode->AddRef();
- }
-private:
- CNode *_pnode;
+struct NodeEvictionCandidate
+{
+ NodeId id;
+ int64_t nTimeConnected;
+ int64_t nMinPingUsecTime;
+ CAddress addr;
};
-static bool ReverseCompareNodeMinPingTime(const CNodeRef &a, const CNodeRef &b)
+static bool ReverseCompareNodeMinPingTime(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b)
{
- return a->nMinPingUsecTime > b->nMinPingUsecTime;
+ return a.nMinPingUsecTime > b.nMinPingUsecTime;
}
-static bool ReverseCompareNodeTimeConnected(const CNodeRef &a, const CNodeRef &b)
+static bool ReverseCompareNodeTimeConnected(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b)
{
- return a->nTimeConnected > b->nTimeConnected;
+ return a.nTimeConnected > b.nTimeConnected;
}
class CompareNetGroupKeyed
@@ -855,14 +862,14 @@ public:
GetRandBytes(vchSecretKey.data(), vchSecretKey.size());
}
- bool operator()(const CNodeRef &a, const CNodeRef &b)
+ bool operator()(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b)
{
std::vector<unsigned char> vchGroupA, vchGroupB;
CSHA256 hashA, hashB;
std::vector<unsigned char> vchA(32), vchB(32);
- vchGroupA = a->addr.GetGroup();
- vchGroupB = b->addr.GetGroup();
+ vchGroupA = a.addr.GetGroup();
+ vchGroupB = b.addr.GetGroup();
hashA.Write(begin_ptr(vchGroupA), vchGroupA.size());
hashB.Write(begin_ptr(vchGroupB), vchGroupB.size());
@@ -886,7 +893,7 @@ public:
* simultaneously better at all of them than honest peers.
*/
static bool AttemptToEvictConnection(bool fPreferNewConnection) {
- std::vector<CNodeRef> vEvictionCandidates;
+ std::vector<NodeEvictionCandidate> vEvictionCandidates;
{
LOCK(cs_vNodes);
@@ -897,7 +904,8 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) {
continue;
if (node->fDisconnect)
continue;
- vEvictionCandidates.push_back(CNodeRef(node));
+ NodeEvictionCandidate candidate = {node->id, node->nTimeConnected, node->nMinPingUsecTime, node->addr};
+ vEvictionCandidates.push_back(candidate);
}
}
@@ -932,16 +940,16 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) {
std::vector<unsigned char> naMostConnections;
unsigned int nMostConnections = 0;
int64_t nMostConnectionsTime = 0;
- std::map<std::vector<unsigned char>, std::vector<CNodeRef> > mapAddrCounts;
- BOOST_FOREACH(const CNodeRef &node, vEvictionCandidates) {
- mapAddrCounts[node->addr.GetGroup()].push_back(node);
- int64_t grouptime = mapAddrCounts[node->addr.GetGroup()][0]->nTimeConnected;
- size_t groupsize = mapAddrCounts[node->addr.GetGroup()].size();
+ std::map<std::vector<unsigned char>, std::vector<NodeEvictionCandidate> > mapAddrCounts;
+ BOOST_FOREACH(const NodeEvictionCandidate &node, vEvictionCandidates) {
+ mapAddrCounts[node.addr.GetGroup()].push_back(node);
+ int64_t grouptime = mapAddrCounts[node.addr.GetGroup()][0].nTimeConnected;
+ size_t groupsize = mapAddrCounts[node.addr.GetGroup()].size();
if (groupsize > nMostConnections || (groupsize == nMostConnections && grouptime > nMostConnectionsTime)) {
nMostConnections = groupsize;
nMostConnectionsTime = grouptime;
- naMostConnections = node->addr.GetGroup();
+ naMostConnections = node.addr.GetGroup();
}
}
@@ -956,9 +964,15 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) {
return false;
// Disconnect from the network group with the most connections
- vEvictionCandidates[0]->fDisconnect = true;
-
- return true;
+ NodeId evicted = vEvictionCandidates.front().id;
+ LOCK(cs_vNodes);
+ for(std::vector<CNode*>::const_iterator it(vNodes.begin()); it != vNodes.end(); ++it) {
+ if ((*it)->GetId() == evicted) {
+ (*it)->fDisconnect = true;
+ return true;
+ }
+ }
+ return false;
}
static void AcceptConnection(const ListenSocket& hListenSocket) {
@@ -1045,7 +1059,7 @@ void ThreadSocketHandler()
{
LOCK(cs_vNodes);
// Disconnect unused nodes
- vector<CNode*> vNodesCopy = vNodes;
+ std::vector<CNode*> vNodesCopy = vNodes;
BOOST_FOREACH(CNode* pnode, vNodesCopy)
{
if (pnode->fDisconnect ||
@@ -1069,7 +1083,7 @@ void ThreadSocketHandler()
}
{
// Delete disconnected nodes
- list<CNode*> vNodesDisconnectedCopy = vNodesDisconnected;
+ std::list<CNode*> vNodesDisconnectedCopy = vNodesDisconnected;
BOOST_FOREACH(CNode* pnode, vNodesDisconnectedCopy)
{
// wait until threads are done using it
@@ -1120,7 +1134,7 @@ void ThreadSocketHandler()
BOOST_FOREACH(const ListenSocket& hListenSocket, vhListenSocket) {
FD_SET(hListenSocket.socket, &fdsetRecv);
- hSocketMax = max(hSocketMax, hListenSocket.socket);
+ hSocketMax = std::max(hSocketMax, hListenSocket.socket);
have_fds = true;
}
@@ -1131,7 +1145,7 @@ void ThreadSocketHandler()
if (pnode->hSocket == INVALID_SOCKET)
continue;
FD_SET(pnode->hSocket, &fdsetError);
- hSocketMax = max(hSocketMax, pnode->hSocket);
+ hSocketMax = std::max(hSocketMax, pnode->hSocket);
have_fds = true;
// Implement the following logic:
@@ -1198,7 +1212,7 @@ void ThreadSocketHandler()
//
// Service each socket
//
- vector<CNode*> vNodesCopy;
+ std::vector<CNode*> vNodesCopy;
{
LOCK(cs_vNodes);
vNodesCopy = vNodes;
@@ -1355,7 +1369,7 @@ void ThreadMapPort()
}
}
- string strDesc = "Bitcoin " + FormatFullVersion();
+ std::string strDesc = "Bitcoin " + FormatFullVersion();
try {
while (true) {
@@ -1441,7 +1455,7 @@ void ThreadDNSAddressSeed()
}
}
- const vector<CDNSSeedData> &vSeeds = Params().DNSSeeds();
+ const std::vector<CDNSSeedData> &vSeeds = Params().DNSSeeds();
int found = 0;
LogPrintf("Loading addresses from DNS seeds (could take a while)\n");
@@ -1450,8 +1464,8 @@ void ThreadDNSAddressSeed()
if (HaveNameProxy()) {
AddOneShot(seed.host);
} else {
- vector<CNetAddr> vIPs;
- vector<CAddress> vAdd;
+ std::vector<CNetAddr> vIPs;
+ std::vector<CAddress> vAdd;
if (LookupHost(seed.host.c_str(), vIPs, 0, true))
{
BOOST_FOREACH(const CNetAddr& ip, vIPs)
@@ -1508,7 +1522,7 @@ void DumpData()
void static ProcessOneShot()
{
- string strDest;
+ std::string strDest;
{
LOCK(cs_vOneShots);
if (vOneShots.empty())
@@ -1574,7 +1588,7 @@ void ThreadOpenConnections()
// Only connect out to one peer per network group (/16 for IPv4).
// Do this here so we don't have to critsect vNodes inside mapAddresses critsect.
int nOutbound = 0;
- set<vector<unsigned char> > setConnected;
+ std::set<std::vector<unsigned char> > setConnected;
{
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes) {
@@ -1632,7 +1646,7 @@ void ThreadOpenAddedConnections()
if (HaveNameProxy()) {
while(true) {
- list<string> lAddresses(0);
+ std::list<std::string> lAddresses(0);
{
LOCK(cs_vAddedNodes);
BOOST_FOREACH(const std::string& strAddNode, vAddedNodes)
@@ -1650,32 +1664,25 @@ void ThreadOpenAddedConnections()
for (unsigned int i = 0; true; i++)
{
- list<string> lAddresses(0);
+ std::list<std::string> lAddresses(0);
{
LOCK(cs_vAddedNodes);
BOOST_FOREACH(const std::string& strAddNode, vAddedNodes)
lAddresses.push_back(strAddNode);
}
- list<vector<CService> > lservAddressesToAdd(0);
+ std::list<std::vector<CService> > lservAddressesToAdd(0);
BOOST_FOREACH(const std::string& strAddNode, lAddresses) {
- vector<CService> vservNode(0);
+ std::vector<CService> vservNode(0);
if(Lookup(strAddNode.c_str(), vservNode, Params().GetDefaultPort(), fNameLookup, 0))
- {
lservAddressesToAdd.push_back(vservNode);
- {
- LOCK(cs_setservAddNodeAddresses);
- BOOST_FOREACH(const CService& serv, vservNode)
- setservAddNodeAddresses.insert(serv);
- }
- }
}
// Attempt to connect to each IP for each addnode entry until at least one is successful per addnode entry
// (keeping in mind that addnode entries can have many IPs if fNameLookup)
{
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
- for (list<vector<CService> >::iterator it = lservAddressesToAdd.begin(); it != lservAddressesToAdd.end(); it++)
+ for (std::list<std::vector<CService> >::iterator it = lservAddressesToAdd.begin(); it != lservAddressesToAdd.end(); it++)
BOOST_FOREACH(const CService& addrNode, *(it))
if (pnode->addr == addrNode)
{
@@ -1684,7 +1691,7 @@ void ThreadOpenAddedConnections()
break;
}
}
- BOOST_FOREACH(vector<CService>& vserv, lservAddressesToAdd)
+ BOOST_FOREACH(std::vector<CService>& vserv, lservAddressesToAdd)
{
CSemaphoreGrant grant(*semOutbound);
OpenNetworkConnection(CAddress(vserv[i % vserv.size()]), &grant);
@@ -1731,7 +1738,7 @@ void ThreadMessageHandler()
while (true)
{
- vector<CNode*> vNodesCopy;
+ std::vector<CNode*> vNodesCopy;
{
LOCK(cs_vNodes);
vNodesCopy = vNodes;
@@ -1752,7 +1759,7 @@ void ThreadMessageHandler()
TRY_LOCK(pnode->cs_vRecvMsg, lockRecv);
if (lockRecv)
{
- if (!g_signals.ProcessMessages(pnode))
+ if (!GetNodeSignals().ProcessMessages(pnode))
pnode->CloseSocketDisconnect();
if (pnode->nSendSize < SendBufferSize())
@@ -1770,7 +1777,7 @@ void ThreadMessageHandler()
{
TRY_LOCK(pnode->cs_vSend, lockSend);
if (lockSend)
- g_signals.SendMessages(pnode);
+ GetNodeSignals().SendMessages(pnode);
}
boost::this_thread::interruption_point();
}
@@ -1791,7 +1798,7 @@ void ThreadMessageHandler()
-bool BindListenPort(const CService &addrBind, string& strError, bool fWhitelisted)
+bool BindListenPort(const CService &addrBind, std::string& strError, bool fWhitelisted)
{
strError = "";
int nOne = 1;
@@ -1899,7 +1906,7 @@ void static Discover(boost::thread_group& threadGroup)
char pszHostName[256] = "";
if (gethostname(pszHostName, sizeof(pszHostName)) != SOCKET_ERROR)
{
- vector<CNetAddr> vaddr;
+ std::vector<CNetAddr> vaddr;
if (LookupHost(pszHostName, vaddr, 0, true))
{
BOOST_FOREACH (const CNetAddr &addr, vaddr)
@@ -1950,6 +1957,7 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler)
if (adb.Read(addrman))
LogPrintf("Loaded %i addresses from peers.dat %dms\n", addrman.size(), GetTimeMillis() - nStart);
else {
+ addrman.Clear(); // Addrman can be in an inconsistent state after failure, reset it
LogPrintf("Invalid or missing peers.dat; recreating\n");
DumpAddresses();
}
@@ -2069,7 +2077,7 @@ public:
instance_of_cnetcleanup;
-void RelayTransaction(const CTransaction& tx, CFeeRate feerate)
+void RelayTransaction(const CTransaction& tx)
{
CInv inv(MSG_TX, tx.GetHash());
{
@@ -2299,7 +2307,7 @@ bool CAddrDB::Read(CAddrMan& addr)
// Don't try to resize to a negative number if file is small
if (fileSize >= sizeof(uint256))
dataSize = fileSize - sizeof(uint256);
- vector<unsigned char> vchData;
+ std::vector<unsigned char> vchData;
vchData.resize(dataSize);
uint256 hashIn;
@@ -2320,6 +2328,11 @@ bool CAddrDB::Read(CAddrMan& addr)
if (hashIn != hashTmp)
return error("%s: Checksum mismatch, data corrupted", __func__);
+ return Read(addr, ssPeers);
+}
+
+bool CAddrDB::Read(CAddrMan& addr, CDataStream& ssPeers)
+{
unsigned char pchMsgTmp[4];
try {
// de-serialize file header (network specific magic number) and ..
@@ -2333,6 +2346,8 @@ bool CAddrDB::Read(CAddrMan& addr)
ssPeers >> addr;
}
catch (const std::exception& e) {
+ // de-serialization has failed, ensure addrman is left in a clean state
+ addr.Clear();
return error("%s: Deserialize or I/O error - %s", __func__, e.what());
}
@@ -2579,7 +2594,7 @@ bool CBanDB::Read(banmap_t& banSet)
// Don't try to resize to a negative number if file is small
if (fileSize >= sizeof(uint256))
dataSize = fileSize - sizeof(uint256);
- vector<unsigned char> vchData;
+ std::vector<unsigned char> vchData;
vchData.resize(dataSize);
uint256 hashIn;
@@ -2619,26 +2634,6 @@ bool CBanDB::Read(banmap_t& banSet)
return true;
}
-void DumpBanlist()
-{
- CNode::SweepBanned(); // clean unused entries (if bantime has expired)
-
- if (!CNode::BannedSetIsDirty())
- return;
-
- int64_t nStart = GetTimeMillis();
-
- CBanDB bandb;
- banmap_t banmap;
- CNode::SetBannedSetDirty(false);
- CNode::GetBanned(banmap);
- if (!bandb.Write(banmap))
- CNode::SetBannedSetDirty(true);
-
- LogPrint("net", "Flushed %d banned node ips/subnets to banlist.dat %dms\n",
- banmap.size(), GetTimeMillis() - nStart);
-}
-
int64_t PoissonNextSend(int64_t nNow, int average_interval_seconds) {
return nNow + (int64_t)(log1p(GetRand(1ULL << 48) * -0.0000000000000035527136788 /* -1/2^48 */) * average_interval_seconds * -1000000.0 + 0.5);
}
diff --git a/src/net.h b/src/net.h
index b6ec7bf3e2..998ee49260 100644
--- a/src/net.h
+++ b/src/net.h
@@ -83,7 +83,6 @@ CNode* FindNode(const CNetAddr& ip);
CNode* FindNode(const CSubNet& subNet);
CNode* FindNode(const std::string& addrName);
CNode* FindNode(const CService& ip);
-CNode* ConnectNode(CAddress addrConnect, const char *pszDest = NULL);
bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false);
void MapPort(bool fUseUPnP);
unsigned short GetListenPort();
@@ -783,7 +782,7 @@ public:
class CTransaction;
-void RelayTransaction(const CTransaction& tx, CFeeRate feerate);
+void RelayTransaction(const CTransaction& tx);
/** Access to the (IP) address database (peers.dat) */
class CAddrDB
@@ -794,6 +793,7 @@ public:
CAddrDB();
bool Write(const CAddrMan& addr);
bool Read(CAddrMan& addr);
+ bool Read(CAddrMan& addr, CDataStream& ssPeers);
};
/** Access to the banlist database (banlist.dat) */
@@ -807,8 +807,6 @@ public:
bool Read(banmap_t& banSet);
};
-void DumpBanlist();
-
/** Return a timestamp in the future (in microseconds) for exponentially distributed events. */
int64_t PoissonNextSend(int64_t nNow, int average_interval_seconds);
diff --git a/src/netbase.cpp b/src/netbase.cpp
index b44a8b16e2..572ae70871 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -291,10 +291,25 @@ struct ProxyCredentials
std::string password;
};
+std::string Socks5ErrorString(int err)
+{
+ switch(err) {
+ case 0x01: return "general failure";
+ case 0x02: return "connection not allowed";
+ case 0x03: return "network unreachable";
+ case 0x04: return "host unreachable";
+ case 0x05: return "connection refused";
+ case 0x06: return "TTL expired";
+ case 0x07: return "protocol error";
+ case 0x08: return "address type not supported";
+ default: return "unknown";
+ }
+}
+
/** Connect using SOCKS5 (as described in RFC1928) */
static bool Socks5(const std::string& strDest, int port, const ProxyCredentials *auth, SOCKET& hSocket)
{
- LogPrintf("SOCKS5 connecting %s\n", strDest);
+ LogPrint("net", "SOCKS5 connecting %s\n", strDest);
if (strDest.size() > 255) {
CloseSocket(hSocket);
return error("Hostname too long");
@@ -318,7 +333,8 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
char pchRet1[2];
if (!InterruptibleRecv(pchRet1, 2, SOCKS5_RECV_TIMEOUT, hSocket)) {
CloseSocket(hSocket);
- return error("Error reading proxy response");
+ LogPrintf("Socks5() connect to %s:%d failed: InterruptibleRecv() timeout or other failure\n", strDest, port);
+ return false;
}
if (pchRet1[0] != 0x05) {
CloseSocket(hSocket);
@@ -379,19 +395,10 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
return error("Proxy failed to accept request");
}
if (pchRet2[1] != 0x00) {
+ // Failures to connect to a peer that are not proxy errors
CloseSocket(hSocket);
- switch (pchRet2[1])
- {
- case 0x01: return error("Proxy error: general failure");
- case 0x02: return error("Proxy error: connection not allowed");
- case 0x03: return error("Proxy error: network unreachable");
- case 0x04: return error("Proxy error: host unreachable");
- case 0x05: return error("Proxy error: connection refused");
- case 0x06: return error("Proxy error: TTL expired");
- case 0x07: return error("Proxy error: protocol error");
- case 0x08: return error("Proxy error: address type not supported");
- default: return error("Proxy error: unknown");
- }
+ LogPrintf("Socks5() connect to %s:%d failed: %s\n", strDest, port, Socks5ErrorString(pchRet2[1]));
+ return false;
}
if (pchRet2[2] != 0x00) {
CloseSocket(hSocket);
@@ -423,7 +430,7 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
CloseSocket(hSocket);
return error("Error reading from proxy");
}
- LogPrintf("SOCKS5 connected %s\n", strDest);
+ LogPrint("net", "SOCKS5 connected %s\n", strDest);
return true;
}
diff --git a/src/qt/askpassphrasedialog.cpp b/src/qt/askpassphrasedialog.cpp
index 415bffb991..e8aa79679c 100644
--- a/src/qt/askpassphrasedialog.cpp
+++ b/src/qt/askpassphrasedialog.cpp
@@ -77,10 +77,7 @@ AskPassphraseDialog::AskPassphraseDialog(Mode mode, QWidget *parent) :
AskPassphraseDialog::~AskPassphraseDialog()
{
- // Attempt to overwrite text so that they do not linger around in memory
- ui->passEdit1->setText(QString(" ").repeated(ui->passEdit1->text().size()));
- ui->passEdit2->setText(QString(" ").repeated(ui->passEdit2->text().size()));
- ui->passEdit3->setText(QString(" ").repeated(ui->passEdit3->text().size()));
+ secureClearPassFields();
delete ui;
}
@@ -103,6 +100,8 @@ void AskPassphraseDialog::accept()
newpass1.assign(ui->passEdit2->text().toStdString().c_str());
newpass2.assign(ui->passEdit3->text().toStdString().c_str());
+ secureClearPassFields();
+
switch(mode)
{
case Encrypt: {
@@ -260,3 +259,17 @@ bool AskPassphraseDialog::eventFilter(QObject *object, QEvent *event)
}
return QDialog::eventFilter(object, event);
}
+
+static void SecureClearQLineEdit(QLineEdit* edit)
+{
+ // Attempt to overwrite text so that they do not linger around in memory
+ edit->setText(QString(" ").repeated(edit->text().size()));
+ edit->clear();
+}
+
+void AskPassphraseDialog::secureClearPassFields()
+{
+ SecureClearQLineEdit(ui->passEdit1);
+ SecureClearQLineEdit(ui->passEdit2);
+ SecureClearQLineEdit(ui->passEdit3);
+}
diff --git a/src/qt/askpassphrasedialog.h b/src/qt/askpassphrasedialog.h
index 727b5a1ada..34bf7ccb31 100644
--- a/src/qt/askpassphrasedialog.h
+++ b/src/qt/askpassphrasedialog.h
@@ -42,6 +42,7 @@ private:
private Q_SLOTS:
void textChanged();
+ void secureClearPassFields();
protected:
bool event(QEvent *event);
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 9c21bb24ce..6218ab6ab0 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -370,6 +370,7 @@ void BitcoinApplication::createSplashScreen(const NetworkStyle *networkStyle)
splash->setAttribute(Qt::WA_DeleteOnClose);
splash->show();
connect(this, SIGNAL(splashFinished(QWidget*)), splash, SLOT(slotFinish(QWidget*)));
+ connect(this, SIGNAL(requestedShutdown()), splash, SLOT(close()));
}
void BitcoinApplication::startThread()
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index b00cdfcaf2..50c19c3848 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -320,12 +320,14 @@ void BitcoinGUI::createActions()
aboutAction = new QAction(platformStyle->TextColorIcon(":/icons/about"), tr("&About %1").arg(tr(PACKAGE_NAME)), this);
aboutAction->setStatusTip(tr("Show information about %1").arg(tr(PACKAGE_NAME)));
aboutAction->setMenuRole(QAction::AboutRole);
+ aboutAction->setEnabled(false);
aboutQtAction = new QAction(platformStyle->TextColorIcon(":/icons/about_qt"), tr("About &Qt"), this);
aboutQtAction->setStatusTip(tr("Show information about Qt"));
aboutQtAction->setMenuRole(QAction::AboutQtRole);
optionsAction = new QAction(platformStyle->TextColorIcon(":/icons/options"), tr("&Options..."), this);
optionsAction->setStatusTip(tr("Modify configuration options for %1").arg(tr(PACKAGE_NAME)));
optionsAction->setMenuRole(QAction::PreferencesRole);
+ optionsAction->setEnabled(false);
toggleHideAction = new QAction(platformStyle->TextColorIcon(":/icons/about"), tr("&Show / Hide"), this);
toggleHideAction->setStatusTip(tr("Show or hide the main Window"));
@@ -343,6 +345,8 @@ void BitcoinGUI::createActions()
openRPCConsoleAction = new QAction(platformStyle->TextColorIcon(":/icons/debugwindow"), tr("&Debug window"), this);
openRPCConsoleAction->setStatusTip(tr("Open debugging and diagnostic console"));
+ // initially disable the debug window menu item
+ openRPCConsoleAction->setEnabled(false);
usedSendingAddressesAction = new QAction(platformStyle->TextColorIcon(":/icons/address-book"), tr("&Sending addresses..."), this);
usedSendingAddressesAction->setStatusTip(tr("Show the list of used sending addresses and labels"));
@@ -457,8 +461,8 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel)
setNumConnections(clientModel->getNumConnections());
connect(clientModel, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int)));
- setNumBlocks(clientModel->getNumBlocks(), clientModel->getLastBlockDate(), clientModel->getVerificationProgress(NULL));
- connect(clientModel, SIGNAL(numBlocksChanged(int,QDateTime,double)), this, SLOT(setNumBlocks(int,QDateTime,double)));
+ setNumBlocks(clientModel->getNumBlocks(), clientModel->getLastBlockDate(), clientModel->getVerificationProgress(NULL), false);
+ connect(clientModel, SIGNAL(numBlocksChanged(int,QDateTime,double,bool)), this, SLOT(setNumBlocks(int,QDateTime,double,bool)));
// Receive and report messages from client model
connect(clientModel, SIGNAL(message(QString,QString,unsigned int)), this, SLOT(message(QString,QString,unsigned int)));
@@ -474,6 +478,16 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel)
}
#endif // ENABLE_WALLET
unitDisplayControl->setOptionsModel(clientModel->getOptionsModel());
+
+ OptionsModel* optionsModel = clientModel->getOptionsModel();
+ if(optionsModel)
+ {
+ // be aware of the tray icon disable state change reported by the OptionsModel object.
+ connect(optionsModel,SIGNAL(hideTrayIconChanged(bool)),this,SLOT(setTrayIconVisible(bool)));
+
+ // initialize the disable state of the tray icon with the current value in the model.
+ setTrayIconVisible(optionsModel->getHideTrayIcon());
+ }
} else {
// Disable possibility to show main window via action
toggleHideAction->setEnabled(false);
@@ -535,7 +549,7 @@ void BitcoinGUI::createTrayIcon(const NetworkStyle *networkStyle)
QString toolTip = tr("%1 client").arg(tr(PACKAGE_NAME)) + " " + networkStyle->getTitleAddText();
trayIcon->setToolTip(toolTip);
trayIcon->setIcon(networkStyle->getTrayAndWindowIcon());
- trayIcon->show();
+ trayIcon->hide();
#endif
notificator = new Notificator(QApplication::applicationName(), trayIcon, this);
@@ -686,7 +700,7 @@ void BitcoinGUI::setNumConnections(int count)
labelConnectionsIcon->setToolTip(tr("%n active connection(s) to Bitcoin network", "", count));
}
-void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress)
+void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, bool header)
{
if(!clientModel)
return;
@@ -698,15 +712,25 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVer
enum BlockSource blockSource = clientModel->getBlockSource();
switch (blockSource) {
case BLOCK_SOURCE_NETWORK:
+ if (header) {
+ return;
+ }
progressBarLabel->setText(tr("Synchronizing with network..."));
break;
case BLOCK_SOURCE_DISK:
- progressBarLabel->setText(tr("Importing blocks from disk..."));
+ if (header) {
+ progressBarLabel->setText(tr("Indexing blocks on disk..."));
+ } else {
+ progressBarLabel->setText(tr("Processing blocks on disk..."));
+ }
break;
case BLOCK_SOURCE_REINDEX:
progressBarLabel->setText(tr("Reindexing blocks on disk..."));
break;
case BLOCK_SOURCE_NONE:
+ if (header) {
+ return;
+ }
// Case: not Importing, not Reindexing and no network connection
progressBarLabel->setText(tr("No block source available..."));
break;
@@ -891,6 +915,14 @@ void BitcoinGUI::closeEvent(QCloseEvent *event)
QMainWindow::closeEvent(event);
}
+void BitcoinGUI::showEvent(QShowEvent *event)
+{
+ // enable the debug window when the main window shows up
+ openRPCConsoleAction->setEnabled(true);
+ aboutAction->setEnabled(true);
+ optionsAction->setEnabled(true);
+}
+
#ifdef ENABLE_WALLET
void BitcoinGUI::incomingTransaction(const QString& date, int unit, const CAmount& amount, const QString& type, const QString& address, const QString& label)
{
@@ -1044,6 +1076,14 @@ void BitcoinGUI::showProgress(const QString &title, int nProgress)
progressDialog->setValue(nProgress);
}
+void BitcoinGUI::setTrayIconVisible(bool fHideTrayIcon)
+{
+ if (trayIcon)
+ {
+ trayIcon->setVisible(!fHideTrayIcon);
+ }
+}
+
static bool ThreadSafeMessageBox(BitcoinGUI *gui, const std::string& message, const std::string& caption, unsigned int style)
{
bool modal = (style & CClientUIInterface::MODAL);
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index 871ca1ba34..12e7702ed8 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -72,6 +72,7 @@ public:
protected:
void changeEvent(QEvent *e);
void closeEvent(QCloseEvent *event);
+ void showEvent(QShowEvent *event);
void dragEnterEvent(QDragEnterEvent *event);
void dropEvent(QDropEvent *event);
bool eventFilter(QObject *object, QEvent *event);
@@ -150,7 +151,7 @@ public Q_SLOTS:
/** Set number of connections shown in the UI */
void setNumConnections(int count);
/** Set number of blocks and last block date shown in the UI */
- void setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress);
+ void setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, bool headers);
/** Notify the user of an event from the core network or transaction handling code.
@param[in] title the message box / notification title
@@ -218,6 +219,9 @@ private Q_SLOTS:
/** Show progress dialog e.g. for verifychain */
void showProgress(const QString &title, int nProgress);
+
+ /** When hideTrayIcon setting is changed in OptionsModel hide or show the icon accordingly. */
+ void setTrayIconVisible(bool);
};
class UnitDisplayStatusBarControl : public QLabel
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index 697736cc88..108500654b 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -24,6 +24,7 @@
class CBlockIndex;
static const int64_t nClientStartupTime = GetTime();
+static int64_t nLastHeaderTipUpdateNotification = 0;
static int64_t nLastBlockTipUpdateNotification = 0;
ClientModel::ClientModel(OptionsModel *optionsModel, QObject *parent) :
@@ -226,7 +227,7 @@ static void BannedListChanged(ClientModel *clientmodel)
QMetaObject::invokeMethod(clientmodel, "updateBanlist", Qt::QueuedConnection);
}
-static void BlockTipChanged(ClientModel *clientmodel, bool initialSync, const CBlockIndex *pIndex)
+static void BlockTipChanged(ClientModel *clientmodel, bool initialSync, const CBlockIndex *pIndex, bool fHeader)
{
// lock free async UI updates in case we have a new block tip
// during initial sync, only update the UI if the last update
@@ -235,14 +236,17 @@ static void BlockTipChanged(ClientModel *clientmodel, bool initialSync, const CB
if (initialSync)
now = GetTimeMillis();
+ int64_t& nLastUpdateNotification = fHeader ? nLastHeaderTipUpdateNotification : nLastBlockTipUpdateNotification;
+
// if we are in-sync, update the UI regardless of last update time
- if (!initialSync || now - nLastBlockTipUpdateNotification > MODEL_UPDATE_DELAY) {
+ if (!initialSync || now - nLastUpdateNotification > MODEL_UPDATE_DELAY) {
//pass a async signal to the UI thread
QMetaObject::invokeMethod(clientmodel, "numBlocksChanged", Qt::QueuedConnection,
Q_ARG(int, pIndex->nHeight),
Q_ARG(QDateTime, QDateTime::fromTime_t(pIndex->GetBlockTime())),
- Q_ARG(double, clientmodel->getVerificationProgress(pIndex)));
- nLastBlockTipUpdateNotification = now;
+ Q_ARG(double, clientmodel->getVerificationProgress(pIndex)),
+ Q_ARG(bool, fHeader));
+ nLastUpdateNotification = now;
}
}
@@ -253,7 +257,8 @@ void ClientModel::subscribeToCoreSignals()
uiInterface.NotifyNumConnectionsChanged.connect(boost::bind(NotifyNumConnectionsChanged, this, _1));
uiInterface.NotifyAlertChanged.connect(boost::bind(NotifyAlertChanged, this));
uiInterface.BannedListChanged.connect(boost::bind(BannedListChanged, this));
- uiInterface.NotifyBlockTip.connect(boost::bind(BlockTipChanged, this, _1, _2));
+ uiInterface.NotifyBlockTip.connect(boost::bind(BlockTipChanged, this, _1, _2, false));
+ uiInterface.NotifyHeaderTip.connect(boost::bind(BlockTipChanged, this, _1, _2, true));
}
void ClientModel::unsubscribeFromCoreSignals()
@@ -263,5 +268,6 @@ void ClientModel::unsubscribeFromCoreSignals()
uiInterface.NotifyNumConnectionsChanged.disconnect(boost::bind(NotifyNumConnectionsChanged, this, _1));
uiInterface.NotifyAlertChanged.disconnect(boost::bind(NotifyAlertChanged, this));
uiInterface.BannedListChanged.disconnect(boost::bind(BannedListChanged, this));
- uiInterface.NotifyBlockTip.disconnect(boost::bind(BlockTipChanged, this, _1, _2));
+ uiInterface.NotifyBlockTip.disconnect(boost::bind(BlockTipChanged, this, _1, _2, false));
+ uiInterface.NotifyHeaderTip.disconnect(boost::bind(BlockTipChanged, this, _1, _2, true));
}
diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h
index 109f95a2a7..4396804319 100644
--- a/src/qt/clientmodel.h
+++ b/src/qt/clientmodel.h
@@ -89,7 +89,7 @@ private:
Q_SIGNALS:
void numConnectionsChanged(int count);
- void numBlocksChanged(int count, const QDateTime& blockDate, double nVerificationProgress);
+ void numBlocksChanged(int count, const QDateTime& blockDate, double nVerificationProgress, bool header);
void mempoolSizeChanged(long count, size_t mempoolSizeInBytes);
void alertsChanged(const QString &warnings);
void bytesChanged(quint64 totalBytesIn, quint64 totalBytesOut);
diff --git a/src/qt/forms/optionsdialog.ui b/src/qt/forms/optionsdialog.ui
index c712e6ea01..0b29201872 100644
--- a/src/qt/forms/optionsdialog.ui
+++ b/src/qt/forms/optionsdialog.ui
@@ -505,6 +505,16 @@
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_Window">
<item>
+ <widget class="QCheckBox" name="hideTrayIcon">
+ <property name="toolTip">
+ <string>&amp;Hide the icon from the system tray.</string>
+ </property>
+ <property name="text">
+ <string>Hide tray icon</string>
+ </property>
+ </widget>
+ </item>
+ <item>
<widget class="QCheckBox" name="minimizeToTray">
<property name="toolTip">
<string>Show only a tray icon after minimizing the window.</string>
diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp
index 95a3fa8d21..f2db398899 100644
--- a/src/qt/optionsdialog.cpp
+++ b/src/qt/optionsdialog.cpp
@@ -198,6 +198,7 @@ void OptionsDialog::setMapper()
/* Window */
#ifndef Q_OS_MAC
+ mapper->addMapping(ui->hideTrayIcon, OptionsModel::HideTrayIcon);
mapper->addMapping(ui->minimizeToTray, OptionsModel::MinimizeToTray);
mapper->addMapping(ui->minimizeOnClose, OptionsModel::MinimizeOnClose);
#endif
@@ -243,6 +244,19 @@ void OptionsDialog::on_cancelButton_clicked()
reject();
}
+void OptionsDialog::on_hideTrayIcon_stateChanged(int fState)
+{
+ if(fState)
+ {
+ ui->minimizeToTray->setChecked(false);
+ ui->minimizeToTray->setEnabled(false);
+ }
+ else
+ {
+ ui->minimizeToTray->setEnabled(true);
+ }
+}
+
void OptionsDialog::showRestartWarning(bool fPersistent)
{
ui->statusLabel->setStyleSheet("QLabel { color: red; }");
diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h
index e944fb9ee9..41b56d1386 100644
--- a/src/qt/optionsdialog.h
+++ b/src/qt/optionsdialog.h
@@ -49,6 +49,8 @@ private Q_SLOTS:
void on_resetButton_clicked();
void on_okButton_clicked();
void on_cancelButton_clicked();
+
+ void on_hideTrayIcon_stateChanged(int fState);
void showRestartWarning(bool fPersistent = false);
void clearStatusLabel();
diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp
index d091bb9e61..cc2cbc0e66 100644
--- a/src/qt/optionsmodel.cpp
+++ b/src/qt/optionsmodel.cpp
@@ -51,9 +51,14 @@ void OptionsModel::Init(bool resetSettings)
// These are Qt-only settings:
// Window
+ if (!settings.contains("fHideTrayIcon"))
+ settings.setValue("fHideTrayIcon", false);
+ fHideTrayIcon = settings.value("fHideTrayIcon").toBool();
+ Q_EMIT hideTrayIconChanged(fHideTrayIcon);
+
if (!settings.contains("fMinimizeToTray"))
settings.setValue("fMinimizeToTray", false);
- fMinimizeToTray = settings.value("fMinimizeToTray").toBool();
+ fMinimizeToTray = settings.value("fMinimizeToTray").toBool() && !fHideTrayIcon;
if (!settings.contains("fMinimizeOnClose"))
settings.setValue("fMinimizeOnClose", false);
@@ -166,6 +171,8 @@ QVariant OptionsModel::data(const QModelIndex & index, int role) const
{
case StartAtStartup:
return GUIUtil::GetStartOnSystemStartup();
+ case HideTrayIcon:
+ return fHideTrayIcon;
case MinimizeToTray:
return fMinimizeToTray;
case MapPortUPnP:
@@ -242,6 +249,11 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in
case StartAtStartup:
successful = GUIUtil::SetStartOnSystemStartup(value.toBool());
break;
+ case HideTrayIcon:
+ fHideTrayIcon = value.toBool();
+ settings.setValue("fHideTrayIcon", fHideTrayIcon);
+ Q_EMIT hideTrayIconChanged(fHideTrayIcon);
+ break;
case MinimizeToTray:
fMinimizeToTray = value.toBool();
settings.setValue("fMinimizeToTray", fMinimizeToTray);
diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h
index 841711dd2d..3b491ceac2 100644
--- a/src/qt/optionsmodel.h
+++ b/src/qt/optionsmodel.h
@@ -28,6 +28,7 @@ public:
enum OptionID {
StartAtStartup, // bool
+ HideTrayIcon, // bool
MinimizeToTray, // bool
MapPortUPnP, // bool
MinimizeOnClose, // bool
@@ -58,6 +59,7 @@ public:
void setDisplayUnit(const QVariant &value);
/* Explicit getters */
+ bool getHideTrayIcon() { return fHideTrayIcon; }
bool getMinimizeToTray() { return fMinimizeToTray; }
bool getMinimizeOnClose() { return fMinimizeOnClose; }
int getDisplayUnit() { return nDisplayUnit; }
@@ -72,6 +74,7 @@ public:
private:
/* Qt-only settings */
+ bool fHideTrayIcon;
bool fMinimizeToTray;
bool fMinimizeOnClose;
QString language;
@@ -87,6 +90,7 @@ private:
Q_SIGNALS:
void displayUnitChanged(int unit);
void coinControlFeaturesChanged(bool);
+ void hideTrayIconChanged(bool);
};
#endif // BITCOIN_QT_OPTIONSMODEL_H
diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp
index d577345e49..6a0404cbf7 100644
--- a/src/qt/overviewpage.cpp
+++ b/src/qt/overviewpage.cpp
@@ -219,7 +219,7 @@ void OverviewPage::setWalletModel(WalletModel *model)
filter->setDynamicSortFilter(true);
filter->setSortRole(Qt::EditRole);
filter->setShowInactive(false);
- filter->sort(TransactionTableModel::Status, Qt::DescendingOrder);
+ filter->sort(TransactionTableModel::Date, Qt::DescendingOrder);
ui->listTransactions->setModel(filter);
ui->listTransactions->setModelColumn(TransactionTableModel::ToAddress);
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index d8647d902a..b11648e46f 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -353,8 +353,8 @@ void RPCConsole::setClientModel(ClientModel *model)
setNumConnections(model->getNumConnections());
connect(model, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int)));
- setNumBlocks(model->getNumBlocks(), model->getLastBlockDate(), model->getVerificationProgress(NULL));
- connect(model, SIGNAL(numBlocksChanged(int,QDateTime,double)), this, SLOT(setNumBlocks(int,QDateTime,double)));
+ setNumBlocks(model->getNumBlocks(), model->getLastBlockDate(), model->getVerificationProgress(NULL), false);
+ connect(model, SIGNAL(numBlocksChanged(int,QDateTime,double,bool)), this, SLOT(setNumBlocks(int,QDateTime,double,bool)));
updateTrafficStats(model->getTotalBytesRecv(), model->getTotalBytesSent());
connect(model, SIGNAL(bytesChanged(quint64,quint64)), this, SLOT(updateTrafficStats(quint64, quint64)));
@@ -585,10 +585,12 @@ void RPCConsole::setNumConnections(int count)
ui->numberOfConnections->setText(connections);
}
-void RPCConsole::setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress)
+void RPCConsole::setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, bool headers)
{
- ui->numberOfBlocks->setText(QString::number(count));
- ui->lastBlockTime->setText(blockDate.toString());
+ if (!headers) {
+ ui->numberOfBlocks->setText(QString::number(count));
+ ui->lastBlockTime->setText(blockDate.toString());
+ }
}
void RPCConsole::setMempoolSize(long numberOfTxs, size_t dynUsage)
@@ -885,15 +887,13 @@ void RPCConsole::banSelectedNode(int bantime)
// Get currently selected peer address
QString strNode = GUIUtil::getEntryData(ui->peerWidget, 0, PeerTableModel::Address);
// Find possible nodes, ban it and clear the selected node
- if (CNode *bannedNode = FindNode(strNode.toStdString())) {
+ if (FindNode(strNode.toStdString())) {
std::string nStr = strNode.toStdString();
std::string addr;
int port = 0;
SplitHostPort(nStr, port, addr);
CNode::Ban(CNetAddr(addr), BanReasonManuallyAdded, bantime);
- bannedNode->fDisconnect = true;
- DumpBanlist();
clearSelectedNode();
clientModel->getBanTableModel()->refresh();
@@ -912,7 +912,6 @@ void RPCConsole::unbanSelectedNode()
if (possibleSubnet.IsValid())
{
CNode::Unban(possibleSubnet);
- DumpBanlist();
clientModel->getBanTableModel()->refresh();
}
}
diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h
index 2923587bc8..28affa954d 100644
--- a/src/qt/rpcconsole.h
+++ b/src/qt/rpcconsole.h
@@ -87,7 +87,7 @@ public Q_SLOTS:
/** Set number of connections shown in the UI */
void setNumConnections(int count);
/** Set number of blocks and last block date shown in the UI */
- void setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress);
+ void setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, bool headers);
/** Set size (number of transactions and memory usage) of the mempool in the UI */
void setMempoolSize(long numberOfTxs, size_t dynUsage);
/** Go forward or back in history */
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index 780a6c9709..6d50be56ec 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -26,6 +26,9 @@
#include <QScrollBar>
#include <QSettings>
#include <QTextDocument>
+#include <QTimer>
+
+#define SEND_CONFIRM_DELAY 3
SendCoinsDialog::SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *parent) :
QDialog(parent),
@@ -121,7 +124,7 @@ void SendCoinsDialog::setClientModel(ClientModel *clientModel)
this->clientModel = clientModel;
if (clientModel) {
- connect(clientModel, SIGNAL(numBlocksChanged(int,QDateTime,double)), this, SLOT(updateSmartFeeLabel()));
+ connect(clientModel, SIGNAL(numBlocksChanged(int,QDateTime,double,bool)), this, SLOT(updateSmartFeeLabel()));
}
}
@@ -311,10 +314,10 @@ void SendCoinsDialog::on_sendButton_clicked()
questionString.append(QString("<span style='font-size:10pt;font-weight:normal;'><br />(=%2)</span>")
.arg(alternativeUnits.join(" " + tr("or") + "<br />")));
- QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm send coins"),
- questionString.arg(formatted.join("<br />")),
- QMessageBox::Yes | QMessageBox::Cancel,
- QMessageBox::Cancel);
+ SendConfirmationDialog confirmationDialog(tr("Confirm send coins"),
+ questionString.arg(formatted.join("<br />")), SEND_CONFIRM_DELAY, this);
+ confirmationDialog.exec();
+ QMessageBox::StandardButton retval = (QMessageBox::StandardButton)confirmationDialog.result();
if(retval != QMessageBox::Yes)
{
@@ -828,3 +831,45 @@ void SendCoinsDialog::coinControlUpdateLabels()
ui->labelCoinControlInsuffFunds->hide();
}
}
+
+SendConfirmationDialog::SendConfirmationDialog(const QString &title, const QString &text, int secDelay,
+ QWidget *parent) :
+ QMessageBox(QMessageBox::Question, title, text, QMessageBox::Yes | QMessageBox::Cancel, parent), secDelay(secDelay)
+{
+ setDefaultButton(QMessageBox::Cancel);
+ yesButton = button(QMessageBox::Yes);
+ updateYesButton();
+ connect(&countDownTimer, SIGNAL(timeout()), this, SLOT(countDown()));
+}
+
+int SendConfirmationDialog::exec()
+{
+ updateYesButton();
+ countDownTimer.start(1000);
+ return QMessageBox::exec();
+}
+
+void SendConfirmationDialog::countDown()
+{
+ secDelay--;
+ updateYesButton();
+
+ if(secDelay <= 0)
+ {
+ countDownTimer.stop();
+ }
+}
+
+void SendConfirmationDialog::updateYesButton()
+{
+ if(secDelay > 0)
+ {
+ yesButton->setEnabled(false);
+ yesButton->setText(tr("Yes") + " (" + QString::number(secDelay) + ")");
+ }
+ else
+ {
+ yesButton->setEnabled(true);
+ yesButton->setText(tr("Yes"));
+ }
+}
diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h
index ec171734fa..be4f2ee44b 100644
--- a/src/qt/sendcoinsdialog.h
+++ b/src/qt/sendcoinsdialog.h
@@ -8,7 +8,9 @@
#include "walletmodel.h"
#include <QDialog>
+#include <QMessageBox>
#include <QString>
+#include <QTimer>
class ClientModel;
class OptionsModel;
@@ -100,4 +102,24 @@ Q_SIGNALS:
void message(const QString &title, const QString &message, unsigned int style);
};
+
+
+class SendConfirmationDialog : public QMessageBox
+{
+ Q_OBJECT
+
+public:
+ SendConfirmationDialog(const QString &title, const QString &text, int secDelay = 0, QWidget *parent = 0);
+ int exec();
+
+private Q_SLOTS:
+ void countDown();
+ void updateYesButton();
+
+private:
+ QAbstractButton *yesButton;
+ QTimer countDownTimer;
+ int secDelay;
+};
+
#endif // BITCOIN_QT_SENDCOINSDIALOG_H
diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp
index eb6111e682..199a7b2d77 100644
--- a/src/qt/transactionview.cpp
+++ b/src/qt/transactionview.cpp
@@ -203,7 +203,7 @@ void TransactionView::setModel(WalletModel *model)
transactionView->setSelectionBehavior(QAbstractItemView::SelectRows);
transactionView->setSelectionMode(QAbstractItemView::ExtendedSelection);
transactionView->setSortingEnabled(true);
- transactionView->sortByColumn(TransactionTableModel::Status, Qt::DescendingOrder);
+ transactionView->sortByColumn(TransactionTableModel::Date, Qt::DescendingOrder);
transactionView->verticalHeader()->hide();
transactionView->setColumnWidth(TransactionTableModel::Status, STATUS_COLUMN_WIDTH);
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index a0d0e70442..3867310cd6 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -447,7 +447,7 @@ bool WalletModel::changePassphrase(const SecureString &oldPass, const SecureStri
bool WalletModel::backupWallet(const QString &filename)
{
- return BackupWallet(*wallet, filename.toLocal8Bit().data());
+ return wallet->BackupWallet(filename.toLocal8Bit().data());
}
// Handlers for core signals
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 6960415e2e..cf3c73c4df 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -973,7 +973,6 @@ UniValue reconsiderblock(const UniValue& params, bool fHelp)
std::string strHash = params[0].get_str();
uint256 hash(uint256S(strHash));
- CValidationState state;
{
LOCK(cs_main);
@@ -981,12 +980,11 @@ UniValue reconsiderblock(const UniValue& params, bool fHelp)
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
CBlockIndex* pblockindex = mapBlockIndex[hash];
- ReconsiderBlock(state, pblockindex);
+ ResetBlockFailureFlags(pblockindex);
}
- if (state.IsValid()) {
- ActivateBestChain(state, Params());
- }
+ CValidationState state;
+ ActivateBestChain(state, Params());
if (!state.IsValid()) {
throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason());
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index 320091b9c4..e09af89656 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -565,20 +565,12 @@ UniValue setban(const UniValue& params, bool fHelp)
absolute = true;
isSubnet ? CNode::Ban(subNet, BanReasonManuallyAdded, banTime, absolute) : CNode::Ban(netAddr, BanReasonManuallyAdded, banTime, absolute);
-
- //disconnect possible nodes
- while(CNode *bannedNode = (isSubnet ? FindNode(subNet) : FindNode(netAddr)))
- bannedNode->fDisconnect = true;
}
else if(strCommand == "remove")
{
if (!( isSubnet ? CNode::Unban(subNet) : CNode::Unban(netAddr) ))
throw JSONRPCError(RPC_MISC_ERROR, "Error: Unban failed");
}
-
- DumpBanlist(); //store banlist to disk
- uiInterface.BannedListChanged();
-
return NullUniValue;
}
@@ -624,8 +616,6 @@ UniValue clearbanned(const UniValue& params, bool fHelp)
);
CNode::ClearBanned();
- DumpBanlist(); //store banlist to disk
- uiInterface.BannedListChanged();
return NullUniValue;
}
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index de8cd68f66..bec7ebe55f 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -819,12 +819,11 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp)
const CCoins* existingCoins = view.AccessCoins(hashTx);
bool fHaveMempool = mempool.exists(hashTx);
bool fHaveChain = existingCoins && existingCoins->nHeight < 1000000000;
- CFeeRate txFeeRate = CFeeRate(0);
if (!fHaveMempool && !fHaveChain) {
// push to local node and sync with wallets
CValidationState state;
bool fMissingInputs;
- if (!AcceptToMemoryPool(mempool, state, tx, false, &fMissingInputs, &txFeeRate, false, nMaxRawTxFee)) {
+ if (!AcceptToMemoryPool(mempool, state, tx, false, &fMissingInputs, false, nMaxRawTxFee)) {
if (state.IsInvalid()) {
throw JSONRPCError(RPC_TRANSACTION_REJECTED, strprintf("%i: %s", state.GetRejectCode(), state.GetRejectReason()));
} else {
@@ -837,7 +836,7 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp)
} else if (fHaveChain) {
throw JSONRPCError(RPC_TRANSACTION_ALREADY_IN_CHAIN, "transaction already in block chain");
}
- RelayTransaction(tx, txFeeRate);
+ RelayTransaction(tx);
return hashTx.GetHex();
}
diff --git a/src/scheduler.cpp b/src/scheduler.cpp
index 184ddc28ab..52777b61f9 100644
--- a/src/scheduler.cpp
+++ b/src/scheduler.cpp
@@ -79,6 +79,7 @@ void CScheduler::serviceQueue()
}
}
--nThreadsServicingQueue;
+ newTaskScheduled.notify_one();
}
void CScheduler::stop(bool drain)
diff --git a/src/test/data/script_tests.json b/src/test/data/script_tests.json
index e75b7825ed..757d94b526 100644
--- a/src/test/data/script_tests.json
+++ b/src/test/data/script_tests.json
@@ -700,6 +700,8 @@
["0x17 0x3014020002107777777777777777777777777777777701", "0 CHECKSIG NOT", "", "OK", "Zero-length R is correctly encoded"],
["0x17 0x3014021077777777777777777777777777777777020001", "0 CHECKSIG NOT", "", "OK", "Zero-length S is correctly encoded for DERSIG"],
["0x27 0x302402107777777777777777777777777777777702108777777777777777777777777777777701", "0 CHECKSIG NOT", "", "OK", "Negative S is correctly encoded"],
+
+["2147483648", "NOP3", "CHECKSEQUENCEVERIFY", "OK", "CSV passes if stack top bit 1 << 31 is set"],
["", "DEPTH", "P2SH,STRICTENC", "EVAL_FALSE", "Test the test: we should have an empty stack after scriptSig evaluation"],
[" ", "DEPTH", "P2SH,STRICTENC", "EVAL_FALSE", "and multiple spaces should not change that."],
@@ -855,7 +857,7 @@
["2 2 LSHIFT", "8 EQUAL", "P2SH,STRICTENC", "DISABLED_OPCODE", "disabled"],
["2 1 RSHIFT", "1 EQUAL", "P2SH,STRICTENC", "DISABLED_OPCODE", "disabled"],
-["1","NOP1 CHECKLOCKTIMEVERIFY NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 2 EQUAL", "P2SH,STRICTENC", "EVAL_FALSE"],
+["1", "NOP1 CHECKLOCKTIMEVERIFY NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 2 EQUAL", "P2SH,STRICTENC", "EVAL_FALSE"],
["'NOP_1_to_10' NOP1 CHECKLOCKTIMEVERIFY NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10","'NOP_1_to_11' EQUAL", "P2SH,STRICTENC", "EVAL_FALSE"],
["Ensure 100% coverage of discouraged NOPS"],
@@ -1820,5 +1822,12 @@
"P2SH with CLEANSTACK"
],
+["CHECKSEQUENCEVERIFY tests"],
+["", "NOP3", "CHECKSEQUENCEVERIFY", "INVALID_STACK_OPERATION", "CSV automatically fails on a empty stack"],
+["-1", "NOP3", "CHECKSEQUENCEVERIFY", "NEGATIVE_LOCKTIME", "CSV automatically fails if stack top is negative"],
+["0x0100", "NOP3", "CHECKSEQUENCEVERIFY,MINIMALDATA", "UNKNOWN_ERROR", "CSV fails if stack top is not minimally encoded"],
+["0", "NOP3", "CHECKSEQUENCEVERIFY", "UNSATISFIED_LOCKTIME", "CSV fails if stack top bit 1 << 31 is set and the tx version < 2"],
+["4294967296", "NOP3", "CHECKSEQUENCEVERIFY", "UNSATISFIED_LOCKTIME",
+ "CSV fails if stack top bit 1 << 31 is not set, and tx version < 2"],
["The End"]
]
diff --git a/src/test/hash_tests.cpp b/src/test/hash_tests.cpp
index 35079d1614..8baaf3645f 100644
--- a/src/test/hash_tests.cpp
+++ b/src/test/hash_tests.cpp
@@ -47,4 +47,24 @@ BOOST_AUTO_TEST_CASE(murmurhash3)
#undef T
}
+BOOST_AUTO_TEST_CASE(siphash)
+{
+ CSipHasher hasher(0x0706050403020100ULL, 0x0F0E0D0C0B0A0908ULL);
+ BOOST_CHECK_EQUAL(hasher.Finalize(), 0x726fdb47dd0e0e31ull);
+ hasher.Write(0x0706050403020100ULL);
+ BOOST_CHECK_EQUAL(hasher.Finalize(), 0x93f5f5799a932462ull);
+ hasher.Write(0x0F0E0D0C0B0A0908ULL);
+ BOOST_CHECK_EQUAL(hasher.Finalize(), 0x3f2acc7f57c29bdbull);
+ hasher.Write(0x1716151413121110ULL);
+ BOOST_CHECK_EQUAL(hasher.Finalize(), 0xb8ad50c6f649af94ull);
+ hasher.Write(0x1F1E1D1C1B1A1918ULL);
+ BOOST_CHECK_EQUAL(hasher.Finalize(), 0x7127512f72f27cceull);
+ hasher.Write(0x2726252423222120ULL);
+ BOOST_CHECK_EQUAL(hasher.Finalize(), 0x0e3ea96b5304a7d0ull);
+ hasher.Write(0x2F2E2D2C2B2A2928ULL);
+ BOOST_CHECK_EQUAL(hasher.Finalize(), 0xe612a3cb9ecba951ull);
+
+ BOOST_CHECK_EQUAL(SipHashUint256(0x0706050403020100ULL, 0x0F0E0D0C0B0A0908ULL, uint256S("1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100")), 0x7127512f72f27cceull);
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp
new file mode 100644
index 0000000000..b38d61f330
--- /dev/null
+++ b/src/test/net_tests.cpp
@@ -0,0 +1,145 @@
+// Copyright (c) 2012-2016 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include "addrman.h"
+#include "test/test_bitcoin.h"
+#include <string>
+#include <boost/test/unit_test.hpp>
+#include "hash.h"
+#include "serialize.h"
+#include "streams.h"
+#include "net.h"
+#include "chainparams.h"
+
+using namespace std;
+
+class CAddrManSerializationMock : public CAddrMan
+{
+public:
+ virtual void Serialize(CDataStream& s, int nType, int nVersionDummy) const = 0;
+
+ //! Ensure that bucket placement is always the same for testing purposes.
+ void MakeDeterministic()
+ {
+ nKey.SetNull();
+ seed_insecure_rand(true);
+ }
+};
+
+class CAddrManUncorrupted : public CAddrManSerializationMock
+{
+public:
+ void Serialize(CDataStream& s, int nType, int nVersionDummy) const
+ {
+ CAddrMan::Serialize(s, nType, nVersionDummy);
+ }
+};
+
+class CAddrManCorrupted : public CAddrManSerializationMock
+{
+public:
+ void Serialize(CDataStream& s, int nType, int nVersionDummy) const
+ {
+ // Produces corrupt output that claims addrman has 20 addrs when it only has one addr.
+ unsigned char nVersion = 1;
+ s << nVersion;
+ s << ((unsigned char)32);
+ s << nKey;
+ s << 10; // nNew
+ s << 10; // nTried
+
+ int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT ^ (1 << 30);
+ s << nUBuckets;
+
+ CAddress addr = CAddress(CService("252.1.1.1", 7777));
+ CAddrInfo info = CAddrInfo(addr, CNetAddr("252.2.2.2"));
+ s << info;
+ }
+};
+
+CDataStream AddrmanToStream(CAddrManSerializationMock& addrman)
+{
+ CDataStream ssPeersIn(SER_DISK, CLIENT_VERSION);
+ ssPeersIn << FLATDATA(Params().MessageStart());
+ ssPeersIn << addrman;
+ std::string str = ssPeersIn.str();
+ vector<unsigned char> vchData(str.begin(), str.end());
+ return CDataStream(vchData, SER_DISK, CLIENT_VERSION);
+}
+
+BOOST_FIXTURE_TEST_SUITE(net_tests, BasicTestingSetup)
+
+BOOST_AUTO_TEST_CASE(caddrdb_read)
+{
+ CAddrManUncorrupted addrmanUncorrupted;
+ addrmanUncorrupted.MakeDeterministic();
+
+ CService addr1 = CService("250.7.1.1", 8333);
+ CService addr2 = CService("250.7.2.2", 9999);
+ CService addr3 = CService("250.7.3.3", 9999);
+
+ // Add three addresses to new table.
+ addrmanUncorrupted.Add(CAddress(addr1), CService("252.5.1.1", 8333));
+ addrmanUncorrupted.Add(CAddress(addr2), CService("252.5.1.1", 8333));
+ addrmanUncorrupted.Add(CAddress(addr3), CService("252.5.1.1", 8333));
+
+ // Test that the de-serialization does not throw an exception.
+ CDataStream ssPeers1 = AddrmanToStream(addrmanUncorrupted);
+ bool exceptionThrown = false;
+ CAddrMan addrman1;
+
+ BOOST_CHECK(addrman1.size() == 0);
+ try {
+ unsigned char pchMsgTmp[4];
+ ssPeers1 >> FLATDATA(pchMsgTmp);
+ ssPeers1 >> addrman1;
+ } catch (const std::exception& e) {
+ exceptionThrown = true;
+ }
+
+ BOOST_CHECK(addrman1.size() == 3);
+ BOOST_CHECK(exceptionThrown == false);
+
+ // Test that CAddrDB::Read creates an addrman with the correct number of addrs.
+ CDataStream ssPeers2 = AddrmanToStream(addrmanUncorrupted);
+
+ CAddrMan addrman2;
+ CAddrDB adb;
+ BOOST_CHECK(addrman2.size() == 0);
+ adb.Read(addrman2, ssPeers2);
+ BOOST_CHECK(addrman2.size() == 3);
+}
+
+
+BOOST_AUTO_TEST_CASE(caddrdb_read_corrupted)
+{
+ CAddrManCorrupted addrmanCorrupted;
+ addrmanCorrupted.MakeDeterministic();
+
+ // Test that the de-serialization of corrupted addrman throws an exception.
+ CDataStream ssPeers1 = AddrmanToStream(addrmanCorrupted);
+ bool exceptionThrown = false;
+ CAddrMan addrman1;
+ BOOST_CHECK(addrman1.size() == 0);
+ try {
+ unsigned char pchMsgTmp[4];
+ ssPeers1 >> FLATDATA(pchMsgTmp);
+ ssPeers1 >> addrman1;
+ } catch (const std::exception& e) {
+ exceptionThrown = true;
+ }
+ // Even through de-serialization failed addrman is not left in a clean state.
+ BOOST_CHECK(addrman1.size() == 1);
+ BOOST_CHECK(exceptionThrown);
+
+ // Test that CAddrDB::Read leaves addrman in a clean state if de-serialization fails.
+ CDataStream ssPeers2 = AddrmanToStream(addrmanCorrupted);
+
+ CAddrMan addrman2;
+ CAddrDB adb;
+ BOOST_CHECK(addrman2.size() == 0);
+ adb.Read(addrman2, ssPeers2);
+ BOOST_CHECK(addrman2.size() == 0);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/scheduler_tests.cpp b/src/test/scheduler_tests.cpp
index 9acd0e2430..aa12dfbd54 100644
--- a/src/test/scheduler_tests.cpp
+++ b/src/test/scheduler_tests.cpp
@@ -40,7 +40,6 @@ static void MicroSleep(uint64_t n)
#endif
}
-#if 0 /* Disabled for now because there is a race condition issue in this test - see #6540 */
BOOST_AUTO_TEST_CASE(manythreads)
{
seed_insecure_rand(false);
@@ -116,6 +115,5 @@ BOOST_AUTO_TEST_CASE(manythreads)
}
BOOST_CHECK_EQUAL(counterSum, 200);
}
-#endif
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp
index 237b26329b..c29e30792a 100644
--- a/src/test/txvalidationcache_tests.cpp
+++ b/src/test/txvalidationcache_tests.cpp
@@ -23,7 +23,7 @@ ToMemPool(CMutableTransaction& tx)
LOCK(cs_main);
CValidationState state;
- return AcceptToMemoryPool(mempool, state, tx, false, NULL, NULL, true, 0);
+ return AcceptToMemoryPool(mempool, state, tx, false, NULL, true, 0);
}
BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup)
diff --git a/src/txmempool.h b/src/txmempool.h
index bca8dd9791..3e1d387975 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -17,6 +17,7 @@
#undef foreach
#include "boost/multi_index_container.hpp"
#include "boost/multi_index/ordered_index.hpp"
+#include "boost/multi_index/hashed_index.hpp"
class CAutoFile;
class CBlockIndex;
@@ -422,7 +423,7 @@ public:
CTxMemPoolEntry,
boost::multi_index::indexed_by<
// sorted by txid
- boost::multi_index::ordered_unique<mempoolentry_txid>,
+ boost::multi_index::hashed_unique<mempoolentry_txid, SaltedTxidHasher>,
// sorted by fee rate
boost::multi_index::ordered_non_unique<
boost::multi_index::tag<descendant_score>,
diff --git a/src/ui_interface.h b/src/ui_interface.h
index a27918c507..7ebfc17e5d 100644
--- a/src/ui_interface.h
+++ b/src/ui_interface.h
@@ -96,6 +96,9 @@ public:
/** New block has been accepted */
boost::signals2::signal<void (bool, const CBlockIndex *)> NotifyBlockTip;
+ /** Best header has changed */
+ boost::signals2::signal<void (bool, const CBlockIndex *)> NotifyHeaderTip;
+
/** Banlist did change. */
boost::signals2::signal<void (void)> BannedListChanged;
};
diff --git a/src/uint256.cpp b/src/uint256.cpp
index c58c88bf4a..f22ddcd1ef 100644
--- a/src/uint256.cpp
+++ b/src/uint256.cpp
@@ -80,67 +80,3 @@ template std::string base_blob<256>::GetHex() const;
template std::string base_blob<256>::ToString() const;
template void base_blob<256>::SetHex(const char*);
template void base_blob<256>::SetHex(const std::string&);
-
-static void inline HashMix(uint32_t& a, uint32_t& b, uint32_t& c)
-{
- // Taken from lookup3, by Bob Jenkins.
- a -= c;
- a ^= ((c << 4) | (c >> 28));
- c += b;
- b -= a;
- b ^= ((a << 6) | (a >> 26));
- a += c;
- c -= b;
- c ^= ((b << 8) | (b >> 24));
- b += a;
- a -= c;
- a ^= ((c << 16) | (c >> 16));
- c += b;
- b -= a;
- b ^= ((a << 19) | (a >> 13));
- a += c;
- c -= b;
- c ^= ((b << 4) | (b >> 28));
- b += a;
-}
-
-static void inline HashFinal(uint32_t& a, uint32_t& b, uint32_t& c)
-{
- // Taken from lookup3, by Bob Jenkins.
- c ^= b;
- c -= ((b << 14) | (b >> 18));
- a ^= c;
- a -= ((c << 11) | (c >> 21));
- b ^= a;
- b -= ((a << 25) | (a >> 7));
- c ^= b;
- c -= ((b << 16) | (b >> 16));
- a ^= c;
- a -= ((c << 4) | (c >> 28));
- b ^= a;
- b -= ((a << 14) | (a >> 18));
- c ^= b;
- c -= ((b << 24) | (b >> 8));
-}
-
-uint64_t uint256::GetHash(const uint256& salt) const
-{
- uint32_t a, b, c;
- const uint32_t *pn = (const uint32_t*)data;
- const uint32_t *salt_pn = (const uint32_t*)salt.data;
- a = b = c = 0xdeadbeef + WIDTH;
-
- a += pn[0] ^ salt_pn[0];
- b += pn[1] ^ salt_pn[1];
- c += pn[2] ^ salt_pn[2];
- HashMix(a, b, c);
- a += pn[3] ^ salt_pn[3];
- b += pn[4] ^ salt_pn[4];
- c += pn[5] ^ salt_pn[5];
- HashMix(a, b, c);
- a += pn[6] ^ salt_pn[6];
- b += pn[7] ^ salt_pn[7];
- HashFinal(a, b, c);
-
- return ((((uint64_t)b) << 32) | c);
-}
diff --git a/src/uint256.h b/src/uint256.h
index bcdb6dd7c2..dd8432d74c 100644
--- a/src/uint256.h
+++ b/src/uint256.h
@@ -83,6 +83,19 @@ public:
return sizeof(data);
}
+ uint64_t GetUint64(int pos) const
+ {
+ const uint8_t* ptr = data + pos * 8;
+ return ((uint64_t)ptr[0]) | \
+ ((uint64_t)ptr[1]) << 8 | \
+ ((uint64_t)ptr[2]) << 16 | \
+ ((uint64_t)ptr[3]) << 24 | \
+ ((uint64_t)ptr[4]) << 32 | \
+ ((uint64_t)ptr[5]) << 40 | \
+ ((uint64_t)ptr[6]) << 48 | \
+ ((uint64_t)ptr[7]) << 56;
+ }
+
template<typename Stream>
void Serialize(Stream& s, int nType, int nVersion) const
{
@@ -127,11 +140,6 @@ public:
{
return ReadLE64(data);
}
-
- /** A more secure, salted hash function.
- * @note This hash is not stable between little and big endian.
- */
- uint64_t GetHash(const uint256& salt) const;
};
/* uint256 from const char *.
diff --git a/src/util.cpp b/src/util.cpp
index 3f0f8be544..80f2193016 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -113,7 +113,7 @@ string strMiscWarning;
bool fLogTimestamps = DEFAULT_LOGTIMESTAMPS;
bool fLogTimeMicros = DEFAULT_LOGTIMEMICROS;
bool fLogIPs = DEFAULT_LOGIPS;
-volatile bool fReopenDebugLog = false;
+volatile sig_atomic_t fReopenDebugLog = false;
CTranslationInterface translationInterface;
/** Init OpenSSL library multithreading support */
diff --git a/src/util.h b/src/util.h
index 45e81ab67f..88a00d3ca1 100644
--- a/src/util.h
+++ b/src/util.h
@@ -28,6 +28,10 @@
#include <boost/signals2/signal.hpp>
#include <boost/thread/exceptions.hpp>
+#ifndef WIN32
+#include <signal.h>
+#endif
+
static const bool DEFAULT_LOGTIMEMICROS = false;
static const bool DEFAULT_LOGIPS = false;
static const bool DEFAULT_LOGTIMESTAMPS = true;
@@ -50,7 +54,7 @@ extern std::string strMiscWarning;
extern bool fLogTimestamps;
extern bool fLogTimeMicros;
extern bool fLogIPs;
-extern volatile bool fReopenDebugLog;
+extern volatile sig_atomic_t fReopenDebugLog;
extern CTranslationInterface translationInterface;
extern const char * const BITCOIN_CONF_FILENAME;
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 623037e766..b9f086b092 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -673,38 +673,6 @@ UniValue getreceivedbyaccount(const UniValue& params, bool fHelp)
}
-CAmount GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth, const isminefilter& filter)
-{
- CAmount nBalance = 0;
-
- // Tally wallet transactions
- for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
- {
- const CWalletTx& wtx = (*it).second;
- if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
- continue;
-
- CAmount nReceived, nSent, nFee;
- wtx.GetAccountAmounts(strAccount, nReceived, nSent, nFee, filter);
-
- if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
- nBalance += nReceived;
- nBalance -= nSent + nFee;
- }
-
- // Tally internal accounting entries
- nBalance += walletdb.GetAccountCreditDebit(strAccount);
-
- return nBalance;
-}
-
-CAmount GetAccountBalance(const string& strAccount, int nMinDepth, const isminefilter& filter)
-{
- CWalletDB walletdb(pwalletMain->strWalletFile);
- return GetAccountBalance(walletdb, strAccount, nMinDepth, filter);
-}
-
-
UniValue getbalance(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
@@ -775,7 +743,7 @@ UniValue getbalance(const UniValue& params, bool fHelp)
string strAccount = AccountFromValue(params[0]);
- CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, filter);
+ CAmount nBalance = pwalletMain->GetAccountBalance(strAccount, nMinDepth, filter);
return ValueFromAmount(nBalance);
}
@@ -923,7 +891,7 @@ UniValue sendfrom(const UniValue& params, bool fHelp)
EnsureWalletIsUnlocked();
// Check funds
- CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
+ CAmount nBalance = pwalletMain->GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
if (nAmount > nBalance)
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
@@ -1026,7 +994,7 @@ UniValue sendmany(const UniValue& params, bool fHelp)
EnsureWalletIsUnlocked();
// Check funds
- CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
+ CAmount nBalance = pwalletMain->GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
if (totalAmount > nBalance)
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
@@ -1836,7 +1804,7 @@ UniValue backupwallet(const UniValue& params, bool fHelp)
LOCK2(cs_main, pwalletMain->cs_wallet);
string strDest = params[0].get_str();
- if (!BackupWallet(*pwalletMain, strDest))
+ if (!pwalletMain->BackupWallet(strDest))
throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
return NullUniValue;
@@ -2233,7 +2201,7 @@ UniValue settxfee(const UniValue& params, bool fHelp)
"settxfee amount\n"
"\nSet the transaction fee per kB. Overwrites the paytxfee parameter.\n"
"\nArguments:\n"
- "1. amount (numeric or sting, required) The transaction fee in " + CURRENCY_UNIT + "/kB\n"
+ "1. amount (numeric or string, required) The transaction fee in " + CURRENCY_UNIT + "/kB\n"
"\nResult\n"
"true|false (boolean) Returns true if successful\n"
"\nExamples:\n"
@@ -2328,8 +2296,6 @@ UniValue listunspent(const UniValue& params, bool fHelp)
"\nReturns array of unspent transaction outputs\n"
"with between minconf and maxconf (inclusive) confirmations.\n"
"Optionally filter to only include txouts paid to specified addresses.\n"
- "Results are an array of Objects, each of which has:\n"
- "{txid, vout, scriptPubKey, amount, confirmations}\n"
"\nArguments:\n"
"1. minconf (numeric, optional, default=1) The minimum confirmations to filter\n"
"2. maxconf (numeric, optional, default=9999999) The maximum confirmations to filter\n"
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 29d7138547..5d1a431190 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -368,6 +368,7 @@ void CWallet::Flush(bool shutdown)
bool CWallet::Verify()
{
+ LogPrintf("Using BerkeleyDB version %s\n", DbEnv::version(0, 0, 0));
std::string walletFile = GetArg("-wallet", DEFAULT_WALLET_DAT);
LogPrintf("Using wallet %s\n", walletFile);
@@ -729,7 +730,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletD
// Write to disk
if (fInsertedNew || fUpdated)
- if (!wtx.WriteToDisk(pwalletdb))
+ if (!pwalletdb->WriteTx(wtx))
return false;
// Break debit/credit balance caches:
@@ -829,7 +830,7 @@ bool CWallet::AbandonTransaction(const uint256& hashTx)
wtx.nIndex = -1;
wtx.setAbandoned();
wtx.MarkDirty();
- wtx.WriteToDisk(&walletdb);
+ walletdb.WriteTx(wtx);
NotifyTransactionChanged(this, wtx.GetHash(), CT_UPDATED);
// Iterate over all its outputs, and mark transactions in the wallet that spend them abandoned too
TxSpends::const_iterator iter = mapTxSpends.lower_bound(COutPoint(hashTx, 0));
@@ -891,7 +892,7 @@ void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx)
wtx.nIndex = -1;
wtx.hashBlock = hashBlock;
wtx.MarkDirty();
- wtx.WriteToDisk(&walletdb);
+ walletdb.WriteTx(wtx);
// Iterate over all its outputs, and mark transactions in the wallet that spend them conflicted too
TxSpends::const_iterator iter = mapTxSpends.lower_bound(COutPoint(now, 0));
while (iter != mapTxSpends.end() && iter->first.hash == now) {
@@ -1186,12 +1187,6 @@ void CWalletTx::GetAccountAmounts(const string& strAccount, CAmount& nReceived,
}
}
-
-bool CWalletTx::WriteToDisk(CWalletDB *pwalletdb)
-{
- return pwalletdb->WriteTx(GetHash(), *this);
-}
-
/**
* Scan the block chain (starting in pindexStart) for transactions
* from or to us. If fUpdate is true, found transactions that already
@@ -1277,9 +1272,7 @@ bool CWalletTx::RelayWalletTransaction()
{
if (GetDepthInMainChain() == 0 && !isAbandoned() && InMempool()) {
LogPrintf("Relaying wtx %s\n", GetHash().ToString());
- CFeeRate feeRate;
- mempool.lookupFeeRate(GetHash(), feeRate);
- RelayTransaction((CTransaction)*this, feeRate);
+ RelayTransaction((CTransaction)*this);
return true;
}
}
@@ -2766,6 +2759,37 @@ set< set<CTxDestination> > CWallet::GetAddressGroupings()
return ret;
}
+CAmount CWallet::GetAccountBalance(const std::string& strAccount, int nMinDepth, const isminefilter& filter)
+{
+ CWalletDB walletdb(strWalletFile);
+ return GetAccountBalance(walletdb, strAccount, nMinDepth, filter);
+}
+
+CAmount CWallet::GetAccountBalance(CWalletDB& walletdb, const std::string& strAccount, int nMinDepth, const isminefilter& filter)
+{
+ CAmount nBalance = 0;
+
+ // Tally wallet transactions
+ for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ {
+ const CWalletTx& wtx = (*it).second;
+ if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
+ continue;
+
+ CAmount nReceived, nSent, nFee;
+ wtx.GetAccountAmounts(strAccount, nReceived, nSent, nFee, filter);
+
+ if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
+ nBalance += nReceived;
+ nBalance -= nSent + nFee;
+ }
+
+ // Tally internal accounting entries
+ nBalance += walletdb.GetAccountCreditDebit(strAccount);
+
+ return nBalance;
+}
+
std::set<CTxDestination> CWallet::GetAccountAddresses(const std::string& strAccount) const
{
LOCK(cs_wallet);
@@ -3194,7 +3218,7 @@ bool CWallet::InitLoadWallet()
copyTo->fFromMe = copyFrom->fFromMe;
copyTo->strFromAccount = copyFrom->strFromAccount;
copyTo->nOrderPos = copyFrom->nOrderPos;
- copyTo->WriteToDisk(&walletdb);
+ walletdb.WriteTx(*copyTo);
}
}
}
@@ -3259,6 +3283,46 @@ bool CWallet::ParameterInteraction()
return true;
}
+bool CWallet::BackupWallet(const std::string& strDest)
+{
+ if (!fFileBacked)
+ return false;
+ while (true)
+ {
+ {
+ LOCK(bitdb.cs_db);
+ if (!bitdb.mapFileUseCount.count(strWalletFile) || bitdb.mapFileUseCount[strWalletFile] == 0)
+ {
+ // Flush log data to the dat file
+ bitdb.CloseDb(strWalletFile);
+ bitdb.CheckpointLSN(strWalletFile);
+ bitdb.mapFileUseCount.erase(strWalletFile);
+
+ // Copy wallet file
+ boost::filesystem::path pathSrc = GetDataDir() / strWalletFile;
+ boost::filesystem::path pathDest(strDest);
+ if (boost::filesystem::is_directory(pathDest))
+ pathDest /= strWalletFile;
+
+ try {
+#if BOOST_VERSION >= 104000
+ boost::filesystem::copy_file(pathSrc, pathDest, boost::filesystem::copy_option::overwrite_if_exists);
+#else
+ boost::filesystem::copy_file(pathSrc, pathDest);
+#endif
+ LogPrintf("copied %s to %s\n", strWalletFile, pathDest.string());
+ return true;
+ } catch (const boost::filesystem::filesystem_error& e) {
+ LogPrintf("error copying %s to %s - %s\n", strWalletFile, pathDest.string(), e.what());
+ return false;
+ }
+ }
+ }
+ MilliSleep(100);
+ }
+ return false;
+}
+
CKeyPool::CKeyPool()
{
nTime = GetTime();
@@ -3336,5 +3400,5 @@ int CMerkleTx::GetBlocksToMaturity() const
bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, CAmount nAbsurdFee)
{
CValidationState state;
- return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, NULL, false, nAbsurdFee);
+ return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, false, nAbsurdFee);
}
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index c3bd343edd..b2180a5a26 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -394,8 +394,6 @@ public:
bool InMempool() const;
bool IsTrusted() const;
- bool WriteToDisk(CWalletDB *pwalletdb);
-
int64_t GetTxTime() const;
int GetRequestCount() const;
@@ -778,6 +776,8 @@ public:
std::set< std::set<CTxDestination> > GetAddressGroupings();
std::map<CTxDestination, CAmount> GetAddressBalances();
+ CAmount GetAccountBalance(const std::string& strAccount, int nMinDepth, const isminefilter& filter);
+ CAmount GetAccountBalance(CWalletDB& walletdb, const std::string& strAccount, int nMinDepth, const isminefilter& filter);
std::set<CTxDestination> GetAccountAddresses(const std::string& strAccount) const;
isminetype IsMine(const CTxIn& txin) const;
@@ -885,6 +885,8 @@ public:
/* Wallets parameter interaction */
static bool ParameterInteraction();
+
+ bool BackupWallet(const std::string& strDest);
};
/** A key allocated from the key pool. */
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index f2b5408e92..b5037c9a65 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -55,10 +55,10 @@ bool CWalletDB::ErasePurpose(const string& strPurpose)
return Erase(make_pair(string("purpose"), strPurpose));
}
-bool CWalletDB::WriteTx(uint256 hash, const CWalletTx& wtx)
+bool CWalletDB::WriteTx(const CWalletTx& wtx)
{
nWalletDBUpdated++;
- return Write(std::make_pair(std::string("tx"), hash), wtx);
+ return Write(std::make_pair(std::string("tx"), wtx.GetHash()), wtx);
}
bool CWalletDB::EraseTx(uint256 hash)
@@ -291,7 +291,7 @@ DBErrors CWalletDB::ReorderTransactions(CWallet* pwallet)
if (pwtx)
{
- if (!WriteTx(pwtx->GetHash(), *pwtx))
+ if (!WriteTx(*pwtx))
return DB_LOAD_FAIL;
}
else
@@ -315,7 +315,7 @@ DBErrors CWalletDB::ReorderTransactions(CWallet* pwallet)
// Since we're changing the order, write it back
if (pwtx)
{
- if (!WriteTx(pwtx->GetHash(), *pwtx))
+ if (!WriteTx(*pwtx))
return DB_LOAD_FAIL;
}
else
@@ -698,7 +698,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
pwallet->nTimeFirstKey = 1; // 0 would be considered 'no value'
BOOST_FOREACH(uint256 hash, wss.vWalletUpgrade)
- WriteTx(hash, pwallet->mapWallet[hash]);
+ WriteTx(pwallet->mapWallet[hash]);
// Rewrite encrypted wallets of versions 0.4.0 and 0.5.0rc:
if (wss.fIsEncrypted && (wss.nFileVersion == 40000 || wss.nFileVersion == 50000))
@@ -903,46 +903,6 @@ void ThreadFlushWalletDB(const string& strFile)
}
}
-bool BackupWallet(const CWallet& wallet, const string& strDest)
-{
- if (!wallet.fFileBacked)
- return false;
- while (true)
- {
- {
- LOCK(bitdb.cs_db);
- if (!bitdb.mapFileUseCount.count(wallet.strWalletFile) || bitdb.mapFileUseCount[wallet.strWalletFile] == 0)
- {
- // Flush log data to the dat file
- bitdb.CloseDb(wallet.strWalletFile);
- bitdb.CheckpointLSN(wallet.strWalletFile);
- bitdb.mapFileUseCount.erase(wallet.strWalletFile);
-
- // Copy wallet file
- boost::filesystem::path pathSrc = GetDataDir() / wallet.strWalletFile;
- boost::filesystem::path pathDest(strDest);
- if (boost::filesystem::is_directory(pathDest))
- pathDest /= wallet.strWalletFile;
-
- try {
-#if BOOST_VERSION >= 104000
- boost::filesystem::copy_file(pathSrc, pathDest, boost::filesystem::copy_option::overwrite_if_exists);
-#else
- boost::filesystem::copy_file(pathSrc, pathDest);
-#endif
- LogPrintf("copied %s to %s\n", wallet.strWalletFile, pathDest.string());
- return true;
- } catch (const boost::filesystem::filesystem_error& e) {
- LogPrintf("error copying %s to %s - %s\n", wallet.strWalletFile, pathDest.string(), e.what());
- return false;
- }
- }
- }
- MilliSleep(100);
- }
- return false;
-}
-
//
// Try to (very carefully!) recover wallet file if there is a problem.
//
diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h
index fe6c366343..00c10ea70f 100644
--- a/src/wallet/walletdb.h
+++ b/src/wallet/walletdb.h
@@ -87,7 +87,7 @@ public:
bool WritePurpose(const std::string& strAddress, const std::string& purpose);
bool ErasePurpose(const std::string& strAddress);
- bool WriteTx(uint256 hash, const CWalletTx& wtx);
+ bool WriteTx(const CWalletTx& wtx);
bool EraseTx(uint256 hash);
bool WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, const CKeyMetadata &keyMeta);
@@ -141,7 +141,6 @@ private:
bool WriteAccountingEntry(const uint64_t nAccEntryNum, const CAccountingEntry& acentry);
};
-bool BackupWallet(const CWallet& wallet, const std::string& strDest);
void ThreadFlushWalletDB(const std::string& strFile);
#endif // BITCOIN_WALLET_WALLETDB_H