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
-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.py3
-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/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.py29
-rw-r--r--qa/rpc-tests/test_framework/util.py39
-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.test.include1
-rw-r--r--src/addrman.h8
-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.cpp28
-rw-r--r--src/main.cpp99
-rw-r--r--src/main.h4
-rw-r--r--src/net.cpp253
-rw-r--r--src/net.h4
-rw-r--r--src/netbase.cpp37
-rw-r--r--src/qt/bitcoingui.cpp30
-rw-r--r--src/qt/bitcoingui.h3
-rw-r--r--src/qt/clientmodel.cpp18
-rw-r--r--src/qt/clientmodel.h2
-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.cpp2
-rw-r--r--src/qt/transactionview.cpp2
-rw-r--r--src/rpc/net.cpp10
-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/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/wallet/rpcwallet.cpp4
93 files changed, 944 insertions, 464 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/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 a8fb878dcb..aae258315e 100755
--- a/qa/rpc-tests/bip9-softforks.py
+++ b/qa/rpc-tests/bip9-softforks.py
@@ -32,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])
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/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 3480de6c6e..49f4192269 100755
--- a/qa/rpc-tests/test_framework/test_framework.py
+++ b/qa/rpc-tests/test_framework/test_framework.py
@@ -15,7 +15,6 @@ import traceback
from .util import (
initialize_chain,
- assert_equal,
start_nodes,
connect_nodes_bi,
sync_blocks,
@@ -32,21 +31,26 @@ 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()
@@ -161,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")
@@ -181,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",
@@ -193,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 6784177aaa..3948b664e3 100644
--- a/qa/rpc-tests/test_framework/util.py
+++ b/qa/rpc-tests/test_framework/util.py
@@ -35,6 +35,8 @@ 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
@@ -182,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:
@@ -212,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()
@@ -238,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)
@@ -325,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):
@@ -343,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.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/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 fd1241d930..f95027410d 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -327,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
@@ -404,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) + ". " +
@@ -554,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);
@@ -581,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);
@@ -595,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 {
@@ -603,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();
@@ -1158,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";
@@ -1219,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);
@@ -1248,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;
}
@@ -1358,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"))
{
diff --git a/src/main.cpp b/src/main.cpp
index 09f82312a9..9ba90b4ead 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -2811,10 +2811,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);
@@ -2884,6 +2883,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
@@ -2902,15 +2923,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();
@@ -3398,11 +3426,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;
@@ -3474,7 +3503,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);
@@ -3492,6 +3521,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__);
@@ -4037,15 +4068,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);
@@ -4057,10 +4099,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());
@@ -4068,6 +4111,7 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB
}
range.first++;
mapBlocksUnknownParent.erase(it);
+ NotifyHeaderTip();
}
}
} catch (const std::exception& e) {
@@ -4698,25 +4742,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);
}
}
@@ -5079,6 +5121,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) {
@@ -5086,6 +5129,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;
@@ -5106,7 +5156,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.
@@ -5162,6 +5212,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 576f73b5f2..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) */
diff --git a/src/net.cpp b/src/net.cpp
index aa5b47340a..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();
}
@@ -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 fd80056c6b..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();
@@ -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/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index 9984486364..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)));
@@ -696,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;
@@ -708,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;
@@ -901,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)
{
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index 27ef11c75c..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
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/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 54ebd25833..6d50be56ec 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -124,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()));
}
}
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/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/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/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/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 623037e766..27596929f1 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -2233,7 +2233,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 +2328,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"