diff options
60 files changed, 602 insertions, 263 deletions
diff --git a/contrib/devtools/git-subtree-check.sh b/contrib/devtools/git-subtree-check.sh index 1cb82fe682..2384d66cad 100755 --- a/contrib/devtools/git-subtree-check.sh +++ b/contrib/devtools/git-subtree-check.sh @@ -1,4 +1,7 @@ #!/bin/sh +# Copyright (c) 2015 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. DIR="$1" COMMIT="$2" diff --git a/contrib/devtools/optimize-pngs.py b/contrib/devtools/optimize-pngs.py index 799e0cc7d0..b7b8dc0082 100755 --- a/contrib/devtools/optimize-pngs.py +++ b/contrib/devtools/optimize-pngs.py @@ -1,4 +1,7 @@ #!/usr/bin/env python +# Copyright (c) 2014-2015 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. ''' Run this script every time you change one of the png files. Using pngcrush, it will optimize the png files, remove various color profiles, remove ancillary chunks (alla) and text chunks (text). #pngcrush -brute -ow -rem gAMA -rem cHRM -rem iCCP -rem sRGB -rem alla -rem text diff --git a/contrib/devtools/security-check.py b/contrib/devtools/security-check.py index c61d652641..b4b4b4603d 100755 --- a/contrib/devtools/security-check.py +++ b/contrib/devtools/security-check.py @@ -1,4 +1,7 @@ #!/usr/bin/env python +# Copyright (c) 2015-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. ''' Perform basic ELF security checks on a series of executables. Exit status will be 0 if successful, and the program will be silent. diff --git a/contrib/devtools/test-security-check.py b/contrib/devtools/test-security-check.py index 324b7bcd85..c0f120392e 100755 --- a/contrib/devtools/test-security-check.py +++ b/contrib/devtools/test-security-check.py @@ -1,4 +1,7 @@ #!/usr/bin/env python2 +# Copyright (c) 2015-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. ''' Test script for security-check.py ''' diff --git a/contrib/gitian-build.sh b/contrib/gitian-build.sh index ee47d138f3..53c24e3a87 100755 --- a/contrib/gitian-build.sh +++ b/contrib/gitian-build.sh @@ -1,3 +1,7 @@ +# Copyright (c) 2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + # What to do sign=false verify=false diff --git a/contrib/macdeploy/detached-sig-apply.sh b/contrib/macdeploy/detached-sig-apply.sh index 781fe315ed..91674a92e6 100755 --- a/contrib/macdeploy/detached-sig-apply.sh +++ b/contrib/macdeploy/detached-sig-apply.sh @@ -1,4 +1,8 @@ #!/bin/sh +# Copyright (c) 2014-2015 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + set -e UNSIGNED="$1" diff --git a/contrib/macdeploy/detached-sig-create.sh b/contrib/macdeploy/detached-sig-create.sh index 89a2da32f7..5022ea88bc 100755 --- a/contrib/macdeploy/detached-sig-create.sh +++ b/contrib/macdeploy/detached-sig-create.sh @@ -1,4 +1,8 @@ #!/bin/sh +# Copyright (c) 2014-2015 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + set -e ROOTDIR=dist diff --git a/contrib/macdeploy/extract-osx-sdk.sh b/contrib/macdeploy/extract-osx-sdk.sh index 46d2d825d4..ff9fbd58df 100755 --- a/contrib/macdeploy/extract-osx-sdk.sh +++ b/contrib/macdeploy/extract-osx-sdk.sh @@ -1,4 +1,8 @@ #!/bin/bash +# Copyright (c) 2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + set -e INPUTFILE="Xcode_7.3.1.dmg" diff --git a/contrib/qos/tc.sh b/contrib/qos/tc.sh index f620604212..aaf5e1fa11 100644 --- a/contrib/qos/tc.sh +++ b/contrib/qos/tc.sh @@ -1,3 +1,7 @@ +# Copyright (c) 2013 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + #network interface on which to limit traffic IF="eth0" #limit of the network interface in question diff --git a/contrib/qt_translations.py b/contrib/qt_translations.py deleted file mode 100755 index fd8a8b7129..0000000000 --- a/contrib/qt_translations.py +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env python - -# Helpful little script that spits out a comma-separated list of -# language codes for Qt icons that should be included -# in binary bitcoin distributions - -import glob -import os -import re -import sys - -if len(sys.argv) != 3: - sys.exit("Usage: %s $QTDIR/translations $BITCOINDIR/src/qt/locale"%sys.argv[0]) - -d1 = sys.argv[1] -d2 = sys.argv[2] - -l1 = set([ re.search(r'qt_(.*).qm', f).group(1) for f in glob.glob(os.path.join(d1, 'qt_*.qm')) ]) -l2 = set([ re.search(r'bitcoin_(.*).qm', f).group(1) for f in glob.glob(os.path.join(d2, 'bitcoin_*.qm')) ]) - -print ",".join(sorted(l1.intersection(l2))) - diff --git a/contrib/seeds/makeseeds.py b/contrib/seeds/makeseeds.py index 4072405ef5..041f224f40 100755 --- a/contrib/seeds/makeseeds.py +++ b/contrib/seeds/makeseeds.py @@ -1,4 +1,7 @@ #!/usr/bin/env python +# Copyright (c) 2013-2015 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. # # Generate seeds.txt from Pieter's DNS seeder # diff --git a/contrib/spendfrom/setup.py b/contrib/spendfrom/setup.py index 01b9768a5b..f80736752a 100644 --- a/contrib/spendfrom/setup.py +++ b/contrib/spendfrom/setup.py @@ -1,3 +1,6 @@ +# Copyright (c) 2013 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. from distutils.core import setup setup(name='btcspendfrom', version='1.0', diff --git a/contrib/spendfrom/spendfrom.py b/contrib/spendfrom/spendfrom.py index 72ee0425eb..086b91b267 100755 --- a/contrib/spendfrom/spendfrom.py +++ b/contrib/spendfrom/spendfrom.py @@ -1,4 +1,7 @@ #!/usr/bin/env python +# Copyright (c) 2013 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. # # Use the raw transactions API to spend bitcoins received on particular addresses, # and send any change back to that same address. diff --git a/contrib/testgen/base58.py b/contrib/testgen/base58.py index b716495145..72b288b2dc 100644 --- a/contrib/testgen/base58.py +++ b/contrib/testgen/base58.py @@ -1,3 +1,6 @@ +# Copyright (c) 2012 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. ''' Bitcoin base58 encoding and decoding. diff --git a/contrib/testgen/gen_base58_test_vectors.py b/contrib/testgen/gen_base58_test_vectors.py index 1813436953..8518774db3 100755 --- a/contrib/testgen/gen_base58_test_vectors.py +++ b/contrib/testgen/gen_base58_test_vectors.py @@ -1,4 +1,7 @@ #!/usr/bin/env python +# Copyright (c) 2012 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. ''' Generate valid and invalid base58 address and private key test vectors. diff --git a/contrib/tidy_datadir.sh b/contrib/tidy_datadir.sh index 5d6d826444..8960f8811d 100755 --- a/contrib/tidy_datadir.sh +++ b/contrib/tidy_datadir.sh @@ -1,4 +1,7 @@ #!/bin/bash +# Copyright (c) 2013 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. if [ -d "$1" ]; then cd "$1" diff --git a/contrib/verify-commits/gpg.sh b/contrib/verify-commits/gpg.sh index 375d711725..09ff237544 100755 --- a/contrib/verify-commits/gpg.sh +++ b/contrib/verify-commits/gpg.sh @@ -1,4 +1,8 @@ #!/bin/sh +# Copyright (c) 2014-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. + INPUT=$(cat /dev/stdin) VALID=false REVSIG=false diff --git a/contrib/verify-commits/pre-push-hook.sh b/contrib/verify-commits/pre-push-hook.sh index c57222818a..c21febb9e9 100755 --- a/contrib/verify-commits/pre-push-hook.sh +++ b/contrib/verify-commits/pre-push-hook.sh @@ -1,4 +1,8 @@ #!/bin/bash +# Copyright (c) 2014-2015 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + if ! [[ "$2" =~ ^(git@)?(www.)?github.com(:|/)bitcoin/bitcoin(.git)?$ ]]; then exit 0 fi diff --git a/contrib/verify-commits/verify-commits.sh b/contrib/verify-commits/verify-commits.sh index 5219331e2e..cfe4f11a0b 100755 --- a/contrib/verify-commits/verify-commits.sh +++ b/contrib/verify-commits/verify-commits.sh @@ -1,4 +1,8 @@ #!/bin/sh +# Copyright (c) 2014-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. + # Not technically POSIX-compliant due to use of "local", but almost every # shell anyone uses today supports it, so its probably fine diff --git a/contrib/verifybinaries/verify.sh b/contrib/verifybinaries/verify.sh index e22b911743..e20770c96a 100755 --- a/contrib/verifybinaries/verify.sh +++ b/contrib/verifybinaries/verify.sh @@ -1,4 +1,7 @@ #!/bin/bash +# Copyright (c) 2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. ### This script attempts to download the signature file SHA256SUMS.asc from bitcoin.org ### It first checks if the signature passes, and then downloads the files specified in diff --git a/contrib/zmq/zmq_sub.py b/contrib/zmq/zmq_sub.py index 6268123dd8..3dea5e3c14 100755 --- a/contrib/zmq/zmq_sub.py +++ b/contrib/zmq/zmq_sub.py @@ -1,4 +1,7 @@ #!/usr/bin/env python2 +# Copyright (c) 2014-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. import array import binascii diff --git a/doc/build-osx.md b/doc/build-osx.md index c9eb4225ab..bc90a30562 100644 --- a/doc/build-osx.md +++ b/doc/build-osx.md @@ -16,7 +16,7 @@ Then install [Homebrew](http://brew.sh). Dependencies ---------------------- - brew install automake berkeley-db4 libtool boost --c++11 miniupnpc openssl pkg-config protobuf --c++11 qt5 libevent + brew install automake berkeley-db4 libtool boost --c++11 miniupnpc openssl pkg-config homebrew/versions/protobuf260 --c++11 qt5 libevent NOTE: Building with Qt4 is still supported, however, could result in a broken UI. Building with Qt5 is recommended. diff --git a/doc/gitian-building.md b/doc/gitian-building.md index 938f92ff12..4914d90df4 100644 --- a/doc/gitian-building.md +++ b/doc/gitian-building.md @@ -95,14 +95,14 @@ After creating the VM, we need to configure it. - Click `Ok` twice to save. -Get the [Debian 8.x net installer](http://cdimage.debian.org/debian-cd/8.5.0/amd64/iso-cd/debian-8.5.0-amd64-netinst.iso) (a more recent minor version should also work, see also [Debian Network installation](https://www.debian.org/CD/netinst/)). -This DVD image can be validated using a SHA256 hashing tool, for example on +Get the [Debian 8.x net installer](http://cdimage.debian.org/mirror/cdimage/archive/8.5.0/amd64/iso-cd/debian-8.5.0-amd64-netinst.iso) (a more recent minor version should also work, see also [Debian Network installation](https://www.debian.org/CD/netinst/)). +This DVD image can be [validated](https://www.debian.org/CD/verify) using a SHA256 hashing tool, for example on Unixy OSes by entering the following in a terminal: echo "ad4e8c27c561ad8248d5ebc1d36eb172f884057bfeb2c22ead823f59fa8c3dff debian-8.5.0-amd64-netinst.iso" | sha256sum -c # (must return OK) -Then start the VM. On the first launch you will be asked for a CD or DVD image. Choose the downloaded iso. +Then start the VM. On the first launch you will be asked for a CD or DVD image. Choose the downloaded ISO. ![](gitian-building/select_startup_disk.png) @@ -336,8 +336,8 @@ There will be a lot of warnings printed during the build of the image. These can Getting and building the inputs -------------------------------- -Follow the instructions in [doc/release-process.md](release-process.md#fetch-and-build-inputs-first-time-or-when-dependency-versions-change) -in the bitcoin repository under 'Fetch and build inputs' to install sources which require +Follow the instructions in [doc/release-process.md](release-process.md#fetch-and-create-inputs-first-time-or-when-dependency-versions-change) +in the bitcoin repository under 'Fetch and create inputs' to install sources which require manual intervention. Also optionally follow the next step: 'Seed the Gitian sources cache and offline git repositories' which will fetch the remaining files required for building offline. diff --git a/doc/translation_process.md b/doc/translation_process.md index a443a16fe2..9e9ced2457 100644 --- a/doc/translation_process.md +++ b/doc/translation_process.md @@ -6,7 +6,7 @@ The Bitcoin-Core project has been designed to support multiple localisations. Th ### Helping to translate (using Transifex) Transifex is setup to monitor the Github repo for updates, and when code containing new translations is found, Transifex will process any changes. It may take several hours after a pull-request has been merged, to appear in the Transifex web interface. -Multiple language support is critical in assisting Bitcoin’s global adoption, and growth. One of Bitcoin’s greatest strengths is cross-boarder money transfers, any help making that easier is greatly appreciated. +Multiple language support is critical in assisting Bitcoin’s global adoption, and growth. One of Bitcoin’s greatest strengths is cross-border money transfers, any help making that easier is greatly appreciated. See the [Transifex Bitcoin project](https://www.transifex.com/projects/p/bitcoin/) to assist in translations. You should also join the translation mailing list for announcements - see details below. diff --git a/qa/pull-tester/rpc-tests.py b/qa/pull-tester/rpc-tests.py index 771f6c7a0f..9e187b019b 100755 --- a/qa/pull-tester/rpc-tests.py +++ b/qa/pull-tester/rpc-tests.py @@ -251,21 +251,27 @@ class RPCTestHandler: self.num_running += 1 t = self.test_list.pop(0) port_seed = ["--portseed=%s" % len(self.test_list)] + log_stdout = tempfile.SpooledTemporaryFile(max_size=2**16) + log_stderr = tempfile.SpooledTemporaryFile(max_size=2**16) self.jobs.append((t, time.time(), subprocess.Popen((RPC_TESTS_DIR + t).split() + self.flags + port_seed, universal_newlines=True, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE))) + stdout=log_stdout, + stderr=log_stderr), + log_stdout, + log_stderr)) if not self.jobs: raise IndexError('pop from empty list') while True: # Return first proc that finishes time.sleep(.5) for j in self.jobs: - (name, time0, proc) = j + (name, time0, proc, log_out, log_err) = j if proc.poll() is not None: - (stdout, stderr) = proc.communicate(timeout=3) + log_out.seek(0), log_err.seek(0) + [stdout, stderr] = [l.read().decode('utf-8') for l in (log_out, log_err)] + log_out.close(), log_err.close() passed = stderr == "" and proc.returncode == 0 self.num_running -= 1 self.jobs.remove(j) diff --git a/qa/rpc-tests/create_cache.py b/qa/rpc-tests/create_cache.py index b6161e0917..1ace6310d0 100755 --- a/qa/rpc-tests/create_cache.py +++ b/qa/rpc-tests/create_cache.py @@ -12,9 +12,15 @@ from test_framework.test_framework import BitcoinTestFramework class CreateCache(BitcoinTestFramework): + def __init__(self): + super().__init__() + + # Test network and test nodes are not required: + self.num_nodes = 0 + self.nodes = [] + def setup_network(self): - # Don't setup any test nodes - self.options.noshutdown = True + pass def run_test(self): pass diff --git a/qa/rpc-tests/p2p-compactblocks.py b/qa/rpc-tests/p2p-compactblocks.py index 7fe7ecc16c..bf4fb43add 100755 --- a/qa/rpc-tests/p2p-compactblocks.py +++ b/qa/rpc-tests/p2p-compactblocks.py @@ -78,6 +78,13 @@ class TestNode(SingleNodeConnCB): headers_message.headers = [CBlockHeader(b) for b in new_blocks] self.send_message(headers_message) + def request_headers_and_sync(self, locator, hashstop=0): + self.clear_block_announcement() + self.get_headers(locator, hashstop) + assert(wait_until(self.received_block_announcement, timeout=30)) + assert(self.received_block_announcement()) + self.clear_block_announcement() + class CompactBlocksTest(BitcoinTestFramework): def __init__(self): @@ -130,7 +137,7 @@ class CompactBlocksTest(BitcoinTestFramework): # Test "sendcmpct": # - No compact block announcements or getdata(MSG_CMPCT_BLOCK) unless # sendcmpct is sent. - # - If sendcmpct is sent with version > 0, the message is ignored. + # - If sendcmpct is sent with version > 1, the message is ignored. # - If sendcmpct is sent with boolean 0, then block announcements are not # made with compact blocks. # - If sendcmpct is then sent with boolean 1, then new block announcements @@ -142,57 +149,66 @@ class CompactBlocksTest(BitcoinTestFramework): def received_sendcmpct(): return (self.test_node.last_sendcmpct is not None) got_message = wait_until(received_sendcmpct, timeout=30) + assert(received_sendcmpct()) assert(got_message) assert_equal(self.test_node.last_sendcmpct.version, 1) tip = int(self.nodes[0].getbestblockhash(), 16) def check_announcement_of_new_block(node, peer, predicate): - self.test_node.clear_block_announcement() + peer.clear_block_announcement() node.generate(1) - got_message = wait_until(peer.received_block_announcement, timeout=30) + got_message = wait_until(lambda: peer.block_announced, timeout=30) + assert(peer.block_announced) assert(got_message) with mininode_lock: - assert(predicate) + assert(predicate(peer)) # We shouldn't get any block announcements via cmpctblock yet. - check_announcement_of_new_block(self.nodes[0], self.test_node, lambda: self.test_node.last_cmpctblock is None) + check_announcement_of_new_block(self.nodes[0], self.test_node, lambda p: p.last_cmpctblock is None) # Try one more time, this time after requesting headers. - self.test_node.clear_block_announcement() - self.test_node.get_headers(locator=[tip], hashstop=0) - wait_until(self.test_node.received_block_announcement, timeout=30) - self.test_node.clear_block_announcement() + self.test_node.request_headers_and_sync(locator=[tip]) + check_announcement_of_new_block(self.nodes[0], self.test_node, lambda p: p.last_cmpctblock is None and p.last_inv is not None) - check_announcement_of_new_block(self.nodes[0], self.test_node, lambda: self.test_node.last_cmpctblock is None and self.test_node.last_inv is not None) + # Test a few ways of using sendcmpct that should NOT + # result in compact block announcements. + # Before each test, sync the headers chain. + self.test_node.request_headers_and_sync(locator=[tip]) # Now try a SENDCMPCT message with too-high version sendcmpct = msg_sendcmpct() sendcmpct.version = 2 - self.test_node.send_message(sendcmpct) + self.test_node.send_and_ping(sendcmpct) + check_announcement_of_new_block(self.nodes[0], self.test_node, lambda p: p.last_cmpctblock is None) - check_announcement_of_new_block(self.nodes[0], self.test_node, lambda: self.test_node.last_cmpctblock is None) + # Headers sync before next test. + self.test_node.request_headers_and_sync(locator=[tip]) # Now try a SENDCMPCT message with valid version, but announce=False - self.test_node.send_message(msg_sendcmpct()) - check_announcement_of_new_block(self.nodes[0], self.test_node, lambda: self.test_node.last_cmpctblock is None) + self.test_node.send_and_ping(msg_sendcmpct()) + check_announcement_of_new_block(self.nodes[0], self.test_node, lambda p: p.last_cmpctblock is None) + + # Headers sync before next test. + self.test_node.request_headers_and_sync(locator=[tip]) # Finally, try a SENDCMPCT message with announce=True sendcmpct.version = 1 sendcmpct.announce = True - self.test_node.send_message(sendcmpct) - check_announcement_of_new_block(self.nodes[0], self.test_node, lambda: self.test_node.last_cmpctblock is not None) + self.test_node.send_and_ping(sendcmpct) + check_announcement_of_new_block(self.nodes[0], self.test_node, lambda p: p.last_cmpctblock is not None) - # Try one more time - check_announcement_of_new_block(self.nodes[0], self.test_node, lambda: self.test_node.last_cmpctblock is not None) + # Try one more time (no headers sync should be needed!) + check_announcement_of_new_block(self.nodes[0], self.test_node, lambda p: p.last_cmpctblock is not None) # Try one more time, after turning on sendheaders - self.test_node.send_message(msg_sendheaders()) - check_announcement_of_new_block(self.nodes[0], self.test_node, lambda: self.test_node.last_cmpctblock is not None) + self.test_node.send_and_ping(msg_sendheaders()) + check_announcement_of_new_block(self.nodes[0], self.test_node, lambda p: p.last_cmpctblock is not None) # Now turn off announcements sendcmpct.announce = False - check_announcement_of_new_block(self.nodes[0], self.test_node, lambda: self.test_node.last_cmpctblock is None and self.test_node.last_headers is not None) + self.test_node.send_and_ping(sendcmpct) + check_announcement_of_new_block(self.nodes[0], self.test_node, lambda p: p.last_cmpctblock is None and p.last_headers is not None) # This test actually causes bitcoind to (reasonably!) disconnect us, so do this last. def test_invalid_cmpctblock_message(self): diff --git a/qa/rpc-tests/test_framework/blockstore.py b/qa/rpc-tests/test_framework/blockstore.py index 6120dd574b..1e2bbb277a 100644 --- a/qa/rpc-tests/test_framework/blockstore.py +++ b/qa/rpc-tests/test_framework/blockstore.py @@ -1,4 +1,7 @@ #!/usr/bin/env python3 +# Copyright (c) 2015-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. # BlockStore: a helper class that keeps a map of blocks and implements # helper functions for responding to getheaders and getdata, # and for constructing a getheaders message diff --git a/qa/rpc-tests/wallet.py b/qa/rpc-tests/wallet.py index 5d96e7a6e5..3420be1a2e 100755 --- a/qa/rpc-tests/wallet.py +++ b/qa/rpc-tests/wallet.py @@ -18,9 +18,10 @@ class WalletTest (BitcoinTestFramework): super().__init__() self.setup_clean_chain = True self.num_nodes = 4 + self.extra_args = [['-usehd={:d}'.format(i%2==0)] for i in range(4)] def setup_network(self, split=False): - self.nodes = start_nodes(3, self.options.tmpdir) + self.nodes = start_nodes(3, self.options.tmpdir, self.extra_args[:3]) connect_nodes_bi(self.nodes,0,1) connect_nodes_bi(self.nodes,1,2) connect_nodes_bi(self.nodes,0,2) @@ -154,7 +155,7 @@ class WalletTest (BitcoinTestFramework): txid2 = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1) sync_mempools(self.nodes) - self.nodes.append(start_node(3, self.options.tmpdir)) + self.nodes.append(start_node(3, self.options.tmpdir, self.extra_args[3])) connect_nodes_bi(self.nodes, 0, 3) sync_blocks(self.nodes) diff --git a/qa/rpc-tests/walletbackup.py b/qa/rpc-tests/walletbackup.py index b991d5c761..e12cb10a50 100755 --- a/qa/rpc-tests/walletbackup.py +++ b/qa/rpc-tests/walletbackup.py @@ -45,12 +45,12 @@ class WalletBackupTest(BitcoinTestFramework): super().__init__() self.setup_clean_chain = True self.num_nodes = 4 + # nodes 1, 2,3 are spenders, let's give them a keypool=100 + self.extra_args = [["-keypool=100"], ["-keypool=100"], ["-keypool=100"], []] # 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(self.num_nodes, self.options.tmpdir, extra_args) + self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, self.extra_args) connect_nodes(self.nodes[0], 3) connect_nodes(self.nodes[1], 3) connect_nodes(self.nodes[2], 3) @@ -79,6 +79,7 @@ class WalletBackupTest(BitcoinTestFramework): # Must sync mempools before mining. sync_mempools(self.nodes) self.nodes[3].generate(1) + sync_blocks(self.nodes) # As above, this mirrors the original bash test. def start_three(self): diff --git a/share/qt/extract_strings_qt.py b/share/qt/extract_strings_qt.py index 9624abf1fc..92e0df259e 100755 --- a/share/qt/extract_strings_qt.py +++ b/share/qt/extract_strings_qt.py @@ -1,4 +1,7 @@ #!/usr/bin/env python +# 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. ''' Extract _("...") strings for translation and convert to Qt stringdefs so that they can be picked up by Qt linguist. diff --git a/share/qt/protobuf.pri b/share/qt/protobuf.pri deleted file mode 100644 index 865fe86555..0000000000 --- a/share/qt/protobuf.pri +++ /dev/null @@ -1,35 +0,0 @@ -# Based on: http://code.google.com/p/ostinato/source/browse/protobuf.pri -# -# Qt qmake integration with Google Protocol Buffers compiler protoc -# -# To compile protocol buffers with qt qmake, specify PROTOS variable and -# include this file -# -# Example: -# PROTOS = a.proto b.proto -# include(protobuf.pri) -# -# Set PROTO_PATH if you need to set the protoc --proto_path search path -# Set PROTOC to the path to the protoc compiler if it is not in your $PATH -# - -isEmpty(PROTO_DIR):PROTO_DIR = . -isEmpty(PROTOC):PROTOC = protoc - -PROTOPATHS = -for(p, PROTO_PATH):PROTOPATHS += --proto_path=$${p} - -protobuf_decl.name = protobuf header -protobuf_decl.input = PROTOS -protobuf_decl.output = $${PROTO_DIR}/${QMAKE_FILE_BASE}.pb.h -protobuf_decl.commands = $${PROTOC} --cpp_out="$${PROTO_DIR}" $${PROTOPATHS} --proto_path=${QMAKE_FILE_IN_PATH} ${QMAKE_FILE_NAME} -protobuf_decl.variable_out = GENERATED_FILES -QMAKE_EXTRA_COMPILERS += protobuf_decl - -protobuf_impl.name = protobuf implementation -protobuf_impl.input = PROTOS -protobuf_impl.output = $${PROTO_DIR}/${QMAKE_FILE_BASE}.pb.cc -protobuf_impl.depends = $${PROTO_DIR}/${QMAKE_FILE_BASE}.pb.h -protobuf_impl.commands = $$escape_expand(\\n) -protobuf_impl.variable_out = GENERATED_SOURCES -QMAKE_EXTRA_COMPILERS += protobuf_impl diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include index 813a343ffa..0a7efb5d5b 100644 --- a/src/Makefile.qttest.include +++ b/src/Makefile.qttest.include @@ -1,13 +1,16 @@ bin_PROGRAMS += qt/test/test_bitcoin-qt TESTS += qt/test/test_bitcoin-qt -TEST_QT_MOC_CPP = qt/test/moc_uritests.cpp +TEST_QT_MOC_CPP = \ + qt/test/moc_rpcnestedtests.cpp \ + qt/test/moc_uritests.cpp if ENABLE_WALLET TEST_QT_MOC_CPP += qt/test/moc_paymentservertests.cpp endif TEST_QT_H = \ + qt/test/rpcnestedtests.h \ qt/test/uritests.h \ qt/test/paymentrequestdata.h \ qt/test/paymentservertests.h @@ -16,6 +19,7 @@ qt_test_test_bitcoin_qt_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_ $(QT_INCLUDES) $(QT_TEST_INCLUDES) $(PROTOBUF_CFLAGS) qt_test_test_bitcoin_qt_SOURCES = \ + qt/test/rpcnestedtests.cpp \ qt/test/test_main.cpp \ qt/test/uritests.cpp \ $(TEST_QT_H) diff --git a/src/init.cpp b/src/init.cpp index 8d1e330a05..75182345ee 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -759,10 +759,7 @@ void InitParameterInteraction() if (GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY)) { if (SoftSetBoolArg("-whitelistrelay", false)) LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting -whitelistrelay=0\n", __func__); -#ifdef ENABLE_WALLET - if (SoftSetBoolArg("-walletbroadcast", false)) - LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting -walletbroadcast=0\n", __func__); -#endif + // walletbroadcast is disabled in CWallet::ParameterInteraction() } // Forcing relay from whitelisted hosts implies we will accept relays from them in the first place. @@ -821,12 +818,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) return InitError("Initializing networking failed"); #ifndef WIN32 - if (GetBoolArg("-sysperms", false)) { -#ifdef ENABLE_WALLET - if (!GetBoolArg("-disablewallet", false)) - return InitError("-sysperms is not allowed in combination with enabled wallet functionality"); -#endif - } else { + if (!GetBoolArg("-sysperms", false)) { umask(077); } @@ -854,15 +846,10 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) // also see: InitParameterInteraction() - // if using block pruning, then disable txindex + // if using block pruning, then disallow txindex if (GetArg("-prune", 0)) { if (GetBoolArg("-txindex", DEFAULT_TXINDEX)) return InitError(_("Prune mode is incompatible with -txindex.")); -#ifdef ENABLE_WALLET - if (GetBoolArg("-rescan", false)) { - return InitError(_("Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.")); - } -#endif } // Make sure enough file descriptors are available @@ -948,9 +935,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) RegisterAllCoreRPCCommands(tableRPC); #ifdef ENABLE_WALLET - bool fDisableWallet = GetBoolArg("-disablewallet", false); - if (!fDisableWallet) - RegisterWalletRPCCommands(tableRPC); + RegisterWalletRPCCommands(tableRPC); #endif nConnectTimeout = GetArg("-timeout", DEFAULT_CONNECT_TIMEOUT); @@ -980,7 +965,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) #ifdef ENABLE_WALLET if (!CWallet::ParameterInteraction()) return false; -#endif // ENABLE_WALLET +#endif fIsBareMultisigStd = GetBoolArg("-permitbaremultisig", DEFAULT_PERMIT_BAREMULTISIG); fAcceptDatacarrier = GetBoolArg("-datacarrier", DEFAULT_ACCEPT_DATACARRIER); @@ -1108,15 +1093,13 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) // ********************************************************* Step 5: verify wallet database integrity #ifdef ENABLE_WALLET - if (!fDisableWallet) { - if (!CWallet::Verify()) - return false; - } // (!fDisableWallet) -#endif // ENABLE_WALLET + if (!CWallet::Verify()) + return false; +#endif // ********************************************************* Step 6: network initialization assert(!g_connman); - g_connman = std::unique_ptr<CConnman>(new CConnman()); + g_connman = std::unique_ptr<CConnman>(new CConnman(GetRand(std::numeric_limits<uint64_t>::max()), GetRand(std::numeric_limits<uint64_t>::max()))); CConnman& connman = *g_connman; RegisterNodeSignals(GetNodeSignals()); @@ -1249,8 +1232,11 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) RegisterValidationInterface(pzmqNotificationInterface); } #endif + uint64_t nMaxOutboundLimit = 0; //unlimited unless -maxuploadtarget is set + uint64_t nMaxOutboundTimeframe = MAX_UPLOAD_TIMEFRAME; + if (mapArgs.count("-maxuploadtarget")) { - connman.SetMaxOutboundTarget(GetArg("-maxuploadtarget", DEFAULT_MAX_UPLOAD_TARGET)*1024*1024); + nMaxOutboundLimit = GetArg("-maxuploadtarget", DEFAULT_MAX_UPLOAD_TARGET)*1024*1024; } // ********************************************************* Step 7: load block chain @@ -1437,17 +1423,11 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) // ********************************************************* Step 8: load wallet #ifdef ENABLE_WALLET - if (fDisableWallet) { - pwalletMain = NULL; - LogPrintf("Wallet disabled!\n"); - } else { - CWallet::InitLoadWallet(); - if (!pwalletMain) - return false; - } -#else // ENABLE_WALLET + if (!CWallet::InitLoadWallet()) + return false; +#else LogPrintf("No wallet support compiled in!\n"); -#endif // !ENABLE_WALLET +#endif // ********************************************************* Step 9: data directory maintenance @@ -1533,6 +1513,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) connOptions.nSendBufferMaxSize = 1000*GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER); connOptions.nReceiveFloodSize = 1000*GetArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER); + connOptions.nMaxOutboundTimeframe = nMaxOutboundTimeframe; + connOptions.nMaxOutboundLimit = nMaxOutboundLimit; + if(!connman.Start(threadGroup, scheduler, strNodeError, connOptions)) return InitError(strNodeError); diff --git a/src/main.cpp b/src/main.cpp index 593897f516..e5ddd31d0c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -113,6 +113,8 @@ CScript COINBASE_FLAGS; const string strMessageMagic = "Bitcoin Signed Message:\n"; +static const uint64_t RANDOMIZER_ID_ADDRESS_RELAY = 0x3cac0035b5866b90ULL; // SHA256("main address relay")[0:8] + // Internal stuff namespace { @@ -2062,7 +2064,7 @@ bool UndoReadFromDisk(CBlockUndo& blockundo, const CDiskBlockPos& pos, const uin // Open history file to read CAutoFile filein(OpenUndoFile(pos, true), SER_DISK, CLIENT_VERSION); if (filein.IsNull()) - return error("%s: OpenBlockFile failed", __func__); + return error("%s: OpenUndoFile failed", __func__); // Read block uint256 hashChecksum; @@ -4739,11 +4741,9 @@ static void RelayAddress(const CAddress& addr, bool fReachable, CConnman& connma // Relay to a limited number of other nodes // 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 const uint64_t salt0 = GetRand(std::numeric_limits<uint64_t>::max()); - static const uint64_t salt1 = GetRand(std::numeric_limits<uint64_t>::max()); uint64_t hashAddr = addr.GetHash(); std::multimap<uint64_t, CNode*> mapMix; - const CSipHasher hasher = CSipHasher(salt0, salt1).Write(hashAddr << 32).Write((GetTime() + hashAddr) / (24*60*60)); + const CSipHasher hasher = connman.GetDeterministicRandomizer(RANDOMIZER_ID_ADDRESS_RELAY).Write(hashAddr << 32).Write((GetTime() + hashAddr) / (24*60*60)); auto sortfunc = [&mapMix, &hasher](CNode* pnode) { if (pnode->nVersion >= CADDR_TIME_VERSION) { diff --git a/src/net.cpp b/src/net.cpp index cc9728b853..cce06f2d64 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -63,6 +63,7 @@ const static std::string NET_MESSAGE_COMMAND_OTHER = "*other*"; +static const uint64_t RANDOMIZER_ID_NETGROUP = 0x6c0edd8036ef4036ULL; // SHA256("netgroup")[0:8] // // Global state variables // @@ -387,7 +388,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo addrman.Attempt(addrConnect, fCountFailure); // Add node - CNode* pnode = new CNode(GetNewNodeId(), nLocalServices, GetBestHeight(), hSocket, addrConnect, pszDest ? pszDest : "", false); + CNode* pnode = new CNode(GetNewNodeId(), nLocalServices, GetBestHeight(), hSocket, addrConnect, CalculateKeyedNetGroup(addrConnect), pszDest ? pszDest : "", false); GetNodeSignals().InitializeNode(pnode->GetId(), pnode); pnode->AddRef(); @@ -448,7 +449,7 @@ void CNode::PushVersion() { int64_t nTime = (fInbound ? GetAdjustedTime() : GetTime()); CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService(), addr.nServices)); - CAddress addrMe = GetLocalAddress(&addr, nLocalServices); + CAddress addrMe = CAddress(CService(), nLocalServices); if (fLogIPs) LogPrint("net", "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%d\n", PROTOCOL_VERSION, nMyStartingHeight, addrMe.ToString(), addrYou.ToString(), id); else @@ -1022,7 +1023,7 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) { } } - CNode* pnode = new CNode(GetNewNodeId(), nLocalServices, GetBestHeight(), hSocket, addr, "", true); + CNode* pnode = new CNode(GetNewNodeId(), nLocalServices, GetBestHeight(), hSocket, addr, CalculateKeyedNetGroup(addr), "", true); GetNodeSignals().InitializeNode(pnode->GetId(), pnode); pnode->AddRef(); pnode->fWhitelisted = whitelisted; @@ -2023,7 +2024,7 @@ void Discover(boost::thread_group& threadGroup) #endif } -CConnman::CConnman() +CConnman::CConnman(uint64_t nSeed0In, uint64_t nSeed1In) : nSeed0(nSeed0In), nSeed1(nSeed1In) { setBannedIsDirty = false; fAddressesInitialized = false; @@ -2046,9 +2047,7 @@ bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, st { nTotalBytesRecv = 0; nTotalBytesSent = 0; - nMaxOutboundLimit = 0; nMaxOutboundTotalBytesSentInCycle = 0; - nMaxOutboundTimeframe = 60*60*24; //1 day nMaxOutboundCycleStartTime = 0; nRelevantServices = connOptions.nRelevantServices; @@ -2060,6 +2059,9 @@ bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, st nSendBufferMaxSize = connOptions.nSendBufferMaxSize; nReceiveFloodSize = connOptions.nSendBufferMaxSize; + nMaxOutboundLimit = connOptions.nMaxOutboundLimit; + nMaxOutboundTimeframe = connOptions.nMaxOutboundTimeframe; + SetBestHeight(connOptions.nBestHeight); clientInterface = connOptions.uiInterface; @@ -2108,7 +2110,7 @@ bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, st if (pnodeLocalHost == NULL) { CNetAddr local; LookupHost("127.0.0.1", local, false); - pnodeLocalHost = new CNode(GetNewNodeId(), nLocalServices, GetBestHeight(), INVALID_SOCKET, CAddress(CService(local, 0), nLocalServices)); + pnodeLocalHost = new CNode(GetNewNodeId(), nLocalServices, GetBestHeight(), INVALID_SOCKET, CAddress(CService(local, 0), nLocalServices), 0); GetNodeSignals().InitializeNode(pnodeLocalHost->GetId(), pnodeLocalHost); } @@ -2498,10 +2500,10 @@ void CNode::Fuzz(int nChance) unsigned int CConnman::GetReceiveFloodSize() const { return nReceiveFloodSize; } unsigned int CConnman::GetSendBufferSize() const{ return nSendBufferMaxSize; } -CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNameIn, bool fInboundIn) : +CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress& addrIn, uint64_t nKeyedNetGroupIn, const std::string& addrNameIn, bool fInboundIn) : ssSend(SER_NETWORK, INIT_PROTO_VERSION), addr(addrIn), - nKeyedNetGroup(CalculateKeyedNetGroup(addrIn)), + nKeyedNetGroup(nKeyedNetGroupIn), addrKnown(5000, 0.001), filterInventoryKnown(50000, 0.000001) { @@ -2694,12 +2696,14 @@ 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); } -/* static */ uint64_t CNode::CalculateKeyedNetGroup(const CAddress& ad) +CSipHasher CConnman::GetDeterministicRandomizer(uint64_t id) { - static const uint64_t k0 = GetRand(std::numeric_limits<uint64_t>::max()); - static const uint64_t k1 = GetRand(std::numeric_limits<uint64_t>::max()); + return CSipHasher(nSeed0, nSeed1).Write(id); +} +uint64_t CConnman::CalculateKeyedNetGroup(const CAddress& ad) +{ std::vector<unsigned char> vchNetGroup(ad.GetGroup()); - return CSipHasher(k0, k1).Write(&vchNetGroup[0], vchNetGroup.size()).Finalize(); + return GetDeterministicRandomizer(RANDOMIZER_ID_NETGROUP).Write(&vchNetGroup[0], vchNetGroup.size()).Finalize(); } @@ -11,6 +11,7 @@ #include "amount.h" #include "bloom.h" #include "compat.h" +#include "hash.h" #include "limitedmap.h" #include "netaddress.h" #include "protocol.h" @@ -72,6 +73,8 @@ static const size_t SETASKFOR_MAX_SZ = 2 * MAX_INV_SZ; static const unsigned int DEFAULT_MAX_PEER_CONNECTIONS = 125; /** The default for -maxuploadtarget. 0 = Unlimited */ static const uint64_t DEFAULT_MAX_UPLOAD_TARGET = 0; +/** The default timeframe for -maxuploadtarget. 1 day. */ +static const uint64_t MAX_UPLOAD_TIMEFRAME = 60 * 60 * 24; /** Default for blocks only*/ static const bool DEFAULT_BLOCKSONLY = false; @@ -120,8 +123,10 @@ public: CClientUIInterface* uiInterface = nullptr; unsigned int nSendBufferMaxSize = 0; unsigned int nReceiveFloodSize = 0; + uint64_t nMaxOutboundTimeframe = 0; + uint64_t nMaxOutboundLimit = 0; }; - CConnman(); + CConnman(uint64_t seed0, uint64_t seed1); ~CConnman(); bool Start(boost::thread_group& threadGroup, CScheduler& scheduler, std::string& strNodeError, Options options); void Stop(); @@ -294,6 +299,8 @@ public: void SetBestHeight(int height); int GetBestHeight() const; + /** Get a unique deterministic randomizer. */ + CSipHasher GetDeterministicRandomizer(uint64_t id); private: struct ListenSocket { @@ -311,6 +318,8 @@ private: void ThreadSocketHandler(); void ThreadDNSAddressSeed(); + uint64_t CalculateKeyedNetGroup(const CAddress& ad); + CNode* FindNode(const CNetAddr& ip); CNode* FindNode(const CSubNet& subNet); CNode* FindNode(const std::string& addrName); @@ -388,6 +397,9 @@ private: int nMaxFeeler; std::atomic<int> nBestHeight; CClientUIInterface* clientInterface; + + /** SipHasher seeds for deterministic randomness */ + const uint64_t nSeed0, nSeed1; }; extern std::unique_ptr<CConnman> g_connman; void Discover(boost::thread_group& threadGroup); @@ -656,14 +668,13 @@ public: CAmount lastSentFeeFilter; int64_t nextSendTimeFeeFilter; - CNode(NodeId id, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress &addrIn, const std::string &addrNameIn = "", bool fInboundIn = false); + CNode(NodeId id, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress &addrIn, uint64_t nKeyedNetGroupIn, const std::string &addrNameIn = "", bool fInboundIn = false); ~CNode(); private: CNode(const CNode&); void operator=(const CNode&); - static uint64_t CalculateKeyedNetGroup(const CAddress& ad); uint64_t nLocalHostNonce; ServiceFlags nLocalServices; diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp index 2fdc59ea07..4afbe99fd3 100644 --- a/src/primitives/transaction.cpp +++ b/src/primitives/transaction.cpp @@ -131,6 +131,11 @@ unsigned int CTransaction::CalculateModifiedSize(unsigned int nTxSize) const return nTxSize; } +unsigned int CTransaction::GetTotalSize() const +{ + return ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION); +} + std::string CTransaction::ToString() const { std::string str; diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index 5689d15bf7..16c2e5c454 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -415,6 +415,13 @@ public: // Compute modified tx size for priority calculation (optionally given tx size) unsigned int CalculateModifiedSize(unsigned int nTxSize=0) const; + + /** + * Get the total transaction size in bytes, including witness data. + * "Total Size" defined in BIP141 and BIP144. + * @return Total transaction size in bytes + */ + unsigned int GetTotalSize() const; bool IsCoinBase() const { diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 272df3fdae..8bfd63b31f 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -77,6 +77,7 @@ const QString BitcoinGUI::DEFAULT_WALLET = "~Default"; BitcoinGUI::BitcoinGUI(const PlatformStyle *platformStyle, const NetworkStyle *networkStyle, QWidget *parent) : QMainWindow(parent), + enableWallet(false), clientModel(0), walletFrame(0), unitDisplayControl(0), @@ -122,10 +123,7 @@ BitcoinGUI::BitcoinGUI(const PlatformStyle *platformStyle, const NetworkStyle *n QString windowTitle = tr(PACKAGE_NAME) + " - "; #ifdef ENABLE_WALLET - /* if compiled with wallet support, -disablewallet can still disable the wallet */ - enableWallet = !GetBoolArg("-disablewallet", false); -#else - enableWallet = false; + enableWallet = WalletModel::isWalletEnabled(); #endif // ENABLE_WALLET if(enableWallet) { diff --git a/src/qt/paymentrequest.proto b/src/qt/paymentrequest.proto index b2281c4c7b..d2721a34bd 100644 --- a/src/qt/paymentrequest.proto +++ b/src/qt/paymentrequest.proto @@ -6,6 +6,8 @@ // https://en.bitcoin.it/wiki/Payment_Request // +syntax = "proto2"; + package payments; option java_package = "org.bitcoin.protocols.payments"; option java_outer_classname = "Protos"; diff --git a/src/qt/res/movies/makespinner.sh b/src/qt/res/movies/makespinner.sh index a4c2fddbbf..d0deb1238c 100755 --- a/src/qt/res/movies/makespinner.sh +++ b/src/qt/res/movies/makespinner.sh @@ -1,3 +1,7 @@ +# Copyright (c) 2014-2015 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + FRAMEDIR=$(dirname $0) for i in {0..35} do diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index f35f401d06..a316b951c4 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -113,9 +113,11 @@ public: #include "rpcconsole.moc" /** - * Split shell command line into a list of arguments. Aims to emulate \c bash and friends. + * Split shell command line into a list of arguments and execute the command(s). + * Aims to emulate \c bash and friends. * - * - Arguments are delimited with whitespace + * - Command nesting is possible with brackets [example: validateaddress(getnewaddress())] + * - Arguments are delimited with whitespace or comma * - Extra whitespace at the beginning and end and between arguments will be ignored * - Text can be "double" or 'single' quoted * - The backslash \c \ is used as escape character @@ -123,11 +125,15 @@ public: * - Within double quotes, only escape \c " and backslashes before a \c " or another backslash * - Within single quotes, no escaping is possible and no special interpretation takes place * - * @param[out] args Parsed arguments will be appended to this list + * @param[out] result stringified Result from the executed command(chain) * @param[in] strCommand Command line to split */ -bool parseCommandLine(std::vector<std::string> &args, const std::string &strCommand) + +bool RPCConsole::RPCExecuteCommandLine(std::string &strResult, const std::string &strCommand) { + std::vector< std::vector<std::string> > stack; + stack.push_back(std::vector<std::string>()); + enum CmdParseState { STATE_EATING_SPACES, @@ -135,95 +141,180 @@ bool parseCommandLine(std::vector<std::string> &args, const std::string &strComm STATE_SINGLEQUOTED, STATE_DOUBLEQUOTED, STATE_ESCAPE_OUTER, - STATE_ESCAPE_DOUBLEQUOTED + STATE_ESCAPE_DOUBLEQUOTED, + STATE_COMMAND_EXECUTED, + STATE_COMMAND_EXECUTED_INNER } state = STATE_EATING_SPACES; std::string curarg; - Q_FOREACH(char ch, strCommand) + UniValue lastResult; + + std::string strCommandTerminated = strCommand; + if (strCommandTerminated.back() != '\n') + strCommandTerminated += "\n"; + for(char ch: strCommandTerminated) { switch(state) { - case STATE_ARGUMENT: // In or after argument - case STATE_EATING_SPACES: // Handle runs of whitespace - switch(ch) + case STATE_COMMAND_EXECUTED_INNER: + case STATE_COMMAND_EXECUTED: { - case '"': state = STATE_DOUBLEQUOTED; break; - case '\'': state = STATE_SINGLEQUOTED; break; - case '\\': state = STATE_ESCAPE_OUTER; break; - case ' ': case '\n': case '\t': - if(state == STATE_ARGUMENT) // Space ends argument + bool breakParsing = true; + switch(ch) { - args.push_back(curarg); - curarg.clear(); + case '[': curarg.clear(); state = STATE_COMMAND_EXECUTED_INNER; break; + default: + if (state == STATE_COMMAND_EXECUTED_INNER) + { + if (ch != ']') + { + // append char to the current argument (which is also used for the query command) + curarg += ch; + break; + } + if (curarg.size()) + { + // if we have a value query, query arrays with index and objects with a string key + UniValue subelement; + if (lastResult.isArray()) + { + for(char argch: curarg) + if (!std::isdigit(argch)) + throw std::runtime_error("Invalid result query"); + subelement = lastResult[atoi(curarg.c_str())]; + } + else if (lastResult.isObject()) + subelement = find_value(lastResult, curarg); + else + throw std::runtime_error("Invalid result query"); //no array or object: abort + lastResult = subelement; + } + + state = STATE_COMMAND_EXECUTED; + break; + } + // don't break parsing when the char is required for the next argument + breakParsing = false; + + // pop the stack and return the result to the current command arguments + stack.pop_back(); + + // don't stringify the json in case of a string to avoid doublequotes + if (lastResult.isStr()) + curarg = lastResult.get_str(); + else + curarg = lastResult.write(2); + + // if we have a non empty result, use it as stack argument otherwise as general result + if (curarg.size()) + { + if (stack.size()) + stack.back().push_back(curarg); + else + strResult = curarg; + } + curarg.clear(); + // assume eating space state + state = STATE_EATING_SPACES; } - state = STATE_EATING_SPACES; - break; - default: curarg += ch; state = STATE_ARGUMENT; + if (breakParsing) + break; } - break; - case STATE_SINGLEQUOTED: // Single-quoted string - switch(ch) + case STATE_ARGUMENT: // In or after argument + case STATE_EATING_SPACES: // Handle runs of whitespace + switch(ch) { - case '\'': state = STATE_ARGUMENT; break; - default: curarg += ch; + case '"': state = STATE_DOUBLEQUOTED; break; + case '\'': state = STATE_SINGLEQUOTED; break; + case '\\': state = STATE_ESCAPE_OUTER; break; + case '(': case ')': case '\n': + if (state == STATE_ARGUMENT) + { + if (ch == '(' && stack.size() && stack.back().size() > 0) + stack.push_back(std::vector<std::string>()); + if (curarg.size()) + { + // don't allow commands after executed commands on baselevel + if (!stack.size()) + throw std::runtime_error("Invalid Syntax"); + stack.back().push_back(curarg); + } + curarg.clear(); + state = STATE_EATING_SPACES; + } + if ((ch == ')' || ch == '\n') && stack.size() > 0) + { + std::string strPrint; + // Convert argument list to JSON objects in method-dependent way, + // and pass it along with the method name to the dispatcher. + lastResult = tableRPC.execute(stack.back()[0], RPCConvertValues(stack.back()[0], std::vector<std::string>(stack.back().begin() + 1, stack.back().end()))); + + state = STATE_COMMAND_EXECUTED; + curarg.clear(); + } + break; + case ' ': case ',': case '\t': + if(state == STATE_ARGUMENT) // Space ends argument + { + if (curarg.size()) + stack.back().push_back(curarg); + curarg.clear(); + } + state = STATE_EATING_SPACES; + break; + default: curarg += ch; state = STATE_ARGUMENT; } - break; - case STATE_DOUBLEQUOTED: // Double-quoted string - switch(ch) + break; + case STATE_SINGLEQUOTED: // Single-quoted string + switch(ch) { - case '"': state = STATE_ARGUMENT; break; - case '\\': state = STATE_ESCAPE_DOUBLEQUOTED; break; - default: curarg += ch; + case '\'': state = STATE_ARGUMENT; break; + default: curarg += ch; } - break; - case STATE_ESCAPE_OUTER: // '\' outside quotes - curarg += ch; state = STATE_ARGUMENT; - break; - case STATE_ESCAPE_DOUBLEQUOTED: // '\' in double-quoted text - if(ch != '"' && ch != '\\') curarg += '\\'; // keep '\' for everything but the quote and '\' itself - curarg += ch; state = STATE_DOUBLEQUOTED; - break; + break; + case STATE_DOUBLEQUOTED: // Double-quoted string + switch(ch) + { + case '"': state = STATE_ARGUMENT; break; + case '\\': state = STATE_ESCAPE_DOUBLEQUOTED; break; + default: curarg += ch; + } + break; + case STATE_ESCAPE_OUTER: // '\' outside quotes + curarg += ch; state = STATE_ARGUMENT; + break; + case STATE_ESCAPE_DOUBLEQUOTED: // '\' in double-quoted text + if(ch != '"' && ch != '\\') curarg += '\\'; // keep '\' for everything but the quote and '\' itself + curarg += ch; state = STATE_DOUBLEQUOTED; + break; } } switch(state) // final state { - case STATE_EATING_SPACES: - return true; - case STATE_ARGUMENT: - args.push_back(curarg); - return true; - default: // ERROR to end in one of the other states - return false; + case STATE_COMMAND_EXECUTED: + if (lastResult.isStr()) + strResult = lastResult.get_str(); + else + strResult = lastResult.write(2); + case STATE_ARGUMENT: + case STATE_EATING_SPACES: + return true; + default: // ERROR to end in one of the other states + return false; } } void RPCExecutor::request(const QString &command) { - std::vector<std::string> args; - if(!parseCommandLine(args, command.toStdString())) - { - Q_EMIT reply(RPCConsole::CMD_ERROR, QString("Parse error: unbalanced ' or \"")); - return; - } - if(args.empty()) - return; // Nothing to do try { - std::string strPrint; - // Convert argument list to JSON objects in method-dependent way, - // and pass it along with the method name to the dispatcher. - UniValue result = tableRPC.execute( - args[0], - RPCConvertValues(args[0], std::vector<std::string>(args.begin() + 1, args.end()))); - - // Format result reply - if (result.isNull()) - strPrint = ""; - else if (result.isStr()) - strPrint = result.get_str(); - else - strPrint = result.write(2); - - Q_EMIT reply(RPCConsole::CMD_REPLY, QString::fromStdString(strPrint)); + std::string result; + std::string executableCommand = command.toStdString() + "\n"; + if(!RPCConsole::RPCExecuteCommandLine(result, executableCommand)) + { + Q_EMIT reply(RPCConsole::CMD_ERROR, QString("Parse error: unbalanced ' or \"")); + return; + } + Q_EMIT reply(RPCConsole::CMD_REPLY, QString::fromStdString(result)); } catch (UniValue& objError) { diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h index 28affa954d..50224a1cc0 100644 --- a/src/qt/rpcconsole.h +++ b/src/qt/rpcconsole.h @@ -35,6 +35,8 @@ public: explicit RPCConsole(const PlatformStyle *platformStyle, QWidget *parent); ~RPCConsole(); + static bool RPCExecuteCommandLine(std::string &strResult, const std::string &strCommand); + void setClientModel(ClientModel *model); enum MessageClass { diff --git a/src/qt/test/rpcnestedtests.cpp b/src/qt/test/rpcnestedtests.cpp new file mode 100644 index 0000000000..3dae33bafb --- /dev/null +++ b/src/qt/test/rpcnestedtests.cpp @@ -0,0 +1,93 @@ +// Copyright (c) 2016 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "rpcnestedtests.h" + +#include "chainparams.h" +#include "consensus/validation.h" +#include "main.h" +#include "rpc/register.h" +#include "rpc/server.h" +#include "rpcconsole.h" +#include "test/testutil.h" +#include "univalue.h" +#include "util.h" + +#include <QDir> + +#include <boost/filesystem.hpp> + +void RPCNestedTests::rpcNestedTests() +{ + UniValue jsonRPCError; + + // do some test setup + // could be moved to a more generic place when we add more tests on QT level + const CChainParams& chainparams = Params(); + RegisterAllCoreRPCCommands(tableRPC); + ClearDatadirCache(); + std::string path = QDir::tempPath().toStdString() + "/" + strprintf("test_bitcoin_qt_%lu_%i", (unsigned long)GetTime(), (int)(GetRand(100000))); + QDir dir(QString::fromStdString(path)); + dir.mkpath("."); + mapArgs["-datadir"] = path; + //mempool.setSanityCheck(1.0); + pblocktree = new CBlockTreeDB(1 << 20, true); + pcoinsdbview = new CCoinsViewDB(1 << 23, true); + pcoinsTip = new CCoinsViewCache(pcoinsdbview); + InitBlockIndex(chainparams); + { + CValidationState state; + bool ok = ActivateBestChain(state, chainparams); + QVERIFY(ok); + } + + SetRPCWarmupFinished(); + + std::string result; + std::string result2; + RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo()[chain]"); //simple result filtering with path + QVERIFY(result=="main"); + + RPCConsole::RPCExecuteCommandLine(result, "getblock(getbestblockhash())"); //simple 2 level nesting + RPCConsole::RPCExecuteCommandLine(result, "getblock(getblock(getbestblockhash())[hash], true)"); + + RPCConsole::RPCExecuteCommandLine(result, "getblock( getblock( getblock(getbestblockhash())[hash] )[hash], true)"); //4 level nesting with whitespace, filtering path and boolean parameter + + RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo"); + QVERIFY(result.substr(0,1) == "{"); + + RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo()"); + QVERIFY(result.substr(0,1) == "{"); + + RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo "); //whitespace at the end will be tolerated + QVERIFY(result.substr(0,1) == "{"); + +#if QT_VERSION >= 0x050300 + // do the QVERIFY_EXCEPTION_THROWN checks only with Qt5.3 and higher (QVERIFY_EXCEPTION_THROWN was introduced in Qt5.3) + QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo() .\n"), std::runtime_error); //invalid syntax + QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo() getblockchaininfo()"), std::runtime_error); //invalid syntax + (RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo(")); //tolerate non closing brackets if we have no arguments + (RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo()()()")); //tolerate non command brackts + QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo(True)"), UniValue); //invalid argument + QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "a(getblockchaininfo(True))"), UniValue); //method not found +#endif + + (RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo()[\"chain\"]")); //Quote path identifier are allowed, but look after a child contaning the quotes in the key + QVERIFY(result == "null"); + + (RPCConsole::RPCExecuteCommandLine(result, "createrawtransaction [] {} 0")); //parameter not in brackets are allowed + (RPCConsole::RPCExecuteCommandLine(result2, "createrawtransaction([],{},0)")); //parameter in brackets are allowed + QVERIFY(result == result2); + (RPCConsole::RPCExecuteCommandLine(result2, "createrawtransaction( [], {} , 0 )")); //whitespace between parametres is allowed + QVERIFY(result == result2); + + RPCConsole::RPCExecuteCommandLine(result, "getblock(getbestblockhash())[tx][0]"); + QVERIFY(result == "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"); + + delete pcoinsTip; + delete pcoinsdbview; + delete pblocktree; + + boost::filesystem::remove_all(boost::filesystem::path(path)); +} diff --git a/src/qt/test/rpcnestedtests.h b/src/qt/test/rpcnestedtests.h new file mode 100644 index 0000000000..9ad409019f --- /dev/null +++ b/src/qt/test/rpcnestedtests.h @@ -0,0 +1,25 @@ +// Copyright (c) 2016 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_QT_TEST_RPC_NESTED_TESTS_H +#define BITCOIN_QT_TEST_RPC_NESTED_TESTS_H + +#include <QObject> +#include <QTest> + +#include "txdb.h" +#include "txmempool.h" + +class RPCNestedTests : public QObject +{ + Q_OBJECT + + private Q_SLOTS: + void rpcNestedTests(); + +private: + CCoinsViewDB *pcoinsdbview; +}; + +#endif // BITCOIN_QT_TEST_RPC_NESTED_TESTS_H diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp index db193420bf..dbaab54fb6 100644 --- a/src/qt/test/test_main.cpp +++ b/src/qt/test/test_main.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2015 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -6,6 +6,9 @@ #include "config/bitcoin-config.h" #endif +#include "chainparams.h" +#include "key.h" +#include "rpcnestedtests.h" #include "util.h" #include "uritests.h" @@ -27,10 +30,17 @@ Q_IMPORT_PLUGIN(qtwcodecs) Q_IMPORT_PLUGIN(qkrcodecs) #endif +extern void noui_connect(); + // This is all you need to run all the tests int main(int argc, char *argv[]) { + ECC_Start(); SetupEnvironment(); + SetupNetworking(); + SelectParams(CBaseChainParams::MAIN); + noui_connect(); + bool fInvalid = false; // Don't remove this, it's needed to access @@ -48,6 +58,10 @@ int main(int argc, char *argv[]) if (QTest::qExec(&test2) != 0) fInvalid = true; #endif + RPCNestedTests test3; + if (QTest::qExec(&test3) != 0) + fInvalid = true; + ECC_Stop(); return fInvalid; } diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index bae0cbd1c8..65144e7865 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -241,6 +241,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco strHTML += "<br><b>" + tr("Comment") + ":</b><br>" + GUIUtil::HtmlEscape(wtx.mapValue["comment"], true) + "<br>"; strHTML += "<b>" + tr("Transaction ID") + ":</b> " + rec->getTxID() + "<br>"; + strHTML += "<b>" + tr("Transaction total size") + ":</b> " + QString::number(wtx.GetTotalSize()) + " bytes<br>"; strHTML += "<b>" + tr("Output index") + ":</b> " + QString::number(rec->getOutputIndex()) + "<br>"; // Message from normal bitcoin:URI (bitcoin:123...?message=example) diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 73851e97fc..ad3ba996f1 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -684,6 +684,11 @@ bool WalletModel::abandonTransaction(uint256 hash) const return wallet->AbandonTransaction(hash); } +bool WalletModel::isWalletEnabled() +{ + return !GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET); +} + bool WalletModel::hdEnabled() const { return wallet->IsHDEnabled(); diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index a15ecf899b..4456215512 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -203,6 +203,8 @@ public: bool transactionCanBeAbandoned(uint256 hash) const; bool abandonTransaction(uint256 hash) const; + static bool isWalletEnabled(); + bool hdEnabled() const; private: diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp index 33f107d84b..97abeb7211 100644 --- a/src/test/DoS_tests.cpp +++ b/src/test/DoS_tests.cpp @@ -48,7 +48,7 @@ BOOST_AUTO_TEST_CASE(DoS_banning) { connman->ClearBanned(); CAddress addr1(ip(0xa0b0c001), NODE_NONE); - CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, "", true); + CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 0, "", true); GetNodeSignals().InitializeNode(dummyNode1.GetId(), &dummyNode1); dummyNode1.nVersion = 1; Misbehaving(dummyNode1.GetId(), 100); // Should get banned @@ -57,7 +57,7 @@ BOOST_AUTO_TEST_CASE(DoS_banning) BOOST_CHECK(!connman->IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned CAddress addr2(ip(0xa0b0c002), NODE_NONE); - CNode dummyNode2(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr2, "", true); + CNode dummyNode2(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr2, 1, "", true); GetNodeSignals().InitializeNode(dummyNode2.GetId(), &dummyNode2); dummyNode2.nVersion = 1; Misbehaving(dummyNode2.GetId(), 50); @@ -74,7 +74,7 @@ BOOST_AUTO_TEST_CASE(DoS_banscore) connman->ClearBanned(); mapArgs["-banscore"] = "111"; // because 11 is my favorite number CAddress addr1(ip(0xa0b0c001), NODE_NONE); - CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, "", true); + CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 3, "", true); GetNodeSignals().InitializeNode(dummyNode1.GetId(), &dummyNode1); dummyNode1.nVersion = 1; Misbehaving(dummyNode1.GetId(), 100); @@ -96,7 +96,7 @@ BOOST_AUTO_TEST_CASE(DoS_bantime) SetMockTime(nStartTime); // Overrides future calls to GetTime() CAddress addr(ip(0xa0b0c001), NODE_NONE); - CNode dummyNode(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr, "", true); + CNode dummyNode(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr, 4, "", true); GetNodeSignals().InitializeNode(dummyNode.GetId(), &dummyNode); dummyNode.nVersion = 1; diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp index bc9a98ab04..680708533e 100644 --- a/src/test/net_tests.cpp +++ b/src/test/net_tests.cpp @@ -164,12 +164,12 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test) bool fInboundIn = false; // Test that fFeeler is false by default. - CNode* pnode1 = new CNode(id++, NODE_NETWORK, height, hSocket, addr, pszDest, fInboundIn); + CNode* pnode1 = new CNode(id++, NODE_NETWORK, height, hSocket, addr, 0, pszDest, fInboundIn); BOOST_CHECK(pnode1->fInbound == false); BOOST_CHECK(pnode1->fFeeler == false); fInboundIn = true; - CNode* pnode2 = new CNode(id++, NODE_NETWORK, height, hSocket, addr, pszDest, fInboundIn); + CNode* pnode2 = new CNode(id++, NODE_NETWORK, height, hSocket, addr, 1, pszDest, fInboundIn); BOOST_CHECK(pnode2->fInbound == true); BOOST_CHECK(pnode2->fFeeler == false); } diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index b1ceef4f64..02843d8525 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -72,7 +72,7 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha nScriptCheckThreads = 3; for (int i=0; i < nScriptCheckThreads-1; i++) threadGroup.create_thread(&ThreadScriptCheck); - g_connman = std::unique_ptr<CConnman>(new CConnman()); + g_connman = std::unique_ptr<CConnman>(new CConnman(0x1337, 0x1337)); // Deterministic randomness for tests. connman = g_connman.get(); RegisterNodeSignals(GetNodeSignals()); } diff --git a/src/util.cpp b/src/util.cpp index c7d147a11e..93cc0412b5 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -600,19 +600,19 @@ bool TryCreateDirectory(const boost::filesystem::path& p) return false; } -void FileCommit(FILE *fileout) +void FileCommit(FILE *file) { - fflush(fileout); // harmless if redundantly called + fflush(file); // harmless if redundantly called #ifdef WIN32 - HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(fileout)); + HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file)); FlushFileBuffers(hFile); #else #if defined(__linux__) || defined(__NetBSD__) - fdatasync(fileno(fileout)); + fdatasync(fileno(file)); #elif defined(__APPLE__) && defined(F_FULLFSYNC) - fcntl(fileno(fileout), F_FULLFSYNC, 0); + fcntl(fileno(file), F_FULLFSYNC, 0); #else - fsync(fileno(fileout)); + fsync(fileno(file)); #endif #endif } diff --git a/src/util.h b/src/util.h index 39328b51ef..45b3658557 100644 --- a/src/util.h +++ b/src/util.h @@ -93,7 +93,7 @@ bool error(const char* fmt, const Args&... args) void PrintExceptionContinue(const std::exception *pex, const char* pszThread); void ParseParameters(int argc, const char*const argv[]); -void FileCommit(FILE *fileout); +void FileCommit(FILE *file); bool TruncateFile(FILE *file, unsigned int length); int RaiseFileDescriptorLimit(int nMinFD); void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length); diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index 42ebdb9b9b..e80fa7dff8 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -344,8 +344,6 @@ UniValue removeprunedfunds(const UniValue& params, bool fHelp) throw JSONRPCError(RPC_INTERNAL_ERROR, "Transaction does not exist in wallet."); } - ThreadFlushWalletDB(pwalletMain->strWalletFile); - return NullUniValue; } diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 993caad400..3eb7e5d9ba 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2630,6 +2630,9 @@ static const CRPCCommand commands[] = void RegisterWalletRPCCommands(CRPCTable &t) { + if (GetBoolArg("-disablewallet", false)) + return; + for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) t.appendCommand(commands[vcidx].name, &commands[vcidx]); } diff --git a/src/wallet/test/accounting_tests.cpp b/src/wallet/test/accounting_tests.cpp index a6cada46a2..a833be13d0 100644 --- a/src/wallet/test/accounting_tests.cpp +++ b/src/wallet/test/accounting_tests.cpp @@ -3,7 +3,6 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "wallet/wallet.h" -#include "wallet/walletdb.h" #include "wallet/test/wallet_test_fixture.h" @@ -17,13 +16,13 @@ extern CWallet* pwalletMain; BOOST_FIXTURE_TEST_SUITE(accounting_tests, WalletTestingSetup) static void -GetResults(CWalletDB& walletdb, std::map<CAmount, CAccountingEntry>& results) +GetResults(std::map<CAmount, CAccountingEntry>& results) { std::list<CAccountingEntry> aes; results.clear(); - BOOST_CHECK(walletdb.ReorderTransactions(pwalletMain) == DB_LOAD_OK); - walletdb.ListAccountCreditDebit("", aes); + BOOST_CHECK(pwalletMain->ReorderTransactions() == DB_LOAD_OK); + pwalletMain->ListAccountCreditDebit("", aes); BOOST_FOREACH(CAccountingEntry& ae, aes) { results[ae.nOrderPos] = ae; @@ -32,7 +31,6 @@ GetResults(CWalletDB& walletdb, std::map<CAmount, CAccountingEntry>& results) BOOST_AUTO_TEST_CASE(acc_orderupgrade) { - CWalletDB walletdb(pwalletMain->strWalletFile); std::vector<CWalletTx*> vpwtx; CWalletTx wtx; CAccountingEntry ae; @@ -45,7 +43,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade) ae.nTime = 1333333333; ae.strOtherAccount = "b"; ae.strComment = ""; - pwalletMain->AddAccountingEntry(ae, walletdb); + pwalletMain->AddAccountingEntry(ae); wtx.mapValue["comment"] = "z"; pwalletMain->AddToWallet(wtx); @@ -55,9 +53,9 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade) ae.nTime = 1333333336; ae.strOtherAccount = "c"; - pwalletMain->AddAccountingEntry(ae, walletdb); + pwalletMain->AddAccountingEntry(ae); - GetResults(walletdb, results); + GetResults(results); BOOST_CHECK(pwalletMain->nOrderPosNext == 3); BOOST_CHECK(2 == results.size()); @@ -71,9 +69,9 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade) ae.nTime = 1333333330; ae.strOtherAccount = "d"; ae.nOrderPos = pwalletMain->IncOrderPosNext(); - pwalletMain->AddAccountingEntry(ae, walletdb); + pwalletMain->AddAccountingEntry(ae); - GetResults(walletdb, results); + GetResults(results); BOOST_CHECK(results.size() == 3); BOOST_CHECK(pwalletMain->nOrderPosNext == 4); @@ -105,7 +103,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade) vpwtx[2]->nTimeReceived = (unsigned int)1333333329; vpwtx[2]->nOrderPos = -1; - GetResults(walletdb, results); + GetResults(results); BOOST_CHECK(results.size() == 3); BOOST_CHECK(pwalletMain->nOrderPosNext == 6); @@ -121,9 +119,9 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade) ae.nTime = 1333333334; ae.strOtherAccount = "e"; ae.nOrderPos = -1; - pwalletMain->AddAccountingEntry(ae, walletdb); + pwalletMain->AddAccountingEntry(ae); - GetResults(walletdb, results); + GetResults(results); BOOST_CHECK(results.size() == 4); BOOST_CHECK(pwalletMain->nOrderPosNext == 7); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 4c10ea0edb..abb1ea7e76 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -414,6 +414,9 @@ void CWallet::Flush(bool shutdown) bool CWallet::Verify() { + if (GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) + return true; + LogPrintf("Using BerkeleyDB version %s\n", DbEnv::version(0, 0, 0)); std::string walletFile = GetArg("-wallet", DEFAULT_WALLET_DAT); @@ -649,6 +652,12 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase) return true; } +DBErrors CWallet::ReorderTransactions() +{ + CWalletDB walletdb(strWalletFile); + return walletdb.ReorderTransactions(this); +} + int64_t CWallet::IncOrderPosNext(CWalletDB *pwalletdb) { AssertLockHeld(cs_wallet); // nOrderPosNext @@ -677,7 +686,7 @@ bool CWallet::AccountMove(std::string strFrom, std::string strTo, CAmount nAmoun debit.nTime = nNow; debit.strOtherAccount = strTo; debit.strComment = strComment; - AddAccountingEntry(debit, walletdb); + AddAccountingEntry(debit, &walletdb); // Credit CAccountingEntry credit; @@ -687,7 +696,7 @@ bool CWallet::AccountMove(std::string strFrom, std::string strTo, CAmount nAmoun credit.nTime = nNow; credit.strOtherAccount = strFrom; credit.strComment = strComment; - AddAccountingEntry(credit, walletdb); + AddAccountingEntry(credit, &walletdb); if (!walletdb.TxnCommit()) return false; @@ -2501,9 +2510,21 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CCon return true; } -bool CWallet::AddAccountingEntry(const CAccountingEntry& acentry, CWalletDB & pwalletdb) +void CWallet::ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& entries) { + CWalletDB walletdb(strWalletFile); + return walletdb.ListAccountCreditDebit(strAccount, entries); +} + +bool CWallet::AddAccountingEntry(const CAccountingEntry& acentry) +{ + CWalletDB walletdb(strWalletFile); + + return AddAccountingEntry(acentry, &walletdb); +} + +bool CWallet::AddAccountingEntry(const CAccountingEntry& acentry, CWalletDB *pwalletdb) { - if (!pwalletdb.WriteAccountingEntry_Backend(acentry)) + if (!pwalletdb->WriteAccountingEntry_Backend(acentry)) return false; laccentries.push_back(acentry); @@ -3275,6 +3296,12 @@ std::string CWallet::GetWalletHelpString(bool showDebug) bool CWallet::InitLoadWallet() { + if (GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) { + pwalletMain = NULL; + LogPrintf("Wallet disabled!\n"); + return true; + } + std::string walletFile = GetArg("-wallet", DEFAULT_WALLET_DAT); // needed to restore wallet transaction meta data after -zapwallettxes @@ -3446,6 +3473,18 @@ bool CWallet::InitLoadWallet() bool CWallet::ParameterInteraction() { + if (GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) + return true; + + if (GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY) && SoftSetBoolArg("-walletbroadcast", false)) { + LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting -walletbroadcast=0\n", __func__); + } + + if (GetBoolArg("-sysperms", false)) + return InitError("-sysperms is not allowed in combination with enabled wallet functionality"); + if (GetArg("-prune", 0) && GetBoolArg("-rescan", false)) + return InitError(_("Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.")); + if (mapArgs.count("-mintxfee")) { CAmount n = 0; diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 61aff6e45a..f6c658928f 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -59,7 +59,7 @@ static const bool DEFAULT_WALLET_RBF = false; //! Largest (in bytes) free transaction we're willing to create static const unsigned int MAX_FREE_TRANSACTION_CREATE_SIZE = 1000; static const bool DEFAULT_WALLETBROADCAST = true; - +static const bool DEFAULT_DISABLE_WALLET = false; //! if set, all keys will be derived by using BIP32 static const bool DEFAULT_USE_HD_WALLET = true; @@ -741,6 +741,7 @@ public: * @return next transaction order id */ int64_t IncOrderPosNext(CWalletDB *pwalletdb = NULL); + DBErrors ReorderTransactions(); bool AccountMove(std::string strFrom, std::string strTo, CAmount nAmount, std::string strComment = ""); bool GetAccountPubkey(CPubKey &pubKey, std::string strAccount, bool bForceNew = false); @@ -775,7 +776,9 @@ public: std::string& strFailReason, const CCoinControl *coinControl = NULL, bool sign = true); bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CConnman* connman); - bool AddAccountingEntry(const CAccountingEntry&, CWalletDB & pwalletdb); + void ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& entries); + bool AddAccountingEntry(const CAccountingEntry&); + bool AddAccountingEntry(const CAccountingEntry&, CWalletDB *pwalletdb); static CFeeRate minTxFee; static CFeeRate fallbackFee; |