diff options
130 files changed, 2664 insertions, 1220 deletions
diff --git a/.travis.yml b/.travis.yml index dadac3165e..0de7ca6f75 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,11 +24,13 @@ env: # ARM - HOST=arm-linux-gnueabihf PACKAGES="g++-arm-linux-gnueabihf" DEP_OPTS="NO_QT=1" CHECK_DOC=1 GOAL="install" BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports" # Win32 - - HOST=i686-w64-mingw32 DPKG_ADD_ARCH="i386" DEP_OPTS="NO_QT=1" PACKAGES="python3 nsis g++-mingw-w64-i686 wine1.6 bc" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-reduce-exports" + - HOST=i686-w64-mingw32 DPKG_ADD_ARCH="i386" DEP_OPTS="NO_QT=1" PACKAGES="python3 nsis g++-mingw-w64-i686 wine1.6" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-reduce-exports" +# Qt4 & system libs + - HOST=x86_64-unknown-linux-gnu PACKAGES="python3-zmq qt4-dev-tools libssl-dev libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-program-options-dev libboost-test-dev libboost-thread-dev libdb5.1++-dev libminiupnpc-dev libzmq3-dev libprotobuf-dev protobuf-compiler libqrencode-dev xvfb" NO_DEPENDS=1 NEED_XVFB=1 RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-zmq --with-incompatible-bdb --enable-glibc-back-compat --enable-reduce-exports --with-gui=qt4 CPPFLAGS=-DDEBUG_LOCKORDER" # 32-bit + dash - - HOST=i686-pc-linux-gnu PACKAGES="g++-multilib bc python3-zmq" DEP_OPTS="NO_QT=1" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-zmq --enable-glibc-back-compat --enable-reduce-exports LDFLAGS=-static-libstdc++" USE_SHELL="/bin/dash" + - HOST=i686-pc-linux-gnu PACKAGES="g++-multilib python3-zmq" DEP_OPTS="NO_QT=1" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-zmq --enable-glibc-back-compat --enable-reduce-exports LDFLAGS=-static-libstdc++" USE_SHELL="/bin/dash" # Win64 - - HOST=x86_64-w64-mingw32 DPKG_ADD_ARCH="i386" DEP_OPTS="NO_QT=1" PACKAGES="python3 nsis g++-mingw-w64-x86-64 wine1.6 bc" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-reduce-exports" + - HOST=x86_64-w64-mingw32 DPKG_ADD_ARCH="i386" DEP_OPTS="NO_QT=1" PACKAGES="python3 nsis g++-mingw-w64-x86-64 wine1.6" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-reduce-exports" # x86_64 Linux (uses qt5 dev package instead of depends Qt to speed up build and avoid timeout) - HOST=x86_64-unknown-linux-gnu PACKAGES="python3-zmq qtbase5-dev qttools5-dev-tools protobuf-compiler libdbus-1-dev libharfbuzz-dev" DEP_OPTS="NO_QT=1 NO_UPNP=1 DEBUG=1 ALLOW_HOST_PACKAGES=1" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-zmq --with-gui=qt5 --enable-glibc-back-compat --enable-reduce-exports CPPFLAGS=-DDEBUG_LOCKORDER" # x86_64 Linux, No wallet @@ -38,18 +40,23 @@ env: before_install: - export PATH=$(echo $PATH | tr ':' "\n" | sed '/\/opt\/python/d' | tr "\n" ":" | sed "s|::|:|g") + - export PATH=$(echo $PATH | tr ':' "\n" | sed '/\/opt\/pyenv/d' | tr "\n" ":" | sed "s|::|:|g") install: - if [ -n "$DPKG_ADD_ARCH" ]; then sudo dpkg --add-architecture "$DPKG_ADD_ARCH" ; fi - if [ -n "$PACKAGES" ]; then travis_retry sudo apt-get update; fi - if [ -n "$PACKAGES" ]; then travis_retry sudo apt-get install --no-install-recommends --no-upgrade -qq $PACKAGES; fi before_script: - - if [ "$TRAVIS_EVENT_TYPE" = "pull_request" ]; then contrib/devtools/commit-script-check.sh $TRAVIS_COMMIT_RANGE; fi - - unset CC; unset CXX + - if [ "$CHECK_DOC" = 1 -a "$TRAVIS_EVENT_TYPE" = "pull_request" ]; then contrib/devtools/commit-script-check.sh $TRAVIS_COMMIT_RANGE; fi - if [ "$CHECK_DOC" = 1 ]; then contrib/devtools/check-doc.py; fi + - if [ "$CHECK_DOC" = 1 ]; then contrib/devtools/check-rpc-mappings.py .; fi + - if [ "$CHECK_DOC" = 1 ]; then contrib/devtools/lint-all.sh; fi + - unset CC; unset CXX - mkdir -p depends/SDKs depends/sdk-sources - if [ -n "$OSX_SDK" -a ! -f depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz ]; then curl --location --fail $SDK_URL/MacOSX${OSX_SDK}.sdk.tar.gz -o depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz; fi - if [ -n "$OSX_SDK" -a -f depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz ]; then tar -C depends/SDKs -xf depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz; fi - - make $MAKEJOBS -C depends HOST=$HOST $DEP_OPTS + - if [ -z "$NO_DEPENDS" ]; then make $MAKEJOBS -C depends HOST=$HOST $DEP_OPTS; fi + # Start xvfb if needed, as documented at https://docs.travis-ci.com/user/gui-and-headless-browsers/#Using-xvfb-to-Run-Tests-That-Require-a-GUI + - if [ "$NEED_XVFB" = 1 ]; then export DISPLAY=:99.0; /sbin/start-stop-daemon --start --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -ac; fi script: - if [ "$CHECK_DOC" = 1 -a "$TRAVIS_REPO_SLUG" = "bitcoin/bitcoin" -a "$TRAVIS_PULL_REQUEST" = "false" ]; then while read LINE; do travis_retry gpg --keyserver hkp://subset.pool.sks-keyservers.net --recv-keys $LINE; done < contrib/verify-commits/trusted-keys; fi - if [ "$CHECK_DOC" = 1 -a "$TRAVIS_REPO_SLUG" = "bitcoin/bitcoin" -a "$TRAVIS_PULL_REQUEST" = "false" ]; then git fetch --unshallow; fi @@ -58,7 +65,7 @@ script: - if [ -n "$USE_SHELL" ]; then export CONFIG_SHELL="$USE_SHELL"; fi - OUTDIR=$BASE_OUTDIR/$TRAVIS_PULL_REQUEST/$TRAVIS_JOB_NUMBER-$HOST - BITCOIN_CONFIG_ALL="--disable-dependency-tracking --prefix=$TRAVIS_BUILD_DIR/depends/$HOST --bindir=$OUTDIR/bin --libdir=$OUTDIR/lib" - - depends/$HOST/native/bin/ccache --max-size=$CCACHE_SIZE + - if [ -z "$NO_DEPENDS" ]; then depends/$HOST/native/bin/ccache --max-size=$CCACHE_SIZE; fi - test -n "$USE_SHELL" && eval '"$USE_SHELL" -c "./autogen.sh"' || ./autogen.sh - mkdir build && cd build - ../configure --cache-file=config.cache $BITCOIN_CONFIG_ALL $BITCOIN_CONFIG || ( cat config.log && false) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 56521a5f7d..aed6d79542 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -157,6 +157,14 @@ behaviour of code within the pull request (bugs must be preserved as is). Project maintainers aim for a quick turnaround on refactoring pull requests, so where possible keep them short, uncomplex and easy to verify. +Pull requests that refactor the code should not be made by new contributors. It +requires a certain level of experience to know where the code belongs to and to +understand the full ramification (including rebase effort of open pull requests). + +Trivial pull requests or pull requests that refactor the code with no clear +benefits may be immediately closed by the maintainers to reduce unnecessary +workload on reviewing. + "Decision Making" Process ------------------------- diff --git a/contrib/devtools/check-doc.py b/contrib/devtools/check-doc.py index 3279dc3612..10c3bab03b 100755 --- a/contrib/devtools/check-doc.py +++ b/contrib/devtools/check-doc.py @@ -22,7 +22,7 @@ CMD_GREP_DOCS = r"egrep -r -I 'HelpMessageOpt\(\"\-[^\"=]+?(=|\")' %s" % (CMD_RO REGEX_ARG = re.compile(r'(?:map(?:Multi)?Args(?:\.count\(|\[)|Get(?:Bool)?Arg\()\"(\-[^\"]+?)\"') REGEX_DOC = re.compile(r'HelpMessageOpt\(\"(\-[^\"=]+?)(?:=|\")') # list unsupported, deprecated and duplicate args as they need no documentation -SET_DOC_OPTIONAL = set(['-rpcssl', '-benchmark', '-h', '-help', '-socks', '-tor', '-debugnet', '-whitelistalwaysrelay', '-prematurewitness', '-walletprematurewitness', '-promiscuousmempoolflags', '-blockminsize', '-dbcrashratio', '-forcecompactdb']) +SET_DOC_OPTIONAL = set(['-rpcssl', '-benchmark', '-h', '-help', '-socks', '-tor', '-debugnet', '-whitelistalwaysrelay', '-prematurewitness', '-walletprematurewitness', '-promiscuousmempoolflags', '-blockminsize', '-dbcrashratio', '-forcecompactdb', '-usehd']) def main(): used = check_output(CMD_GREP_ARGS, shell=True) diff --git a/contrib/devtools/check-rpc-mappings.py b/contrib/devtools/check-rpc-mappings.py new file mode 100755 index 0000000000..d2698de041 --- /dev/null +++ b/contrib/devtools/check-rpc-mappings.py @@ -0,0 +1,158 @@ +#!/usr/bin/env python3 +# Copyright (c) 2017 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Check RPC argument consistency.""" + +from collections import defaultdict +import os +import re +import sys + +# Source files (relative to root) to scan for dispatch tables +SOURCES = [ + "src/rpc/server.cpp", + "src/rpc/blockchain.cpp", + "src/rpc/mining.cpp", + "src/rpc/misc.cpp", + "src/rpc/net.cpp", + "src/rpc/rawtransaction.cpp", + "src/wallet/rpcwallet.cpp", +] +# Source file (relative to root) containing conversion mapping +SOURCE_CLIENT = 'src/rpc/client.cpp' +# Argument names that should be ignored in consistency checks +IGNORE_DUMMY_ARGS = {'dummy', 'arg0', 'arg1', 'arg2', 'arg3', 'arg4', 'arg5', 'arg6', 'arg7', 'arg8', 'arg9'} + +class RPCCommand: + def __init__(self, name, args): + self.name = name + self.args = args + +class RPCArgument: + def __init__(self, names, idx): + self.names = names + self.idx = idx + self.convert = False + +def parse_string(s): + assert s[0] == '"' + assert s[-1] == '"' + return s[1:-1] + +def process_commands(fname): + """Find and parse dispatch table in implementation file `fname`.""" + cmds = [] + in_rpcs = False + with open(fname, "r") as f: + for line in f: + line = line.rstrip() + if not in_rpcs: + if re.match("static const CRPCCommand .*\[\] =", line): + in_rpcs = True + else: + if line.startswith('};'): + in_rpcs = False + elif '{' in line and '"' in line: + m = re.search('{ *("[^"]*"), *("[^"]*"), *&([^,]*), *{([^}]*)} *},', line) + assert m, 'No match to table expression: %s' % line + name = parse_string(m.group(2)) + args_str = m.group(4).strip() + if args_str: + args = [RPCArgument(parse_string(x.strip()).split('|'), idx) for idx, x in enumerate(args_str.split(','))] + else: + args = [] + cmds.append(RPCCommand(name, args)) + assert not in_rpcs, "Something went wrong with parsing the C++ file: update the regexps" + return cmds + +def process_mapping(fname): + """Find and parse conversion table in implementation file `fname`.""" + cmds = [] + in_rpcs = False + with open(fname, "r") as f: + for line in f: + line = line.rstrip() + if not in_rpcs: + if line == 'static const CRPCConvertParam vRPCConvertParams[] =': + in_rpcs = True + else: + if line.startswith('};'): + in_rpcs = False + elif '{' in line and '"' in line: + m = re.search('{ *("[^"]*"), *([0-9]+) *, *("[^"]*") *},', line) + assert m, 'No match to table expression: %s' % line + name = parse_string(m.group(1)) + idx = int(m.group(2)) + argname = parse_string(m.group(3)) + cmds.append((name, idx, argname)) + assert not in_rpcs + return cmds + +def main(): + root = sys.argv[1] + + # Get all commands from dispatch tables + cmds = [] + for fname in SOURCES: + cmds += process_commands(os.path.join(root, fname)) + + cmds_by_name = {} + for cmd in cmds: + cmds_by_name[cmd.name] = cmd + + # Get current convert mapping for client + client = SOURCE_CLIENT + mapping = set(process_mapping(os.path.join(root, client))) + + print('* Checking consistency between dispatch tables and vRPCConvertParams') + + # Check mapping consistency + errors = 0 + for (cmdname, argidx, argname) in mapping: + try: + rargnames = cmds_by_name[cmdname].args[argidx].names + except IndexError: + print('ERROR: %s argument %i (named %s in vRPCConvertParams) is not defined in dispatch table' % (cmdname, argidx, argname)) + errors += 1 + continue + if argname not in rargnames: + print('ERROR: %s argument %i is named %s in vRPCConvertParams but %s in dispatch table' % (cmdname, argidx, argname, rargnames), file=sys.stderr) + errors += 1 + + # Check for conflicts in vRPCConvertParams conversion + # All aliases for an argument must either be present in the + # conversion table, or not. Anything in between means an oversight + # and some aliases won't work. + for cmd in cmds: + for arg in cmd.args: + convert = [((cmd.name, arg.idx, argname) in mapping) for argname in arg.names] + if any(convert) != all(convert): + print('ERROR: %s argument %s has conflicts in vRPCConvertParams conversion specifier %s' % (cmd.name, arg.names, convert)) + errors += 1 + arg.convert = all(convert) + + # Check for conversion difference by argument name. + # It is preferable for API consistency that arguments with the same name + # have the same conversion, so bin by argument name. + all_methods_by_argname = defaultdict(list) + converts_by_argname = defaultdict(list) + for cmd in cmds: + for arg in cmd.args: + for argname in arg.names: + all_methods_by_argname[argname].append(cmd.name) + converts_by_argname[argname].append(arg.convert) + + for argname, convert in converts_by_argname.items(): + if all(convert) != any(convert): + if argname in IGNORE_DUMMY_ARGS: + # these are testing or dummy, don't warn for them + continue + print('WARNING: conversion mismatch for argument named %s (%s)' % + (argname, list(zip(all_methods_by_argname[argname], converts_by_argname[argname])))) + + sys.exit(errors > 0) + + +if __name__ == '__main__': + main() diff --git a/contrib/devtools/lint-all.sh b/contrib/devtools/lint-all.sh new file mode 100755 index 0000000000..b6d86959c6 --- /dev/null +++ b/contrib/devtools/lint-all.sh @@ -0,0 +1,22 @@ +#!/bin/bash +# +# Copyright (c) 2017 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 runs all contrib/devtools/lint-*.sh files, and fails if any exit +# with a non-zero status code. + +set -u + +SCRIPTDIR=$(dirname "${BASH_SOURCE[0]}") +LINTALL=$(basename "${BASH_SOURCE[0]}") + +for f in "${SCRIPTDIR}"/lint-*.sh; do + if [ "$(basename "$f")" != "$LINTALL" ]; then + if ! "$f"; then + echo "^---- failure generated from $f" + exit 1 + fi + fi +done diff --git a/contrib/devtools/lint-whitespace.sh b/contrib/devtools/lint-whitespace.sh new file mode 100755 index 0000000000..989923f31a --- /dev/null +++ b/contrib/devtools/lint-whitespace.sh @@ -0,0 +1,88 @@ +#!/bin/bash +# +# Copyright (c) 2017 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +# +# Check for new lines in diff that introduce trailing whitespace. + +# We can't run this check unless we know the commit range for the PR. +if [ -z "${TRAVIS_COMMIT_RANGE}" ]; then + echo "Cannot run lint-whitespace.sh without commit range. To run locally, use:" + echo "TRAVIS_COMMIT_RANGE='<commit range>' .lint-whitespace.sh" + echo "For example:" + echo "TRAVIS_COMMIT_RANGE='47ba2c3...ee50c9e' .lint-whitespace.sh" + exit 1 +fi + +showdiff() { + if ! git diff -U0 "${TRAVIS_COMMIT_RANGE}" -- "." ":(exclude)src/leveldb/" ":(exclude)src/secp256k1/" ":(exclude)src/univalue/" ":(exclude)doc/release-notes/"; then + echo "Failed to get a diff" + exit 1 + fi +} + +showcodediff() { + if ! git diff -U0 "${TRAVIS_COMMIT_RANGE}" -- *.cpp *.h *.md *.py *.sh ":(exclude)src/leveldb/" ":(exclude)src/secp256k1/" ":(exclude)src/univalue/" ":(exclude)doc/release-notes/"; then + echo "Failed to get a diff" + exit 1 + fi +} + +RET=0 + +# Check if trailing whitespace was found in the diff. +if showdiff | grep -E -q '^\+.*\s+$'; then + echo "This diff appears to have added new lines with trailing whitespace." + echo "The following changes were suspected:" + FILENAME="" + SEEN=0 + while read -r line; do + if [[ "$line" =~ ^diff ]]; then + FILENAME="$line" + SEEN=0 + elif [[ "$line" =~ ^@@ ]]; then + LINENUMBER="$line" + else + if [ "$SEEN" -eq 0 ]; then + # The first time a file is seen with trailing whitespace, we print the + # filename (preceded by a newline). + echo + echo "$FILENAME" + echo "$LINENUMBER" + SEEN=1 + fi + echo "$line" + fi + done < <(showdiff | grep -E '^(diff --git |@@|\+.*\s+$)') + RET=1 +fi + +# Check if tab characters were found in the diff. +if showcodediff | grep -P -q '^\+.*\t'; then + echo "This diff appears to have added new lines with tab characters instead of spaces." + echo "The following changes were suspected:" + FILENAME="" + SEEN=0 + while read -r line; do + if [[ "$line" =~ ^diff ]]; then + FILENAME="$line" + SEEN=0 + elif [[ "$line" =~ ^@@ ]]; then + LINENUMBER="$line" + else + if [ "$SEEN" -eq 0 ]; then + # The first time a file is seen with a tab character, we print the + # filename (preceded by a newline). + echo + echo "$FILENAME" + echo "$LINENUMBER" + SEEN=1 + fi + echo "$line" + fi + done < <(showcodediff | grep -P '^(diff --git |@@|\+.*\t)') + RET=1 +fi + +exit $RET diff --git a/depends/packages/libevent.mk b/depends/packages/libevent.mk index 00231d75d5..5f622f8e6e 100644 --- a/depends/packages/libevent.mk +++ b/depends/packages/libevent.mk @@ -9,7 +9,7 @@ define $(package)_preprocess_cmds endef define $(package)_set_vars - $(package)_config_opts=--disable-shared --disable-openssl --disable-libevent-regress + $(package)_config_opts=--disable-shared --disable-openssl --disable-libevent-regress --disable-samples $(package)_config_opts_release=--disable-debug-mode $(package)_config_opts_linux=--with-pic endef diff --git a/doc/README.md b/doc/README.md index 275ae67e54..988019869e 100644 --- a/doc/README.md +++ b/doc/README.md @@ -37,6 +37,7 @@ Building --------------------- The following are developer notes on how to build Bitcoin on your native platform. They are not complete guides, but include notes on the necessary libraries, compile flags, etc. +- [Dependencies](dependencies.md) - [OS X Build Notes](build-osx.md) - [Unix Build Notes](build-unix.md) - [Windows Build Notes](build-windows.md) diff --git a/doc/build-openbsd.md b/doc/build-openbsd.md index cd800464b4..4ea8e30b53 100644 --- a/doc/build-openbsd.md +++ b/doc/build-openbsd.md @@ -18,12 +18,12 @@ pkg_add automake # (select highest version, e.g. 1.15) pkg_add python # (select highest version, e.g. 3.5) ``` -The default C++ compiler that comes with OpenBSD 5.9 is g++ 4.2. This version is old (from 2007), and is not able to compile the current version of Bitcoin Core, primarily as it has no C++11 support, but even before there were issues. So here we will be installing a newer compiler. +See [dependencies.md](dependencies.md) for a complete overview. GCC ------- -You can install a newer version of gcc with: +The default C++ compiler that comes with OpenBSD 5.9 is g++ 4.2. This version is old (from 2007), and is not able to compile the current version of Bitcoin Core, primarily as it has no C++11 support, but even before there were issues. So here we will be installing a newer compiler: ```bash pkg_add g++ # (select newest 4.x version, e.g. 4.9.3) diff --git a/doc/build-osx.md b/doc/build-osx.md index 1320d309c4..836c856a64 100644 --- a/doc/build-osx.md +++ b/doc/build-osx.md @@ -18,6 +18,8 @@ Dependencies brew install automake berkeley-db4 libtool boost --c++11 miniupnpc openssl pkg-config protobuf python3 qt libevent +See [dependencies.md](dependencies.md) for a complete overview. + If you want to build the disk image with `make deploy` (.dmg / optional), you need RSVG brew install librsvg diff --git a/doc/build-unix.md b/doc/build-unix.md index 2e82934cd1..8a102abaea 100644 --- a/doc/build-unix.md +++ b/doc/build-unix.md @@ -49,7 +49,7 @@ Optional dependencies: univalue | Utility | JSON parsing and encoding (bundled version will be used unless --with-system-univalue passed to configure) libzmq3 | ZMQ notification | Optional, allows generating ZMQ notifications (requires ZMQ version >= 4.x) -For the versions used in the release, see [release-process.md](release-process.md) under *Fetch and build inputs*. +For the versions used, see [dependencies.md](dependencies.md) Memory Requirements -------------------- diff --git a/doc/build-windows.md b/doc/build-windows.md index ca1a05dfb4..ce837a222a 100644 --- a/doc/build-windows.md +++ b/doc/build-windows.md @@ -62,6 +62,8 @@ A host toolchain (`build-essential`) is necessary because some dependency packages (such as `protobuf`) need to build host utilities that are used in the build process. +See also: [dependencies.md](dependencies.md). + ## Building for 64-bit Windows To build executables for Windows 64-bit, install the following dependencies: diff --git a/doc/dependencies.md b/doc/dependencies.md new file mode 100644 index 0000000000..964c03ba88 --- /dev/null +++ b/doc/dependencies.md @@ -0,0 +1,31 @@ +Dependencies +============ + +These are the dependencies currently used by Bitcoin Core. You can find instructions for installing them in the `build-*.md` file for your platform. + +| Dependency | Version used | Minimum required | CVEs | Shared | [Bundled Qt library](https://doc.qt.io/qt-5/configure-options.html) | +| --- | --- | --- | --- | --- | --- | +| Berkeley DB | [4.8.30](http://www.oracle.com/technetwork/database/database-technologies/berkeleydb/downloads/index.html) | 4.8.x | No | | | +| Boost | [1.64.0](http://www.boost.org/users/download/) | [1.47.0](https://github.com/bitcoin/bitcoin/pull/8920) | No | | | +| ccache | [3.3.4](https://ccache.samba.org/download.html) | | No | | | +| Clang | | [3.3+](http://llvm.org/releases/download.html) (C++11 support) | | | | +| D-Bus | [1.10.18](https://cgit.freedesktop.org/dbus/dbus/tree/NEWS?h=dbus-1.10) | | No | Yes | | +| Expat | [2.2.1](https://libexpat.github.io/) | | No | Yes | | +| fontconfig | [2.12.1](https://www.freedesktop.org/software/fontconfig/release/) | | No | Yes | | +| FreeType | [2.7.1](http://download.savannah.gnu.org/releases/freetype) | | No | | | +| GCC | | [4.7+](https://gcc.gnu.org/) | | | | +| HarfBuzz-NG | | | | | | +| libevent | [2.1.8-stable](https://github.com/libevent/libevent/releases) | 2.0.22 | No | | | +| libjpeg | | | | | [Yes](https://github.com/bitcoin/bitcoin/blob/master/depends/packages/qt.mk#L75) | +| libpng | | | | | [Yes](https://github.com/bitcoin/bitcoin/blob/master/depends/packages/qt.mk#L74) | +| MiniUPnPc | [2.0.20170509](http://miniupnp.free.fr/files) | | No | | | +| OpenSSL | [1.0.1k](https://www.openssl.org/source) | | Yes | | | +| PCRE | | | | | [Yes](https://github.com/bitcoin/bitcoin/blob/master/depends/packages/qt.mk#L76) | +| protobuf | [2.6.3](https://github.com/google/protobuf/releases) | | No | | | +| Python (tests) | | [3.4](https://www.python.org/downloads) | | | | +| qrencode | [3.4.4](https://fukuchi.org/works/qrencode) | | No | | | +| Qt | [5.7.1](https://download.qt.io/official_releases/qt/) | 4.7+ | No | | | +| XCB | | | | | [Yes](https://github.com/bitcoin/bitcoin/blob/master/depends/packages/qt.mk#L94) (Linux only) | +| xkbcommon | | | | | [Yes](https://github.com/bitcoin/bitcoin/blob/master/depends/packages/qt.mk#L93) (Linux only) | +| ZeroMQ | [4.1.5](https://github.com/zeromq/libzmq/releases) | | No | | | +| zlib | [1.2.11](http://zlib.net/) | | | | No | diff --git a/doc/developer-notes.md b/doc/developer-notes.md index 2f04d6ee6c..8fdae25340 100644 --- a/doc/developer-notes.md +++ b/doc/developer-notes.md @@ -613,9 +613,14 @@ A few guidelines for introducing and reviewing new RPC interfaces: from there. - A RPC method must either be a wallet method or a non-wallet method. Do not - introduce new methods such as `getinfo` and `signrawtransaction` that differ - in behavior based on presence of a wallet. + introduce new methods such as `signrawtransaction` that differ in behavior + based on presence of a wallet. - *Rationale*: as well as complicating the implementation and interfering with the introduction of multi-wallet, wallet and non-wallet code should be separated to avoid introducing circular dependencies between code units. + +- Try to make the RPC response a JSON object. + + - *Rationale*: If a RPC response is not a JSON object then it is harder to avoid API breakage if + new data in the response is needed. diff --git a/doc/man/bitcoin-cli.1 b/doc/man/bitcoin-cli.1 index 0493241b1e..6787638443 100644 --- a/doc/man/bitcoin-cli.1 +++ b/doc/man/bitcoin-cli.1 @@ -1,9 +1,9 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. -.TH BITCOIN-CLI "1" "February 2017" "bitcoin-cli v0.14.99.0" "User Commands" +.TH BITCOIN-CLI "1" "September 2017" "bitcoin-cli v0.15.99.0" "User Commands" .SH NAME -bitcoin-cli \- manual page for bitcoin-cli v0.14.99.0 +bitcoin-cli \- manual page for bitcoin-cli v0.15.99.0 .SH DESCRIPTION -Bitcoin Core RPC client version v0.14.99.0 +Bitcoin Core RPC client version v0.15.99.0 .SS "Usage:" .TP bitcoin\-cli [options] <command> [params] @@ -64,12 +64,29 @@ Password for JSON\-RPC connections .HP \fB\-rpcclienttimeout=\fR<n> .IP -Timeout during HTTP requests (default: 900) +Timeout in seconds during HTTP requests, or 0 for no timeout. (default: +900) +.HP +\fB\-stdinrpcpass\fR +.TP +Read RPC password from standard input as a single line. +When combined +.IP +with \fB\-stdin\fR, the first line from standard input is used for the +RPC password. .HP \fB\-stdin\fR .IP Read extra arguments from standard input, one per line until EOF/Ctrl\-D -(recommended for sensitive information such as passphrases) +(recommended for sensitive information such as passphrases). +When combined with \fB\-stdinrpcpass\fR, the first line from standard +input is used for the RPC password. +.HP +\fB\-rpcwallet=\fR<walletname> +.IP +Send RPC for non\-default wallet on RPC server (argument is wallet +filename in bitcoind directory, required if bitcoind/\-Qt runs +with multiple wallets) .SH COPYRIGHT Copyright (C) 2009-2017 The Bitcoin Core developers diff --git a/doc/man/bitcoin-qt.1 b/doc/man/bitcoin-qt.1 index ce252612e5..ae35d50ac3 100644 --- a/doc/man/bitcoin-qt.1 +++ b/doc/man/bitcoin-qt.1 @@ -1,9 +1,9 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. -.TH BITCOIN-QT "1" "February 2017" "bitcoin-qt v0.14.99.0" "User Commands" +.TH BITCOIN-QT "1" "September 2017" "bitcoin-qt v0.15.99.0" "User Commands" .SH NAME -bitcoin-qt \- manual page for bitcoin-qt v0.14.99.0 +bitcoin-qt \- manual page for bitcoin-qt v0.15.99.0 .SH DESCRIPTION -Bitcoin Core version v0.14.99.0 (64\-bit) +Bitcoin Core version v0.15.99.0 (64\-bit) Usage: .IP bitcoin\-qt [command\-line options] @@ -32,9 +32,9 @@ block hash) If this block is in the chain assume that it and its ancestors are valid and potentially skip their script verification (0 to verify all, default: -00000000000000000013176bf8d7dfeab4e1db31dc93bc311b436e82ab226b90, +0000000000000000003b9ce759c2a087d52abc4266f8f4ebd6d768b89defa50a, testnet: -00000000000128796ee387cf110ccb9d2f36cffaf7f73079c995377c65ac0dcc) +0000000002e9e7b00e1f6dc5123a04aad68dd0f0968d8c7aa45f6640795c37b1) .HP \fB\-conf=\fR<file> .IP @@ -46,7 +46,7 @@ Specify data directory .HP \fB\-dbcache=\fR<n> .IP -Set database cache size in megabytes (4 to 16384, default: 300) +Set database cache size in megabytes (4 to 16384, default: 450) .HP \fB\-loadblock=\fR<file> .IP @@ -65,6 +65,10 @@ Keep the transaction memory pool below <n> megabytes (default: 300) Do not keep transactions in the mempool longer than <n> hours (default: 336) .HP +\fB\-persistmempool\fR +.IP +Whether to save the mempool on shutdown and load on restart (default: 1) +.HP \fB\-blockreconstructionextratxn=\fR<n> .IP Extra transactions to keep in memory for compact block reconstructions @@ -131,8 +135,8 @@ for IPv6 .HP \fB\-connect=\fR<ip> .IP -Connect only to the specified node(s); \fB\-noconnect\fR or \fB\-connect\fR=\fI\,0\/\fR alone to -disable automatic connections +Connect only to the specified node(s); \fB\-connect\fR=\fI\,0\/\fR disables automatic +connections .HP \fB\-discover\fR .IP @@ -146,7 +150,7 @@ Allow DNS lookups for \fB\-addnode\fR, \fB\-seednode\fR and \fB\-connect\fR (def \fB\-dnsseed\fR .IP Query for peer addresses via DNS lookup, if low on addresses (default: 1 -unless \fB\-connect\fR/\-noconnect) +unless \fB\-connect\fR used) .HP \fB\-externalip=\fR<ip> .IP @@ -158,8 +162,7 @@ Always query for peer addresses via DNS lookup (default: 0) .HP \fB\-listen\fR .IP -Accept connections from outside (default: 1 if no \fB\-proxy\fR or -\fB\-connect\fR/\-noconnect) +Accept connections from outside (default: 1 if no \fB\-proxy\fR or \fB\-connect\fR) .HP \fB\-listenonion\fR .IP @@ -214,11 +217,6 @@ Connect through SOCKS5 proxy Randomize credentials for every proxy connection. This enables Tor stream isolation (default: 1) .HP -\fB\-rpcserialversion\fR -.IP -Sets the serialization of raw transaction or block hex returned in -non\-verbose mode, non\-segwit(0) or segwit(1) (default: 1) -.HP \fB\-seednode=\fR<ip> .IP Connect to a node to retrieve peer addresses, and disconnect @@ -253,16 +251,6 @@ times. Whitelisted peers cannot be DoS banned and their transactions are always relayed, even if they are already in the mempool, useful e.g. for a gateway .HP -\fB\-whitelistrelay\fR -.IP -Accept relayed transactions received from whitelisted peers even when -not relaying transactions (default: 1) -.HP -\fB\-whitelistforcerelay\fR -.IP -Force relay of transactions from whitelisted peers even if they violate -local relay policy (default: 1) -.HP \fB\-maxuploadtarget=\fR<n> .IP Tries to keep outbound traffic under the given target (in MiB per 24h), @@ -276,13 +264,21 @@ Do not load the wallet and disable wallet RPC calls .HP \fB\-keypool=\fR<n> .IP -Set key pool size to <n> (default: 100) +Set key pool size to <n> (default: 1000) .HP \fB\-fallbackfee=\fR<amt> .IP A fee rate (in BTC/kB) that will be used when fee estimation has insufficient data (default: 0.0002) .HP +\fB\-discardfee=\fR<amt> +.IP +The fee rate (in BTC/kB) that indicates your tolerance for discarding +change by adding it to the fee (default: 0.0001). Note: An output +is discarded if it is dust at this rate, but we will always +discard up to the dust relay fee and a discard fee above that is +limited by the fee estimate for the longest target +.HP \fB\-mintxfee=\fR<amt> .IP Fees (in BTC/kB) smaller than this are considered zero fee for @@ -309,11 +305,6 @@ Spend unconfirmed change when sending transactions (default: 1) If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: 6) .HP -\fB\-usehd\fR -.IP -Use hierarchical deterministic key generation (HD) after BIP32. Only has -effect during wallet creation/first start (default: 1) -.HP \fB\-walletrbf\fR .IP Send transactions with full\-RBF opt\-in enabled (default: 0) @@ -370,10 +361,16 @@ Append comment to the user agent string .IP Output debugging information (default: 0, supplying <category> is optional). If <category> is not supplied or if <category> = 1, -output all debugging information.<category> can be: addrman, -alert, bench, cmpctblock, coindb, db, http, libevent, lock, -mempool, mempoolrej, net, proxy, prune, rand, reindex, rpc, -selectcoins, tor, zmq, qt. +output all debugging information. <category> can be: net, tor, +mempool, http, bench, zmq, db, rpc, estimatefee, addrman, +selectcoins, reindex, cmpctblock, rand, prune, proxy, mempoolrej, +libevent, coindb, qt, leveldb. +.HP +\fB\-debugexclude=\fR<category> +.IP +Exclude debugging information for a category. Can be used in conjunction +with \fB\-debug\fR=\fI\,1\/\fR to output debug logs for all categories except one +or more specified categories. .HP \fB\-help\-debug\fR .IP @@ -387,11 +384,6 @@ Include IP addresses in debug output (default: 0) .IP Prepend debug output with timestamp (default: 1) .HP -\fB\-minrelaytxfee=\fR<amt> -.IP -Fees (in BTC/kB) smaller than this are considered zero fee for relaying, -mining and transaction creation (default: 0.00001) -.HP \fB\-maxtxfee=\fR<amt> .IP Maximum total fees (in BTC) to use in a single wallet transaction or raw @@ -431,21 +423,32 @@ Maximum size of data in data carrier transactions we relay and mine \fB\-mempoolreplacement\fR .IP Enable transaction replacement in the memory pool (default: 1) +.HP +\fB\-minrelaytxfee=\fR<amt> +.IP +Fees (in BTC/kB) smaller than this are considered zero fee for relaying, +mining and transaction creation (default: 0.00001) +.HP +\fB\-whitelistrelay\fR +.IP +Accept relayed transactions received from whitelisted peers even when +not relaying transactions (default: 1) +.HP +\fB\-whitelistforcerelay\fR +.IP +Force relay of transactions from whitelisted peers even if they violate +local relay policy (default: 1) .PP Block creation options: .HP \fB\-blockmaxweight=\fR<n> .IP -Set maximum BIP141 block weight (default: 3000000) +Set maximum BIP141 block weight (default: 3996000) .HP \fB\-blockmaxsize=\fR<n> .IP -Set maximum block size in bytes (default: 750000) -.HP -\fB\-blockprioritysize=\fR<n> -.IP -Set maximum size of high\-priority/low\-fee transactions in bytes -(default: 0) +Set maximum BIP141 block weight to this * 4. Deprecated, use +blockmaxweight .HP \fB\-blockmintxfee=\fR<amt> .IP @@ -462,11 +465,14 @@ Accept command line and JSON\-RPC commands .IP Accept public REST requests (default: 0) .HP -\fB\-rpcbind=\fR<addr> +\fB\-rpcbind=\fR<addr>[:port] .IP -Bind to given address to listen for JSON\-RPC connections. Use -[host]:port notation for IPv6. This option can be specified -multiple times (default: bind to all interfaces) +Bind to given address to listen for JSON\-RPC connections. This option is +ignored unless \fB\-rpcallowip\fR is also passed. Port is optional and +overrides \fB\-rpcport\fR. Use [host]:port notation for IPv6. This +option can be specified multiple times (default: 127.0.0.1 and +::1 i.e., localhost, or if \fB\-rpcallowip\fR has been specified, +0.0.0.0 and :: i.e., all addresses) .HP \fB\-rpccookiefile=\fR<loc> .IP @@ -501,6 +507,11 @@ single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24). This option can be specified multiple times .HP +\fB\-rpcserialversion\fR +.IP +Sets the serialization of raw transaction or block hex returned in +non\-verbose mode, non\-segwit(0) or segwit(1) (default: 1) +.HP \fB\-rpcthreads=\fR<n> .IP Set the number of threads to service RPC calls (default: 4) diff --git a/doc/man/bitcoin-tx.1 b/doc/man/bitcoin-tx.1 index 98adf2f5b1..8b72fbde05 100644 --- a/doc/man/bitcoin-tx.1 +++ b/doc/man/bitcoin-tx.1 @@ -1,9 +1,9 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. -.TH BITCOIN-TX "1" "February 2017" "bitcoin-tx v0.14.99.0" "User Commands" +.TH BITCOIN-TX "1" "September 2017" "bitcoin-tx v0.15.99.0" "User Commands" .SH NAME -bitcoin-tx \- manual page for bitcoin-tx v0.14.99.0 +bitcoin-tx \- manual page for bitcoin-tx v0.15.99.0 .SH DESCRIPTION -Bitcoin Core bitcoin\-tx utility version v0.14.99.0 +Bitcoin Core bitcoin\-tx utility version v0.15.99.0 .SS "Usage:" .TP bitcoin\-tx [options] <hex\-tx> [commands] @@ -63,6 +63,11 @@ nversion=N .IP Set TX version to N .IP +replaceable(=N) +.IP +Set RBF opt\-in sequence number for input N (if not provided, opt\-in all +available inputs) +.IP outaddr=VALUE:ADDRESS .IP Add address\-based output to TX diff --git a/doc/man/bitcoind.1 b/doc/man/bitcoind.1 index fb066e0c6f..baf747436f 100644 --- a/doc/man/bitcoind.1 +++ b/doc/man/bitcoind.1 @@ -1,9 +1,9 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. -.TH BITCOIND "1" "February 2017" "bitcoind v0.14.99.0" "User Commands" +.TH BITCOIND "1" "September 2017" "bitcoind v0.15.99.0" "User Commands" .SH NAME -bitcoind \- manual page for bitcoind v0.14.99.0 +bitcoind \- manual page for bitcoind v0.15.99.0 .SH DESCRIPTION -Bitcoin Core Daemon version v0.14.99.0 +Bitcoin Core Daemon version v0.15.99.0 .SS "Usage:" .TP bitcoind [options] @@ -33,9 +33,9 @@ block hash) If this block is in the chain assume that it and its ancestors are valid and potentially skip their script verification (0 to verify all, default: -00000000000000000013176bf8d7dfeab4e1db31dc93bc311b436e82ab226b90, +0000000000000000003b9ce759c2a087d52abc4266f8f4ebd6d768b89defa50a, testnet: -00000000000128796ee387cf110ccb9d2f36cffaf7f73079c995377c65ac0dcc) +0000000002e9e7b00e1f6dc5123a04aad68dd0f0968d8c7aa45f6640795c37b1) .HP \fB\-conf=\fR<file> .IP @@ -51,7 +51,7 @@ Specify data directory .HP \fB\-dbcache=\fR<n> .IP -Set database cache size in megabytes (4 to 16384, default: 300) +Set database cache size in megabytes (4 to 16384, default: 450) .HP \fB\-loadblock=\fR<file> .IP @@ -70,6 +70,10 @@ Keep the transaction memory pool below <n> megabytes (default: 300) Do not keep transactions in the mempool longer than <n> hours (default: 336) .HP +\fB\-persistmempool\fR +.IP +Whether to save the mempool on shutdown and load on restart (default: 1) +.HP \fB\-blockreconstructionextratxn=\fR<n> .IP Extra transactions to keep in memory for compact block reconstructions @@ -136,8 +140,8 @@ for IPv6 .HP \fB\-connect=\fR<ip> .IP -Connect only to the specified node(s); \fB\-noconnect\fR or \fB\-connect\fR=\fI\,0\/\fR alone to -disable automatic connections +Connect only to the specified node(s); \fB\-connect\fR=\fI\,0\/\fR disables automatic +connections .HP \fB\-discover\fR .IP @@ -151,7 +155,7 @@ Allow DNS lookups for \fB\-addnode\fR, \fB\-seednode\fR and \fB\-connect\fR (def \fB\-dnsseed\fR .IP Query for peer addresses via DNS lookup, if low on addresses (default: 1 -unless \fB\-connect\fR/\-noconnect) +unless \fB\-connect\fR used) .HP \fB\-externalip=\fR<ip> .IP @@ -163,8 +167,7 @@ Always query for peer addresses via DNS lookup (default: 0) .HP \fB\-listen\fR .IP -Accept connections from outside (default: 1 if no \fB\-proxy\fR or -\fB\-connect\fR/\-noconnect) +Accept connections from outside (default: 1 if no \fB\-proxy\fR or \fB\-connect\fR) .HP \fB\-listenonion\fR .IP @@ -219,11 +222,6 @@ Connect through SOCKS5 proxy Randomize credentials for every proxy connection. This enables Tor stream isolation (default: 1) .HP -\fB\-rpcserialversion\fR -.IP -Sets the serialization of raw transaction or block hex returned in -non\-verbose mode, non\-segwit(0) or segwit(1) (default: 1) -.HP \fB\-seednode=\fR<ip> .IP Connect to a node to retrieve peer addresses, and disconnect @@ -258,16 +256,6 @@ times. Whitelisted peers cannot be DoS banned and their transactions are always relayed, even if they are already in the mempool, useful e.g. for a gateway .HP -\fB\-whitelistrelay\fR -.IP -Accept relayed transactions received from whitelisted peers even when -not relaying transactions (default: 1) -.HP -\fB\-whitelistforcerelay\fR -.IP -Force relay of transactions from whitelisted peers even if they violate -local relay policy (default: 1) -.HP \fB\-maxuploadtarget=\fR<n> .IP Tries to keep outbound traffic under the given target (in MiB per 24h), @@ -281,13 +269,21 @@ Do not load the wallet and disable wallet RPC calls .HP \fB\-keypool=\fR<n> .IP -Set key pool size to <n> (default: 100) +Set key pool size to <n> (default: 1000) .HP \fB\-fallbackfee=\fR<amt> .IP A fee rate (in BTC/kB) that will be used when fee estimation has insufficient data (default: 0.0002) .HP +\fB\-discardfee=\fR<amt> +.IP +The fee rate (in BTC/kB) that indicates your tolerance for discarding +change by adding it to the fee (default: 0.0001). Note: An output +is discarded if it is dust at this rate, but we will always +discard up to the dust relay fee and a discard fee above that is +limited by the fee estimate for the longest target +.HP \fB\-mintxfee=\fR<amt> .IP Fees (in BTC/kB) smaller than this are considered zero fee for @@ -314,11 +310,6 @@ Spend unconfirmed change when sending transactions (default: 1) If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: 6) .HP -\fB\-usehd\fR -.IP -Use hierarchical deterministic key generation (HD) after BIP32. Only has -effect during wallet creation/first start (default: 1) -.HP \fB\-walletrbf\fR .IP Send transactions with full\-RBF opt\-in enabled (default: 0) @@ -375,10 +366,16 @@ Append comment to the user agent string .IP Output debugging information (default: 0, supplying <category> is optional). If <category> is not supplied or if <category> = 1, -output all debugging information.<category> can be: addrman, -alert, bench, cmpctblock, coindb, db, http, libevent, lock, -mempool, mempoolrej, net, proxy, prune, rand, reindex, rpc, -selectcoins, tor, zmq. +output all debugging information. <category> can be: net, tor, +mempool, http, bench, zmq, db, rpc, estimatefee, addrman, +selectcoins, reindex, cmpctblock, rand, prune, proxy, mempoolrej, +libevent, coindb, qt, leveldb. +.HP +\fB\-debugexclude=\fR<category> +.IP +Exclude debugging information for a category. Can be used in conjunction +with \fB\-debug\fR=\fI\,1\/\fR to output debug logs for all categories except one +or more specified categories. .HP \fB\-help\-debug\fR .IP @@ -392,11 +389,6 @@ Include IP addresses in debug output (default: 0) .IP Prepend debug output with timestamp (default: 1) .HP -\fB\-minrelaytxfee=\fR<amt> -.IP -Fees (in BTC/kB) smaller than this are considered zero fee for relaying, -mining and transaction creation (default: 0.00001) -.HP \fB\-maxtxfee=\fR<amt> .IP Maximum total fees (in BTC) to use in a single wallet transaction or raw @@ -436,21 +428,32 @@ Maximum size of data in data carrier transactions we relay and mine \fB\-mempoolreplacement\fR .IP Enable transaction replacement in the memory pool (default: 1) +.HP +\fB\-minrelaytxfee=\fR<amt> +.IP +Fees (in BTC/kB) smaller than this are considered zero fee for relaying, +mining and transaction creation (default: 0.00001) +.HP +\fB\-whitelistrelay\fR +.IP +Accept relayed transactions received from whitelisted peers even when +not relaying transactions (default: 1) +.HP +\fB\-whitelistforcerelay\fR +.IP +Force relay of transactions from whitelisted peers even if they violate +local relay policy (default: 1) .PP Block creation options: .HP \fB\-blockmaxweight=\fR<n> .IP -Set maximum BIP141 block weight (default: 3000000) +Set maximum BIP141 block weight (default: 3996000) .HP \fB\-blockmaxsize=\fR<n> .IP -Set maximum block size in bytes (default: 750000) -.HP -\fB\-blockprioritysize=\fR<n> -.IP -Set maximum size of high\-priority/low\-fee transactions in bytes -(default: 0) +Set maximum BIP141 block weight to this * 4. Deprecated, use +blockmaxweight .HP \fB\-blockmintxfee=\fR<amt> .IP @@ -467,11 +470,14 @@ Accept command line and JSON\-RPC commands .IP Accept public REST requests (default: 0) .HP -\fB\-rpcbind=\fR<addr> +\fB\-rpcbind=\fR<addr>[:port] .IP -Bind to given address to listen for JSON\-RPC connections. Use -[host]:port notation for IPv6. This option can be specified -multiple times (default: bind to all interfaces) +Bind to given address to listen for JSON\-RPC connections. This option is +ignored unless \fB\-rpcallowip\fR is also passed. Port is optional and +overrides \fB\-rpcport\fR. Use [host]:port notation for IPv6. This +option can be specified multiple times (default: 127.0.0.1 and +::1 i.e., localhost, or if \fB\-rpcallowip\fR has been specified, +0.0.0.0 and :: i.e., all addresses) .HP \fB\-rpccookiefile=\fR<loc> .IP @@ -506,6 +512,11 @@ single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24). This option can be specified multiple times .HP +\fB\-rpcserialversion\fR +.IP +Sets the serialization of raw transaction or block hex returned in +non\-verbose mode, non\-segwit(0) or segwit(1) (default: 1) +.HP \fB\-rpcthreads=\fR<n> .IP Set the number of threads to service RPC calls (default: 4) diff --git a/doc/release-notes.md b/doc/release-notes.md index aa1d1bea14..04fb0f333b 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -8,7 +8,7 @@ Bitcoin Core version *version* is now available from: This is a new major version release, including new features, various bugfixes and performance improvements, as well as updated translations. -Please report bugs using the issue tracker at github: +Please report bugs using the issue tracker at GitHub: <https://github.com/bitcoin/bitcoin/issues> @@ -21,7 +21,7 @@ How to Upgrade If you are running an older version, shut it down. Wait until it has completely shut down (which might take a few minutes for older versions), then run the -installer (on Windows) or just copy over /Applications/Bitcoin-Qt (on Mac) +installer (on Windows) or just copy over `/Applications/Bitcoin-Qt` (on Mac) or `bitcoind`/`bitcoin-qt` (on Linux). The first time you run version 0.15.0, your chainstate database will be converted to a @@ -56,6 +56,33 @@ frequently tested on them. Notable changes =============== +Miner block size limiting deprecated +------------------------------------ + +Though blockmaxweight has been preferred for limiting the size of blocks returned by +getblocktemplate since 0.13.0, blockmaxsize remained as an option for those who wished +to limit their block size directly. Using this option resulted in a few UI issues as +well as non-optimal fee selection and ever-so-slightly worse performance, and has thus +now been deprecated. Further, the blockmaxsize option is now used only to calculate an +implied blockmaxweight, instead of limiting block size directly. Any miners who wish +to limit their blocks by size, instead of by weight, will have to do so manually by +removing transactions from their block template directly. + +HD-wallets by default +--------------------- +Due to a backward-incompatible change in the wallet database, wallets created +with version 0.16.0 will be rejected by previous versions. Also, version 0.16.0 +will only create hierarchical deterministic (HD) wallets. + +Low-level RPC changes +---------------------- +- The "currentblocksize" value in getmininginfo has been removed. +- The deprecated RPC `getinfo` was removed. It is recommended that the more specific RPCs are used: + * `getblockchaininfo` + * `getnetworkinfo` + * `getwalletinfo` + * `getmininginfo` + Credits ======= diff --git a/doc/release-notes/release-notes-0.15.0.1.md b/doc/release-notes/release-notes-0.15.0.1.md new file mode 100644 index 0000000000..53ab02cbb0 --- /dev/null +++ b/doc/release-notes/release-notes-0.15.0.1.md @@ -0,0 +1,87 @@ +Bitcoin Core version *0.15.0.1* is now available from: + + <https://bitcoin.org/bin/bitcoin-core-0.15.0.1/> + +and + + <https://bitcoincore.org/bin/bitcoin-core-0.15.0.1/> + +This is a minor bug fix for 0.15.0. + +Please report bugs using the issue tracker at GitHub: + + <https://github.com/bitcoin/bitcoin/issues> + +To receive security and update notifications, please subscribe to: + + <https://bitcoincore.org/en/list/announcements/join/> + +How to Upgrade +============== + +If you are running an older version, shut it down. Wait until it has completely +shut down (which might take a few minutes for older versions), then run the +installer (on Windows) or just copy over `/Applications/Bitcoin-Qt` (on Mac) +or `bitcoind`/`bitcoin-qt` (on Linux). + +The first time you run version 0.15.0 or higher, your chainstate database will +be converted to a new format, which will take anywhere from a few minutes to +half an hour, depending on the speed of your machine. + +The file format of `fee_estimates.dat` changed in version 0.15.0. Hence, a +downgrade from version 0.15.0 or upgrade to version 0.15.0 will cause all fee +estimates to be discarded. + +Note that the block database format also changed in version 0.8.0 and there is no +automatic upgrade code from before version 0.8 to version 0.15.0. Upgrading +directly from 0.7.x and earlier without redownloading the blockchain is not supported. +However, as usual, old wallet versions are still supported. + +Downgrading warning +------------------- + +The chainstate database for this release is not compatible with previous +releases, so if you run 0.15 and then decide to switch back to any +older version, you will need to run the old release with the `-reindex-chainstate` +option to rebuild the chainstate data structures in the old format. + +If your node has pruning enabled, this will entail re-downloading and +processing the entire blockchain. + +Compatibility +============== + +Bitcoin Core is extensively tested on multiple operating systems using +the Linux kernel, macOS 10.8+, and Windows Vista and later. Windows XP is not supported. + +Bitcoin Core should also work on most other Unix-like systems but is not +frequently tested on them. + +Notable changes +=============== + +GUI startup crash issue +------------------------- + +After upgrade to 0.15.0, some clients would crash at startup because a custom +fee setting was configured that no longer exists in the GUI. This is a minimal +patch to avoid this issue from occuring. + +0.15.0.1 Change log +==================== + +- #11332 `46c8d23` Fix possible crash with invalid nCustomFeeRadio in QSettings (achow101, TheBlueMatt) + +Also the manpages were updated, as this was forgotten for 0.15.0. + +Credits +======= + +Thanks to everyone who directly contributed to this release: + +- Andrew Chow +- Matt Corallo +- Jonas Schnelli +- Wladimir J. van der Laan + +As well as everyone that helped translating on [Transifex](https://www.transifex.com/projects/p/bitcoin/). diff --git a/doc/release-notes/release-notes-0.15.0.md b/doc/release-notes/release-notes-0.15.0.md new file mode 100644 index 0000000000..29816cacf7 --- /dev/null +++ b/doc/release-notes/release-notes-0.15.0.md @@ -0,0 +1,878 @@ +Bitcoin Core version *0.15.0* is now available from: + + <https://bitcoin.org/bin/bitcoin-core-0.15.0/> + +This is a new major version release, including new features, various bugfixes +and performance improvements, as well as updated translations. + +Please report bugs using the issue tracker at GitHub: + + <https://github.com/bitcoin/bitcoin/issues> + +To receive security and update notifications, please subscribe to: + + <https://bitcoincore.org/en/list/announcements/join/> + +How to Upgrade +============== + +If you are running an older version, shut it down. Wait until it has completely +shut down (which might take a few minutes for older versions), then run the +installer (on Windows) or just copy over `/Applications/Bitcoin-Qt` (on Mac) +or `bitcoind`/`bitcoin-qt` (on Linux). + +The first time you run version 0.15.0, your chainstate database will be converted to a +new format, which will take anywhere from a few minutes to half an hour, +depending on the speed of your machine. + +The file format of `fee_estimates.dat` changed in version 0.15.0. Hence, a +downgrade from version 0.15.0 or upgrade to version 0.15.0 will cause all fee +estimates to be discarded. + +Note that the block database format also changed in version 0.8.0 and there is no +automatic upgrade code from before version 0.8 to version 0.15.0. Upgrading +directly from 0.7.x and earlier without redownloading the blockchain is not supported. +However, as usual, old wallet versions are still supported. + +Downgrading warning +------------------- + +The chainstate database for this release is not compatible with previous +releases, so if you run 0.15 and then decide to switch back to any +older version, you will need to run the old release with the `-reindex-chainstate` +option to rebuild the chainstate data structures in the old format. + +If your node has pruning enabled, this will entail re-downloading and +processing the entire blockchain. + +Compatibility +============== + +Bitcoin Core is extensively tested on multiple operating systems using +the Linux kernel, macOS 10.8+, and Windows Vista and later. Windows XP is not supported. + +Bitcoin Core should also work on most other Unix-like systems but is not +frequently tested on them. + +Notes for 0.15.0 +================ + +Current SegWit support +---------------------- + +Version 0.15.0 supports adding a segregated witness address via the `addwitnessaddress` RPC, but +please note that this is a testing/expert RPC, which does not guarantee recovery from backup. Only use +this RPC if you know what you are doing. More complete wallet support for segregated witness is coming +in a next version. + +Rescanning with encrypted wallets +--------------------------------- + +As in previous versions, when using an encrypted HD wallet, the keypool cannot be topped up without unlocking +the wallet. This means that currently, in order to recover from a backup of an encrypted HD wallet, the user +must unlock the wallet with a really long timeout and manually trigger a rescan, otherwise they risk missing +some keys when auto-topup cannot run. Unfortunately there is no `rescan` RPC in this version, that will be +included in a future version, so for now a rescan can be triggered using one of the `import*` commands, using +a dummy address generated by another (trusted) wallet. + +Notable changes +=============== + +Performance Improvements +------------------------ + +Version 0.15 contains a number of significant performance improvements, which make +Initial Block Download, startup, transaction and block validation much faster: + +- The chainstate database (which is used for tracking UTXOs) has been changed + from a per-transaction model to a per-output model (See [PR 10195](https://github.com/bitcoin/bitcoin/pull/10195)). Advantages of this model + are that it: + - avoids the CPU overhead of deserializing and serializing the unused outputs; + - has more predictable memory usage; + - uses simpler code; + - is adaptable to various future cache flushing strategies. + + As a result, validating the blockchain during Initial Block Download (IBD) and reindex + is ~30-40% faster, uses 10-20% less memory, and flushes to disk far less frequently. + The only downside is that the on-disk database is 15% larger. During the conversion from the previous format + a few extra gigabytes may be used. +- Earlier versions experienced a spike in memory usage while flushing UTXO updates to disk. + As a result, only half of the available memory was actually used as cache, and the other half was + reserved to accommodate flushing. This is no longer the case (See [PR 10148](https://github.com/bitcoin/bitcoin/pull/10148)), and the entirety of + the available cache (see `-dbcache`) is now actually used as cache. This reduces the flushing + frequency by a factor 2 or more. +- In previous versions, signature validation for transactions has been cached when the + transaction is accepted to the mempool. Version 0.15 extends this to cache the entire script + validity (See [PR 10192](https://github.com/bitcoin/bitcoin/pull/10192)). This means that if a transaction in a block has already been accepted to the + mempool, the scriptSig does not need to be re-evaluated. Empirical tests show that + this results in new block validation being 40-50% faster. +- LevelDB has been upgraded to version 1.20 (See [PR 10544](https://github.com/bitcoin/bitcoin/pull/10544)). This version contains hardware acceleration for CRC + on architectures supporting SSE 4.2. As a result, synchronization and block validation are now faster. +- SHA256 hashing has been optimized for architectures supporting SSE 4 (See [PR 10821](https://github.com/bitcoin/bitcoin/pull/10821)). SHA256 is around + 50% faster on supported hardware, which results in around 5% faster IBD and block + validation. In version 0.15, SHA256 hardware optimization is disabled in release builds by + default, but can be enabled by using `--enable-experimental-asm` when building. +- Refill of the keypool no longer flushes the wallet between each key which resulted in a ~20x speedup in creating a new wallet. Part of this speedup was used to increase the default keypool to 1000 keys to make recovery more robust. (See [PR 10831](https://github.com/bitcoin/bitcoin/pull/10831)). + +Fee Estimation Improvements +--------------------------- + +Fee estimation has been significantly improved in version 0.15, with more accurate fee estimates used by the wallet and a wider range of options for advanced users of the `estimatesmartfee` and `estimaterawfee` RPCs (See [PR 10199](https://github.com/bitcoin/bitcoin/pull/10199)). + +### Changes to internal logic and wallet behavior + +- Internally, estimates are now tracked on 3 different time horizons. This allows for longer targets and means estimates adjust more quickly to changes in conditions. +- Estimates can now be *conservative* or *economical*. *Conservative* estimates use longer time horizons to produce an estimate which is less susceptible to rapid changes in fee conditions. *Economical* estimates use shorter time horizons and will be more affected by short-term changes in fee conditions. Economical estimates may be considerably lower during periods of low transaction activity (for example over weekends), but may result in transactions being unconfirmed if prevailing fees increase rapidly. +- By default, the wallet will use conservative fee estimates to increase the reliability of transactions being confirmed within the desired target. For transactions that are marked as replaceable, the wallet will use an economical estimate by default, since the fee can be 'bumped' if the fee conditions change rapidly (See [PR 10589](https://github.com/bitcoin/bitcoin/pull/10589)). +- Estimates can now be made for confirmation targets up to 1008 blocks (one week). +- More data on historical fee rates is stored, leading to more precise fee estimates. +- Transactions which leave the mempool due to eviction or other non-confirmed reasons are now taken into account by the fee estimation logic, leading to more accurate fee estimates. +- The fee estimation logic will make sure enough data has been gathered to return a meaningful estimate. If there is insufficient data, a fallback default fee is used. + +### Changes to fee estimate RPCs + +- The `estimatefee` RPC is now deprecated in favor of using only `estimatesmartfee` (which is the implementation used by the GUI) +- The `estimatesmartfee` RPC interface has been changed (See [PR 10707](https://github.com/bitcoin/bitcoin/pull/10707)): + - The `nblocks` argument has been renamed to `conf_target` (to be consistent with other RPC methods). + - An `estimate_mode` argument has been added. This argument takes one of the following strings: `CONSERVATIVE`, `ECONOMICAL` or `UNSET` (which defaults to `CONSERVATIVE`). + - The RPC return object now contains an `errors` member, which returns errors encountered during processing. + - If Bitcoin Core has not been running for long enough and has not seen enough blocks or transactions to produce an accurate fee estimation, an error will be returned (previously a value of -1 was used to indicate an error, which could be confused for a feerate). +- A new `estimaterawfee` RPC is added to provide raw fee data. External clients can query and use this data in their own fee estimation logic. + +Multi-wallet support +-------------------- + +Bitcoin Core now supports loading multiple, separate wallets (See [PR 8694](https://github.com/bitcoin/bitcoin/pull/8694), [PR 10849](https://github.com/bitcoin/bitcoin/pull/10849)). The wallets are completely separated, with individual balances, keys and received transactions. + +Multi-wallet is enabled by using more than one `-wallet` argument when starting Bitcoin, either on the command line or in the Bitcoin config file. + +**In Bitcoin-Qt, only the first wallet will be displayed and accessible for creating and signing transactions.** GUI selectable multiple wallets will be supported in a future version. However, even in 0.15 other loaded wallets will remain synchronized to the node's current tip in the background. This can be useful if running a pruned node, since loading a wallet where the most recent sync is beyond the pruned height results in having to download and revalidate the whole blockchain. Continuing to synchronize all wallets in the background avoids this problem. + +Bitcoin Core 0.15.0 contains the following changes to the RPC interface and `bitcoin-cli` for multi-wallet: + +* When running Bitcoin Core with a single wallet, there are **no** changes to the RPC interface or `bitcoin-cli`. All RPC calls and `bitcoin-cli` commands continue to work as before. +* When running Bitcoin Core with multi-wallet, all *node-level* RPC methods continue to work as before. HTTP RPC requests should be send to the normal `<RPC IP address>:<RPC port>/` endpoint, and `bitcoin-cli` commands should be run as before. A *node-level* RPC method is any method which does not require access to the wallet. +* When running Bitcoin Core with multi-wallet, *wallet-level* RPC methods must specify the wallet for which they're intended in every request. HTTP RPC requests should be send to the `<RPC IP address>:<RPC port>/wallet/<wallet name>/` endpoint, for example `127.0.0.1:8332/wallet/wallet1.dat/`. `bitcoin-cli` commands should be run with a `-rpcwallet` option, for example `bitcoin-cli -rpcwallet=wallet1.dat getbalance`. +* A new *node-level* `listwallets` RPC method is added to display which wallets are currently loaded. The names returned by this method are the same as those used in the HTTP endpoint and for the `rpcwallet` argument. + +Note that while multi-wallet is now fully supported, the RPC multi-wallet interface should be considered unstable for version 0.15.0, and there may backwards-incompatible changes in future versions. + +Replace-by-fee control in the GUI +--------------------------------- + +Bitcoin Core has supported creating opt-in replace-by-fee (RBF) transactions +since version 0.12.0, and since version 0.14.0 has included a `bumpfee` RPC method to +replace unconfirmed opt-in RBF transactions with a new transaction that pays +a higher fee. + +In version 0.15, creating an opt-in RBF transaction and replacing the unconfirmed +transaction with a higher-fee transaction are both supported in the GUI (See [PR 9592](https://github.com/bitcoin/bitcoin/pull/9592)). + +Removal of Coin Age Priority +---------------------------- + +In previous versions of Bitcoin Core, a portion of each block could be reserved for transactions based on the age and value of UTXOs they spent. This concept (Coin Age Priority) is a policy choice by miners, and there are no consensus rules around the inclusion of Coin Age Priority transactions in blocks. In practice, only a few miners continue to use Coin Age Priority for transaction selection in blocks. Bitcoin Core 0.15 removes all remaining support for Coin Age Priority (See [PR 9602](https://github.com/bitcoin/bitcoin/pull/9602)). This has the following implications: + +- The concept of *free transactions* has been removed. High Coin Age Priority transactions would previously be allowed to be relayed even if they didn't attach a miner fee. This is no longer possible since there is no concept of Coin Age Priority. The `-limitfreerelay` and `-relaypriority` options which controlled relay of free transactions have therefore been removed. +- The `-sendfreetransactions` option has been removed, since almost all miners do not include transactions which do not attach a transaction fee. +- The `-blockprioritysize` option has been removed. +- The `estimatepriority` and `estimatesmartpriority` RPCs have been removed. +- The `getmempoolancestors`, `getmempooldescendants`, `getmempoolentry` and `getrawmempool` RPCs no longer return `startingpriority` and `currentpriority`. +- The `prioritisetransaction` RPC no longer takes a `priority_delta` argument, which is replaced by a `dummy` argument for backwards compatibility with clients using positional arguments. The RPC is still used to change the apparent fee-rate of the transaction by using the `fee_delta` argument. +- `-minrelaytxfee` can now be set to 0. If `minrelaytxfee` is set, then fees smaller than `minrelaytxfee` (per kB) are rejected from relaying, mining and transaction creation. This defaults to 1000 satoshi/kB. +- The `-printpriority` option has been updated to only output the fee rate and hash of transactions included in a block by the mining code. + +Mempool Persistence Across Restarts +----------------------------------- + +Version 0.14 introduced mempool persistence across restarts (the mempool is saved to a `mempool.dat` file in the data directory prior to shutdown and restores the mempool when the node is restarted). Version 0.15 allows this feature to be switched on or off using the `-persistmempool` command-line option (See [PR 9966](https://github.com/bitcoin/bitcoin/pull/9966)). By default, the option is set to true, and the mempool is saved on shutdown and reloaded on startup. If set to false, the `mempool.dat` file will not be loaded on startup or saved on shutdown. + +New RPC methods +--------------- + +Version 0.15 introduces several new RPC methods: + +- `abortrescan` stops current wallet rescan, e.g. when triggered by an `importprivkey` call (See [PR 10208](https://github.com/bitcoin/bitcoin/pull/10208)). +- `combinerawtransaction` accepts a JSON array of raw transactions and combines them into a single raw transaction (See [PR 10571](https://github.com/bitcoin/bitcoin/pull/10571)). +- `estimaterawfee` returns raw fee data so that customized logic can be implemented to analyze the data and calculate estimates. See [Fee Estimation Improvements](#fee-estimation-improvements) for full details on changes to the fee estimation logic and interface. +- `getchaintxstats` returns statistics about the total number and rate of transactions + in the chain (See [PR 9733](https://github.com/bitcoin/bitcoin/pull/9733)). +- `listwallets` lists wallets which are currently loaded. See the *Multi-wallet* section + of these release notes for full details (See [Multi-wallet support](#multi-wallet-support)). +- `uptime` returns the total runtime of the `bitcoind` server since its last start (See [PR 10400](https://github.com/bitcoin/bitcoin/pull/10400)). + +Low-level RPC changes +--------------------- + +- When using Bitcoin Core in multi-wallet mode, RPC requests for wallet methods must specify + the wallet that they're intended for. See [Multi-wallet support](#multi-wallet-support) for full details. + +- The new database model no longer stores information about transaction + versions of unspent outputs (See [Performance improvements](#performance-improvements)). This means that: + - The `gettxout` RPC no longer has a `version` field in the response. + - The `gettxoutsetinfo` RPC reports `hash_serialized_2` instead of `hash_serialized`, + which does not commit to the transaction versions of unspent outputs, but does + commit to the height and coinbase information. + - The `getutxos` REST path no longer reports the `txvers` field in JSON format, + and always reports 0 for transaction versions in the binary format + +- The `estimatefee` RPC is deprecated. Clients should switch to using the `estimatesmartfee` RPC, which returns better fee estimates. See [Fee Estimation Improvements](#fee-estimation-improvements) for full details on changes to the fee estimation logic and interface. + +- The `gettxoutsetinfo` response now contains `disk_size` and `bogosize` instead of + `bytes_serialized`. The first is a more accurate estimate of actual disk usage, but + is not deterministic. The second is unrelated to disk usage, but is a + database-independent metric of UTXO set size: it counts every UTXO entry as 50 + the + length of its scriptPubKey (See [PR 10426](https://github.com/bitcoin/bitcoin/pull/10426)). + +- `signrawtransaction` can no longer be used to combine multiple transactions into a single transaction. Instead, use the new `combinerawtransaction` RPC (See [PR 10571](https://github.com/bitcoin/bitcoin/pull/10571)). + +- `fundrawtransaction` no longer accepts a `reserveChangeKey` option. This option used to allow RPC users to fund a raw transaction using an key from the keypool for the change address without removing it from the available keys in the keypool. The key could then be re-used for a `getnewaddress` call, which could potentially result in confusing or dangerous behaviour (See [PR 10784](https://github.com/bitcoin/bitcoin/pull/10784)). + +- `estimatepriority` and `estimatesmartpriority` have been removed. See [Removal of Coin Age Priority](#removal-of-coin-age-priority). + +- The `listunspent` RPC now takes a `query_options` argument (see [PR 8952](https://github.com/bitcoin/bitcoin/pull/8952)), which is a JSON object + containing one or more of the following members: + - `minimumAmount` - a number specifying the minimum value of each UTXO + - `maximumAmount` - a number specifying the maximum value of each UTXO + - `maximumCount` - a number specifying the minimum number of UTXOs + - `minimumSumAmount` - a number specifying the minimum sum value of all UTXOs + +- The `getmempoolancestors`, `getmempooldescendants`, `getmempoolentry` and `getrawmempool` RPCs no longer return `startingpriority` and `currentpriority`. See [Removal of Coin Age Priority](#removal-of-coin-age-priority). + +- The `dumpwallet` RPC now returns the full absolute path to the dumped wallet. It + used to return no value, even if successful (See [PR 9740](https://github.com/bitcoin/bitcoin/pull/9740)). + +- In the `getpeerinfo` RPC, the return object for each peer now returns an `addrbind` member, which contains the ip address and port of the connection to the peer. This is in addition to the `addrlocal` member which contains the ip address and port of the local node as reported by the peer (See [PR 10478](https://github.com/bitcoin/bitcoin/pull/10478)). + +- The `disconnectnode` RPC can now disconnect a node specified by node ID (as well as by IP address/port). To disconnect a node based on node ID, call the RPC with the new `nodeid` argument (See [PR 10143](https://github.com/bitcoin/bitcoin/pull/10143)). + +- The second argument in `prioritisetransaction` has been renamed from `priority_delta` to `dummy` since Bitcoin Core no longer has a concept of coin age priority. The `dummy` argument has no functional effect, but is retained for positional argument compatibility. See [Removal of Coin Age Priority](#removal-of-coin-age-priority). + +- The `resendwallettransactions` RPC throws an error if the `-walletbroadcast` option is set to false (See [PR 10995](https://github.com/bitcoin/bitcoin/pull/10995)). + +- The second argument in the `submitblock` RPC argument has been renamed from `parameters` to `dummy`. This argument never had any effect, and the renaming is simply to communicate this fact to the user (See [PR 10191](https://github.com/bitcoin/bitcoin/pull/10191)) + (Clients should, however, use positional arguments for `submitblock` in order to be compatible with BIP 22.) + +- The `verbose` argument of `getblock` has been renamed to `verbosity` and now takes an integer from 0 to 2. Verbose level 0 is equivalent to `verbose=false`. Verbose level 1 is equivalent to `verbose=true`. Verbose level 2 will give the full transaction details of each transaction in the output as given by `getrawtransaction`. The old behavior of using the `verbose` named argument and a boolean value is still maintained for compatibility. + +- Error codes have been updated to be more accurate for the following error cases (See [PR 9853](https://github.com/bitcoin/bitcoin/pull/9853)): + - `getblock` now returns RPC_MISC_ERROR if the block can't be found on disk (for + example if the block has been pruned). Previously returned RPC_INTERNAL_ERROR. + - `pruneblockchain` now returns RPC_MISC_ERROR if the blocks cannot be pruned + because the node is not in pruned mode. Previously returned RPC_METHOD_NOT_FOUND. + - `pruneblockchain` now returns RPC_INVALID_PARAMETER if the blocks cannot be pruned + because the supplied timestamp is too late. Previously returned RPC_INTERNAL_ERROR. + - `pruneblockchain` now returns RPC_MISC_ERROR if the blocks cannot be pruned + because the blockchain is too short. Previously returned RPC_INTERNAL_ERROR. + - `setban` now returns RPC_CLIENT_INVALID_IP_OR_SUBNET if the supplied IP address + or subnet is invalid. Previously returned RPC_CLIENT_NODE_ALREADY_ADDED. + - `setban` now returns RPC_CLIENT_INVALID_IP_OR_SUBNET if the user tries to unban + a node that has not previously been banned. Previously returned RPC_MISC_ERROR. + - `removeprunedfunds` now returns RPC_WALLET_ERROR if `bitcoind` is unable to remove + the transaction. Previously returned RPC_INTERNAL_ERROR. + - `removeprunedfunds` now returns RPC_INVALID_PARAMETER if the transaction does not + exist in the wallet. Previously returned RPC_INTERNAL_ERROR. + - `fundrawtransaction` now returns RPC_INVALID_ADDRESS_OR_KEY if an invalid change + address is provided. Previously returned RPC_INVALID_PARAMETER. + - `fundrawtransaction` now returns RPC_WALLET_ERROR if `bitcoind` is unable to create + the transaction. The error message provides further details. Previously returned + RPC_INTERNAL_ERROR. + - `bumpfee` now returns RPC_INVALID_PARAMETER if the provided transaction has + descendants in the wallet. Previously returned RPC_MISC_ERROR. + - `bumpfee` now returns RPC_INVALID_PARAMETER if the provided transaction has + descendants in the mempool. Previously returned RPC_MISC_ERROR. + - `bumpfee` now returns RPC_WALLET_ERROR if the provided transaction has + has been mined or conflicts with a mined transaction. Previously returned + RPC_INVALID_ADDRESS_OR_KEY. + - `bumpfee` now returns RPC_WALLET_ERROR if the provided transaction is not + BIP 125 replaceable. Previously returned RPC_INVALID_ADDRESS_OR_KEY. + - `bumpfee` now returns RPC_WALLET_ERROR if the provided transaction has already + been bumped by a different transaction. Previously returned RPC_INVALID_REQUEST. + - `bumpfee` now returns RPC_WALLET_ERROR if the provided transaction contains + inputs which don't belong to this wallet. Previously returned RPC_INVALID_ADDRESS_OR_KEY. + - `bumpfee` now returns RPC_WALLET_ERROR if the provided transaction has multiple change + outputs. Previously returned RPC_MISC_ERROR. + - `bumpfee` now returns RPC_WALLET_ERROR if the provided transaction has no change + output. Previously returned RPC_MISC_ERROR. + - `bumpfee` now returns RPC_WALLET_ERROR if the fee is too high. Previously returned + RPC_MISC_ERROR. + - `bumpfee` now returns RPC_WALLET_ERROR if the fee is too low. Previously returned + RPC_MISC_ERROR. + - `bumpfee` now returns RPC_WALLET_ERROR if the change output is too small to bump the + fee. Previously returned RPC_MISC_ERROR. + +0.15.0 Change log +================= + +### RPC and other APIs +- #9485 `61a640e` ZMQ example using python3 and asyncio (mcelrath) +- #9894 `0496e15` remove 'label' filter for rpc command help (instagibbs) +- #9853 `02bd6e9` Fix error codes from various RPCs (jnewbery) +- #9842 `598ef9c` Fix RPC failure testing (continuation of #9707) (jnewbery) +- #10038 `d34995a` Add mallocinfo mode to `getmemoryinfo` RPC (laanwj) +- #9500 `3568b30` [Qt][RPC] Autocomplete commands for 'help' command in debug console (achow101) +- #10056 `e6156a0` [zmq] Call va_end() on va_start()ed args (kallewoof) +- #10086 `7438cea` Trivial: move rpcserialversion into RPC option group (jlopp) +- #10150 `350b224` [rpc] Add logging rpc (jnewbery) +- #10208 `393160c` [wallet] Rescan abortability (kallewoof) +- #10143 `a987def` [net] Allow disconnectnode RPC to be called with node id (jnewbery) +- #10281 `0e8499c` doc: Add RPC interface guidelines (laanwj) +- #9733 `d4732f3` Add getchaintxstats RPC (sipa) +- #10310 `f4b15e2` [doc] Add hint about getmempoolentry to getrawmempool help (kallewoof) +- #8704 `96c850c` [RPC] Transaction details in getblock (achow101) +- #8952 `9390845` Add query options to listunspent RPC call (pedrobranco) +- #10413 `08ac35a` Fix docs (there's no rpc command setpaytxfee) (RHavar) +- #8384 `e317c0d` Add witness data output to TxInError messages (instagibbs) +- #9571 `4677151` RPC: getblockchaininfo returns BIP signaling statistics (pinheadmz) +- #10450 `ef2d062` Fix bumpfee rpc "errors" return value (ryanofsky) +- #10475 `39039b1` [RPC] getmempoolinfo mempoolminfee is a BTC/KB feerate (instagibbs) +- #10478 `296928e` rpc: Add listen address to incoming connections in `getpeerinfo` (laanwj) +- #10403 `08d0390` Fix importmulti failure to return rescan errors (ryanofsky) +- #9740 `9fec4da` Add friendly output to dumpwallet (aideca) +- #10426 `16f6c98` Replace bytes_serialized with bogosize (sipa) +- #10252 `980deaf` RPC/Mining: Restore API compatibility for prioritisetransaction (luke-jr) +- #9672 `46311e7` Opt-into-RBF for RPC & bitcoin-tx (luke-jr) +- #10481 `9c248e3` Decodehextx scripts sanity check (achow101) +- #10488 `fa1f106` Note that the prioritizetransaction dummy value is deprecated, and has no meaning (TheBlueMatt) +- #9738 `c94b89e` gettxoutproof() should return consistent result (jnewbery) +- #10191 `00350bd` [trivial] Rename unused RPC arguments 'dummy' (jnewbery) +- #10627 `b62b4c8` fixed listunspent rpc convert parameter (tnakagawa) +- #10412 `bef02fb` Improve wallet rescan API (ryanofsky) +- #10400 `1680ee0` [RPC] Add an uptime command that displays the amount of time (in seconds) bitcoind has been running (rvelhote) +- #10683 `d81bec7` rpc: Move the `generate` RPC call to rpcwallet (laanwj) +- #10710 `30bc0f6` REST/RPC example update (Mirobit) +- #10747 `9edda0c` [rpc] fix verbose argument for getblock in bitcoin-cli (jnewbery) +- #10589 `104f5f2` More economical fee estimates for RBF and RPC options to control (morcos) +- #10543 `b27b004` Change API to estimaterawfee (morcos) +- #10807 `afd2fca` getbalance example covers at least 6 confirms (instagibbs) +- #10707 `75b5643` Better API for estimatesmartfee RPC (morcos) +- #10784 `9e8d6a3` Do not allow users to get keys from keypool without reserving them (TheBlueMatt) +- #10857 `d445a2c` [RPC] Add a deprecation warning to getinfo's output (achow101) +- #10571 `adf170d` [RPC]Move transaction combining from signrawtransaction to new RPC (achow101) +- #10783 `041dad9` [RPC] Various rpc argument fixes (instagibbs) +- #9622 `6ef3c7e` [rpc] listsinceblock should include lost transactions when parameter is a reorg'd block (kallewoof) +- #10799 `8537187` Prevent user from specifying conflicting parameters to fundrawtx (TheBlueMatt) +- #10931 `0b11a07` Fix misleading "Method not found" multiwallet errors (ryanofsky) +- #10788 `f66c596` [RPC] Fix addwitnessaddress by replacing ismine with producesignature (achow101) +- #10999 `627c3c0` Fix amounts formatting in `decoderawtransaction` (laanwj) +- #11002 `4268426` [wallet] return correct error code from resendwallettransaction (jnewbery) +- #11029 `96a63a3` [RPC] trivial: gettxout no longer shows version of tx (FelixWeis) +- #11083 `6c2b008` Fix combinerawtransaction RPC help result section (jonasnick) +- #11027 `07164bb` [RPC] Only return hex field once in getrawtransaction (achow101) +- #10698 `5af6572` Be consistent in calling transactions "replaceable" for Opt-In RBF (TheBlueMatt) + +### Block and transaction handling +- #9801 `a8c5751` Removed redundant parameter from mempool.PrioritiseTransaction (gubatron) +- #9819 `1efc99c` Remove harmless read of unusued priority estimates (morcos) +- #9822 `b7547fa` Remove block file location upgrade code (benma) +- #9602 `30ff3a2` Remove coin age priority and free transactions - implementation (morcos) +- #9548 `47510ad` Remove min reasonable fee (morcos) +- #10249 `c73af54` Switch CCoinsMap from boost to std unordered_map (sipa) +- #9966 `2a183de` Control mempool persistence using a command line parameter (jnewbery) +- #10199 `318ea50` Better fee estimates (morcos) +- #10196 `bee3529` Bugfix: PrioritiseTransaction updates the mempool tx counter (sdaftuar) +- #10195 `1088b02` Switch chainstate db and cache to per-txout model (sipa) +- #10284 `c2ab38b` Always log debug information for fee calculation in CreateTransaction (morcos) +- #10503 `efbcf2b` Use REJECT_DUPLICATE for already known and conflicted txn (sipa) +- #10537 `b3eb0d6` Few Minor per-utxo assert-semantics re-adds and tweak (TheBlueMatt) +- #10626 `8c841a3` doc: Remove outdated minrelaytxfee comment (MarcoFalke) +- #10559 `234ffc6` Change semantics of HaveCoinInCache to match HaveCoin (morcos) +- #10581 `7878353` Simplify return values of GetCoin/HaveCoin(InCache) (sipa) +- #10684 `a381f6a` Remove no longer used mempool.exists(outpoint) (morcos) +- #10148 `d4e551a` Use non-atomic flushing with block replay (sipa) +- #10685 `30c2130` Clarify CCoinsViewMemPool documentation (TheBlueMatt) +- #10558 `90a002e` Address nits from per-utxo change (morcos) +- #10706 `6859ad2` Improve wallet fee logic and fix GUI bugs (morcos) +- #10526 `754aa02` Force on-the-fly compaction during pertxout upgrade (sipa) +- #10985 `d896d5c` Add undocumented -forcecompactdb to force LevelDB compactions (sipa) +- #10292 `e4bbd3d` Improved efficiency in COutPoint constructors (mm-s) +- #10290 `8d6d43e` Add -stopatheight for benchmarking (sipa) + +### P2P protocol and network code +- #9726 `7639d38` netbase: Do not print an error on connection timeouts through proxy (laanwj) +- #9805 `5b583ef` Add seed.btc.petertodd.org to mainnet DNS seeds (petertodd) +- #9861 `22f609f` Trivial: Debug log ambiguity fix for peer addrs (keystrike) +- #9774 `90cb2a2` Enable host lookups for -proxy and -onion parameters (jmcorgan) +- #9558 `7b585cf` Clarify assumptions made about when BlockCheck is called (TheBlueMatt) +- #10135 `e19586a` [p2p] Send the correct error code in reject messages (jnewbery) +- #9665 `eab00d9` Use cached [compact] blocks to respond to getdata messages (TheBlueMatt) +- #10215 `a077a90` Check interruptNet during dnsseed lookups (TheBlueMatt) +- #10234 `faf2dea` [net] listbanned RPC and QT should show correct banned subnets (jnewbery) +- #10134 `314ebdf` [qa] Fixes segwit block relay test after inv-direct-fetch was disabled (sdaftuar) +- #10351 `3f57c55` removed unused code in INV message (Greg-Griffith) +- #10061 `ae78609` [net] Added SetSocketNoDelay() utility function (tjps) +- #10408 `28c6e8d` Net: Improvements to Tor control port parser (str4d) +- #10460 `5c63d66` Broadcast address every day, not 9 hours (sipa) +- #10471 `400fdd0` Denote functions CNode::GetRecvVersion() and CNode::GetRefCount() as const (pavlosantoniou) +- #10345 `67700b3` [P2P] Timeout for headers sync (sdaftuar) +- #10564 `8d9f45e` Return early in IsBanned (gmaxwell) +- #10587 `de8db47` Net: Fix resource leak in ReadBinaryFile(...) (practicalswift) +- #9549 `b33ca14` [net] Avoid possibility of NULL pointer dereference in MarkBlockAsInFlight(...) (practicalswift) +- #10446 `2772dc9` net: avoid extra dns query per seed (theuni) +- #10824 `9dd6a2b` Avoid unnecessary work in SetNetworkActive (promag) +- #10948 `df3a6f4` p2p: Hardcoded seeds update pre-0.15 branch (laanwj) +- #10977 `02f4c4a` [net] Fix use of uninitialized value in getnetworkinfo(const JSONRPCRequest&) (practicalswift) +- #10982 `c8b62c7` Disconnect network service bits 6 and 8 until Aug 1, 2018 (TheBlueMatt) +- #11012 `0e5cff6` Make sure to clean up mapBlockSource if we've already seen the block (theuni) + +### Validation +- #9725 `67023e9` CValidationInterface Cleanups (TheBlueMatt) +- #10178 `2584925` Remove CValidationInterface::UpdatedTransaction (TheBlueMatt) +- #10201 `a6548a4` pass Consensus::Params& to functions in validation.cpp and make them static (mariodian) +- #10297 `431a548` Simplify DisconnectBlock arguments/return value (sipa) +- #10464 `f94b7d5` Introduce static DoWarning (simplify UpdateTip) (jtimon) +- #10569 `2e7d8f8` Fix stopatheight (achow101) +- #10192 `2935b46` Cache full script execution results in addition to signatures (TheBlueMatt) +- #10179 `21ed30a` Give CValidationInterface Support for calling notifications on the CScheduler Thread (TheBlueMatt) +- #10557 `66270a4` Make check to distinguish between orphan txs and old txs more efficient (morcos) +- #10775 `7c2400c` nCheckDepth chain height fix (romanornr) +- #10821 `16240f4` Add SSE4 optimized SHA256 (sipa) +- #10854 `04d395e` Avoid using sizes on non-fixed-width types to derive protocol constants (gmaxwell) +- #10945 `2a50b11` Update defaultAssumeValid according to release-process.md (gmaxwell) +- #10986 `2361208` Update chain transaction statistics (sipa) +- #11028 `6bdf4b3` Avoid masking of difficulty adjustment errors by checkpoints (sipa) +- #9533 `cb598cf` Allow non-power-of-2 signature cache sizes (sipa) +- #9208 `acd9957` Improve DisconnectTip performance (sdaftuar) +- #10618 `f90603a` Remove confusing MAX_BLOCK_BASE_SIZE (gmaxwell) +- #10758 `bd92424` Fix some chainstate-init-order bugs (TheBlueMatt) +- #10550 `b7296bc` Don't return stale data from CCoinsViewCache::Cursor() (ryanofsky) +- #10998 `2507fd5` Fix upgrade cancel warnings (TheBlueMatt) +- #9868 `cbdb473` Abstract out the command line options for block assembly (sipa) + +### Build system +- #9727 `5f0556d` Remove fallbacks for boost_filesystem < v3 (laanwj) +- #9788 `50a2265` gitian: bump descriptors for master (theuni) +- #9794 `7ca2f54` Minor update to qrencode package builder (mitchellcash) +- #9514 `2cc0df1` release: Windows signing script (theuni) +- #9921 `8b789d8` build: Probe MSG_DONTWAIT in the same way as MSG_NOSIGNAL (laanwj) +- #10011 `32d1b34` build: Fix typo s/HAVE_DONTWAIT/HAVE_MSG_DONTWAIT (laanwj) +- #9946 `90dd9e6` Fix build errors if spaces in path or parent directory (pinheadmz) +- #10136 `81da4c7` build: Disable Wshadow warning (laanwj) +- #10166 `64962ae` Ignore Doxyfile generated from Doxyfile.in template (paveljanik) +- #10239 `0416ea9` Make Boost use std::atomic internally (sipa) +- #10228 `27faa6c` build: regenerate bitcoin-config.h as necessary (theuni) +- #10273 `8979f45` [scripts] Minor improvements to `macdeployqtplus` script (chrisgavin) +- #10325 `a26280b` 0.15.0 Depends Updates (fanquake) +- #10328 `79aeff6` Update contrib/debian to latest Ubuntu PPA upload (TheBlueMatt) +- #7522 `d25449f` Bugfix: Only use git for build info if the repository is actually the right one (luke-jr) +- #10489 `e654d61` build: silence gcc7's implicit fallthrough warning (theuni) +- #10549 `ad1a13e` Avoid printing generic and duplicated "checking for QT" during ./configure (drizzt) +- #10628 `8465b68` [depends] expat 2.2.1 (fanquake) +- #10806 `db825d2` build: verify that the assembler can handle crc32 functions (theuni) +- #10766 `b4d03be` Building Environment: Set ARFLAGS to cr (ReneNyffenegger) +- #10803 `91edda8` Explicitly search for bdb5.3 (pstratem) +- #10855 `81560b0` random: only use getentropy on openbsd (theuni) +- #10508 `1caafa6` Run Qt wallet tests on travis (ryanofsky) +- #10851 `e222618` depends: fix fontconfig with newer glibc (theuni) +- #10971 `88b1e4b` build: fix missing sse42 in depends builds (theuni) +- #11097 `129b03f` gitian: quick hack to fix version string in releases (theuni) +- #10039 `919aaf6` Fix compile errors with Qt 5.3.2 and Boost 1.55.0 (ryanofsky) +- #10168 `7032021` Fix build warning from #error text (jnewbery) +- #10301 `318392c` Check if sys/random.h is required for getentropy (jameshilliard) + +### GUI +- #9724 `1a9fd5c` Qt/Intro: Add explanation of IBD process (luke-jr) +- #9834 `b00ba62` qt: clean up initialize/shutdown signals (benma) +- #9481 `ce01e62` [Qt] Show more significant warning if we fall back to the default fee (jonasschnelli) +- #9974 `b9f930b` Add basic Qt wallet test (ryanofsky) +- #9690 `a387d3a` Change 'Clear' button string to 'Reset' (da2x) +- #9592 `9c7b7cf` [Qt] Add checkbox in the GUI to opt-in to RBF when creating a transaction (ryanofsky) +- #10098 `2b477e6` Make qt wallet test compatible with qt4 (ryanofsky) +- #9890 `1fa4ae6` Add a button to open the config file in a text editor (ericshawlinux) +- #10156 `51833a1` Fix for issues with startup and multiple monitors on windows (AllanDoensen) +- #10177 `de01da7` Changed "Send" button default status from true to false (KibbledJiveElkZoo) +- #10221 `e96486c` Stop treating coinbase outputs differently in GUI: show them at 1conf (TheBlueMatt) +- #10231 `987a6c0` [Qt] Reduce a significant cs_main lock freeze (jonasschnelli) +- #10242 `f6f3b58` [qt] Don't call method on null WalletModel object (ryanofsky) +- #10093 `a3e756b` [Qt] Don't add arguments of sensitive command to console window (jonasschnelli) +- #10362 `95546c8` [GUI] Add OSX keystroke to RPCConsole info (spencerlievens) +- #9697 `962cd3f` [Qt] simple fee bumper with user verification (jonasschnelli) +- #10390 `e477516` [wallet] remove minimum total fee option (instagibbs) +- #10420 `4314544` Add Qt tests for wallet spends & bumpfee (ryanofsky) +- #10454 `c1c9a95` Fix broken q4 test build (ryanofsky) +- #10449 `64beb13` Overhaul Qt fee bumper (jonasschnelli) +- #10582 `7c72fb9` Pass in smart fee slider value to coin control dialog (morcos) +- #10673 `4c72cc3` [qt] Avoid potential null pointer dereference in TransactionView::exportClicked() (practicalswift) +- #10769 `8fdd23a` [Qt] replace fee slider with a Dropdown, extend conf. targets (jonasschnelli) +- #10870 `412b466` [Qt] Use wallet 0 in rpc console if running with multiple wallets (jonasschnelli) +- #10988 `a9dd111` qt: Increase BLOCK_CHAIN_SIZE constants (laanwj) +- #10644 `e292140` Slightly overhaul NSI pixmaps (jonasschnelli) +- #10660 `0c3542e` Allow to cancel the txdb upgrade via splashscreen keypress 'q' (jonasschnelli) + +### Wallet +- #9359 `f7ec7cf` Add test for CWalletTx::GetImmatureCredit() returning stale values (ryanofsky) +- #9576 `56ab672` [wallet] Remove redundant initialization (practicalswift) +- #9333 `fa625b0` Document CWalletTx::mapValue entries and remove erase of nonexistent "version" entry (ryanofsky) +- #9906 `72fb515` Disallow copy constructor CReserveKeys (instagibbs) +- #9369 `3178b2c` Factor out CWallet::nTimeSmart computation into a method (ryanofsky) +- #9830 `afcd7c0` Add safe flag to listunspent result (NicolasDorier) +- #9993 `c49355c` Initialize nRelockTime (pstratem) +- #9818 `3d857f3` Save watch only key timestamps when reimporting keys (ryanofsky) +- #9294 `f34cdcb` Use internal HD chain for change outputs (hd split) (jonasschnelli) +- #10164 `e183ea2` Wallet: reduce excess logic InMempool() (kewde) +- #10186 `c9ff4f8` Remove SYNC_TRANSACTION_NOT_IN_BLOCK magic number (jnewbery) +- #10226 `64c45aa` wallet: Use boost to more portably ensure -wallet specifies only a filename (luke-jr) +- #9827 `c91ca0a` Improve ScanForWalletTransactions return value (ryanofsky) +- #9951 `fa1ac28` Wallet database handling abstractions/simplifications (laanwj) +- #10265 `c29a0d4` [wallet] [moveonly] Check non-null pindex before potentially referencing (kallewoof) +- #10283 `a550f6e` Cleanup: reduce to one GetMinimumFee call signature (morcos) +- #10294 `e2b99b1` [Wallet] unset change position when there is no change (instagibbs) +- #10115 `d3dce0e` Avoid reading the old hd master key during wallet encryption (TheBlueMatt) +- #10341 `18c9deb` rpc/wallet: Workaround older UniValue which returns a std::string temporary for get_str (luke-jr) +- #10308 `94e5227` [wallet] Securely erase potentially sensitive keys/values (tjps) +- #10257 `ea1fd43` [test] Add test for getmemoryinfo (jimmysong) +- #10295 `ce8176d` [qt] Move some WalletModel functions into CWallet (ryanofsky) +- #10506 `7cc2c67` Fix bumpfee test after #10449 (ryanofsky) +- #10500 `098b01d` Avoid CWalletTx copies in GetAddressBalances and GetAddressGroupings (ryanofsky) +- #10455 `0747d33` Simplify feebumper minimum fee code slightly (ryanofsky) +- #10522 `2805d60` [wallet] Remove unused variables (practicalswift) +- #8694 `177433a` Basic multiwallet support (luke-jr) +- #10598 `7a74f88` Supress struct/class mismatch warnings introduced in #10284 (paveljanik) +- #9343 `209eef6` Don't create change at dust limit (morcos) +- #10744 `ed88e31` Use method name via __func__ macro (darksh1ne) +- #10712 `e8b9523` Add change output if necessary to reduce excess fee (morcos) +- #10816 `1c011ff` Properly forbid -salvagewallet and -zapwallettxes for multi wallet (morcos) +- #10235 `5cfdda2` Track keypool entries as internal vs external in memory (TheBlueMatt) +- #10330 `bf0a08b` [wallet] fix zapwallettxes interaction with persistent mempool (jnewbery) +- #10831 `0b01935` Batch flushing operations to the walletdb during top up and increase keypool size (gmaxwell) +- #10795 `7b6e8bc` No longer ever reuse keypool indexes (TheBlueMatt) +- #10849 `bde4f93` Multiwallet: simplest endpoint support (jonasschnelli) +- #10817 `9022aa3` Redefine Dust and add a discard_rate (morcos) +- #10883 `bf3b742` Rename -usewallet to -rpcwallet (morcos) +- #10604 `420238d` [wallet] [tests] Add listwallets RPC, include wallet name in `getwalletinfo` and add multiwallet test (jnewbery) +- #10885 `70888a3` Reject invalid wallets (promag) +- #10949 `af56397` Clarify help message for -discardfee (morcos) +- #10942 `2e857bb` Eliminate fee overpaying edge case when subtracting fee from recipients (morcos) +- #10995 `fa64636` Fix resendwallettransactions assert failure if -walletbroadcast=0 (TheBlueMatt) +- #11022 `653a46d` Basic keypool topup (jnewbery) +- #11081 `9fe1f6b` Add length check for CExtKey deserialization (jonasschnelli, guidovranken) +- #11044 `4ef8374` [wallet] Keypool topup cleanups (jnewbery) +- #11145 `e51bb71` Fix rounding bug in calculation of minimum change (morcos) +- #9605 `779f2f9` Use CScheduler for wallet flushing, remove ThreadFlushWalletDB (TheBlueMatt) +- #10108 `4e3efd4` ApproximateBestSubset should take inputs by reference, not value (RHavar) + +### Tests and QA +- #9744 `8efd1c8` Remove unused module from rpc-tests (34ro) +- #9657 `7ff4a53` Improve rpc-tests.py (jnewbery) +- #9766 `7146d96` Add --exclude option to rpc-tests.py (jnewbery) +- #9577 `d6064a8` Fix docstrings in qa tests (jnewbery) +- #9823 `a13a417` qa: Set correct path for binaries in rpc tests (MarcoFalke) +- #9847 `6206252` Extra test vector for BIP32 (sipa) +- #9350 `88c2ae3` [Trivial] Adding label for amount inside of tx_valid/tx_invalid.json (Christewart) +- #9888 `36afd4d` travis: Verify commits only for one target (MarcoFalke) +- #9904 `58861ad` test: Fail if InitBlockIndex fails (laanwj) +- #9828 `67c5cc1` Avoid -Wshadow warnings in wallet_tests (ryanofsky) +- #9832 `48c3429` [qa] assert_start_raises_init_error (NicolasDorier) +- #9739 `9d5fcbf` Fix BIP68 activation test (jnewbery) +- #9547 `d32581c` bench: Assert that division by zero is unreachable (practicalswift) +- #9843 `c78adbf` Fix segwit getblocktemplate test (jnewbery) +- #9929 `d5ce14e` tests: Delete unused function _rpchost_to_args (laanwj) +- #9555 `19be26a` [test] Avoid reading a potentially uninitialized variable in tx_invalid-test (transaction_tests.cpp) (practicalswift) +- #9945 `ac23a7c` Improve logging in bctest.py if there is a formatting mismatch (jnewbery) +- #9768 `8910b47` [qa] Add logging to test_framework.py (jnewbery) +- #9972 `21833f9` Fix extended rpc tests broken by #9768 (jnewbery) +- #9977 `857d1e1` QA: getblocktemplate_longpoll.py should always use >0 fee tx (sdaftuar) +- #9970 `3cc13ea` Improve readability of segwit.py, smartfees.py (sdaftuar) +- #9497 `2c781fb` CCheckQueue Unit Tests (JeremyRubin) +- #10024 `9225de2` [trivial] Use log.info() instead of print() in remaining functional test cases (jnewbery) +- #9956 `3192e52` Reorganise qa directory (jnewbery) +- #10017 `02d64bd` combine_logs.py - aggregates log files from multiple bitcoinds during functional tests (jnewbery) +- #10047 `dfef6b6` [tests] Remove unused variables and imports (practicalswift) +- #9701 `a230b05` Make bumpfee tests less fragile (ryanofsky) +- #10053 `ca20923` [test] Allow functional test cases to be skipped (jnewbery) +- #10052 `a0b1e57` [test] Run extended tests once daily in Travis (jnewbery) +- #10069 `1118493` [QA] Fix typo in fundrawtransaction test (NicolasDorier) +- #10083 `c044f03` [QA] Renaming rawTx into rawtx (NicolasDorier) +- #10073 `b1a4f27` Actually run assumevalid.py (jnewbery) +- #9780 `c412fd8` Suppress noisy output from qa tests in Travis (jnewbery) +- #10096 `79af9fb` Check that all test scripts in test/functional are being run (jnewbery) +- #10076 `5b029aa` [qa] combine_logs: Use ordered list for logfiles (MarcoFalke) +- #10107 `f2734c2` Remove unused variable. Remove accidental trailing semicolons in Python code (practicalswift) +- #10109 `8ac8041` Remove SingleNodeConnCB (jnewbery) +- #10114 `edc62c9` [tests] sync_with_ping should assert that ping hasn't timed out (jnewbery) +- #10128 `427d2fd` Speed Up CuckooCache tests (JeremyRubin) +- #10072 `12af74b` Remove sources of unreliablility in extended functional tests (jnewbery) +- #10077 `ebfd653` [qa] Add setnetworkactive smoke test (MarcoFalke) +- #10152 `080d7c7` [trivial] remove unused line in Travis config (jnewbery) +- #10159 `df1ca9e` [tests] color test results and sort alphabetically (jnewbery) +- #10124 `88799ea` [test] Suppress test logging spam (jnewbery) +- #10142 `ed09dd3` Run bitcoin_test-qt under minimal QPA platform (ryanofsky) +- #9949 `a27dbc5` [bench] Avoid function call arguments which are pointers to uninitialized values (practicalswift) +- #10187 `b44adf9` tests: Fix test_runner return value in case of skipped test (laanwj) +- #10197 `d86bb07` [tests] Functional test warnings (jnewbery) +- #10219 `9111df9` Tests: Order Python Tests Differently (jimmysong) +- #10229 `f3db4c6` Tests: Add test for getdifficulty (jimmysong) +- #10224 `2723bcd` [test] Add test for getaddednodeinfo (jimmysong) +- #10023 `c530c15` [tests] remove maxblocksinflight.py (functionality covered by other test) (jnewbery) +- #10097 `1b25b6d` Move zmq test skipping logic into individual test case (jnewbery) +- #10272 `54e2d87` [Tests] Prevent warning: variable 'x' is uninitialized (paveljanik) +- #10225 `e0a7e19` [test] Add aborttrescan tests (kallewoof) +- #10278 `8254a8a` [test] Add Unit Test for GetListenPort (jimmysong) +- #10280 `47535d7` [test] Unit test amount.h/amount.cpp (jimmysong) +- #10256 `80c3a73` [test] Add test for gettxout to wallet.py (jimmysong) +- #10264 `492d22f` [test] Add tests for getconnectioncount, getnettotals and ping (jimmysong) +- #10169 `8f3e384` [tests] Remove func test code duplication (jnewbery) +- #10198 `dc8fc0c` [tests] Remove is_network_split from functional test framework (jnewbery) +- #10255 `3c5e6c9` [test] Add test for listaddressgroupings (jimmysong) +- #10137 `75171f0` Remove unused import. Remove accidental trailing semicolons (practicalswift) +- #10307 `83073de` [tests] allow zmq test to be run in out-of-tree builds (jnewbery) +- #10344 `e927483` [tests] Fix abandonconflict.py intermittency (jnewbery) +- #10318 `170bc2c` [tests] fix wait_for_inv() (jnewbery) +- #10171 `fff72de` [tests] Add node methods to test framework (jnewbery) +- #10352 `23d78c4` test: Add elapsed time to RPC tracing (laanwj) +- #10342 `6a796b2` [tests] Improve mempool_persist test (jnewbery) +- #10287 `776ba23` [tests] Update Unit Test for addrman.h/addrman.cpp (jimmysong) +- #10365 `7ee5236` [tests] increase timeouts in sendheaders test (jnewbery) +- #10361 `f6241b3` qa: disablewallet: Check that wallet is really disabled (MarcoFalke) +- #10371 `4b766fc` [tests] Clean up addrman_tests.cpp (jimmysong) +- #10253 `87abe20` [test] Add test for getnetworkhashps (jimmysong) +- #10376 `8bd16ee` [tests] fix disconnect_ban intermittency (jnewbery) +- #10374 `5411997` qa: Warn when specified test is not found (MarcoFalke) +- #10405 `0542978` tests: Correct testcase in script_tests.json for large number OP_EQUAL (laanwj) +- #10429 `6b99daf` tests: fix spurious addrman test failure (theuni) +- #10433 `8e57256` [tests] improve tmpdir structure (jnewbery) +- #10415 `217b416` [tests] Speed up fuzzing by ~200x when using afl-fuzz (practicalswift) +- #10445 `b4b057a` Add test for empty chain and reorg consistency for gettxoutsetinfo (gmaxwell) +- #10423 `1aefc94` [tests] skipped tests should clean up after themselves (jnewbery) +- #10359 `329fc1d` [tests] functional tests should call BitcoinTestFramework start/stop node methods (jnewbery) +- #10514 `e103b3f` Bugfix: missing == 0 after randrange (sipa) +- #10515 `c871f32` [test] Add test for getchaintxstats (jimmysong) +- #10509 `bea5b00` Remove xvfb configuration from travis (ryanofsky) +- #10535 `30853e1` [qa] fundrawtx: Fix shutdown race (MarcoFalke) +- #9909 `300f8e7` tests: Add FindEarliestAtLeast test for edge cases (ryanofsky) +- #10331 `75e898c` Share config between util and functional tests (jnewbery) +- #10321 `e801084` Use FastRandomContext for all tests (sipa) +- #10524 `6c2d81f` [tests] Remove printf(...) (practicalswift) +- #10547 `71ab6e5` [tests] Use FastRandomContext instead of boost::random::{mt19937,uniform_int_distribution} (practicalswift) +- #10551 `6702617` [Tests] Wallet encryption functional tests (achow101) +- #10555 `643fa0b` [tests] various improvements to zmq_test.py (jnewbery) +- #10533 `d083bd9` [tests] Use cookie auth instead of rpcuser and rpcpassword (achow101) +- #10632 `c68a9a6` qa: Add stopatheight test (MarcoFalke) +- #10636 `4bc853b` [qa] util: Check return code after closing bitcoind proc (MarcoFalke) +- #10662 `e0a7801` Initialize randomness in benchmarks (achow101) +- #10612 `7c87a9c` The young person's guide to the test_framework (jnewbery) +- #10659 `acb1153` [qa] blockchain: Pass on closed connection during generate call (MarcoFalke) +- #10690 `416af3e` [qa] Bugfix: allow overriding extra_args in ComparisonTestFramework (sdaftuar) +- #10556 `65cc7aa` Move stop/start functions from utils.py into BitcoinTestFramework (jnewbery) +- #10704 `dd07f47` [tests] nits in dbcrash.py (jnewbery) +- #10743 `be82498` [test] don't run dbcrash.py on Travis (jnewbery) +- #10761 `d3b5870` [tests] fix replace_by_fee.py (jnewbery) +- #10759 `1d4805c` Fix multi_rpc test for hosts that dont default to utf8 (TheBlueMatt) +- #10190 `e4f226a` [tests] mining functional tests (including regression test for submitblock) (jnewbery) +- #10739 `1fc783f` test: Move variable `state` down where it is used (paveljanik) +- #9980 `fee0d80` Fix mem access violation merkleblock (Christewart) +- #10893 `0c173a1` [QA] Avoid running multiwallet.py twice (jonasschnelli) +- #10927 `9d5e8f9` test: Make sure wallet.backup is created in temp path (laanwj) +- #10899 `f29d5db` [test] Qt: Use _putenv_s instead of setenv on Windows builds (brianmcmichael) +- #10912 `5c8eb79` [tests] Fix incorrect memory_cleanse(…) call in crypto_tests.cpp (practicalswift) +- #11001 `fa8a063` [tests] Test disconnecting unsupported service bits logic (jnewbery) +- #10695 `929fd72` [qa] Rewrite BIP65/BIP66 functional tests (sdaftuar) +- #10963 `ecd2135` [bench] Restore format state of cout after printing with std::fixed/setprecision (practicalswift) +- #11025 `e5d26e4` qa: Fix inv race in example_test (MarcoFalke) +- #10765 `2c811e0` Tests: address placement should be deterministic by default (ReneNyffenegger) +- #11000 `ac016e1` test: Add resendwallettransactions functional tests (promag) +- #11032 `aeb3175` [qa] Fix block message processing error in sendheaders.py (sdaftuar) +- #10105 `0b9fb68` [tests] fixup - make all Travis test runs quiet, non just cron job runs (jnewbery) +- #10222 `6ce7337` [tests] test_runner - check unicode (jnewbery) +- #10327 `35da2ae` [tests] remove import-abort-rescan.py (jnewbery) +- #11023 `bf74d37` [tests] Add option to attach a python debugger if functional test fails (jnewbery) +- #10565 `8c2098a` [coverage] Remove subtrees and benchmarks from coverage report (achow101) + +### Miscellaneous +- #9871 `be8ba2c` Add a tree sha512 hash to merge commits (sipa) +- #9821 `d19d45a` util: Specific GetOSRandom for Linux/FreeBSD/OpenBSD (laanwj) +- #9903 `ba80a68` Docs: add details to -rpcclienttimeout doc (ian-kelling) +- #9910 `53c300f` Docs: correct and elaborate -rpcbind doc (ian-kelling) +- #9905 `01b7cda` [contrib] gh-merge: Move second sha512 check to the end (MarcoFalke) +- #9880 `4df8213` Verify Tree-SHA512s in merge commits, enforce sigs are not SHA1 (TheBlueMatt) +- #9932 `00c13ea` Fix verify-commits on travis and always check top commit's tree (TheBlueMatt) +- #9952 `6996e06` Add historical release notes for 0.14.0 (laanwj) +- #9940 `fa99663` Fix verify-commits on OSX, update for new bad Tree-SHA512, point travis to different keyservers (TheBlueMatt) +- #9963 `8040ae6` util: Properly handle errors during log message formatting (laanwj) +- #9984 `cce056d` devtools: Make github-merge compute SHA512 from git, instead of worktree (laanwj) +- #9995 `8bcf934` [doc] clarify blockchain size and pruning (askmike) +- #9734 `0c17afc` Add updating of chainTxData to release process (sipa) +- #10063 `530fcbd` add missing spaces so that markdown recognizes headline (flack) +- #10085 `db1ae54` Docs: remove 'noconnect' option (jlopp) +- #10090 `8e4f7e7` Update bitcoin.conf with example for pruning (coinables) +- #9424 `1a5aaab` Change LogAcceptCategory to use uint32_t rather than sets of strings (gmaxwell) +- #10036 `fbf36ca` Fix init README format to render correctly on github (jlopp) +- #10058 `a2cd0b0` No need to use OpenSSL malloc/free (tjps) +- #10123 `471ed00` Allow debug logs to be excluded from specified component (jnewbery) +- #10104 `fadf078` linearize script: Option to use RPC cookie (achow101) +- #10162 `a3a2160` [trivial] Log calls to getblocktemplate (jnewbery) +- #10155 `928695b` build: Deduplicate version numbers (laanwj) +- #10211 `a86255b` [doc] Contributor fixes & new "finding reviewers" section (kallewoof) +- #10250 `1428f30` Fix some empty vector references (sipa) +- #10270 `95f5e44` Remove Clang workaround for Boost 1.46 (fanquake) +- #10263 `cb007e4` Trivial: fix fee estimate write error log message (CryptAxe) +- #9670 `bd9ec0e` contrib: github-merge improvements (laanwj) +- #10260 `1d75597` [doc] Minor corrections to osx dependencies (fanquake) +- #10189 `750c5a5` devtools/net: add a verifier for scriptable changes. Use it to make CNode::id private (theuni) +- #10322 `bc64b5a` Use hardware timestamps in RNG seeding (sipa) +- #10381 `7f2b9e0` Shadowing warnings are not enabled by default, update doc accordingly (paveljanik) +- #10380 `b6ee855` [doc] Removing comments about dirty entries on txmempool (madeo) +- #10383 `d0c37ee` [logging] log system time and mock time (jnewbery) +- #10404 `b45a52a` doc: Add logging to FinalizeNode() (sdaftuar) +- #10388 `526e839` Output line to debug.log when IsInitialBlockDownload latches to false (morcos) +- #10372 `15254e9` Add perf counter data to GetStrongRandBytes state in scheduler (TheBlueMatt) +- #10461 `55b72f3` Update style guide (sipa) +- #10486 `10e8c0a` devtools: Retry after signing fails in github-merge (laanwj) +- #10447 `f259263` Make bitcoind invalid argument error message specific (laanwj) +- #10495 `6a38b79` contrib: Update location of seeds.txt (laanwj) +- #10469 `b6b150b` Fixing typo in rpcdump.cpp help message (keystrike) +- #10451 `27b9931` contrib/init/bitcoind.openrcconf: Don't disable wallet by default (luke-jr) +- #10323 `00d3692` Update to latest libsecp256k1 master (sipa) +- #10422 `cec9e1e` Fix timestamp in fee estimate debug message (morcos) +- #10566 `5d034ee` [docs] Use the "domain name setup" image (previously unused) in the gitian docs (practicalswift) +- #10534 `a514ac3` Clarify prevector::erase and avoid swap-to-clear (sipa) +- #10575 `22ec768` Header include guideline (sipa) +- #10480 `fbf5d3b` Improve commit-check-script.sh (sipa) +- #10502 `1ad3d4e` scripted-diff: Remove BOOST_FOREACH, Q_FOREACH and PAIRTYPE (jtimon) +- #10377 `b63be2c` Use rdrand as entropy source on supported platforms (sipa) +- #9895 `228c319` Turn TryCreateDirectory() into TryCreateDirectories() (benma) +- #10602 `d76e84a` Make clang-format use C++11 features (e.g. A<A<int>> instead of A<A<int> >) (practicalswift) +- #10623 `c38f540` doc: Add 0.14.2 release notes (MarcoFalke) +- #10276 `b750b33` contrib/verifybinaries: allow filtering by platform (knocte) +- #10248 `01c4b14` Rewrite addrdb with less duplication using CHashVerifier (sipa) +- #10577 `232508f` Add an explanation of quickly hashing onto a non-power of two range (gmaxwell) +- #10608 `eee398f` Add a comment explaining the use of MAX_BLOCK_BASE_SIZE (gmaxwell) +- #10728 `7397af9` fix typo in help text for removeprunedfunds (AkioNak) +- #10193 `6dbcc74` scripted-diff: Remove #include <boost/foreach.hpp> (jtimon) +- #10676 `379aed0` document script-based return fields for validateaddress (instagibbs) +- #10651 `cef4b5c` Verify binaries from bitcoincore.org and bitcoin.org (TheBlueMatt) +- #10786 `ca4c545` Add PR description to merge commit in github-merge.py (sipa) +- #10812 `c5904e8` [utils] Allow bitcoin-cli's -rpcconnect option to be used with square brackets (jnewbery) +- #10842 `3895e25` Fix incorrect Doxygen tag (@ince → @since). Doxygen parameter name matching (practicalswift) +- #10681 `df0793f` add gdb attach process to test README (instagibbs) +- #10789 `1124328` Punctuation/grammer fixes in rpcwallet.cpp (stevendlander) +- #10655 `78f307b` Properly document target_confirmations in listsinceblock (RHavar) +- #10917 `5c003cb` developer-notes: add reference to snake_case and PascalCase (benma) +- #11003 `4b5a7ce` Docs: Capitalize bullet points in CONTRIBUTING guide (eklitzke) +- #10968 `98aa3f6` Add instructions for parallel gitian builds (coblee) +- #11076 `1c4b9b3` 0.15 release-notes nits: fix redundancy, remove accidental parenthesis & fix range style (practicalswift) +- #11090 `8f0121c` Update contributor names in release-notes.md (Derek701) +- #11056 `cbdd338` disable jni in builds (instagibbs) +- #11080 `2b59cfb` doc: Update build-openbsd for 6.1 (laanwj) +- #11119 `0a6af47` [doc] build-windows: Mention that only trusty works (MarcoFalke) +- #11108 `e8ad101` Changing -txindex requires -reindex, not -reindex-chainstate (TheBlueMatt) +- #9792 `342b9bc` FastRandomContext improvements and switch to ChaCha20 (sipa) +- #9505 `67ed40e` Prevector Quick Destruct (JeremyRubin) +- #10820 `ef37f20` Use cpuid intrinsics instead of asm code (sipa) +- #9999 `a328904` [LevelDB] Plug leveldb logs to bitcoin logs (NicolasDorier) +- #9693 `c5e9e42` Prevent integer overflow in ReadVarInt (gmaxwell) +- #10129 `351d0ad` scheduler: fix sub-second precision with boost < 1.50 (theuni) +- #10153 `fade788` logging: Fix off-by-one for shrinkdebugfile default (MarcoFalke) +- #10305 `c45da32` Fix potential NPD introduced in b297426c (TheBlueMatt) +- #10338 `daf3e7d` Maintain state across GetStrongRandBytes calls (sipa) +- #10544 `a4fe077` Update to LevelDB 1.20 (sipa) +- #10614 `cafe24f` random: fix crash on some 64bit platforms (theuni) +- #10714 `2a09a38` Avoid printing incorrect block indexing time due to uninitialized variable (practicalswift) +- #10837 `8bc6d1f` Fix resource leak on error in GetDevURandom (corebob) +- #10832 `89bb036` init: Factor out AppInitLockDataDirectory and fix startup core dump issue (laanwj) +- #10914 `b995a37` Add missing lock in CScheduler::AreThreadsServicingQueue() (TheBlueMatt) +- #10958 `659c096` Update to latest Bitcoin patches for LevelDB (sipa) +- #10919 `c1c671f` Fix more init bugs (TheBlueMatt) + +Credits +======= + +Thanks to everyone who directly contributed to this release: + +- ロハン ダル +- Ahmad Kazi +- aideca +- Akio Nakamura +- Alex Morcos +- Allan Doensen +- Andres G. Aragoneses +- Andrew Chow +- Angel Leon +- Awemany +- Bob McElrath +- Brian McMichael +- BtcDrak +- Charlie Lee +- Chris Gavin +- Chris Stewart +- Cory Fields +- CryptAxe +- Dag Robole +- Daniel Aleksandersen +- Daniel Cousens +- darksh1ne +- Dimitris Tsapakidis +- Eric Shaw +- Evan Klitzke +- fanquake +- Felix Weis +- flack +- Guido Vranken +- Greg Griffith +- Gregory Maxwell +- Gregory Sanders +- Ian Kelling +- Jack Grigg +- James Evans +- James Hilliard +- Jameson Lopp +- Jeremy Rubin +- Jimmy Song +- João Barbosa +- Johnathan Corgan +- John Newbery +- Jonas Schnelli +- Jorge Timón +- Karl-Johan Alm +- kewde +- KibbledJiveElkZoo +- Kirit Thadaka +- kobake +- Kyle Honeycutt +- Lawrence Nahum +- Luke Dashjr +- Marco Falke +- Marcos Mayorga +- Marijn Stollenga +- Mario Dian +- Mark Friedenbach +- Marko Bencun +- Masahiko Hyuga +- Matt Corallo +- Matthew Zipkin +- Matthias Grundmann +- Michael Goldstein +- Michael Rotarius +- Mikerah +- Mike van Rossum +- Mitchell Cash +- Nicolas Dorier +- Patrick Strateman +- Pavel Janík +- Pavlos Antoniou +- Pavol Rusnak +- Pedro Branco +- Peter Todd +- Pieter Wuille +- practicalswift +- René Nyffenegger +- Ricardo Velhote +- romanornr +- Russell Yanofsky +- Rusty Russell +- Ryan Havar +- shaolinfry +- Shigeya Suzuki +- Simone Madeo +- Spencer Lievens +- Steven D. Lander +- Suhas Daftuar +- Takashi Mitsuta +- Thomas Snider +- Timothy Redaelli +- tintinweb +- tnaka +- Warren Togami +- Wladimir J. van der Laan + +As well as everyone that helped translating on [Transifex](https://www.transifex.com/projects/p/bitcoin/). diff --git a/src/addrman.h b/src/addrman.h index 547088aedf..18f3062287 100644 --- a/src/addrman.h +++ b/src/addrman.h @@ -472,6 +472,8 @@ public: nTried = 0; nNew = 0; nLastGood = 1; //Initially at 1 so that "never" is strictly worse. + mapInfo.clear(); + mapAddr.clear(); } CAddrMan() diff --git a/src/base58.cpp b/src/base58.cpp index 3802f953f9..3b907c20d6 100644 --- a/src/base58.cpp +++ b/src/base58.cpp @@ -212,6 +212,28 @@ int CBase58Data::CompareTo(const CBase58Data& b58) const namespace { +/** base58-encoded Bitcoin addresses. + * Public-key-hash-addresses have version 0 (or 111 testnet). + * The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key. + * Script-hash-addresses have version 5 (or 196 testnet). + * The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script. + */ +class CBitcoinAddress : public CBase58Data { +public: + bool Set(const CKeyID &id); + bool Set(const CScriptID &id); + bool Set(const CTxDestination &dest); + bool IsValid() const; + bool IsValid(const CChainParams ¶ms) const; + + CBitcoinAddress() {} + CBitcoinAddress(const CTxDestination &dest) { Set(dest); } + CBitcoinAddress(const std::string& strAddress) { SetString(strAddress); } + CBitcoinAddress(const char* pszAddress) { SetString(pszAddress); } + + CTxDestination Get() const; +}; + class CBitcoinAddressVisitor : public boost::static_visitor<bool> { private: @@ -271,21 +293,6 @@ CTxDestination CBitcoinAddress::Get() const return CNoDestination(); } -bool CBitcoinAddress::GetKeyID(CKeyID& keyID) const -{ - if (!IsValid() || vchVersion != Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS)) - return false; - uint160 id; - memcpy(&id, vchData.data(), 20); - keyID = CKeyID(id); - return true; -} - -bool CBitcoinAddress::IsScript() const -{ - return IsValid() && vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS); -} - void CBitcoinSecret::SetKey(const CKey& vchSecret) { assert(vchSecret.IsValid()); @@ -318,3 +325,25 @@ bool CBitcoinSecret::SetString(const std::string& strSecret) { return SetString(strSecret.c_str()); } + +std::string EncodeDestination(const CTxDestination& dest) +{ + CBitcoinAddress addr(dest); + if (!addr.IsValid()) return ""; + return addr.ToString(); +} + +CTxDestination DecodeDestination(const std::string& str) +{ + return CBitcoinAddress(str).Get(); +} + +bool IsValidDestinationString(const std::string& str, const CChainParams& params) +{ + return CBitcoinAddress(str).IsValid(params); +} + +bool IsValidDestinationString(const std::string& str) +{ + return CBitcoinAddress(str).IsValid(); +} diff --git a/src/base58.h b/src/base58.h index db12208f74..4b895ca022 100644 --- a/src/base58.h +++ b/src/base58.h @@ -95,30 +95,6 @@ public: bool operator> (const CBase58Data& b58) const { return CompareTo(b58) > 0; } }; -/** base58-encoded Bitcoin addresses. - * Public-key-hash-addresses have version 0 (or 111 testnet). - * The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key. - * Script-hash-addresses have version 5 (or 196 testnet). - * The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script. - */ -class CBitcoinAddress : public CBase58Data { -public: - bool Set(const CKeyID &id); - bool Set(const CScriptID &id); - bool Set(const CTxDestination &dest); - bool IsValid() const; - bool IsValid(const CChainParams ¶ms) const; - - CBitcoinAddress() {} - CBitcoinAddress(const CTxDestination &dest) { Set(dest); } - CBitcoinAddress(const std::string& strAddress) { SetString(strAddress); } - CBitcoinAddress(const char* pszAddress) { SetString(pszAddress); } - - CTxDestination Get() const; - bool GetKeyID(CKeyID &keyID) const; - bool IsScript() const; -}; - /** * A base58-encoded secret key */ @@ -167,4 +143,9 @@ public: typedef CBitcoinExtKeyBase<CExtKey, BIP32_EXTKEY_SIZE, CChainParams::EXT_SECRET_KEY> CBitcoinExtKey; typedef CBitcoinExtKeyBase<CExtPubKey, BIP32_EXTKEY_SIZE, CChainParams::EXT_PUBLIC_KEY> CBitcoinExtPubKey; +std::string EncodeDestination(const CTxDestination& dest); +CTxDestination DecodeDestination(const std::string& str); +bool IsValidDestinationString(const std::string& str); +bool IsValidDestinationString(const std::string& str, const CChainParams& params); + #endif // BITCOIN_BASE58_H diff --git a/src/bench/crypto_hash.cpp b/src/bench/crypto_hash.cpp index 2914a36c7b..410a08e512 100644 --- a/src/bench/crypto_hash.cpp +++ b/src/bench/crypto_hash.cpp @@ -47,7 +47,7 @@ static void SHA256_32b(benchmark::State& state) std::vector<uint8_t> in(32,0); while (state.KeepRunning()) { for (int i = 0; i < 1000000; i++) { - CSHA256().Write(in.data(), in.size()).Finalize(&in[0]); + CSHA256().Write(in.data(), in.size()).Finalize(in.data()); } } } diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index fca6083ea8..3c94c99b3e 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -296,19 +296,22 @@ int CommandLineRPC(int argc, char *argv[]) } std::string rpcPass; if (gArgs.GetBoolArg("-stdinrpcpass", false)) { - if(!std::getline(std::cin,rpcPass)) + if (!std::getline(std::cin, rpcPass)) { throw std::runtime_error("-stdinrpcpass specified but failed to read from standard input"); + } gArgs.ForceSetArg("-rpcpassword", rpcPass); } std::vector<std::string> args = std::vector<std::string>(&argv[1], &argv[argc]); if (gArgs.GetBoolArg("-stdin", false)) { // Read one arg per line from stdin and append std::string line; - while (std::getline(std::cin,line)) + while (std::getline(std::cin, line)) { args.push_back(line); + } } - if (args.size() < 1) + if (args.size() < 1) { throw std::runtime_error("too few parameters (need at least command)"); + } std::string strMethod = args[0]; args.erase(args.begin()); // Remove trailing method name from arguments vector diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index cff90d13af..d8d7934bf6 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -271,11 +271,11 @@ static void MutateTxAddOutAddr(CMutableTransaction& tx, const std::string& strIn // extract and validate ADDRESS std::string strAddr = vStrInputParts[1]; - CBitcoinAddress addr(strAddr); - if (!addr.IsValid()) + CTxDestination destination = DecodeDestination(strAddr); + if (!IsValidDestination(destination)) { throw std::runtime_error("invalid TX output address"); - // build standard output script via GetScriptForDestination() - CScript scriptPubKey = GetScriptForDestination(addr.Get()); + } + CScript scriptPubKey = GetScriptForDestination(destination); // construct TxOut, append to transaction output list CTxOut txout(value, scriptPubKey); @@ -314,10 +314,8 @@ static void MutateTxAddOutPubKey(CMutableTransaction& tx, const std::string& str scriptPubKey = GetScriptForWitness(scriptPubKey); } if (bScriptHash) { - // Get the address for the redeem script, then call - // GetScriptForDestination() to construct a P2SH scriptPubKey. - CBitcoinAddress redeemScriptAddr(scriptPubKey); - scriptPubKey = GetScriptForDestination(redeemScriptAddr.Get()); + // Get the ID for the script, and then construct a P2SH destination for it. + scriptPubKey = GetScriptForDestination(CScriptID(scriptPubKey)); } // construct TxOut, append to transaction output list @@ -381,10 +379,8 @@ static void MutateTxAddOutMultiSig(CMutableTransaction& tx, const std::string& s scriptPubKey = GetScriptForWitness(scriptPubKey); } if (bScriptHash) { - // Get the address for the redeem script, then call - // GetScriptForDestination() to construct a P2SH scriptPubKey. - CBitcoinAddress addr(scriptPubKey); - scriptPubKey = GetScriptForDestination(addr.Get()); + // Get the ID for the script, and then construct a P2SH destination for it. + scriptPubKey = GetScriptForDestination(CScriptID(scriptPubKey)); } // construct TxOut, append to transaction output list @@ -444,11 +440,10 @@ static void MutateTxAddOutScript(CMutableTransaction& tx, const std::string& str } if (bSegWit) { - scriptPubKey = GetScriptForWitness(scriptPubKey); + scriptPubKey = GetScriptForWitness(scriptPubKey); } if (bScriptHash) { - CBitcoinAddress addr(scriptPubKey); - scriptPubKey = GetScriptForDestination(addr.Get()); + scriptPubKey = GetScriptForDestination(CScriptID(scriptPubKey)); } // construct TxOut, append to transaction output list diff --git a/src/chain.h b/src/chain.h index ef7e6f9554..f1036e5d92 100644 --- a/src/chain.h +++ b/src/chain.h @@ -204,14 +204,14 @@ public: unsigned int nChainTx; //! Verification status of this block. See enum BlockStatus - unsigned int nStatus; + uint32_t nStatus; //! block header - int nVersion; + int32_t nVersion; uint256 hashMerkleRoot; - unsigned int nTime; - unsigned int nBits; - unsigned int nNonce; + uint32_t nTime; + uint32_t nBits; + uint32_t nNonce; //! (memory only) Sequential id assigned to distinguish order in which blocks are received. int32_t nSequenceId; diff --git a/src/consensus/validation.h b/src/consensus/validation.h index 5494ce40ea..b6740c9d9f 100644 --- a/src/consensus/validation.h +++ b/src/consensus/validation.h @@ -89,17 +89,16 @@ public: std::string GetDebugMessage() const { return strDebugMessage; } }; +// These implement the weight = (stripped_size * 4) + witness_size formula, +// using only serialization with and without witness data. As witness_size +// is equal to total_size - stripped_size, this formula is identical to: +// weight = (stripped_size * 3) + total_size. static inline int64_t GetTransactionWeight(const CTransaction& tx) { - return ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * (WITNESS_SCALE_FACTOR -1) + ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); + return ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * (WITNESS_SCALE_FACTOR - 1) + ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); } - static inline int64_t GetBlockWeight(const CBlock& block) { - // This implements the weight = (stripped_size * 4) + witness_size formula, - // using only serialization with and without witness data. As witness_size - // is equal to total_size - stripped_size, this formula is identical to: - // weight = (stripped_size * 3) + total_size. return ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * (WITNESS_SCALE_FACTOR - 1) + ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION); } diff --git a/src/core_write.cpp b/src/core_write.cpp index 1431fa0c9b..e16db13650 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -148,8 +148,9 @@ void ScriptPubKeyToUniv(const CScript& scriptPubKey, out.pushKV("type", GetTxnOutputType(type)); UniValue a(UniValue::VARR); - for (const CTxDestination& addr : addresses) - a.push_back(CBitcoinAddress(addr).ToString()); + for (const CTxDestination& addr : addresses) { + a.push_back(EncodeDestination(addr)); + } out.pushKV("addresses", a); } diff --git a/src/init.cpp b/src/init.cpp index a46742e56a..6b9699213f 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -45,7 +45,6 @@ #include "validationinterface.h" #ifdef ENABLE_WALLET #include "wallet/init.h" -#include "wallet/wallet.h" #endif #include "warnings.h" #include <stdint.h> @@ -103,12 +102,11 @@ static const char* FEE_ESTIMATES_FILENAME="fee_estimates.dat"; // created by AppInit() or the Qt main() function. // // A clean exit happens when StartShutdown() or the SIGTERM -// signal handler sets fRequestShutdown, which triggers -// the DetectShutdownThread(), which interrupts the main thread group. -// DetectShutdownThread() then exits, which causes AppInit() to -// continue (it .joins the shutdown thread). -// Shutdown() is then -// called to clean up database connections, and stop other +// signal handler sets fRequestShutdown, which makes main thread's +// WaitForShutdown() interrupts the thread group. +// And then, WaitForShutdown() makes all other on-going threads +// in the thread group join the main thread. +// Shutdown() is then called to clean up database connections, and stop other // threads that should only be stopped after the main network-processing // threads have exited. // @@ -189,17 +187,18 @@ void Shutdown() StopRPC(); StopHTTPServer(); #ifdef ENABLE_WALLET - for (CWalletRef pwallet : vpwallets) { - pwallet->Flush(false); - } + FlushWallets(); #endif MapPort(false); + + // Because these depend on each-other, we make sure that neither can be + // using the other before destroying them. UnregisterValidationInterface(peerLogic.get()); + if(g_connman) g_connman->Stop(); peerLogic.reset(); g_connman.reset(); StopTorControl(); - UnregisterNodeSignals(GetNodeSignals()); if (fDumpMempoolLater && gArgs.GetArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) { DumpMempool(); } @@ -246,9 +245,7 @@ void Shutdown() pblocktree = nullptr; } #ifdef ENABLE_WALLET - for (CWalletRef pwallet : vpwallets) { - pwallet->Flush(true); - } + StopWallets(); #endif #if ENABLE_ZMQ @@ -269,10 +266,7 @@ void Shutdown() UnregisterAllValidationInterfaces(); GetMainSignals().UnregisterBackgroundSignalScheduler(); #ifdef ENABLE_WALLET - for (CWalletRef pwallet : vpwallets) { - delete pwallet; - } - vpwallets.clear(); + CloseWallets(); #endif globalVerifyHandle.reset(); ECC_Stop(); @@ -354,6 +348,9 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-maxorphantx=<n>", strprintf(_("Keep at most <n> unconnectable transactions in memory (default: %u)"), DEFAULT_MAX_ORPHAN_TRANSACTIONS)); strUsage += HelpMessageOpt("-maxmempool=<n>", strprintf(_("Keep the transaction memory pool below <n> megabytes (default: %u)"), DEFAULT_MAX_MEMPOOL_SIZE)); strUsage += HelpMessageOpt("-mempoolexpiry=<n>", strprintf(_("Do not keep transactions in the mempool longer than <n> hours (default: %u)"), DEFAULT_MEMPOOL_EXPIRY)); + if (showDebug) { + strUsage += HelpMessageOpt("-minimumchainwork=<hex>", strprintf("Minimum work assumed to exist on a valid chain in hex (default: %s, testnet: %s)", defaultChainParams->GetConsensus().nMinimumChainWork.GetHex(), testnetChainParams->GetConsensus().nMinimumChainWork.GetHex())); + } strUsage += HelpMessageOpt("-persistmempool", strprintf(_("Whether to save the mempool on shutdown and load on restart (default: %u)"), DEFAULT_PERSIST_MEMPOOL)); strUsage += HelpMessageOpt("-blockreconstructionextratxn=<n>", strprintf(_("Extra transactions to keep in memory for compact block reconstructions (default: %u)"), DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN)); strUsage += HelpMessageOpt("-par=<n>", strprintf(_("Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d)"), @@ -486,7 +483,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageGroup(_("Block creation options:")); strUsage += HelpMessageOpt("-blockmaxweight=<n>", strprintf(_("Set maximum BIP141 block weight (default: %d)"), DEFAULT_BLOCK_MAX_WEIGHT)); - strUsage += HelpMessageOpt("-blockmaxsize=<n>", strprintf(_("Set maximum block size in bytes (default: %d)"), DEFAULT_BLOCK_MAX_SIZE)); + strUsage += HelpMessageOpt("-blockmaxsize=<n>", _("Set maximum BIP141 block weight to this * 4. Deprecated, use blockmaxweight")); strUsage += HelpMessageOpt("-blockmintxfee=<amt>", strprintf(_("Set lowest fee rate (in %s/kB) for transactions to be included in block creation. (default: %s)"), CURRENCY_UNIT, FormatMoney(DEFAULT_BLOCK_MIN_TX_FEE))); if (showDebug) strUsage += HelpMessageOpt("-blockversion=<n>", "Override block version to test forking scenarios"); @@ -787,6 +784,15 @@ void InitParameterInteraction() if (gArgs.SoftSetBoolArg("-whitelistrelay", true)) LogPrintf("%s: parameter interaction: -whitelistforcerelay=1 -> setting -whitelistrelay=1\n", __func__); } + + if (gArgs.IsArgSet("-blockmaxsize")) { + unsigned int max_size = gArgs.GetArg("-blockmaxsize", 0); + if (gArgs.SoftSetArg("blockmaxweight", strprintf("%d", max_size * WITNESS_SCALE_FACTOR))) { + LogPrintf("%s: parameter interaction: -blockmaxsize=%d -> setting -blockmaxweight=%d (-blockmaxsize is deprecated!)\n", __func__, max_size, max_size * WITNESS_SCALE_FACTOR); + } else { + LogPrintf("%s: Ignoring blockmaxsize setting which is overridden by blockmaxweight", __func__); + } + } } static std::string ResolveErrMsg(const char * const optname, const std::string& strBind) @@ -970,6 +976,20 @@ bool AppInitParameterInteraction() else LogPrintf("Validating signatures for all blocks.\n"); + if (gArgs.IsArgSet("-minimumchainwork")) { + const std::string minChainWorkStr = gArgs.GetArg("-minimumchainwork", ""); + if (!IsHexNumber(minChainWorkStr)) { + return InitError(strprintf("Invalid non-hex (%s) minimum chain work value specified", minChainWorkStr)); + } + nMinimumChainWork = UintToArith256(uint256S(minChainWorkStr)); + } else { + nMinimumChainWork = UintToArith256(chainparams.GetConsensus().nMinimumChainWork); + } + LogPrintf("Setting nMinimumChainWork=%s\n", nMinimumChainWork.GetHex()); + if (nMinimumChainWork < UintToArith256(chainparams.GetConsensus().nMinimumChainWork)) { + LogPrintf("Warning: nMinimumChainWork set below default value of %s\n", chainparams.GetConsensus().nMinimumChainWork.GetHex()); + } + // mempool limits int64_t nMempoolSizeMax = gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000; int64_t nMempoolSizeMin = gArgs.GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) * 1000 * 40; @@ -1014,7 +1034,7 @@ bool AppInitParameterInteraction() RegisterAllCoreRPCCommands(tableRPC); #ifdef ENABLE_WALLET - RegisterWalletRPCCommands(tableRPC); + RegisterWalletRPC(tableRPC); #endif nConnectTimeout = gArgs.GetArg("-timeout", DEFAULT_CONNECT_TIMEOUT); @@ -1236,7 +1256,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) // ********************************************************* Step 5: verify wallet database integrity #ifdef ENABLE_WALLET - if (!WalletVerify()) + if (!VerifyWallets()) return false; #endif // ********************************************************* Step 6: network initialization @@ -1251,7 +1271,6 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) peerLogic.reset(new PeerLogicValidation(&connman)); RegisterValidationInterface(peerLogic.get()); - RegisterNodeSignals(GetNodeSignals()); // sanitize comments per BIP-0014, format user agent and check total size std::vector<std::string> uacomments; @@ -1557,7 +1576,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) // ********************************************************* Step 8: load wallet #ifdef ENABLE_WALLET - if (!InitLoadWallet()) + if (!OpenWallets()) return false; #else LogPrintf("No wallet support compiled in!\n"); @@ -1642,6 +1661,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) connOptions.nMaxFeeler = 1; connOptions.nBestHeight = chainActive.Height(); connOptions.uiInterface = &uiInterface; + connOptions.m_msgproc = peerLogic.get(); connOptions.nSendBufferMaxSize = 1000*gArgs.GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER); connOptions.nReceiveFloodSize = 1000*gArgs.GetArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER); @@ -1695,9 +1715,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) uiInterface.InitMessage(_("Done loading")); #ifdef ENABLE_WALLET - for (CWalletRef pwallet : vpwallets) { - pwallet->postInitProcess(scheduler); - } + StartWallets(scheduler); #endif return !fRequestShutdown; diff --git a/src/keystore.h b/src/keystore.h index 528b6e0834..9b85ddb0ec 100644 --- a/src/keystore.h +++ b/src/keystore.h @@ -30,7 +30,7 @@ public: //! Check whether a key corresponding to a given address is present in the store. virtual bool HaveKey(const CKeyID &address) const =0; virtual bool GetKey(const CKeyID &address, CKey& keyOut) const =0; - virtual void GetKeys(std::set<CKeyID> &setAddress) const =0; + virtual std::set<CKeyID> GetKeys() const =0; virtual bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const =0; //! Support for BIP 0013 : see https://github.com/bitcoin/bips/blob/master/bip-0013.mediawiki @@ -71,18 +71,14 @@ public: } return result; } - void GetKeys(std::set<CKeyID> &setAddress) const override + std::set<CKeyID> GetKeys() const override { - setAddress.clear(); - { - LOCK(cs_KeyStore); - KeyMap::const_iterator mi = mapKeys.begin(); - while (mi != mapKeys.end()) - { - setAddress.insert((*mi).first); - mi++; - } + LOCK(cs_KeyStore); + std::set<CKeyID> set_address; + for (const auto& mi : mapKeys) { + set_address.insert(mi.first); } + return set_address; } bool GetKey(const CKeyID &address, CKey &keyOut) const override { diff --git a/src/miner.cpp b/src/miner.cpp index f1942ec570..a9989f4b17 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -43,7 +43,6 @@ // its ancestors. uint64_t nLastBlockTx = 0; -uint64_t nLastBlockSize = 0; uint64_t nLastBlockWeight = 0; int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev) @@ -64,7 +63,6 @@ int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParam BlockAssembler::Options::Options() { blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE); nBlockMaxWeight = DEFAULT_BLOCK_MAX_WEIGHT; - nBlockMaxSize = DEFAULT_BLOCK_MAX_SIZE; } BlockAssembler::BlockAssembler(const CChainParams& params, const Options& options) : chainparams(params) @@ -72,10 +70,6 @@ BlockAssembler::BlockAssembler(const CChainParams& params, const Options& option blockMinFeeRate = options.blockMinFeeRate; // Limit weight to between 4K and MAX_BLOCK_WEIGHT-4K for sanity: nBlockMaxWeight = std::max<size_t>(4000, std::min<size_t>(MAX_BLOCK_WEIGHT - 4000, options.nBlockMaxWeight)); - // Limit size to between 1K and MAX_BLOCK_SERIALIZED_SIZE-1K for sanity: - nBlockMaxSize = std::max<size_t>(1000, std::min<size_t>(MAX_BLOCK_SERIALIZED_SIZE - 1000, options.nBlockMaxSize)); - // Whether we need to account for byte usage (in addition to weight usage) - fNeedSizeAccounting = (nBlockMaxSize < MAX_BLOCK_SERIALIZED_SIZE - 1000); } static BlockAssembler::Options DefaultOptions(const CChainParams& params) @@ -85,20 +79,7 @@ static BlockAssembler::Options DefaultOptions(const CChainParams& params) // If only one is given, only restrict the specified resource. // If both are given, restrict both. BlockAssembler::Options options; - options.nBlockMaxWeight = DEFAULT_BLOCK_MAX_WEIGHT; - options.nBlockMaxSize = DEFAULT_BLOCK_MAX_SIZE; - bool fWeightSet = false; - if (gArgs.IsArgSet("-blockmaxweight")) { - options.nBlockMaxWeight = gArgs.GetArg("-blockmaxweight", DEFAULT_BLOCK_MAX_WEIGHT); - options.nBlockMaxSize = MAX_BLOCK_SERIALIZED_SIZE; - fWeightSet = true; - } - if (gArgs.IsArgSet("-blockmaxsize")) { - options.nBlockMaxSize = gArgs.GetArg("-blockmaxsize", DEFAULT_BLOCK_MAX_SIZE); - if (!fWeightSet) { - options.nBlockMaxWeight = options.nBlockMaxSize * WITNESS_SCALE_FACTOR; - } - } + options.nBlockMaxWeight = gArgs.GetArg("-blockmaxweight", DEFAULT_BLOCK_MAX_WEIGHT); if (gArgs.IsArgSet("-blockmintxfee")) { CAmount n = 0; ParseMoney(gArgs.GetArg("-blockmintxfee", ""), n); @@ -116,7 +97,6 @@ void BlockAssembler::resetBlock() inBlock.clear(); // Reserve space for coinbase tx - nBlockSize = 1000; nBlockWeight = 4000; nBlockSigOpsCost = 400; fIncludeWitness = false; @@ -145,6 +125,7 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc LOCK2(cs_main, mempool.cs); CBlockIndex* pindexPrev = chainActive.Tip(); + assert(pindexPrev != nullptr); nHeight = pindexPrev->nHeight + 1; pblock->nVersion = ComputeBlockVersion(pindexPrev, chainparams.GetConsensus()); @@ -175,7 +156,6 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc int64_t nTime1 = GetTimeMicros(); nLastBlockTx = nBlockTx; - nLastBlockSize = nBlockSize; nLastBlockWeight = nBlockWeight; // Create coinbase transaction. @@ -190,8 +170,7 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc pblocktemplate->vchCoinbaseCommitment = GenerateCoinbaseCommitment(*pblock, pindexPrev, chainparams.GetConsensus()); pblocktemplate->vTxFees[0] = -nFees; - uint64_t nSerializeSize = GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION); - LogPrintf("CreateNewBlock(): total size: %u block weight: %u txs: %u fees: %ld sigops %d\n", nSerializeSize, GetBlockWeight(*pblock), nBlockTx, nFees, nBlockSigOpsCost); + LogPrintf("CreateNewBlock(): block weight: %u txs: %u fees: %ld sigops %d\n", GetBlockWeight(*pblock), nBlockTx, nFees, nBlockSigOpsCost); // Fill in header pblock->hashPrevBlock = pindexPrev->GetBlockHash(); @@ -238,22 +217,13 @@ bool BlockAssembler::TestPackage(uint64_t packageSize, int64_t packageSigOpsCost // - transaction finality (locktime) // - premature witness (in case segwit transactions are added to mempool before // segwit activation) -// - serialized size (in case -blockmaxsize is in use) bool BlockAssembler::TestPackageTransactions(const CTxMemPool::setEntries& package) { - uint64_t nPotentialBlockSize = nBlockSize; // only used with fNeedSizeAccounting for (const CTxMemPool::txiter it : package) { if (!IsFinalTx(it->GetTx(), nHeight, nLockTimeCutoff)) return false; if (!fIncludeWitness && it->GetTx().HasWitness()) return false; - if (fNeedSizeAccounting) { - uint64_t nTxSize = ::GetSerializeSize(it->GetTx(), SER_NETWORK, PROTOCOL_VERSION); - if (nPotentialBlockSize + nTxSize >= nBlockMaxSize) { - return false; - } - nPotentialBlockSize += nTxSize; - } } return true; } @@ -263,9 +233,6 @@ void BlockAssembler::AddToBlock(CTxMemPool::txiter iter) pblock->vtx.emplace_back(iter->GetSharedTx()); pblocktemplate->vTxFees.push_back(iter->GetFee()); pblocktemplate->vTxSigOpsCost.push_back(iter->GetSigOpCost()); - if (fNeedSizeAccounting) { - nBlockSize += ::GetSerializeSize(iter->GetTx(), SER_NETWORK, PROTOCOL_VERSION); - } nBlockWeight += iter->GetTxWeight(); ++nBlockTx; nBlockSigOpsCost += iter->GetSigOpCost(); diff --git a/src/miner.h b/src/miner.h index abd2ff6199..683f4fe085 100644 --- a/src/miner.h +++ b/src/miner.h @@ -139,13 +139,11 @@ private: // Configuration parameters for the block size bool fIncludeWitness; - unsigned int nBlockMaxWeight, nBlockMaxSize; - bool fNeedSizeAccounting; + unsigned int nBlockMaxWeight; CFeeRate blockMinFeeRate; // Information on the current status of the block uint64_t nBlockWeight; - uint64_t nBlockSize; uint64_t nBlockTx; uint64_t nBlockSigOpsCost; CAmount nFees; diff --git a/src/net.cpp b/src/net.cpp index 1eb867b48b..587c9e5110 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -89,10 +89,6 @@ std::string strSubVersion; limitedmap<uint256, int64_t> mapAlreadyAskedFor(MAX_INV_SZ); -// Signals for message handling -static CNodeSignals g_signals; -CNodeSignals& GetNodeSignals() { return g_signals; } - void CConnman::AddOneShot(const std::string& strDest) { LOCK(cs_vOneShots); @@ -1114,7 +1110,7 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) { CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addr, CalculateKeyedNetGroup(addr), nonce, addr_bind, "", true); pnode->AddRef(); pnode->fWhitelisted = whitelisted; - GetNodeSignals().InitializeNode(pnode, *this); + m_msgproc->InitializeNode(pnode); LogPrint(BCLog::NET, "connection from %s accepted\n", addr.ToString()); @@ -1966,7 +1962,7 @@ bool CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai if (fAddnode) pnode->fAddnode = true; - GetNodeSignals().InitializeNode(pnode, *this); + m_msgproc->InitializeNode(pnode); { LOCK(cs_vNodes); vNodes.push_back(pnode); @@ -1996,16 +1992,16 @@ void CConnman::ThreadMessageHandler() continue; // Receive messages - bool fMoreNodeWork = GetNodeSignals().ProcessMessages(pnode, *this, flagInterruptMsgProc); + bool fMoreNodeWork = m_msgproc->ProcessMessages(pnode, flagInterruptMsgProc); fMoreWork |= (fMoreNodeWork && !pnode->fPauseSend); if (flagInterruptMsgProc) return; - // Send messages { LOCK(pnode->cs_sendProcessing); - GetNodeSignals().SendMessages(pnode, *this, flagInterruptMsgProc); + m_msgproc->SendMessages(pnode, flagInterruptMsgProc); } + if (flagInterruptMsgProc) return; } @@ -2324,6 +2320,7 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions) // // Start threads // + assert(m_msgproc); InterruptSocks5(false); interruptNet.reset(); flagInterruptMsgProc = false; @@ -2450,9 +2447,10 @@ void CConnman::DeleteNode(CNode* pnode) { assert(pnode); bool fUpdateConnectionTime = false; - GetNodeSignals().FinalizeNode(pnode->GetId(), fUpdateConnectionTime); - if(fUpdateConnectionTime) + m_msgproc->FinalizeNode(pnode->GetId(), fUpdateConnectionTime); + if(fUpdateConnectionTime) { addrman.Connected(pnode->addr); + } delete pnode; } @@ -33,7 +33,6 @@ #include <arpa/inet.h> #endif -#include <boost/signals2/signal.hpp> class CScheduler; class CNode; @@ -116,7 +115,7 @@ struct CSerializedNetMsg std::string command; }; - +class NetEventsInterface; class CConnman { public: @@ -138,6 +137,7 @@ public: int nMaxFeeler = 0; int nBestHeight = 0; CClientUIInterface* uiInterface = nullptr; + NetEventsInterface* m_msgproc = nullptr; unsigned int nSendBufferMaxSize = 0; unsigned int nReceiveFloodSize = 0; uint64_t nMaxOutboundTimeframe = 0; @@ -158,6 +158,7 @@ public: nMaxFeeler = connOptions.nMaxFeeler; nBestHeight = connOptions.nBestHeight; clientInterface = connOptions.uiInterface; + m_msgproc = connOptions.m_msgproc; nSendBufferMaxSize = connOptions.nSendBufferMaxSize; nReceiveFloodSize = connOptions.nReceiveFloodSize; nMaxOutboundTimeframe = connOptions.nMaxOutboundTimeframe; @@ -398,6 +399,7 @@ private: int nMaxFeeler; std::atomic<int> nBestHeight; CClientUIInterface* clientInterface; + NetEventsInterface* m_msgproc; /** SipHasher seeds for deterministic randomness */ const uint64_t nSeed0, nSeed1; @@ -438,19 +440,18 @@ struct CombinerAll } }; -// Signals for message handling -struct CNodeSignals +/** + * Interface for message handling + */ +class NetEventsInterface { - boost::signals2::signal<bool (CNode*, CConnman&, std::atomic<bool>&), CombinerAll> ProcessMessages; - boost::signals2::signal<bool (CNode*, CConnman&, std::atomic<bool>&), CombinerAll> SendMessages; - boost::signals2::signal<void (CNode*, CConnman&)> InitializeNode; - boost::signals2::signal<void (NodeId, bool&)> FinalizeNode; +public: + virtual bool ProcessMessages(CNode* pnode, std::atomic<bool>& interrupt) = 0; + virtual bool SendMessages(CNode* pnode, std::atomic<bool>& interrupt) = 0; + virtual void InitializeNode(CNode* pnode) = 0; + virtual void FinalizeNode(NodeId id, bool& update_connection_time) = 0; }; - -CNodeSignals& GetNodeSignals(); - - enum { LOCAL_NONE, // unknown diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 596ae1139b..b8900d9888 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -123,11 +123,6 @@ namespace { std::deque<std::pair<int64_t, MapRelay::iterator>> vRelayExpiration; } // namespace -////////////////////////////////////////////////////////////////////////////// -// -// Registration of network node signals. -// - namespace { struct CBlockReject { @@ -244,7 +239,7 @@ void UpdatePreferredDownload(CNode* node, CNodeState* state) nPreferredDownload += state->fPreferredDownload; } -void PushNodeVersion(CNode *pnode, CConnman& connman, int64_t nTime) +void PushNodeVersion(CNode *pnode, CConnman* connman, int64_t nTime) { ServiceFlags nLocalNodeServices = pnode->GetLocalServices(); uint64_t nonce = pnode->GetLocalNonce(); @@ -255,7 +250,7 @@ void PushNodeVersion(CNode *pnode, CConnman& connman, int64_t nTime) CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService(), addr.nServices)); CAddress addrMe = CAddress(CService(), nLocalNodeServices); - connman.PushMessage(pnode, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::VERSION, PROTOCOL_VERSION, (uint64_t)nLocalNodeServices, nTime, addrYou, addrMe, + connman->PushMessage(pnode, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::VERSION, PROTOCOL_VERSION, (uint64_t)nLocalNodeServices, nTime, addrYou, addrMe, nonce, strSubVersion, nNodeStartingHeight, ::fRelayTxes)); if (fLogIPs) { @@ -265,49 +260,6 @@ void PushNodeVersion(CNode *pnode, CConnman& connman, int64_t nTime) } } -void InitializeNode(CNode *pnode, CConnman& connman) { - CAddress addr = pnode->addr; - std::string addrName = pnode->GetAddrName(); - NodeId nodeid = pnode->GetId(); - { - LOCK(cs_main); - mapNodeState.emplace_hint(mapNodeState.end(), std::piecewise_construct, std::forward_as_tuple(nodeid), std::forward_as_tuple(addr, std::move(addrName))); - } - if(!pnode->fInbound) - PushNodeVersion(pnode, connman, GetTime()); -} - -void FinalizeNode(NodeId nodeid, bool& fUpdateConnectionTime) { - fUpdateConnectionTime = false; - LOCK(cs_main); - CNodeState *state = State(nodeid); - - if (state->fSyncStarted) - nSyncStarted--; - - if (state->nMisbehavior == 0 && state->fCurrentlyConnected) { - fUpdateConnectionTime = true; - } - - for (const QueuedBlock& entry : state->vBlocksInFlight) { - mapBlocksInFlight.erase(entry.hash); - } - EraseOrphansFor(nodeid); - nPreferredDownload -= state->fPreferredDownload; - nPeersWithValidatedDownloads -= (state->nBlocksInFlightValidHeaders != 0); - assert(nPeersWithValidatedDownloads >= 0); - - mapNodeState.erase(nodeid); - - if (mapNodeState.empty()) { - // Do a consistency check after the last peer is removed. - assert(mapBlocksInFlight.empty()); - assert(nPreferredDownload == 0); - assert(nPeersWithValidatedDownloads == 0); - } - LogPrint(BCLog::NET, "Cleared nodestate for peer=%d\n", nodeid); -} - // Requires cs_main. // Returns a bool indicating whether we requested this block. // Also used if a block was /not/ received and timed out or started with another peer @@ -315,6 +267,7 @@ bool MarkBlockAsReceived(const uint256& hash) { std::map<uint256, std::pair<NodeId, std::list<QueuedBlock>::iterator> >::iterator itInFlight = mapBlocksInFlight.find(hash); if (itInFlight != mapBlocksInFlight.end()) { CNodeState *state = State(itInFlight->second.first); + assert(state != nullptr); state->nBlocksInFlightValidHeaders -= itInFlight->second.second->fValidatedHeaders; if (state->nBlocksInFlightValidHeaders == 0 && itInFlight->second.second->fValidatedHeaders) { // Last validated block on the queue was received. @@ -402,7 +355,7 @@ void UpdateBlockAvailability(NodeId nodeid, const uint256 &hash) { } } -void MaybeSetPeerAsAnnouncingHeaderAndIDs(NodeId nodeid, CConnman& connman) { +void MaybeSetPeerAsAnnouncingHeaderAndIDs(NodeId nodeid, CConnman* connman) { AssertLockHeld(cs_main); CNodeState* nodestate = State(nodeid); if (!nodestate || !nodestate->fSupportsDesiredCmpctVersion) { @@ -417,20 +370,20 @@ void MaybeSetPeerAsAnnouncingHeaderAndIDs(NodeId nodeid, CConnman& connman) { return; } } - connman.ForNode(nodeid, [&connman](CNode* pfrom){ + connman->ForNode(nodeid, [connman](CNode* pfrom){ bool fAnnounceUsingCMPCTBLOCK = false; uint64_t nCMPCTBLOCKVersion = (pfrom->GetLocalServices() & NODE_WITNESS) ? 2 : 1; if (lNodesAnnouncingHeaderAndIDs.size() >= 3) { // As per BIP152, we only get 3 of our peers to announce // blocks using compact encodings. - connman.ForNode(lNodesAnnouncingHeaderAndIDs.front(), [&connman, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion](CNode* pnodeStop){ - connman.PushMessage(pnodeStop, CNetMsgMaker(pnodeStop->GetSendVersion()).Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion)); + connman->ForNode(lNodesAnnouncingHeaderAndIDs.front(), [connman, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion](CNode* pnodeStop){ + connman->PushMessage(pnodeStop, CNetMsgMaker(pnodeStop->GetSendVersion()).Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion)); return true; }); lNodesAnnouncingHeaderAndIDs.pop_front(); } fAnnounceUsingCMPCTBLOCK = true; - connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion)); + connman->PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion)); lNodesAnnouncingHeaderAndIDs.push_back(pfrom->GetId()); return true; }); @@ -466,7 +419,7 @@ void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<con // Make sure pindexBestKnownBlock is up to date, we'll need it. ProcessBlockAvailability(nodeid); - if (state->pindexBestKnownBlock == nullptr || state->pindexBestKnownBlock->nChainWork < chainActive.Tip()->nChainWork || state->pindexBestKnownBlock->nChainWork < UintToArith256(consensusParams.nMinimumChainWork)) { + if (state->pindexBestKnownBlock == nullptr || state->pindexBestKnownBlock->nChainWork < chainActive.Tip()->nChainWork || state->pindexBestKnownBlock->nChainWork < nMinimumChainWork) { // This peer has nothing interesting. return; } @@ -543,6 +496,50 @@ void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<con } // namespace +void PeerLogicValidation::InitializeNode(CNode *pnode) { + CAddress addr = pnode->addr; + std::string addrName = pnode->GetAddrName(); + NodeId nodeid = pnode->GetId(); + { + LOCK(cs_main); + mapNodeState.emplace_hint(mapNodeState.end(), std::piecewise_construct, std::forward_as_tuple(nodeid), std::forward_as_tuple(addr, std::move(addrName))); + } + if(!pnode->fInbound) + PushNodeVersion(pnode, connman, GetTime()); +} + +void PeerLogicValidation::FinalizeNode(NodeId nodeid, bool& fUpdateConnectionTime) { + fUpdateConnectionTime = false; + LOCK(cs_main); + CNodeState *state = State(nodeid); + assert(state != nullptr); + + if (state->fSyncStarted) + nSyncStarted--; + + if (state->nMisbehavior == 0 && state->fCurrentlyConnected) { + fUpdateConnectionTime = true; + } + + for (const QueuedBlock& entry : state->vBlocksInFlight) { + mapBlocksInFlight.erase(entry.hash); + } + EraseOrphansFor(nodeid); + nPreferredDownload -= state->fPreferredDownload; + nPeersWithValidatedDownloads -= (state->nBlocksInFlightValidHeaders != 0); + assert(nPeersWithValidatedDownloads >= 0); + + mapNodeState.erase(nodeid); + + if (mapNodeState.empty()) { + // Do a consistency check after the last peer is removed. + assert(mapBlocksInFlight.empty()); + assert(nPreferredDownload == 0); + assert(nPeersWithValidatedDownloads == 0); + } + LogPrint(BCLog::NET, "Cleared nodestate for peer=%d\n", nodeid); +} + bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) { LOCK(cs_main); CNodeState *state = State(nodeid); @@ -558,22 +555,6 @@ bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) { return true; } -void RegisterNodeSignals(CNodeSignals& nodeSignals) -{ - nodeSignals.ProcessMessages.connect(&ProcessMessages); - nodeSignals.SendMessages.connect(&SendMessages); - nodeSignals.InitializeNode.connect(&InitializeNode); - nodeSignals.FinalizeNode.connect(&FinalizeNode); -} - -void UnregisterNodeSignals(CNodeSignals& nodeSignals) -{ - nodeSignals.ProcessMessages.disconnect(&ProcessMessages); - nodeSignals.SendMessages.disconnect(&SendMessages); - nodeSignals.InitializeNode.disconnect(&InitializeNode); - nodeSignals.FinalizeNode.disconnect(&FinalizeNode); -} - ////////////////////////////////////////////////////////////////////////////// // // mapOrphanTransactions @@ -865,7 +846,7 @@ void PeerLogicValidation::BlockChecked(const CBlock& block, const CValidationSta !IsInitialBlockDownload() && mapBlocksInFlight.count(hash) == mapBlocksInFlight.size()) { if (it != mapBlockSource.end()) { - MaybeSetPeerAsAnnouncingHeaderAndIDs(it->second.first, *connman); + MaybeSetPeerAsAnnouncingHeaderAndIDs(it->second.first, connman); } } if (it != mapBlockSource.end()) @@ -910,16 +891,16 @@ bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main) return true; } -static void RelayTransaction(const CTransaction& tx, CConnman& connman) +static void RelayTransaction(const CTransaction& tx, CConnman* connman) { CInv inv(MSG_TX, tx.GetHash()); - connman.ForEachNode([&inv](CNode* pnode) + connman->ForEachNode([&inv](CNode* pnode) { pnode->PushInventory(inv); }); } -static void RelayAddress(const CAddress& addr, bool fReachable, CConnman& connman) +static void RelayAddress(const CAddress& addr, bool fReachable, CConnman* connman) { unsigned int nRelayNodes = fReachable ? 2 : 1; // limited relaying of addresses outside our network(s) @@ -927,7 +908,7 @@ static void RelayAddress(const CAddress& addr, bool fReachable, CConnman& connma // Use deterministic randomness to send to the same nodes for 24 hours // at a time so the addrKnowns of the chosen nodes prevent repeats uint64_t hashAddr = addr.GetHash(); - const CSipHasher hasher = connman.GetDeterministicRandomizer(RANDOMIZER_ID_ADDRESS_RELAY).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)); FastRandomContext insecure_rand; std::array<std::pair<uint64_t, CNode*>,2> best{{{0, nullptr}, {0, nullptr}}}; @@ -952,10 +933,10 @@ static void RelayAddress(const CAddress& addr, bool fReachable, CConnman& connma } }; - connman.ForEachNodeThen(std::move(sortfunc), std::move(pushfunc)); + connman->ForEachNodeThen(std::move(sortfunc), std::move(pushfunc)); } -void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParams, CConnman& connman, const std::atomic<bool>& interruptMsgProc) +void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParams, CConnman* connman, const std::atomic<bool>& interruptMsgProc) { std::deque<CInv>::iterator it = pfrom->vRecvGetData.begin(); std::vector<CInv> vNotFound; @@ -1017,7 +998,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam // disconnect node in case we have reached the outbound limit for serving historical blocks // never disconnect whitelisted nodes static const int nOneWeek = 7 * 24 * 60 * 60; // assume > 1 week = historical - if (send && connman.OutboundTargetReached(true) && ( ((pindexBestHeader != nullptr) && (pindexBestHeader->GetBlockTime() - mi->second->GetBlockTime() > nOneWeek)) || inv.type == MSG_FILTERED_BLOCK) && !pfrom->fWhitelisted) + if (send && connman->OutboundTargetReached(true) && ( ((pindexBestHeader != nullptr) && (pindexBestHeader->GetBlockTime() - mi->second->GetBlockTime() > nOneWeek)) || inv.type == MSG_FILTERED_BLOCK) && !pfrom->fWhitelisted) { LogPrint(BCLog::NET, "historical block serving limit reached, disconnect peer=%d\n", pfrom->GetId()); @@ -1040,9 +1021,9 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam pblock = pblockRead; } if (inv.type == MSG_BLOCK) - connman.PushMessage(pfrom, msgMaker.Make(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::BLOCK, *pblock)); + connman->PushMessage(pfrom, msgMaker.Make(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::BLOCK, *pblock)); else if (inv.type == MSG_WITNESS_BLOCK) - connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::BLOCK, *pblock)); + connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::BLOCK, *pblock)); else if (inv.type == MSG_FILTERED_BLOCK) { bool sendMerkleBlock = false; @@ -1055,7 +1036,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam } } if (sendMerkleBlock) { - connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::MERKLEBLOCK, merkleBlock)); + connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::MERKLEBLOCK, merkleBlock)); // CMerkleBlock just contains hashes, so also push any transactions in the block the client did not see // This avoids hurting performance by pointlessly requiring a round-trip // Note that there is currently no way for a node to request any single transactions we didn't send here - @@ -1064,7 +1045,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam // however we MUST always provide at least what the remote peer needs typedef std::pair<unsigned int, uint256> PairType; for (PairType& pair : merkleBlock.vMatchedTxn) - connman.PushMessage(pfrom, msgMaker.Make(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::TX, *pblock->vtx[pair.first])); + connman->PushMessage(pfrom, msgMaker.Make(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::TX, *pblock->vtx[pair.first])); } // else // no response @@ -1079,13 +1060,13 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam int nSendFlags = fPeerWantsWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS; if (CanDirectFetch(consensusParams) && mi->second->nHeight >= chainActive.Height() - MAX_CMPCTBLOCK_DEPTH) { if ((fPeerWantsWitness || !fWitnessesPresentInARecentCompactBlock) && a_recent_compact_block && a_recent_compact_block->header.GetHash() == mi->second->GetBlockHash()) { - connman.PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, *a_recent_compact_block)); + connman->PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, *a_recent_compact_block)); } else { CBlockHeaderAndShortTxIDs cmpctblock(*pblock, fPeerWantsWitness); - connman.PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, cmpctblock)); + connman->PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, cmpctblock)); } } else { - connman.PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::BLOCK, *pblock)); + connman->PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::BLOCK, *pblock)); } } @@ -1097,7 +1078,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam // wait for other stuff first. std::vector<CInv> vInv; vInv.push_back(CInv(MSG_BLOCK, chainActive.Tip()->GetBlockHash())); - connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::INV, vInv)); + connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::INV, vInv)); pfrom->hashContinue.SetNull(); } } @@ -1109,14 +1090,14 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam auto mi = mapRelay.find(inv.hash); int nSendFlags = (inv.type == MSG_TX ? SERIALIZE_TRANSACTION_NO_WITNESS : 0); if (mi != mapRelay.end()) { - connman.PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::TX, *mi->second)); + connman->PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::TX, *mi->second)); push = true; } else if (pfrom->timeLastMempoolReq) { auto txinfo = mempool.info(inv.hash); // To protect privacy, do not answer getdata using the mempool when // that TX couldn't have been INVed in reply to a MEMPOOL request. if (txinfo.tx && txinfo.nTime <= pfrom->timeLastMempoolReq) { - connman.PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::TX, *txinfo.tx)); + connman->PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::TX, *txinfo.tx)); push = true; } } @@ -1143,7 +1124,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam // do that because they want to know about (and store and rebroadcast and // risk analyze) the dependencies of transactions relevant to them, without // having to download the entire memory pool. - connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::NOTFOUND, vNotFound)); + connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::NOTFOUND, vNotFound)); } } @@ -1155,7 +1136,7 @@ uint32_t GetFetchFlags(CNode* pfrom) { return nFetchFlags; } -inline void static SendBlockTransactions(const CBlock& block, const BlockTransactionsRequest& req, CNode* pfrom, CConnman& connman) { +inline void static SendBlockTransactions(const CBlock& block, const BlockTransactionsRequest& req, CNode* pfrom, CConnman* connman) { BlockTransactions resp(req); for (size_t i = 0; i < req.indexes.size(); i++) { if (req.indexes[i] >= block.vtx.size()) { @@ -1169,10 +1150,10 @@ inline void static SendBlockTransactions(const CBlock& block, const BlockTransac LOCK(cs_main); const CNetMsgMaker msgMaker(pfrom->GetSendVersion()); int nSendFlags = State(pfrom->GetId())->fWantsCmpctWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS; - connman.PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::BLOCKTXN, resp)); + connman->PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::BLOCKTXN, resp)); } -bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams, CConnman& connman, const std::atomic<bool>& interruptMsgProc) +bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams, CConnman* connman, const std::atomic<bool>& interruptMsgProc) { LogPrint(BCLog::NET, "received: %s (%u bytes) peer=%d\n", SanitizeString(strCommand), vRecv.size(), pfrom->GetId()); if (gArgs.IsArgSet("-dropmessagestest") && GetRand(gArgs.GetArg("-dropmessagestest", 0)) == 0) @@ -1225,7 +1206,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr // Each connection can only send one version message if (pfrom->nVersion != 0) { - connman.PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_DUPLICATE, std::string("Duplicate version message"))); + connman->PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_DUPLICATE, std::string("Duplicate version message"))); LOCK(cs_main); Misbehaving(pfrom->GetId(), 1); return false; @@ -1249,12 +1230,12 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr nServices = ServiceFlags(nServiceInt); if (!pfrom->fInbound) { - connman.SetServices(pfrom->addr, nServices); + connman->SetServices(pfrom->addr, nServices); } if (pfrom->nServicesExpected & ~nServices) { LogPrint(BCLog::NET, "peer=%d does not offer the expected services (%08x offered, %08x expected); disconnecting\n", pfrom->GetId(), nServices, pfrom->nServicesExpected); - connman.PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_NONSTANDARD, + connman->PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_NONSTANDARD, strprintf("Expected to offer services %08x", pfrom->nServicesExpected))); pfrom->fDisconnect = true; return false; @@ -1275,7 +1256,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr { // disconnect from peers older than this proto version LogPrintf("peer=%d using obsolete version %i; disconnecting\n", pfrom->GetId(), nVersion); - connman.PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_OBSOLETE, + connman->PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_OBSOLETE, strprintf("Version must be %d or greater", MIN_PEER_PROTO_VERSION))); pfrom->fDisconnect = true; return false; @@ -1295,7 +1276,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr if (!vRecv.empty()) vRecv >> fRelay; // Disconnect if we connected to ourself - if (pfrom->fInbound && !connman.CheckIncomingNonce(nNonce)) + if (pfrom->fInbound && !connman->CheckIncomingNonce(nNonce)) { LogPrintf("connected to self at %s, disconnecting\n", pfrom->addr.ToString()); pfrom->fDisconnect = true; @@ -1311,7 +1292,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr if (pfrom->fInbound) PushNodeVersion(pfrom, connman, GetAdjustedTime()); - connman.PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::VERACK)); + connman->PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::VERACK)); pfrom->nServices = nServices; pfrom->SetAddrLocal(addrMe); @@ -1362,12 +1343,12 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr } // Get recent addresses - if (pfrom->fOneShot || pfrom->nVersion >= CADDR_TIME_VERSION || connman.GetAddressCount() < 1000) + if (pfrom->fOneShot || pfrom->nVersion >= CADDR_TIME_VERSION || connman->GetAddressCount() < 1000) { - connman.PushMessage(pfrom, CNetMsgMaker(nSendVersion).Make(NetMsgType::GETADDR)); + connman->PushMessage(pfrom, CNetMsgMaker(nSendVersion).Make(NetMsgType::GETADDR)); pfrom->fGetAddr = true; } - connman.MarkAddressGood(pfrom->addr); + connman->MarkAddressGood(pfrom->addr); } std::string remoteAddr; @@ -1386,7 +1367,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr // If the peer is old enough to have the old alert system, send it the final alert. if (pfrom->nVersion <= 70012) { CDataStream finalAlert(ParseHex("60010000000000000000000000ffffff7f00000000ffffff7ffeffff7f01ffffff7f00000000ffffff7f00ffffff7f002f555247454e543a20416c657274206b657920636f6d70726f6d697365642c2075706772616465207265717569726564004630440220653febd6410f470f6bae11cad19c48413becb1ac2c17f908fd0fd53bdc3abd5202206d0e9c96fe88d4a0f01ed9dedae2b6f9e00da94cad0fecaae66ecf689bf71b50"), SER_NETWORK, PROTOCOL_VERSION); - connman.PushMessage(pfrom, CNetMsgMaker(nSendVersion).Make("alert", finalAlert)); + connman->PushMessage(pfrom, CNetMsgMaker(nSendVersion).Make("alert", finalAlert)); } // Feeler connections exist only to verify if address is online. @@ -1424,7 +1405,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr // We send this to non-NODE NETWORK peers as well, because even // non-NODE NETWORK peers can announce blocks (such as pruning // nodes) - connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::SENDHEADERS)); + connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::SENDHEADERS)); } if (pfrom->nVersion >= SHORT_IDS_BLOCKS_VERSION) { // Tell our peer we are willing to provide version 1 or 2 cmpctblocks @@ -1435,9 +1416,9 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr bool fAnnounceUsingCMPCTBLOCK = false; uint64_t nCMPCTBLOCKVersion = 2; if (pfrom->GetLocalServices() & NODE_WITNESS) - connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion)); + connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion)); nCMPCTBLOCKVersion = 1; - connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion)); + connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion)); } pfrom->fSuccessfullyConnected = true; } @@ -1456,7 +1437,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr vRecv >> vAddr; // Don't want addr from older versions unless seeding - if (pfrom->nVersion < CADDR_TIME_VERSION && connman.GetAddressCount() > 1000) + if (pfrom->nVersion < CADDR_TIME_VERSION && connman->GetAddressCount() > 1000) return true; if (vAddr.size() > 1000) { @@ -1490,7 +1471,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr if (fReachable) vAddrOk.push_back(addr); } - connman.AddNewAddresses(vAddrOk, pfrom->addr, 2 * 60 * 60); + connman->AddNewAddresses(vAddrOk, pfrom->addr, 2 * 60 * 60); if (vAddr.size() < 1000) pfrom->fGetAddr = false; if (pfrom->fOneShot) @@ -1568,7 +1549,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr // fell back to inv we probably have a reorg which we should get the headers for first, // we now only provide a getheaders response here. When we receive the headers, we will // then ask for the blocks we need. - connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), inv.hash)); + connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), inv.hash)); LogPrint(BCLog::NET, "getheaders (%d) %s to peer=%d\n", pindexBestHeader->nHeight, inv.hash.ToString(), pfrom->GetId()); } } @@ -1774,7 +1755,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr // will re-announce the new block via headers (or compact blocks again) // in the SendMessages logic. nodestate->pindexBestHeaderSent = pindex ? pindex : chainActive.Tip(); - connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::HEADERS, vHeaders)); + connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::HEADERS, vHeaders)); } @@ -1955,7 +1936,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr pfrom->GetId(), FormatStateMessage(state)); if (state.GetRejectCode() > 0 && state.GetRejectCode() < REJECT_INTERNAL) // Never send AcceptToMemoryPool's internal codes over P2P - connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(), + connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(), state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash)); if (nDoS > 0) { Misbehaving(pfrom->GetId(), nDoS); @@ -1975,7 +1956,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr if (mapBlockIndex.find(cmpctblock.header.hashPrevBlock) == mapBlockIndex.end()) { // Doesn't connect (or is genesis), instead of DoSing in AcceptBlockHeader, request deeper headers if (!IsInitialBlockDownload()) - connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256())); + connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256())); return true; } } @@ -2030,7 +2011,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr // so we just grab the block via normal getdata std::vector<CInv> vInv(1); vInv[0] = CInv(MSG_BLOCK | GetFetchFlags(pfrom), cmpctblock.header.GetHash()); - connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv)); + connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv)); } return true; } @@ -2074,7 +2055,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr // Duplicate txindexes, the block is now in-flight, so just request it std::vector<CInv> vInv(1); vInv[0] = CInv(MSG_BLOCK | GetFetchFlags(pfrom), cmpctblock.header.GetHash()); - connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv)); + connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv)); return true; } @@ -2091,7 +2072,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr fProcessBLOCKTXN = true; } else { req.blockhash = pindex->GetBlockHash(); - connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETBLOCKTXN, req)); + connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETBLOCKTXN, req)); } } else { // This block is either already in flight from a different @@ -2117,7 +2098,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr // mempool will probably be useless - request the block normally std::vector<CInv> vInv(1); vInv[0] = CInv(MSG_BLOCK | GetFetchFlags(pfrom), cmpctblock.header.GetHash()); - connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv)); + connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv)); return true; } else { // If this was an announce-cmpctblock, we want the same treatment as a header message @@ -2191,7 +2172,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr // Might have collided, fall back to getdata now :( std::vector<CInv> invs; invs.push_back(CInv(MSG_BLOCK | GetFetchFlags(pfrom), resp.blockhash)); - connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, invs)); + connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, invs)); } else { // Block is either okay, or possibly we received // READ_STATUS_CHECKBLOCK_FAILED. @@ -2272,7 +2253,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr // nUnconnectingHeaders gets reset back to 0. if (mapBlockIndex.find(headers[0].hashPrevBlock) == mapBlockIndex.end() && nCount < MAX_BLOCKS_TO_ANNOUNCE) { nodestate->nUnconnectingHeaders++; - connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256())); + connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256())); LogPrint(BCLog::NET, "received header %s: missing prev block %s, sending getheaders (%d) to end (peer=%d, nUnconnectingHeaders=%d)\n", headers[0].GetHash().ToString(), headers[0].hashPrevBlock.ToString(), @@ -2327,7 +2308,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr // TODO: optimize: if pindexLast is an ancestor of chainActive.Tip or pindexBestHeader, continue // from there instead. LogPrint(BCLog::NET, "more getheaders (%d) to end to peer=%d (startheight:%d)\n", pindexLast->nHeight, pfrom->GetId(), pfrom->nStartingHeight); - connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexLast), uint256())); + connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexLast), uint256())); } bool fCanDirectFetch = CanDirectFetch(chainparams.GetConsensus()); @@ -2377,7 +2358,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr // In any case, we want to download using a compact block, not a regular one vGetData[0] = CInv(MSG_CMPCT_BLOCK, vGetData[0].hash); } - connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vGetData)); + connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vGetData)); } } } @@ -2438,7 +2419,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr pfrom->fSentAddr = true; pfrom->vAddrToSend.clear(); - std::vector<CAddress> vAddr = connman.GetAddresses(); + std::vector<CAddress> vAddr = connman->GetAddresses(); FastRandomContext insecure_rand; for (const CAddress &addr : vAddr) pfrom->PushAddress(addr, insecure_rand); @@ -2454,7 +2435,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr return true; } - if (connman.OutboundTargetReached(false) && !pfrom->fWhitelisted) + if (connman->OutboundTargetReached(false) && !pfrom->fWhitelisted) { LogPrint(BCLog::NET, "mempool request with bandwidth limit reached, disconnect peer=%d\n", pfrom->GetId()); pfrom->fDisconnect = true; @@ -2483,7 +2464,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr // it, if the remote node sends a ping once per second and this node takes 5 // seconds to respond to each, the 5th ping the remote sends would appear to // return very quickly. - connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::PONG, nonce)); + connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::PONG, nonce)); } } @@ -2629,13 +2610,13 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr return true; } -static bool SendRejectsAndCheckIfBanned(CNode* pnode, CConnman& connman) +static bool SendRejectsAndCheckIfBanned(CNode* pnode, CConnman* connman) { AssertLockHeld(cs_main); CNodeState &state = *State(pnode->GetId()); for (const CBlockReject& reject : state.rejects) { - connman.PushMessage(pnode, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, (std::string)NetMsgType::BLOCK, reject.chRejectCode, reject.strRejectReason, reject.hashBlock)); + connman->PushMessage(pnode, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, (std::string)NetMsgType::BLOCK, reject.chRejectCode, reject.strRejectReason, reject.hashBlock)); } state.rejects.clear(); @@ -2651,7 +2632,7 @@ static bool SendRejectsAndCheckIfBanned(CNode* pnode, CConnman& connman) LogPrintf("Warning: not banning local peer %s!\n", pnode->addr.ToString()); else { - connman.Ban(pnode->addr, BanReasonNodeMisbehaving); + connman->Ban(pnode->addr, BanReasonNodeMisbehaving); } } return true; @@ -2659,7 +2640,7 @@ static bool SendRejectsAndCheckIfBanned(CNode* pnode, CConnman& connman) return false; } -bool ProcessMessages(CNode* pfrom, CConnman& connman, const std::atomic<bool>& interruptMsgProc) +bool PeerLogicValidation::ProcessMessages(CNode* pfrom, std::atomic<bool>& interruptMsgProc) { const CChainParams& chainparams = Params(); // @@ -2693,7 +2674,7 @@ bool ProcessMessages(CNode* pfrom, CConnman& connman, const std::atomic<bool>& i // Just take one message msgs.splice(msgs.begin(), pfrom->vProcessMsg, pfrom->vProcessMsg.begin()); pfrom->nProcessQueueSize -= msgs.front().vRecv.size() + CMessageHeader::HEADER_SIZE; - pfrom->fPauseRecv = pfrom->nProcessQueueSize > connman.GetReceiveFloodSize(); + pfrom->fPauseRecv = pfrom->nProcessQueueSize > connman->GetReceiveFloodSize(); fMoreWork = !pfrom->vProcessMsg.empty(); } CNetMessage& msg(msgs.front()); @@ -2742,7 +2723,7 @@ bool ProcessMessages(CNode* pfrom, CConnman& connman, const std::atomic<bool>& i } catch (const std::ios_base::failure& e) { - connman.PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_MALFORMED, std::string("error parsing message"))); + connman->PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_MALFORMED, std::string("error parsing message"))); if (strstr(e.what(), "end of data")) { // Allow exceptions from under-length message on vRecv @@ -2796,7 +2777,7 @@ public: } }; -bool SendMessages(CNode* pto, CConnman& connman, const std::atomic<bool>& interruptMsgProc) +bool PeerLogicValidation::SendMessages(CNode* pto, std::atomic<bool>& interruptMsgProc) { const Consensus::Params& consensusParams = Params().GetConsensus(); { @@ -2828,11 +2809,11 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic<bool>& interr pto->nPingUsecStart = GetTimeMicros(); if (pto->nVersion > BIP0031_VERSION) { pto->nPingNonceSent = nonce; - connman.PushMessage(pto, msgMaker.Make(NetMsgType::PING, nonce)); + connman->PushMessage(pto, msgMaker.Make(NetMsgType::PING, nonce)); } else { // Peer is too old to support ping command with nonce, pong will never arrive. pto->nPingNonceSent = 0; - connman.PushMessage(pto, msgMaker.Make(NetMsgType::PING)); + connman->PushMessage(pto, msgMaker.Make(NetMsgType::PING)); } } @@ -2867,14 +2848,14 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic<bool>& interr // receiver rejects addr messages larger than 1000 if (vAddr.size() >= 1000) { - connman.PushMessage(pto, msgMaker.Make(NetMsgType::ADDR, vAddr)); + connman->PushMessage(pto, msgMaker.Make(NetMsgType::ADDR, vAddr)); vAddr.clear(); } } } pto->vAddrToSend.clear(); if (!vAddr.empty()) - connman.PushMessage(pto, msgMaker.Make(NetMsgType::ADDR, vAddr)); + connman->PushMessage(pto, msgMaker.Make(NetMsgType::ADDR, vAddr)); // we only send the big addr message once if (pto->vAddrToSend.capacity() > 40) pto->vAddrToSend.shrink_to_fit(); @@ -2901,7 +2882,7 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic<bool>& interr if (pindexStart->pprev) pindexStart = pindexStart->pprev; LogPrint(BCLog::NET, "initial getheaders (%d) to peer=%d (startheight:%d)\n", pindexStart->nHeight, pto->GetId(), pto->nStartingHeight); - connman.PushMessage(pto, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexStart), uint256())); + connman->PushMessage(pto, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexStart), uint256())); } } @@ -2910,7 +2891,7 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic<bool>& interr // transactions become unconfirmed and spams other nodes. if (!fReindex && !fImporting && !IsInitialBlockDownload()) { - GetMainSignals().Broadcast(nTimeBestReceived, &connman); + GetMainSignals().Broadcast(nTimeBestReceived, connman); } // @@ -2994,10 +2975,10 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic<bool>& interr LOCK(cs_most_recent_block); if (most_recent_block_hash == pBestIndex->GetBlockHash()) { if (state.fWantsCmpctWitness || !fWitnessesPresentInMostRecentCompactBlock) - connman.PushMessage(pto, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, *most_recent_compact_block)); + connman->PushMessage(pto, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, *most_recent_compact_block)); else { CBlockHeaderAndShortTxIDs cmpctblock(*most_recent_block, state.fWantsCmpctWitness); - connman.PushMessage(pto, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, cmpctblock)); + connman->PushMessage(pto, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, cmpctblock)); } fGotBlockFromCache = true; } @@ -3007,7 +2988,7 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic<bool>& interr bool ret = ReadBlockFromDisk(block, pBestIndex, consensusParams); assert(ret); CBlockHeaderAndShortTxIDs cmpctblock(block, state.fWantsCmpctWitness); - connman.PushMessage(pto, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, cmpctblock)); + connman->PushMessage(pto, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, cmpctblock)); } state.pindexBestHeaderSent = pBestIndex; } else if (state.fPreferHeaders) { @@ -3020,7 +3001,7 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic<bool>& interr LogPrint(BCLog::NET, "%s: sending header %s to peer=%d\n", __func__, vHeaders.front().GetHash().ToString(), pto->GetId()); } - connman.PushMessage(pto, msgMaker.Make(NetMsgType::HEADERS, vHeaders)); + connman->PushMessage(pto, msgMaker.Make(NetMsgType::HEADERS, vHeaders)); state.pindexBestHeaderSent = pBestIndex; } else fRevertToInv = true; @@ -3066,7 +3047,7 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic<bool>& interr for (const uint256& hash : pto->vInventoryBlockToSend) { vInv.push_back(CInv(MSG_BLOCK, hash)); if (vInv.size() == MAX_INV_SZ) { - connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv)); + connman->PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv)); vInv.clear(); } } @@ -3112,7 +3093,7 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic<bool>& interr pto->filterInventoryKnown.insert(hash); vInv.push_back(inv); if (vInv.size() == MAX_INV_SZ) { - connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv)); + connman->PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv)); vInv.clear(); } } @@ -3178,7 +3159,7 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic<bool>& interr } } if (vInv.size() == MAX_INV_SZ) { - connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv)); + connman->PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv)); vInv.clear(); } pto->filterInventoryKnown.insert(hash); @@ -3186,7 +3167,7 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic<bool>& interr } } if (!vInv.empty()) - connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv)); + connman->PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv)); // Detect whether we're stalling nNow = GetTimeMicros(); @@ -3281,7 +3262,7 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic<bool>& interr vGetData.push_back(inv); if (vGetData.size() >= 1000) { - connman.PushMessage(pto, msgMaker.Make(NetMsgType::GETDATA, vGetData)); + connman->PushMessage(pto, msgMaker.Make(NetMsgType::GETDATA, vGetData)); vGetData.clear(); } } else { @@ -3291,7 +3272,7 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic<bool>& interr pto->mapAskFor.erase(pto->mapAskFor.begin()); } if (!vGetData.empty()) - connman.PushMessage(pto, msgMaker.Make(NetMsgType::GETDATA, vGetData)); + connman->PushMessage(pto, msgMaker.Make(NetMsgType::GETDATA, vGetData)); // // Message: feefilter @@ -3308,7 +3289,7 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic<bool>& interr // We always have a fee filter of at least minRelayTxFee filterToSend = std::max(filterToSend, ::minRelayTxFee.GetFeePerK()); if (filterToSend != pto->lastSentFeeFilter) { - connman.PushMessage(pto, msgMaker.Make(NetMsgType::FEEFILTER, filterToSend)); + connman->PushMessage(pto, msgMaker.Make(NetMsgType::FEEFILTER, filterToSend)); pto->lastSentFeeFilter = filterToSend; } pto->nextSendTimeFeeFilter = PoissonNextSend(timeNow, AVG_FEEFILTER_BROADCAST_INTERVAL); diff --git a/src/net_processing.h b/src/net_processing.h index f4a43980a5..79745cdd42 100644 --- a/src/net_processing.h +++ b/src/net_processing.h @@ -22,22 +22,31 @@ static const unsigned int DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN = 100; static constexpr int64_t HEADERS_DOWNLOAD_TIMEOUT_BASE = 15 * 60 * 1000000; // 15 minutes static constexpr int64_t HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER = 1000; // 1ms/header -/** Register with a network node to receive its signals */ -void RegisterNodeSignals(CNodeSignals& nodeSignals); -/** Unregister a network node */ -void UnregisterNodeSignals(CNodeSignals& nodeSignals); - -class PeerLogicValidation : public CValidationInterface { +class PeerLogicValidation : public CValidationInterface, public NetEventsInterface { private: CConnman* connman; public: - explicit PeerLogicValidation(CConnman* connmanIn); + explicit PeerLogicValidation(CConnman* connman); void BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexConnected, const std::vector<CTransactionRef>& vtxConflicted) override; void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) override; void BlockChecked(const CBlock& block, const CValidationState& state) override; void NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock>& pblock) override; + + + void InitializeNode(CNode* pnode) override; + void FinalizeNode(NodeId nodeid, bool& fUpdateConnectionTime) override; + /** Process protocol messages received from a given node */ + bool ProcessMessages(CNode* pfrom, std::atomic<bool>& interrupt) override; + /** + * Send queued protocol messages to be sent to a give node. + * + * @param[in] pto The node which we are sending messages to. + * @param[in] interrupt Interrupt condition for processing threads + * @return True if there is more work to be done + */ + bool SendMessages(CNode* pto, std::atomic<bool>& interrupt) override; }; struct CNodeStateStats { @@ -52,16 +61,4 @@ bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats); /** Increase a node's misbehavior score. */ void Misbehaving(NodeId nodeid, int howmuch); -/** Process protocol messages received from a given node */ -bool ProcessMessages(CNode* pfrom, CConnman& connman, const std::atomic<bool>& interrupt); -/** - * Send queued protocol messages to be sent to a give node. - * - * @param[in] pto The node which we are sending messages to. - * @param[in] connman The connection manager for that node. - * @param[in] interrupt Interrupt condition for processing threads - * @return True if there is more work to be done - */ -bool SendMessages(CNode* pto, CConnman& connman, const std::atomic<bool>& interrupt); - #endif // BITCOIN_NET_PROCESSING_H diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp index 605e3e0696..56912d0375 100644 --- a/src/policy/policy.cpp +++ b/src/policy/policy.cpp @@ -54,23 +54,6 @@ bool IsDust(const CTxOut& txout, const CFeeRate& dustRelayFeeIn) return (txout.nValue < GetDustThreshold(txout, dustRelayFeeIn)); } - /** - * Check transaction inputs to mitigate two - * potential denial-of-service attacks: - * - * 1. scriptSigs with extra data stuffed into them, - * not consumed by scriptPubKey (or P2SH script) - * 2. P2SH scripts with a crazy number of expensive - * CHECKSIG/CHECKMULTISIG operations - * - * Why bother? To avoid denial-of-service attacks; an attacker - * can submit a standard HASH... OP_EQUAL transaction, - * which will get accepted into blocks. The redemption - * script can be anything; an attacker could use a very - * expensive-to-check-upon-redemption script like: - * DUP CHECKSIG DROP ... repeated 100 times... OP_1 - */ - bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType, const bool witnessEnabled) { std::vector<std::vector<unsigned char> > vSolutions; @@ -160,6 +143,22 @@ bool IsStandardTx(const CTransaction& tx, std::string& reason, const bool witnes return true; } +/** + * Check transaction inputs to mitigate two + * potential denial-of-service attacks: + * + * 1. scriptSigs with extra data stuffed into them, + * not consumed by scriptPubKey (or P2SH script) + * 2. P2SH scripts with a crazy number of expensive + * CHECKSIG/CHECKMULTISIG operations + * + * Why bother? To avoid denial-of-service attacks; an attacker + * can submit a standard HASH... OP_EQUAL transaction, + * which will get accepted into blocks. The redemption + * script can be anything; an attacker could use a very + * expensive-to-check-upon-redemption script like: + * DUP CHECKSIG DROP ... repeated 100 times... OP_1 + */ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) { if (tx.IsCoinBase()) diff --git a/src/policy/policy.h b/src/policy/policy.h index c06820f84e..ef71dd73bc 100644 --- a/src/policy/policy.h +++ b/src/policy/policy.h @@ -16,10 +16,8 @@ class CCoinsViewCache; class CTxOut; -/** Default for -blockmaxsize, which controls the maximum size of block the mining code will create **/ -static const unsigned int DEFAULT_BLOCK_MAX_SIZE = 750000; /** Default for -blockmaxweight, which controls the range of block weights the mining code will create **/ -static const unsigned int DEFAULT_BLOCK_MAX_WEIGHT = 3000000; +static const unsigned int DEFAULT_BLOCK_MAX_WEIGHT = MAX_BLOCK_WEIGHT - 4000; /** Default for -blockmintxfee, which sets the minimum feerate for a transaction in blocks created by mining code **/ static const unsigned int DEFAULT_BLOCK_MIN_TX_FEE = 1000; /** The maximum weight for transactions we're willing to relay/mine */ diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp index 9b6a814e1f..e0a106adb9 100644 --- a/src/primitives/transaction.cpp +++ b/src/primitives/transaction.cpp @@ -55,7 +55,7 @@ std::string CTxOut::ToString() const } CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::CURRENT_VERSION), nLockTime(0) {} -CMutableTransaction::CMutableTransaction(const CTransaction& tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime) {} +CMutableTransaction::CMutableTransaction(const CTransaction& tx) : vin(tx.vin), vout(tx.vout), nVersion(tx.nVersion), nLockTime(tx.nLockTime) {} uint256 CMutableTransaction::GetHash() const { @@ -76,9 +76,9 @@ uint256 CTransaction::GetWitnessHash() const } /* For backward compatibility, the hash is initialized to 0. TODO: remove the need for this default constructor entirely. */ -CTransaction::CTransaction() : nVersion(CTransaction::CURRENT_VERSION), vin(), vout(), nLockTime(0), hash() {} -CTransaction::CTransaction(const CMutableTransaction &tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime), hash(ComputeHash()) {} -CTransaction::CTransaction(CMutableTransaction &&tx) : nVersion(tx.nVersion), vin(std::move(tx.vin)), vout(std::move(tx.vout)), nLockTime(tx.nLockTime), hash(ComputeHash()) {} +CTransaction::CTransaction() : vin(), vout(), nVersion(CTransaction::CURRENT_VERSION), nLockTime(0), hash() {} +CTransaction::CTransaction(const CMutableTransaction &tx) : vin(tx.vin), vout(tx.vout), nVersion(tx.nVersion), nLockTime(tx.nLockTime), hash(ComputeHash()) {} +CTransaction::CTransaction(CMutableTransaction &&tx) : vin(std::move(tx.vin)), vout(std::move(tx.vout)), nVersion(tx.nVersion), nLockTime(tx.nLockTime), hash(ComputeHash()) {} CAmount CTransaction::GetValueOut() const { diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index 041034bb8b..18d524e23d 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -278,9 +278,9 @@ public: // actually immutable; deserialization and assignment are implemented, // and bypass the constness. This is safe, as they update the entire // structure, including the hash. - const int32_t nVersion; const std::vector<CTxIn> vin; const std::vector<CTxOut> vout; + const int32_t nVersion; const uint32_t nLockTime; private: @@ -361,9 +361,9 @@ public: /** A mutable version of CTransaction. */ struct CMutableTransaction { - int32_t nVersion; std::vector<CTxIn> vin; std::vector<CTxOut> vout; + int32_t nVersion; uint32_t nLockTime; CMutableTransaction(); diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp index 2fa032abdc..0eb7ec4306 100644 --- a/src/qt/addresstablemodel.cpp +++ b/src/qt/addresstablemodel.cpp @@ -82,14 +82,14 @@ public: LOCK(wallet->cs_wallet); for (const std::pair<CTxDestination, CAddressBookData>& item : wallet->mapAddressBook) { - const CBitcoinAddress& address = item.first; - bool fMine = IsMine(*wallet, address.Get()); + const CTxDestination& address = item.first; + bool fMine = IsMine(*wallet, address); AddressTableEntry::Type addressType = translateTransactionType( QString::fromStdString(item.second.purpose), fMine); const std::string& strName = item.second.name; cachedAddressTable.append(AddressTableEntry(addressType, QString::fromStdString(strName), - QString::fromStdString(address.ToString()))); + QString::fromStdString(EncodeDestination(address)))); } } // qLowerBound() and qUpperBound() require our cachedAddressTable list to be sorted in asc order @@ -246,7 +246,7 @@ bool AddressTableModel::setData(const QModelIndex &index, const QVariant &value, if(role == Qt::EditRole) { LOCK(wallet->cs_wallet); /* For SetAddressBook / DelAddressBook */ - CTxDestination curAddress = CBitcoinAddress(rec->address.toStdString()).Get(); + CTxDestination curAddress = DecodeDestination(rec->address.toStdString()); if(index.column() == Label) { // Do nothing, if old label == new label @@ -257,7 +257,7 @@ bool AddressTableModel::setData(const QModelIndex &index, const QVariant &value, } wallet->SetAddressBook(curAddress, value.toString().toStdString(), strPurpose); } else if(index.column() == Address) { - CTxDestination newAddress = CBitcoinAddress(value.toString().toStdString()).Get(); + CTxDestination newAddress = DecodeDestination(value.toString().toStdString()); // Refuse to set invalid address, set error status and return false if(boost::get<CNoDestination>(&newAddress)) { @@ -358,7 +358,7 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con // Check for duplicate addresses { LOCK(wallet->cs_wallet); - if(wallet->mapAddressBook.count(CBitcoinAddress(strAddress).Get())) + if(wallet->mapAddressBook.count(DecodeDestination(strAddress))) { editStatus = DUPLICATE_ADDRESS; return QString(); @@ -384,7 +384,7 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con return QString(); } } - strAddress = CBitcoinAddress(newKey.GetID()).ToString(); + strAddress = EncodeDestination(newKey.GetID()); } else { @@ -394,7 +394,7 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con // Add entry { LOCK(wallet->cs_wallet); - wallet->SetAddressBook(CBitcoinAddress(strAddress).Get(), strLabel, + wallet->SetAddressBook(DecodeDestination(strAddress), strLabel, (type == Send ? "send" : "receive")); } return QString::fromStdString(strAddress); @@ -412,7 +412,7 @@ bool AddressTableModel::removeRows(int row, int count, const QModelIndex &parent } { LOCK(wallet->cs_wallet); - wallet->DelAddressBook(CBitcoinAddress(rec->address.toStdString()).Get()); + wallet->DelAddressBook(DecodeDestination(rec->address.toStdString())); } return true; } @@ -423,8 +423,8 @@ QString AddressTableModel::labelForAddress(const QString &address) const { { LOCK(wallet->cs_wallet); - CBitcoinAddress address_parsed(address.toStdString()); - std::map<CTxDestination, CAddressBookData>::iterator mi = wallet->mapAddressBook.find(address_parsed.Get()); + CTxDestination destination = DecodeDestination(address.toStdString()); + std::map<CTxDestination, CAddressBookData>::iterator mi = wallet->mapAddressBook.find(destination); if (mi != wallet->mapAddressBook.end()) { return QString::fromStdString(mi->second.name); diff --git a/src/qt/bitcoinaddressvalidator.cpp b/src/qt/bitcoinaddressvalidator.cpp index d712705c43..4dd1092806 100644 --- a/src/qt/bitcoinaddressvalidator.cpp +++ b/src/qt/bitcoinaddressvalidator.cpp @@ -89,9 +89,9 @@ QValidator::State BitcoinAddressCheckValidator::validate(QString &input, int &po { Q_UNUSED(pos); // Validate the passed Bitcoin address - CBitcoinAddress addr(input.toStdString()); - if (addr.IsValid()) + if (IsValidDestinationString(input.toStdString())) { return QValidator::Acceptable; + } return QValidator::Invalid; } diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index 562c361799..3ca43eae22 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -660,7 +660,7 @@ void CoinControlDialog::updateView() QString sAddress = ""; if(ExtractDestination(out.tx->tx->vout[out.i].scriptPubKey, outputAddress)) { - sAddress = QString::fromStdString(CBitcoinAddress(outputAddress).ToString()); + sAddress = QString::fromStdString(EncodeDestination(outputAddress)); // if listMode or change => show bitcoin address. In tree mode, address is not shown again for direct wallet address outputs if (!treeMode || (!(sAddress == sWalletAddress))) diff --git a/src/qt/forms/optionsdialog.ui b/src/qt/forms/optionsdialog.ui index 14078b9ee8..e31bfee05e 100644 --- a/src/qt/forms/optionsdialog.ui +++ b/src/qt/forms/optionsdialog.ui @@ -199,10 +199,10 @@ <item> <widget class="QCheckBox" name="allowIncoming"> <property name="toolTip"> - <string>Accept connections from outside</string> + <string>Accept connections from outside.</string> </property> <property name="text"> - <string>Allow incoming connections</string> + <string>Allow incomin&g connections</string> </property> </widget> </item> @@ -399,7 +399,7 @@ <string>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</string> </property> <property name="text"> - <string>Use separate SOCKS5 proxy to reach peers via Tor hidden services:</string> + <string>Use separate SOCKS&5 proxy to reach peers via Tor hidden services:</string> </property> </widget> </item> @@ -507,10 +507,10 @@ <item> <widget class="QCheckBox" name="hideTrayIcon"> <property name="toolTip"> - <string>&Hide the icon from the system tray.</string> + <string>Hide the icon from the system tray.</string> </property> <property name="text"> - <string>Hide tray icon</string> + <string>&Hide tray icon</string> </property> </widget> </item> @@ -610,7 +610,7 @@ <string>Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items. %s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |.</string> </property> <property name="text"> - <string>Third party transaction URLs</string> + <string>&Third party transaction URLs</string> </property> <property name="buddy"> <cstring>thirdPartyTxUrls</cstring> diff --git a/src/qt/forms/sendcoinsdialog.ui b/src/qt/forms/sendcoinsdialog.ui index 1e2f2302b9..a0e48334c1 100644 --- a/src/qt/forms/sendcoinsdialog.ui +++ b/src/qt/forms/sendcoinsdialog.ui @@ -846,19 +846,13 @@ <item> <layout class="QHBoxLayout" name="horizontalLayoutFee13"> <item> - <widget class="QRadioButton" name="radioCustomPerKilobyte"> + <widget class="QLabel" name="labelCustomPerKilobyte"> <property name="toolTip"> <string>If the custom fee is set to 1000 satoshis and the transaction is only 250 bytes, then "per kilobyte" only pays 250 satoshis in fee, while "total at least" pays 1000 satoshis. For transactions bigger than a kilobyte both pay by kilobyte.</string> </property> <property name="text"> <string>per kilobyte</string> </property> - <property name="checked"> - <bool>true</bool> - </property> - <attribute name="buttonGroup"> - <string notr="true">groupCustomFee</string> - </attribute> </widget> </item> <item> @@ -1285,6 +1279,5 @@ <connections/> <buttongroups> <buttongroup name="groupFee"/> - <buttongroup name="groupCustomFee"/> </buttongroups> </ui> diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index f3c5daebec..c3f98f764b 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -112,8 +112,9 @@ static std::string DummyAddress(const CChainParams ¶ms) sourcedata.insert(sourcedata.end(), dummydata, dummydata + sizeof(dummydata)); for(int i=0; i<256; ++i) { // Try every trailing byte std::string s = EncodeBase58(sourcedata.data(), sourcedata.data() + sourcedata.size()); - if (!CBitcoinAddress(s).IsValid()) + if (!IsValidDestinationString(s)) { return s; + } sourcedata[sourcedata.size()-1] += 1; } return ""; @@ -248,7 +249,7 @@ QString formatBitcoinURI(const SendCoinsRecipient &info) bool isDust(const QString& address, const CAmount& amount) { - CTxDestination dest = CBitcoinAddress(address.toStdString()).Get(); + CTxDestination dest = DecodeDestination(address.toStdString()); CScript script = GetScriptForDestination(dest); CTxOut txOut(amount, script); return IsDust(txOut, ::dustRelayFee); @@ -780,47 +781,64 @@ bool SetStartOnSystemStartup(bool fAutoStart) LSSharedFileListItemRef findStartupItemInList(LSSharedFileListRef list, CFURLRef findUrl); LSSharedFileListItemRef findStartupItemInList(LSSharedFileListRef list, CFURLRef findUrl) { - // loop through the list of startup items and try to find the bitcoin app CFArrayRef listSnapshot = LSSharedFileListCopySnapshot(list, nullptr); + if (listSnapshot == nullptr) { + return nullptr; + } + + // loop through the list of startup items and try to find the bitcoin app for(int i = 0; i < CFArrayGetCount(listSnapshot); i++) { LSSharedFileListItemRef item = (LSSharedFileListItemRef)CFArrayGetValueAtIndex(listSnapshot, i); UInt32 resolutionFlags = kLSSharedFileListNoUserInteraction | kLSSharedFileListDoNotMountVolumes; CFURLRef currentItemURL = nullptr; #if defined(MAC_OS_X_VERSION_MAX_ALLOWED) && MAC_OS_X_VERSION_MAX_ALLOWED >= 10100 - if(&LSSharedFileListItemCopyResolvedURL) - currentItemURL = LSSharedFileListItemCopyResolvedURL(item, resolutionFlags, nullptr); + if(&LSSharedFileListItemCopyResolvedURL) + currentItemURL = LSSharedFileListItemCopyResolvedURL(item, resolutionFlags, nullptr); #if defined(MAC_OS_X_VERSION_MIN_REQUIRED) && MAC_OS_X_VERSION_MIN_REQUIRED < 10100 - else - LSSharedFileListItemResolve(item, resolutionFlags, ¤tItemURL, nullptr); + else + LSSharedFileListItemResolve(item, resolutionFlags, ¤tItemURL, nullptr); #endif #else - LSSharedFileListItemResolve(item, resolutionFlags, ¤tItemURL, nullptr); + LSSharedFileListItemResolve(item, resolutionFlags, ¤tItemURL, nullptr); #endif - if(currentItemURL && CFEqual(currentItemURL, findUrl)) { - // found - CFRelease(currentItemURL); - return item; - } if(currentItemURL) { + if (CFEqual(currentItemURL, findUrl)) { + // found + CFRelease(listSnapshot); + CFRelease(currentItemURL); + return item; + } CFRelease(currentItemURL); } } + + CFRelease(listSnapshot); return nullptr; } bool GetStartOnSystemStartup() { CFURLRef bitcoinAppUrl = CFBundleCopyBundleURL(CFBundleGetMainBundle()); + if (bitcoinAppUrl == nullptr) { + return false; + } + LSSharedFileListRef loginItems = LSSharedFileListCreate(nullptr, kLSSharedFileListSessionLoginItems, nullptr); LSSharedFileListItemRef foundItem = findStartupItemInList(loginItems, bitcoinAppUrl); + + CFRelease(bitcoinAppUrl); return !!foundItem; // return boolified object } bool SetStartOnSystemStartup(bool fAutoStart) { CFURLRef bitcoinAppUrl = CFBundleCopyBundleURL(CFBundleGetMainBundle()); + if (bitcoinAppUrl == nullptr) { + return false; + } + LSSharedFileListRef loginItems = LSSharedFileListCreate(nullptr, kLSSharedFileListSessionLoginItems, nullptr); LSSharedFileListItemRef foundItem = findStartupItemInList(loginItems, bitcoinAppUrl); @@ -832,6 +850,8 @@ bool SetStartOnSystemStartup(bool fAutoStart) // remove item LSSharedFileListItemRemove(loginItems, foundItem); } + + CFRelease(bitcoinAppUrl); return true; } #pragma GCC diagnostic pop diff --git a/src/qt/macnotificationhandler.h b/src/qt/macnotificationhandler.h index d4749b3d5f..3a005c3c46 100644 --- a/src/qt/macnotificationhandler.h +++ b/src/qt/macnotificationhandler.h @@ -7,20 +7,17 @@ #include <QObject> -/** Macintosh-specific notification handler (supports UserNotificationCenter and Growl). +/** Macintosh-specific notification handler (supports UserNotificationCenter). */ class MacNotificationHandler : public QObject { Q_OBJECT public: - /** shows a 10.8+ UserNotification in the UserNotificationCenter + /** shows a macOS 10.8+ UserNotification in the UserNotificationCenter */ void showNotification(const QString &title, const QString &text); - /** executes AppleScript */ - void sendAppleScript(const QString &script); - /** check if OS can handle UserNotifications */ bool hasUserNotificationCenterSupport(void); static MacNotificationHandler *instance(); diff --git a/src/qt/macnotificationhandler.mm b/src/qt/macnotificationhandler.mm index 4c96d08c8a..1b16c5f524 100644 --- a/src/qt/macnotificationhandler.mm +++ b/src/qt/macnotificationhandler.mm @@ -47,20 +47,6 @@ void MacNotificationHandler::showNotification(const QString &title, const QStrin } } -// sendAppleScript just take a QString and executes it as apple script -void MacNotificationHandler::sendAppleScript(const QString &script) -{ - QByteArray utf8 = script.toUtf8(); - char* cString = (char *)utf8.constData(); - NSString *scriptApple = [[NSString alloc] initWithUTF8String:cString]; - - NSAppleScript *as = [[NSAppleScript alloc] initWithSource:scriptApple]; - NSDictionary *err = nil; - [as executeAndReturnError:&err]; - [as release]; - [scriptApple release]; -} - bool MacNotificationHandler::hasUserNotificationCenterSupport(void) { Class possibleClass = NSClassFromString(@"NSUserNotificationCenter"); diff --git a/src/qt/modaloverlay.cpp b/src/qt/modaloverlay.cpp index a83f285034..e32a0bdda8 100644 --- a/src/qt/modaloverlay.cpp +++ b/src/qt/modaloverlay.cpp @@ -82,36 +82,38 @@ void ModalOverlay::tipUpdate(int count, const QDateTime& blockDate, double nVeri blockProcessTime.push_front(qMakePair(currentDate.toMSecsSinceEpoch(), nVerificationProgress)); // show progress speed if we have more then one sample - if (blockProcessTime.size() >= 2) - { - double progressStart = blockProcessTime[0].second; + if (blockProcessTime.size() >= 2) { double progressDelta = 0; double progressPerHour = 0; qint64 timeDelta = 0; qint64 remainingMSecs = 0; double remainingProgress = 1.0 - nVerificationProgress; - for (int i = 1; i < blockProcessTime.size(); i++) - { + for (int i = 1; i < blockProcessTime.size(); i++) { QPair<qint64, double> sample = blockProcessTime[i]; // take first sample after 500 seconds or last available one if (sample.first < (currentDate.toMSecsSinceEpoch() - 500 * 1000) || i == blockProcessTime.size() - 1) { - progressDelta = progressStart-sample.second; + progressDelta = blockProcessTime[0].second - sample.second; timeDelta = blockProcessTime[0].first - sample.first; - progressPerHour = progressDelta/(double)timeDelta*1000*3600; - remainingMSecs = remainingProgress / progressDelta * timeDelta; + progressPerHour = progressDelta / (double) timeDelta * 1000 * 3600; + remainingMSecs = (progressDelta > 0) ? remainingProgress / progressDelta * timeDelta : -1; break; } } // show progress increase per hour - ui->progressIncreasePerH->setText(QString::number(progressPerHour*100, 'f', 2)+"%"); + ui->progressIncreasePerH->setText(QString::number(progressPerHour * 100, 'f', 2)+"%"); // show expected remaining time - ui->expectedTimeLeft->setText(GUIUtil::formatNiceTimeOffset(remainingMSecs/1000.0)); + if(remainingMSecs >= 0) { + ui->expectedTimeLeft->setText(GUIUtil::formatNiceTimeOffset(remainingMSecs / 1000.0)); + } else { + ui->expectedTimeLeft->setText(QObject::tr("unknown")); + } static const int MAX_SAMPLES = 5000; - if (blockProcessTime.count() > MAX_SAMPLES) - blockProcessTime.remove(MAX_SAMPLES, blockProcessTime.count()-MAX_SAMPLES); + if (blockProcessTime.count() > MAX_SAMPLES) { + blockProcessTime.remove(MAX_SAMPLES, blockProcessTime.count() - MAX_SAMPLES); + } } // show the last block date diff --git a/src/qt/notificator.cpp b/src/qt/notificator.cpp index a7a7a4ce11..937928315b 100644 --- a/src/qt/notificator.cpp +++ b/src/qt/notificator.cpp @@ -60,22 +60,6 @@ Notificator::Notificator(const QString &_programName, QSystemTrayIcon *_trayIcon if( MacNotificationHandler::instance()->hasUserNotificationCenterSupport()) { mode = UserNotificationCenter; } - else { - // Check if Growl is installed (based on Qt's tray icon implementation) - CFURLRef cfurl; - OSStatus status = LSGetApplicationForInfo(kLSUnknownType, kLSUnknownCreator, CFSTR("growlTicket"), kLSRolesAll, 0, &cfurl); - if (status != kLSApplicationNotFoundErr) { - CFBundleRef bundle = CFBundleCreate(0, cfurl); - if (CFStringCompare(CFBundleGetIdentifier(bundle), CFSTR("com.Growl.GrowlHelperApp"), kCFCompareCaseInsensitive | kCFCompareBackwards) == kCFCompareEqualTo) { - if (CFStringHasSuffix(CFURLGetString(cfurl), CFSTR("/Growl.app/"))) - mode = Growl13; - else - mode = Growl12; - } - CFRelease(cfurl); - CFRelease(bundle); - } - } #endif } @@ -241,52 +225,6 @@ void Notificator::notifySystray(Class cls, const QString &title, const QString & // Based on Qt's tray icon implementation #ifdef Q_OS_MAC -void Notificator::notifyGrowl(Class cls, const QString &title, const QString &text, const QIcon &icon) -{ - const QString script( - "tell application \"%5\"\n" - " set the allNotificationsList to {\"Notification\"}\n" // -- Make a list of all the notification types (all) - " set the enabledNotificationsList to {\"Notification\"}\n" // -- Make a list of the notifications (enabled) - " register as application \"%1\" all notifications allNotificationsList default notifications enabledNotificationsList\n" // -- Register our script with Growl - " notify with name \"Notification\" title \"%2\" description \"%3\" application name \"%1\"%4\n" // -- Send a Notification - "end tell" - ); - - QString notificationApp(QApplication::applicationName()); - if (notificationApp.isEmpty()) - notificationApp = "Application"; - - QPixmap notificationIconPixmap; - if (icon.isNull()) { // If no icon specified, set icon based on class - QStyle::StandardPixmap sicon = QStyle::SP_MessageBoxQuestion; - switch (cls) - { - case Information: sicon = QStyle::SP_MessageBoxInformation; break; - case Warning: sicon = QStyle::SP_MessageBoxWarning; break; - case Critical: sicon = QStyle::SP_MessageBoxCritical; break; - } - notificationIconPixmap = QApplication::style()->standardPixmap(sicon); - } - else { - QSize size = icon.actualSize(QSize(48, 48)); - notificationIconPixmap = icon.pixmap(size); - } - - QString notificationIcon; - QTemporaryFile notificationIconFile; - if (!notificationIconPixmap.isNull() && notificationIconFile.open()) { - QImageWriter writer(¬ificationIconFile, "PNG"); - if (writer.write(notificationIconPixmap.toImage())) - notificationIcon = QString(" image from location \"file://%1\"").arg(notificationIconFile.fileName()); - } - - QString quotedTitle(title), quotedText(text); - quotedTitle.replace("\\", "\\\\").replace("\"", "\\"); - quotedText.replace("\\", "\\\\").replace("\"", "\\"); - QString growlApp(this->mode == Notificator::Growl13 ? "Growl" : "GrowlHelperApp"); - MacNotificationHandler::instance()->sendAppleScript(script.arg(notificationApp, quotedTitle, quotedText, notificationIcon, growlApp)); -} - void Notificator::notifyMacUserNotificationCenter(Class cls, const QString &title, const QString &text, const QIcon &icon) { // icon is not supported by the user notification center yet. OSX will use the app icon. MacNotificationHandler::instance()->showNotification(title, text); @@ -310,10 +248,6 @@ void Notificator::notify(Class cls, const QString &title, const QString &text, c case UserNotificationCenter: notifyMacUserNotificationCenter(cls, title, text, icon); break; - case Growl12: - case Growl13: - notifyGrowl(cls, title, text, icon); - break; #endif default: if(cls == Critical) diff --git a/src/qt/notificator.h b/src/qt/notificator.h index f92b791d4a..67f2b1df69 100644 --- a/src/qt/notificator.h +++ b/src/qt/notificator.h @@ -58,8 +58,6 @@ private: None, /**< Ignore informational notifications, and show a modal pop-up dialog for Critical notifications. */ Freedesktop, /**< Use DBus org.freedesktop.Notifications */ QSystemTray, /**< Use QSystemTray::showMessage */ - Growl12, /**< Use the Growl 1.2 notification system (Mac only) */ - Growl13, /**< Use the Growl 1.3 notification system (Mac only) */ UserNotificationCenter /**< Use the 10.8+ User Notification Center (Mac only) */ }; QString programName; @@ -72,7 +70,6 @@ private: #endif void notifySystray(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout); #ifdef Q_OS_MAC - void notifyGrowl(Class cls, const QString &title, const QString &text, const QIcon &icon); void notifyMacUserNotificationCenter(Class cls, const QString &title, const QString &text, const QIcon &icon); #endif }; diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index d4137d280f..169684cf6d 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -218,17 +218,15 @@ void PaymentServer::ipcParseCommandLine(int argc, char* argv[]) SendCoinsRecipient r; if (GUIUtil::parseBitcoinURI(arg, &r) && !r.address.isEmpty()) { - CBitcoinAddress address(r.address.toStdString()); auto tempChainParams = CreateChainParams(CBaseChainParams::MAIN); - if (address.IsValid(*tempChainParams)) - { + if (IsValidDestinationString(r.address.toStdString(), *tempChainParams)) { SelectParams(CBaseChainParams::MAIN); - } - else { + } else { tempChainParams = CreateChainParams(CBaseChainParams::TESTNET); - if (address.IsValid(*tempChainParams)) + if (IsValidDestinationString(r.address.toStdString(), *tempChainParams)) { SelectParams(CBaseChainParams::TESTNET); + } } } } @@ -441,8 +439,7 @@ void PaymentServer::handleURIOrFile(const QString& s) SendCoinsRecipient recipient; if (GUIUtil::parseBitcoinURI(s, &recipient)) { - CBitcoinAddress address(recipient.address.toStdString()); - if (!address.IsValid()) { + if (!IsValidDestinationString(recipient.address.toStdString())) { Q_EMIT message(tr("URI handling"), tr("Invalid payment address %1").arg(recipient.address), CClientUIInterface::MSG_ERROR); } @@ -560,7 +557,7 @@ bool PaymentServer::processPaymentRequest(const PaymentRequestPlus& request, Sen CTxDestination dest; if (ExtractDestination(sendingTo.first, dest)) { // Append destination address - addresses.append(QString::fromStdString(CBitcoinAddress(dest).ToString())); + addresses.append(QString::fromStdString(EncodeDestination(dest))); } else if (!recipient.authenticatedMerchant.isEmpty()) { // Unauthenticated payment requests to custom bitcoin addresses are not supported diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index a056e858a7..6309070fef 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -114,10 +114,6 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *_platformStyle, QWidget *p settings.setValue("nFeeRadio", 1); // custom if (!settings.contains("nFeeRadio")) settings.setValue("nFeeRadio", 0); // recommended - if (!settings.contains("nCustomFeeRadio") && settings.contains("nTransactionFee") && settings.value("nTransactionFee").toLongLong() > 0) // compatibility - settings.setValue("nCustomFeeRadio", 1); // total at least - if (!settings.contains("nCustomFeeRadio")) - settings.setValue("nCustomFeeRadio", 0); // per kilobyte if (!settings.contains("nSmartFeeSliderPosition")) settings.setValue("nSmartFeeSliderPosition", 0); if (!settings.contains("nTransactionFee")) @@ -127,8 +123,6 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *_platformStyle, QWidget *p ui->groupFee->setId(ui->radioSmartFee, 0); ui->groupFee->setId(ui->radioCustomFee, 1); ui->groupFee->button((int)std::max(0, std::min(1, settings.value("nFeeRadio").toInt())))->setChecked(true); - ui->groupCustomFee->setId(ui->radioCustomPerKilobyte, 0); - ui->groupCustomFee->button((int)std::max(0, std::min(1, settings.value("nCustomFeeRadio").toInt())))->setChecked(true); ui->customFee->setValue(settings.value("nTransactionFee").toLongLong()); ui->checkBoxMinimumFee->setChecked(settings.value("fPayOnlyMinFee").toBool()); minimizeFeeSection(settings.value("fFeeSectionMinimized").toBool()); @@ -178,7 +172,6 @@ void SendCoinsDialog::setModel(WalletModel *_model) connect(ui->confTargetSelector, SIGNAL(currentIndexChanged(int)), this, SLOT(coinControlUpdateLabels())); connect(ui->groupFee, SIGNAL(buttonClicked(int)), this, SLOT(updateFeeSectionControls())); connect(ui->groupFee, SIGNAL(buttonClicked(int)), this, SLOT(coinControlUpdateLabels())); - connect(ui->groupCustomFee, SIGNAL(buttonClicked(int)), this, SLOT(coinControlUpdateLabels())); connect(ui->customFee, SIGNAL(valueChanged()), this, SLOT(coinControlUpdateLabels())); connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(setMinimumFee())); connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(updateFeeSectionControls())); @@ -214,7 +207,6 @@ SendCoinsDialog::~SendCoinsDialog() QSettings settings; settings.setValue("fFeeSectionMinimized", fFeeMinimized); settings.setValue("nFeeRadio", ui->groupFee->checkedId()); - settings.setValue("nCustomFeeRadio", ui->groupCustomFee->checkedId()); settings.setValue("nConfTarget", getConfTargetForIndex(ui->confTargetSelector->currentIndex())); settings.setValue("nTransactionFee", (qint64)ui->customFee->value()); settings.setValue("fPayOnlyMinFee", ui->checkBoxMinimumFee->isChecked()); @@ -609,7 +601,6 @@ void SendCoinsDialog::on_buttonMinimizeFee_clicked() void SendCoinsDialog::setMinimumFee() { - ui->radioCustomPerKilobyte->setChecked(true); ui->customFee->setValue(GetRequiredFee(1000)); } @@ -622,7 +613,7 @@ void SendCoinsDialog::updateFeeSectionControls() ui->labelFeeEstimation ->setEnabled(ui->radioSmartFee->isChecked()); ui->checkBoxMinimumFee ->setEnabled(ui->radioCustomFee->isChecked()); ui->labelMinFeeWarning ->setEnabled(ui->radioCustomFee->isChecked()); - ui->radioCustomPerKilobyte ->setEnabled(ui->radioCustomFee->isChecked() && !ui->checkBoxMinimumFee->isChecked()); + ui->labelCustomPerKilobyte ->setEnabled(ui->radioCustomFee->isChecked() && !ui->checkBoxMinimumFee->isChecked()); ui->customFee ->setEnabled(ui->radioCustomFee->isChecked() && !ui->checkBoxMinimumFee->isChecked()); } @@ -634,8 +625,7 @@ void SendCoinsDialog::updateFeeMinimizedLabel() if (ui->radioSmartFee->isChecked()) ui->labelFeeMinimized->setText(ui->labelSmartFee->text()); else { - ui->labelFeeMinimized->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), ui->customFee->value()) + - ((ui->radioCustomPerKilobyte->isChecked()) ? "/kB" : "")); + ui->labelFeeMinimized->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), ui->customFee->value()) + "/kB"); } } @@ -777,19 +767,18 @@ void SendCoinsDialog::coinControlChangeEdited(const QString& text) CoinControlDialog::coinControl->destChange = CNoDestination(); ui->labelCoinControlChangeLabel->setStyleSheet("QLabel{color:red;}"); - CBitcoinAddress addr = CBitcoinAddress(text.toStdString()); + const CTxDestination dest = DecodeDestination(text.toStdString()); if (text.isEmpty()) // Nothing entered { ui->labelCoinControlChangeLabel->setText(""); } - else if (!addr.IsValid()) // Invalid address + else if (!IsValidDestination(dest)) // Invalid address { ui->labelCoinControlChangeLabel->setText(tr("Warning: Invalid Bitcoin address")); } else // Valid address { - const CTxDestination dest = addr.Get(); if (!model->IsSpendable(dest)) { ui->labelCoinControlChangeLabel->setText(tr("Warning: Unknown change address")); diff --git a/src/qt/signverifymessagedialog.cpp b/src/qt/signverifymessagedialog.cpp index 0950ed0234..cba9d4da38 100644 --- a/src/qt/signverifymessagedialog.cpp +++ b/src/qt/signverifymessagedialog.cpp @@ -117,16 +117,14 @@ void SignVerifyMessageDialog::on_signMessageButton_SM_clicked() /* Clear old signature to ensure users don't get confused on error with an old signature displayed */ ui->signatureOut_SM->clear(); - CBitcoinAddress addr(ui->addressIn_SM->text().toStdString()); - if (!addr.IsValid()) - { + CTxDestination destination = DecodeDestination(ui->addressIn_SM->text().toStdString()); + if (!IsValidDestination(destination)) { ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }"); ui->statusLabel_SM->setText(tr("The entered address is invalid.") + QString(" ") + tr("Please check the address and try again.")); return; } - CKeyID keyID; - if (!addr.GetKeyID(keyID)) - { + const CKeyID* keyID = boost::get<CKeyID>(&destination); + if (!keyID) { ui->addressIn_SM->setValid(false); ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }"); ui->statusLabel_SM->setText(tr("The entered address does not refer to a key.") + QString(" ") + tr("Please check the address and try again.")); @@ -142,7 +140,7 @@ void SignVerifyMessageDialog::on_signMessageButton_SM_clicked() } CKey key; - if (!model->getPrivKey(keyID, key)) + if (!model->getPrivKey(*keyID, key)) { ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }"); ui->statusLabel_SM->setText(tr("Private key for the entered address is not available.")); @@ -164,7 +162,7 @@ void SignVerifyMessageDialog::on_signMessageButton_SM_clicked() ui->statusLabel_SM->setStyleSheet("QLabel { color: green; }"); ui->statusLabel_SM->setText(QString("<nobr>") + tr("Message signed.") + QString("</nobr>")); - ui->signatureOut_SM->setText(QString::fromStdString(EncodeBase64(&vchSig[0], vchSig.size()))); + ui->signatureOut_SM->setText(QString::fromStdString(EncodeBase64(vchSig.data(), vchSig.size()))); } void SignVerifyMessageDialog::on_copySignatureButton_SM_clicked() @@ -197,16 +195,13 @@ void SignVerifyMessageDialog::on_addressBookButton_VM_clicked() void SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked() { - CBitcoinAddress addr(ui->addressIn_VM->text().toStdString()); - if (!addr.IsValid()) - { + CTxDestination destination = DecodeDestination(ui->addressIn_VM->text().toStdString()); + if (!IsValidDestination(destination)) { ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }"); ui->statusLabel_VM->setText(tr("The entered address is invalid.") + QString(" ") + tr("Please check the address and try again.")); return; } - CKeyID keyID; - if (!addr.GetKeyID(keyID)) - { + if (!boost::get<CKeyID>(&destination)) { ui->addressIn_VM->setValid(false); ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }"); ui->statusLabel_VM->setText(tr("The entered address does not refer to a key.") + QString(" ") + tr("Please check the address and try again.")); @@ -237,8 +232,7 @@ void SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked() return; } - if (!(CBitcoinAddress(pubkey.GetID()) == addr)) - { + if (!(CTxDestination(pubkey.GetID()) == destination)) { ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }"); ui->statusLabel_VM->setText(QString("<nobr>") + tr("Message verification failed.") + QString("</nobr>")); return; diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp index 1b7cc69231..a1fbba963c 100644 --- a/src/qt/splashscreen.cpp +++ b/src/qt/splashscreen.cpp @@ -142,8 +142,8 @@ SplashScreen::~SplashScreen() bool SplashScreen::eventFilter(QObject * obj, QEvent * ev) { if (ev->type() == QEvent::KeyPress) { QKeyEvent *keyEvent = static_cast<QKeyEvent *>(ev); - if(keyEvent->text()[0] == 'q' && breakAction != nullptr) { - breakAction(); + if(keyEvent->text()[0] == 'q') { + StartShutdown(); } } return QObject::eventFilter(obj, ev); @@ -170,27 +170,18 @@ static void InitMessage(SplashScreen *splash, const std::string &message) Q_ARG(QColor, QColor(55,55,55))); } -static void ShowProgress(SplashScreen *splash, const std::string &title, int nProgress) +static void ShowProgress(SplashScreen *splash, const std::string &title, int nProgress, bool resume_possible) { - InitMessage(splash, title + strprintf("%d", nProgress) + "%"); -} - -void SplashScreen::setBreakAction(const std::function<void(void)> &action) -{ - breakAction = action; -} - -static void SetProgressBreakAction(SplashScreen *splash, const std::function<void(void)> &action) -{ - QMetaObject::invokeMethod(splash, "setBreakAction", - Qt::QueuedConnection, - Q_ARG(std::function<void(void)>, action)); + InitMessage(splash, title + std::string("\n") + + (resume_possible ? _("(press q to shutdown and continue later)") + : _("press q to shutdown")) + + strprintf("\n%d", nProgress) + "%"); } #ifdef ENABLE_WALLET void SplashScreen::ConnectWallet(CWallet* wallet) { - wallet->ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2)); + wallet->ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2, false)); connectedWallets.push_back(wallet); } #endif @@ -199,8 +190,7 @@ void SplashScreen::subscribeToCoreSignals() { // Connect signals to client uiInterface.InitMessage.connect(boost::bind(InitMessage, this, _1)); - uiInterface.ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2)); - uiInterface.SetProgressBreakAction.connect(boost::bind(SetProgressBreakAction, this, _1)); + uiInterface.ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2, _3)); #ifdef ENABLE_WALLET uiInterface.LoadWallet.connect(boost::bind(&SplashScreen::ConnectWallet, this, _1)); #endif @@ -210,10 +200,10 @@ void SplashScreen::unsubscribeFromCoreSignals() { // Disconnect signals from client uiInterface.InitMessage.disconnect(boost::bind(InitMessage, this, _1)); - uiInterface.ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2)); + uiInterface.ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2, _3)); #ifdef ENABLE_WALLET for (CWallet* const & pwallet : connectedWallets) { - pwallet->ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2)); + pwallet->ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2, false)); } #endif } diff --git a/src/qt/splashscreen.h b/src/qt/splashscreen.h index a88ebb98a8..c6cfd503f7 100644 --- a/src/qt/splashscreen.h +++ b/src/qt/splashscreen.h @@ -36,8 +36,6 @@ public Q_SLOTS: /** Show message and progress */ void showMessage(const QString &message, int alignment, const QColor &color); - /** Sets the break action */ - void setBreakAction(const std::function<void(void)> &action); protected: bool eventFilter(QObject * obj, QEvent * ev); @@ -55,8 +53,6 @@ private: int curAlignment; QList<CWallet*> connectedWallets; - - std::function<void(void)> breakAction; }; #endif // BITCOIN_QT_SPLASHSCREEN_H diff --git a/src/qt/test/paymentservertests.cpp b/src/qt/test/paymentservertests.cpp index c7830071ed..273bd10487 100644 --- a/src/qt/test/paymentservertests.cpp +++ b/src/qt/test/paymentservertests.cpp @@ -24,7 +24,7 @@ X509 *parse_b64der_cert(const char* cert_data) { std::vector<unsigned char> data = DecodeBase64(cert_data); assert(data.size() > 0); - const unsigned char* dptr = &data[0]; + const unsigned char* dptr = data.data(); X509 *cert = d2i_X509(nullptr, &dptr, data.size()); assert(cert); return cert; @@ -43,7 +43,7 @@ static SendCoinsRecipient handleRequest(PaymentServer* server, std::vector<unsig // Write data to a temp file: QTemporaryFile f; f.open(); - f.write((const char*)&data[0], data.size()); + f.write((const char*)data.data(), data.size()); f.close(); // Create a QObject, install event filter from PaymentServer @@ -139,7 +139,7 @@ void PaymentServerTests::paymentServerTests() // Contains a testnet paytoaddress, so payment request network doesn't match client network: data = DecodeBase64(paymentrequest1_cert2_BASE64); - byteArray = QByteArray((const char*)&data[0], data.size()); + byteArray = QByteArray((const char*)data.data(), data.size()); r.paymentRequest.parse(byteArray); // Ensure the request is initialized, because network "main" is default, even for // uninitialized payment requests and that will fail our test here. @@ -148,7 +148,7 @@ void PaymentServerTests::paymentServerTests() // Expired payment request (expires is set to 1 = 1970-01-01 00:00:01): data = DecodeBase64(paymentrequest2_cert2_BASE64); - byteArray = QByteArray((const char*)&data[0], data.size()); + byteArray = QByteArray((const char*)data.data(), data.size()); r.paymentRequest.parse(byteArray); // Ensure the request is initialized QVERIFY(r.paymentRequest.IsInitialized()); @@ -159,7 +159,7 @@ void PaymentServerTests::paymentServerTests() // 9223372036854775807 (uint64), 9223372036854775807 (int64_t) and -1 (int32_t) // -1 is 1969-12-31 23:59:59 (for a 32 bit time values) data = DecodeBase64(paymentrequest3_cert2_BASE64); - byteArray = QByteArray((const char*)&data[0], data.size()); + byteArray = QByteArray((const char*)data.data(), data.size()); r.paymentRequest.parse(byteArray); // Ensure the request is initialized QVERIFY(r.paymentRequest.IsInitialized()); @@ -170,7 +170,7 @@ void PaymentServerTests::paymentServerTests() // 9223372036854775808 (uint64), -9223372036854775808 (int64_t) and 0 (int32_t) // 0 is 1970-01-01 00:00:00 (for a 32 bit time values) data = DecodeBase64(paymentrequest4_cert2_BASE64); - byteArray = QByteArray((const char*)&data[0], data.size()); + byteArray = QByteArray((const char*)data.data(), data.size()); r.paymentRequest.parse(byteArray); // Ensure the request is initialized QVERIFY(r.paymentRequest.IsInitialized()); @@ -190,7 +190,7 @@ void PaymentServerTests::paymentServerTests() // Payment request with amount overflow (amount is set to 21000001 BTC): data = DecodeBase64(paymentrequest5_cert2_BASE64); - byteArray = QByteArray((const char*)&data[0], data.size()); + byteArray = QByteArray((const char*)data.data(), data.size()); r.paymentRequest.parse(byteArray); // Ensure the request is initialized QVERIFY(r.paymentRequest.IsInitialized()); diff --git a/src/qt/test/rpcnestedtests.cpp b/src/qt/test/rpcnestedtests.cpp index 00edd64f72..70fdd4bf58 100644 --- a/src/qt/test/rpcnestedtests.cpp +++ b/src/qt/test/rpcnestedtests.cpp @@ -36,11 +36,6 @@ void RPCNestedTests::rpcNestedTests() // do some test setup // could be moved to a more generic place when we add more tests on QT level tableRPC.appendCommand("rpcNestedTest", &vRPCCommands[0]); - 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("."); - gArgs.ForceSetArg("-datadir", path); //mempool.setSanityCheck(1.0); TestingSetup test; @@ -135,6 +130,4 @@ void RPCNestedTests::rpcNestedTests() QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest(abc,,abc)"), std::runtime_error); //don't tollerate empty arguments when using , QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest(abc,,)"), std::runtime_error); //don't tollerate empty arguments when using , #endif - - fs::remove_all(fs::path(path)); } diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp index 80a00a634a..4c04e67ccc 100644 --- a/src/qt/test/test_main.cpp +++ b/src/qt/test/test_main.cpp @@ -53,6 +53,10 @@ int main(int argc, char *argv[]) SetupNetworking(); SelectParams(CBaseChainParams::MAIN); noui_connect(); + ClearDatadirCache(); + fs::path pathTemp = fs::temp_directory_path() / strprintf("test_bitcoin-qt_%lu_%i", (unsigned long)GetTime(), (int)GetRand(100000)); + fs::create_directories(pathTemp); + gArgs.ForceSetArg("-datadir", pathTemp.string()); bool fInvalid = false; @@ -97,5 +101,7 @@ int main(int argc, char *argv[]) } #endif + fs::remove_all(pathTemp); + return fInvalid; } diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp index ff1eb59f16..5031d7651d 100644 --- a/src/qt/test/wallettests.cpp +++ b/src/qt/test/wallettests.cpp @@ -57,11 +57,11 @@ void ConfirmSend(QString* text = nullptr, bool cancel = false) } //! Send coins to address and return txid. -uint256 SendCoins(CWallet& wallet, SendCoinsDialog& sendCoinsDialog, const CBitcoinAddress& address, CAmount amount, bool rbf) +uint256 SendCoins(CWallet& wallet, SendCoinsDialog& sendCoinsDialog, const CTxDestination& address, CAmount amount, bool rbf) { QVBoxLayout* entries = sendCoinsDialog.findChild<QVBoxLayout*>("entries"); SendCoinsEntry* entry = qobject_cast<SendCoinsEntry*>(entries->itemAt(0)->widget()); - entry->findChild<QValidatedLineEdit*>("payTo")->setText(QString::fromStdString(address.ToString())); + entry->findChild<QValidatedLineEdit*>("payTo")->setText(QString::fromStdString(EncodeDestination(address))); entry->findChild<BitcoinAmountField*>("payAmount")->setValue(amount); sendCoinsDialog.findChild<QFrame*>("frameFee") ->findChild<QFrame*>("frameFeeSelection") @@ -172,8 +172,8 @@ void TestSendCoins() // Send two transactions, and verify they are added to transaction list. TransactionTableModel* transactionTableModel = walletModel.getTransactionTableModel(); QCOMPARE(transactionTableModel->rowCount({}), 105); - uint256 txid1 = SendCoins(wallet, sendCoinsDialog, CBitcoinAddress(CKeyID()), 5 * COIN, false /* rbf */); - uint256 txid2 = SendCoins(wallet, sendCoinsDialog, CBitcoinAddress(CKeyID()), 10 * COIN, true /* rbf */); + uint256 txid1 = SendCoins(wallet, sendCoinsDialog, CKeyID(), 5 * COIN, false /* rbf */); + uint256 txid2 = SendCoins(wallet, sendCoinsDialog, CKeyID(), 10 * COIN, true /* rbf */); QCOMPARE(transactionTableModel->rowCount({}), 107); QVERIFY(FindTx(*transactionTableModel, txid1).isValid()); QVERIFY(FindTx(*transactionTableModel, txid2).isValid()); diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index bcacc47ef3..74f5c774a0 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -91,9 +91,8 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco if (nNet > 0) { // Credit - if (CBitcoinAddress(rec->address).IsValid()) - { - CTxDestination address = CBitcoinAddress(rec->address).Get(); + CTxDestination address = DecodeDestination(rec->address); + if (IsValidDestination(address)) { if (wallet->mapAddressBook.count(address)) { strHTML += "<b>" + tr("From") + ":</b> " + tr("unknown") + "<br>"; @@ -118,7 +117,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco // Online transaction std::string strAddress = wtx.mapValue["to"]; strHTML += "<b>" + tr("To") + ":</b> "; - CTxDestination dest = CBitcoinAddress(strAddress).Get(); + CTxDestination dest = DecodeDestination(strAddress); if (wallet->mapAddressBook.count(dest) && !wallet->mapAddressBook[dest].name.empty()) strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[dest].name) + " "; strHTML += GUIUtil::HtmlEscape(strAddress) + "<br>"; @@ -189,7 +188,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco strHTML += "<b>" + tr("To") + ":</b> "; if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].name.empty()) strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address].name) + " "; - strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address).ToString()); + strHTML += GUIUtil::HtmlEscape(EncodeDestination(address)); if(toSelf == ISMINE_SPENDABLE) strHTML += " (own address)"; else if(toSelf & ISMINE_WATCH_ONLY) @@ -304,7 +303,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco { if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].name.empty()) strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address].name) + " "; - strHTML += QString::fromStdString(CBitcoinAddress(address).ToString()); + strHTML += QString::fromStdString(EncodeDestination(address)); } strHTML = strHTML + " " + tr("Amount") + "=" + BitcoinUnits::formatHtmlWithUnit(unit, vout.nValue); strHTML = strHTML + " IsMine=" + (wallet->IsMine(vout) & ISMINE_SPENDABLE ? tr("true") : tr("false")) + "</li>"; diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp index 36d98ce49d..d40ffd22cd 100644 --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -55,7 +55,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet * { // Received by Bitcoin Address sub.type = TransactionRecord::RecvWithAddress; - sub.address = CBitcoinAddress(address).ToString(); + sub.address = EncodeDestination(address); } else { @@ -127,7 +127,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet * { // Sent to Bitcoin Address sub.type = TransactionRecord::SendToAddress; - sub.address = CBitcoinAddress(address).ToString(); + sub.address = EncodeDestination(address); } else { diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index a3f243a25f..53b1c2967c 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -188,8 +188,7 @@ void WalletModel::updateWatchOnlyFlag(bool fHaveWatchonly) bool WalletModel::validateAddress(const QString &address) { - CBitcoinAddress addressParsed(address.toStdString()); - return addressParsed.IsValid(); + return IsValidDestinationString(address.toStdString()); } WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransaction &transaction, const CCoinControl& coinControl) @@ -247,7 +246,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact setAddress.insert(rcp.address); ++nAddresses; - CScript scriptPubKey = GetScriptForDestination(CBitcoinAddress(rcp.address.toStdString()).Get()); + CScript scriptPubKey = GetScriptForDestination(DecodeDestination(rcp.address.toStdString())); CRecipient recipient = {scriptPubKey, rcp.amount, rcp.fSubtractFeeFromAmount}; vecSend.push_back(recipient); @@ -348,7 +347,7 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran if (!rcp.paymentRequest.IsInitialized()) { std::string strAddress = rcp.address.toStdString(); - CTxDestination dest = CBitcoinAddress(strAddress).Get(); + CTxDestination dest = DecodeDestination(strAddress); std::string strLabel = rcp.label.toStdString(); { LOCK(wallet->cs_wallet); @@ -464,7 +463,7 @@ static void NotifyAddressBookChanged(WalletModel *walletmodel, CWallet *wallet, const CTxDestination &address, const std::string &label, bool isMine, const std::string &purpose, ChangeType status) { - QString strAddress = QString::fromStdString(CBitcoinAddress(address).ToString()); + QString strAddress = QString::fromStdString(EncodeDestination(address)); QString strLabel = QString::fromStdString(label); QString strPurpose = QString::fromStdString(purpose); @@ -596,7 +595,7 @@ bool WalletModel::isSpent(const COutPoint& outpoint) const void WalletModel::listCoins(std::map<QString, std::vector<COutput> >& mapCoins) const { for (auto& group : wallet->ListCoins()) { - auto& resultGroup = mapCoins[QString::fromStdString(CBitcoinAddress(group.first).ToString())]; + auto& resultGroup = mapCoins[QString::fromStdString(EncodeDestination(group.first))]; for (auto& coin : group.second) { resultGroup.emplace_back(std::move(coin)); } @@ -634,7 +633,7 @@ void WalletModel::loadReceiveRequests(std::vector<std::string>& vReceiveRequests bool WalletModel::saveReceiveRequest(const std::string &sAddress, const int64_t nId, const std::string &sRequest) { - CTxDestination dest = CBitcoinAddress(sAddress).Get(); + CTxDestination dest = DecodeDestination(sAddress); std::stringstream ss; ss << nId; diff --git a/src/rest.cpp b/src/rest.cpp index 154ee04eed..0b2c843d5f 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -190,9 +190,6 @@ static bool rest_headers(HTTPRequest* req, return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: .bin, .hex)"); } } - - // not reached - return true; // continue to process further HTTP reqs on this cxn } static bool rest_block(HTTPRequest* req, @@ -253,9 +250,6 @@ static bool rest_block(HTTPRequest* req, return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: " + AvailableDataFormatsString() + ")"); } } - - // not reached - return true; // continue to process further HTTP reqs on this cxn } static bool rest_block_extended(HTTPRequest* req, const std::string& strURIPart) @@ -292,9 +286,6 @@ static bool rest_chaininfo(HTTPRequest* req, const std::string& strURIPart) return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: json)"); } } - - // not reached - return true; // continue to process further HTTP reqs on this cxn } static bool rest_mempool_info(HTTPRequest* req, const std::string& strURIPart) @@ -317,9 +308,6 @@ static bool rest_mempool_info(HTTPRequest* req, const std::string& strURIPart) return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: json)"); } } - - // not reached - return true; // continue to process further HTTP reqs on this cxn } static bool rest_mempool_contents(HTTPRequest* req, const std::string& strURIPart) @@ -342,9 +330,6 @@ static bool rest_mempool_contents(HTTPRequest* req, const std::string& strURIPar return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: json)"); } } - - // not reached - return true; // continue to process further HTTP reqs on this cxn } static bool rest_tx(HTTPRequest* req, const std::string& strURIPart) @@ -394,9 +379,6 @@ static bool rest_tx(HTTPRequest* req, const std::string& strURIPart) return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: " + AvailableDataFormatsString() + ")"); } } - - // not reached - return true; // continue to process further HTTP reqs on this cxn } static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart) @@ -581,9 +563,6 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart) return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: " + AvailableDataFormatsString() + ")"); } } - - // not reached - return true; // continue to process further HTTP reqs on this cxn } static const struct { diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index ef61e5a55d..46f4f16321 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -343,6 +343,7 @@ std::string EntryDescriptionString() " \"ancestorcount\" : n, (numeric) number of in-mempool ancestor transactions (including this one)\n" " \"ancestorsize\" : n, (numeric) virtual transaction size of in-mempool ancestors (including this one)\n" " \"ancestorfees\" : n, (numeric) modified fees (see above) of in-mempool ancestors (including this one)\n" + " \"wtxid\" : hash, (string) hash of serialized transaction, including witness data\n" " \"depends\" : [ (array) unconfirmed transactions used as inputs for this transaction\n" " \"transactionid\", (string) parent transaction id\n" " ... ]\n"; @@ -363,6 +364,7 @@ void entryToJSON(UniValue &info, const CTxMemPoolEntry &e) info.push_back(Pair("ancestorcount", e.GetCountWithAncestors())); info.push_back(Pair("ancestorsize", e.GetSizeWithAncestors())); info.push_back(Pair("ancestorfees", e.GetModFeesWithAncestors())); + info.push_back(Pair("wtxid", mempool.vTxHashes[e.vTxHashesIdx].first.ToString())); const CTransaction& tx = e.GetTx(); std::set<std::string> setDepends; for (const CTxIn& txin : tx.vin) @@ -812,6 +814,7 @@ static void ApplyStats(CCoinsStats &stats, CHashWriter& ss, const uint256& hash, static bool GetUTXOStats(CCoinsView *view, CCoinsStats &stats) { std::unique_ptr<CCoinsViewCursor> pcursor(view->Cursor()); + assert(pcursor); CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); stats.hashBlock = pcursor->GetBestBlock(); @@ -1515,6 +1518,8 @@ UniValue getchaintxstats(const JSONRPCRequest& request) pindex = chainActive.Tip(); } } + + assert(pindex != nullptr); if (blockcount < 1 || blockcount >= pindex->nHeight) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid block count: should be between 1 and the block's height"); @@ -1532,6 +1537,25 @@ UniValue getchaintxstats(const JSONRPCRequest& request) return ret; } +UniValue savemempool(const JSONRPCRequest& request) +{ + if (request.fHelp || request.params.size() != 0) { + throw std::runtime_error( + "savemempool\n" + "\nDumps the mempool to disk.\n" + "\nExamples:\n" + + HelpExampleCli("savemempool", "") + + HelpExampleRpc("savemempool", "") + ); + } + + if (!DumpMempool()) { + throw JSONRPCError(RPC_MISC_ERROR, "Unable to dump mempool to disk"); + } + + return NullUniValue; +} + static const CRPCCommand commands[] = { // category name actor (function) argNames // --------------------- ------------------------ ----------------------- ---------- @@ -1552,6 +1576,7 @@ static const CRPCCommand commands[] = { "blockchain", "gettxout", &gettxout, {"txid","n","include_mempool"} }, { "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, {} }, { "blockchain", "pruneblockchain", &pruneblockchain, {"height"} }, + { "blockchain", "savemempool", &savemempool, {} }, { "blockchain", "verifychain", &verifychain, {"checklevel","nblocks"} }, { "blockchain", "preciousblock", &preciousblock, {"blockhash"} }, diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index 4179453782..406ad2f6ec 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -115,8 +115,8 @@ static const CRPCConvertParam vRPCConvertParams[] = { "keypoolrefill", 0, "newsize" }, { "getrawmempool", 0, "verbose" }, { "estimatefee", 0, "nblocks" }, - { "estimatesmartfee", 0, "nblocks" }, - { "estimaterawfee", 0, "nblocks" }, + { "estimatesmartfee", 0, "conf_target" }, + { "estimaterawfee", 0, "conf_target" }, { "estimaterawfee", 1, "threshold" }, { "prioritisetransaction", 1, "dummy" }, { "prioritisetransaction", 2, "fee_delta" }, diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 73860f375f..f0ffa07e12 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -176,12 +176,13 @@ UniValue generatetoaddress(const JSONRPCRequest& request) nMaxTries = request.params[2].get_int(); } - CBitcoinAddress address(request.params[1].get_str()); - if (!address.IsValid()) + CTxDestination destination = DecodeDestination(request.params[1].get_str()); + if (!IsValidDestination(destination)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Error: Invalid address"); + } std::shared_ptr<CReserveScript> coinbaseScript = std::make_shared<CReserveScript>(); - coinbaseScript->reserveScript = GetScriptForDestination(address.Get()); + coinbaseScript->reserveScript = GetScriptForDestination(destination); return generateBlocks(coinbaseScript, nGenerate, nMaxTries, false); } @@ -195,7 +196,6 @@ UniValue getmininginfo(const JSONRPCRequest& request) "\nResult:\n" "{\n" " \"blocks\": nnn, (numeric) The current block\n" - " \"currentblocksize\": nnn, (numeric) The last block size\n" " \"currentblockweight\": nnn, (numeric) The last block weight\n" " \"currentblocktx\": nnn, (numeric) The last block transaction\n" " \"difficulty\": xxx.xxxxx (numeric) The current difficulty\n" @@ -214,7 +214,6 @@ UniValue getmininginfo(const JSONRPCRequest& request) UniValue obj(UniValue::VOBJ); obj.push_back(Pair("blocks", (int)chainActive.Height())); - obj.push_back(Pair("currentblocksize", (uint64_t)nLastBlockSize)); obj.push_back(Pair("currentblockweight", (uint64_t)nLastBlockWeight)); obj.push_back(Pair("currentblocktx", (uint64_t)nLastBlockTx)); obj.push_back(Pair("difficulty", (double)GetDifficulty())); @@ -979,7 +978,7 @@ static const CRPCCommand commands[] = { "generating", "generatetoaddress", &generatetoaddress, {"nblocks","address","maxtries"} }, { "util", "estimatefee", &estimatefee, {"nblocks"} }, - { "util", "estimatesmartfee", &estimatesmartfee, {"nblocks", "estimate_mode"} }, + { "util", "estimatesmartfee", &estimatesmartfee, {"conf_target", "estimate_mode"} }, { "hidden", "estimaterawfee", &estimaterawfee, {"conf_target", "threshold"} }, }; diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index 76eefabd29..f8cdf57d14 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -31,94 +31,6 @@ #include <univalue.h> -/** - * @note Do not add or change anything in the information returned by this - * method. `getinfo` exists for backwards-compatibility only. It combines - * information from wildly different sources in the program, which is a mess, - * and is thus planned to be deprecated eventually. - * - * Based on the source of the information, new information should be added to: - * - `getblockchaininfo`, - * - `getnetworkinfo` or - * - `getwalletinfo` - * - * Or alternatively, create a specific query method for the information. - **/ -UniValue getinfo(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 0) - throw std::runtime_error( - "getinfo\n" - "\nDEPRECATED. Returns an object containing various state info.\n" - "\nResult:\n" - "{\n" - " \"deprecation-warning\": \"...\" (string) warning that the getinfo command is deprecated and will be removed in 0.16\n" - " \"version\": xxxxx, (numeric) the server version\n" - " \"protocolversion\": xxxxx, (numeric) the protocol version\n" - " \"walletversion\": xxxxx, (numeric) the wallet version\n" - " \"balance\": xxxxxxx, (numeric) the total bitcoin balance of the wallet\n" - " \"blocks\": xxxxxx, (numeric) the current number of blocks processed in the server\n" - " \"timeoffset\": xxxxx, (numeric) the time offset\n" - " \"connections\": xxxxx, (numeric) the number of connections\n" - " \"proxy\": \"host:port\", (string, optional) the proxy used by the server\n" - " \"difficulty\": xxxxxx, (numeric) the current difficulty\n" - " \"testnet\": true|false, (boolean) if the server is using testnet or not\n" - " \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since Unix epoch) of the oldest pre-generated key in the key pool\n" - " \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n" - " \"unlocked_until\": ttt, (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n" - " \"paytxfee\": x.xxxx, (numeric) the transaction fee set in " + CURRENCY_UNIT + "/kB\n" - " \"relayfee\": x.xxxx, (numeric) minimum relay fee for transactions in " + CURRENCY_UNIT + "/kB\n" - " \"errors\": \"...\" (string) any error messages\n" - "}\n" - "\nExamples:\n" - + HelpExampleCli("getinfo", "") - + HelpExampleRpc("getinfo", "") - ); - -#ifdef ENABLE_WALLET - CWallet * const pwallet = GetWalletForJSONRPCRequest(request); - - LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : nullptr); -#else - LOCK(cs_main); -#endif - - proxyType proxy; - GetProxy(NET_IPV4, proxy); - - UniValue obj(UniValue::VOBJ); - obj.push_back(Pair("deprecation-warning", "WARNING: getinfo is deprecated and will be fully removed in 0.16." - " Projects should transition to using getblockchaininfo, getnetworkinfo, and getwalletinfo before upgrading to 0.16")); - obj.push_back(Pair("version", CLIENT_VERSION)); - obj.push_back(Pair("protocolversion", PROTOCOL_VERSION)); -#ifdef ENABLE_WALLET - if (pwallet) { - obj.push_back(Pair("walletversion", pwallet->GetVersion())); - obj.push_back(Pair("balance", ValueFromAmount(pwallet->GetBalance()))); - } -#endif - obj.push_back(Pair("blocks", (int)chainActive.Height())); - obj.push_back(Pair("timeoffset", GetTimeOffset())); - if(g_connman) - obj.push_back(Pair("connections", (int)g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL))); - obj.push_back(Pair("proxy", (proxy.IsValid() ? proxy.proxy.ToStringIPPort() : std::string()))); - obj.push_back(Pair("difficulty", (double)GetDifficulty())); - obj.push_back(Pair("testnet", Params().NetworkIDString() == CBaseChainParams::TESTNET)); -#ifdef ENABLE_WALLET - if (pwallet) { - obj.push_back(Pair("keypoololdest", pwallet->GetOldestKeyPoolTime())); - obj.push_back(Pair("keypoolsize", (int)pwallet->GetKeyPoolSize())); - } - if (pwallet && pwallet->IsCrypted()) { - obj.push_back(Pair("unlocked_until", pwallet->nRelockTime)); - } - obj.push_back(Pair("paytxfee", ValueFromAmount(payTxFee.GetFeePerK()))); -#endif - obj.push_back(Pair("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK()))); - obj.push_back(Pair("errors", GetWarnings("statusbar"))); - return obj; -} - #ifdef ENABLE_WALLET class DescribeAddressVisitor : public boost::static_visitor<UniValue> { @@ -152,8 +64,9 @@ public: obj.push_back(Pair("script", GetTxnOutputType(whichType))); obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end()))); UniValue a(UniValue::VARR); - for (const CTxDestination& addr : addresses) - a.push_back(CBitcoinAddress(addr).ToString()); + for (const CTxDestination& addr : addresses) { + a.push_back(EncodeDestination(addr)); + } obj.push_back(Pair("addresses", a)); if (whichType == TX_MULTISIG) obj.push_back(Pair("sigsrequired", nRequired)); @@ -207,15 +120,14 @@ UniValue validateaddress(const JSONRPCRequest& request) LOCK(cs_main); #endif - CBitcoinAddress address(request.params[0].get_str()); - bool isValid = address.IsValid(); + CTxDestination dest = DecodeDestination(request.params[0].get_str()); + bool isValid = IsValidDestination(dest); UniValue ret(UniValue::VOBJ); ret.push_back(Pair("isvalid", isValid)); if (isValid) { - CTxDestination dest = address.Get(); - std::string currentAddress = address.ToString(); + std::string currentAddress = EncodeDestination(dest); ret.push_back(Pair("address", currentAddress)); CScript scriptPubKey = GetScriptForDestination(dest); @@ -230,10 +142,10 @@ UniValue validateaddress(const JSONRPCRequest& request) if (pwallet && pwallet->mapAddressBook.count(dest)) { ret.push_back(Pair("account", pwallet->mapAddressBook[dest].name)); } - CKeyID keyID; if (pwallet) { const auto& meta = pwallet->mapKeyMetadata; - auto it = address.GetKeyID(keyID) ? meta.find(keyID) : meta.end(); + const CKeyID *keyID = boost::get<CKeyID>(&dest); + auto it = keyID ? meta.find(*keyID) : meta.end(); if (it == meta.end()) { it = meta.find(CScriptID(scriptPubKey)); } @@ -277,16 +189,15 @@ CScript _createmultisig_redeemScript(CWallet * const pwallet, const UniValue& pa const std::string& ks = keys[i].get_str(); #ifdef ENABLE_WALLET // Case 1: Bitcoin address and we have full public key: - CBitcoinAddress address(ks); - if (pwallet && address.IsValid()) { - CKeyID keyID; - if (!address.GetKeyID(keyID)) - throw std::runtime_error( - strprintf("%s does not refer to a key",ks)); + CTxDestination dest = DecodeDestination(ks); + if (pwallet && IsValidDestination(dest)) { + const CKeyID *keyID = boost::get<CKeyID>(&dest); + if (!keyID) { + throw std::runtime_error(strprintf("%s does not refer to a key", ks)); + } CPubKey vchPubKey; - if (!pwallet->GetPubKey(keyID, vchPubKey)) { - throw std::runtime_error( - strprintf("no full public key for address %s",ks)); + if (!pwallet->GetPubKey(*keyID, vchPubKey)) { + throw std::runtime_error(strprintf("no full public key for address %s", ks)); } if (!vchPubKey.IsFullyValid()) throw std::runtime_error(" Invalid public key: "+ks); @@ -357,10 +268,9 @@ UniValue createmultisig(const JSONRPCRequest& request) // Construct using pay-to-script-hash: CScript inner = _createmultisig_redeemScript(pwallet, request.params); CScriptID innerID(inner); - CBitcoinAddress address(innerID); UniValue result(UniValue::VOBJ); - result.push_back(Pair("address", address.ToString())); + result.push_back(Pair("address", EncodeDestination(innerID))); result.push_back(Pair("redeemScript", HexStr(inner.begin(), inner.end()))); return result; @@ -395,13 +305,15 @@ UniValue verifymessage(const JSONRPCRequest& request) std::string strSign = request.params[1].get_str(); std::string strMessage = request.params[2].get_str(); - CBitcoinAddress addr(strAddress); - if (!addr.IsValid()) + CTxDestination destination = DecodeDestination(strAddress); + if (!IsValidDestination(destination)) { throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address"); + } - CKeyID keyID; - if (!addr.GetKeyID(keyID)) + const CKeyID *keyID = boost::get<CKeyID>(&destination); + if (!keyID) { throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key"); + } bool fInvalid = false; std::vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid); @@ -417,7 +329,7 @@ UniValue verifymessage(const JSONRPCRequest& request) if (!pubkey.RecoverCompact(ss.GetHash(), vchSig)) return false; - return (pubkey.GetID() == keyID); + return (pubkey.GetID() == *keyID); } UniValue signmessagewithprivkey(const JSONRPCRequest& request) @@ -459,7 +371,7 @@ UniValue signmessagewithprivkey(const JSONRPCRequest& request) if (!key.SignCompact(ss.GetHash(), vchSig)) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed"); - return EncodeBase64(&vchSig[0], vchSig.size()); + return EncodeBase64(vchSig.data(), vchSig.size()); } UniValue setmocktime(const JSONRPCRequest& request) @@ -651,7 +563,6 @@ UniValue echo(const JSONRPCRequest& request) static const CRPCCommand commands[] = { // category name actor (function) argNames // --------------------- ------------------------ ----------------------- ---------- - { "control", "getinfo", &getinfo, {} }, /* uses wallet if enabled */ { "control", "getmemoryinfo", &getmemoryinfo, {"mode"} }, { "util", "validateaddress", &validateaddress, {"address"} }, /* uses wallet if enabled */ { "util", "createmultisig", &createmultisig, {"nrequired","keys"} }, diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 27daefaf5a..a0322f67b4 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -384,7 +384,7 @@ UniValue createrawtransaction(const JSONRPCRequest& request) rawTx.vin.push_back(in); } - std::set<CBitcoinAddress> setAddress; + std::set<CTxDestination> destinations; std::vector<std::string> addrList = sendTo.getKeys(); for (const std::string& name_ : addrList) { @@ -394,15 +394,16 @@ UniValue createrawtransaction(const JSONRPCRequest& request) CTxOut out(0, CScript() << OP_RETURN << data); rawTx.vout.push_back(out); } else { - CBitcoinAddress address(name_); - if (!address.IsValid()) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ")+name_); + CTxDestination destination = DecodeDestination(name_); + if (!IsValidDestination(destination)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ") + name_); + } - if (setAddress.count(address)) - throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ")+name_); - setAddress.insert(address); + if (!destinations.insert(destination).second) { + throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + name_); + } - CScript scriptPubKey = GetScriptForDestination(address.Get()); + CScript scriptPubKey = GetScriptForDestination(destination); CAmount nAmount = AmountFromValue(sendTo[name_]); CTxOut out(nAmount, scriptPubKey); @@ -529,7 +530,7 @@ UniValue decodescript(const JSONRPCRequest& request) if (type.isStr() && type.get_str() != "scripthash") { // P2SH cannot be wrapped in a P2SH. If this script is already a P2SH, // don't return the address for a P2SH of the P2SH. - r.push_back(Pair("p2sh", CBitcoinAddress(CScriptID(script)).ToString())); + r.push_back(Pair("p2sh", EncodeDestination(CScriptID(script)))); } return r; diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index f9716dfc66..7315500e3b 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -1366,7 +1366,7 @@ static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, stack = std::vector<std::vector<unsigned char> >(witness.stack.begin(), witness.stack.end() - 1); uint256 hashScriptPubKey; CSHA256().Write(&scriptPubKey[0], scriptPubKey.size()).Finalize(hashScriptPubKey.begin()); - if (memcmp(hashScriptPubKey.begin(), &program[0], 32)) { + if (memcmp(hashScriptPubKey.begin(), program.data(), 32)) { return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH); } } else if (program.size() == 20) { diff --git a/src/script/standard.cpp b/src/script/standard.cpp index 2aed393921..b6e2232ab4 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -317,3 +317,7 @@ CScript GetScriptForWitness(const CScript& redeemscript) ret << OP_0 << ToByteVector(hash); return ret; } + +bool IsValidDestination(const CTxDestination& dest) { + return dest.which() != 0; +} diff --git a/src/script/standard.h b/src/script/standard.h index 7619192264..8df143a3a3 100644 --- a/src/script/standard.h +++ b/src/script/standard.h @@ -77,10 +77,13 @@ public: * * CNoDestination: no destination set * * CKeyID: TX_PUBKEYHASH destination * * CScriptID: TX_SCRIPTHASH destination - * A CTxDestination is the internal data type encoded in a CBitcoinAddress + * A CTxDestination is the internal data type encoded in a bitcoin address */ typedef boost::variant<CNoDestination, CKeyID, CScriptID> CTxDestination; +/** Check whether a CTxDestination is a CNoDestination. */ +bool IsValidDestination(const CTxDestination& dest); + /** Get the name of a txnouttype as a C string, or nullptr if unknown. */ const char* GetTxnOutputType(txnouttype t); diff --git a/src/support/cleanse.cpp b/src/support/cleanse.cpp index a2141b2449..95899c9f02 100644 --- a/src/support/cleanse.cpp +++ b/src/support/cleanse.cpp @@ -5,9 +5,35 @@ #include "cleanse.h" -#include <openssl/crypto.h> +#include <cstring> +/* Compilers have a bad habit of removing "superfluous" memset calls that + * are trying to zero memory. For example, when memset()ing a buffer and + * then free()ing it, the compiler might decide that the memset is + * unobservable and thus can be removed. + * + * Previously we used OpenSSL which tried to stop this by a) implementing + * memset in assembly on x86 and b) putting the function in its own file + * for other platforms. + * + * This change removes those tricks in favour of using asm directives to + * scare the compiler away. As best as our compiler folks can tell, this is + * sufficient and will continue to be so. + * + * Adam Langley <agl@google.com> + * Commit: ad1907fe73334d6c696c8539646c21b11178f20f + * BoringSSL (LICENSE: ISC) + */ void memory_cleanse(void *ptr, size_t len) { - OPENSSL_cleanse(ptr, len); + std::memset(ptr, 0, len); + + /* As best as we can tell, this is sufficient to break any optimisations that + might try to eliminate "superfluous" memsets. If there's an easy way to + detect memset_s, it would be better to use that. */ +#if defined(_MSC_VER) + __asm; +#else + __asm__ __volatile__("" : : "r"(ptr) : "memory"); +#endif } diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp index ffbeeb7d91..b88ad5ed1b 100644 --- a/src/test/DoS_tests.cpp +++ b/src/test/DoS_tests.cpp @@ -50,26 +50,26 @@ BOOST_AUTO_TEST_CASE(DoS_banning) CAddress addr1(ip(0xa0b0c001), NODE_NONE); CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 0, 0, CAddress(), "", true); dummyNode1.SetSendVersion(PROTOCOL_VERSION); - GetNodeSignals().InitializeNode(&dummyNode1, *connman); + peerLogic->InitializeNode(&dummyNode1); dummyNode1.nVersion = 1; dummyNode1.fSuccessfullyConnected = true; Misbehaving(dummyNode1.GetId(), 100); // Should get banned - SendMessages(&dummyNode1, *connman, interruptDummy); + peerLogic->SendMessages(&dummyNode1, interruptDummy); BOOST_CHECK(connman->IsBanned(addr1)); 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, 1, 1, CAddress(), "", true); dummyNode2.SetSendVersion(PROTOCOL_VERSION); - GetNodeSignals().InitializeNode(&dummyNode2, *connman); + peerLogic->InitializeNode(&dummyNode2); dummyNode2.nVersion = 1; dummyNode2.fSuccessfullyConnected = true; Misbehaving(dummyNode2.GetId(), 50); - SendMessages(&dummyNode2, *connman, interruptDummy); + peerLogic->SendMessages(&dummyNode2, interruptDummy); BOOST_CHECK(!connman->IsBanned(addr2)); // 2 not banned yet... BOOST_CHECK(connman->IsBanned(addr1)); // ... but 1 still should be Misbehaving(dummyNode2.GetId(), 50); - SendMessages(&dummyNode2, *connman, interruptDummy); + peerLogic->SendMessages(&dummyNode2, interruptDummy); BOOST_CHECK(connman->IsBanned(addr2)); } @@ -82,17 +82,17 @@ BOOST_AUTO_TEST_CASE(DoS_banscore) CAddress addr1(ip(0xa0b0c001), NODE_NONE); CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 3, 1, CAddress(), "", true); dummyNode1.SetSendVersion(PROTOCOL_VERSION); - GetNodeSignals().InitializeNode(&dummyNode1, *connman); + peerLogic->InitializeNode(&dummyNode1); dummyNode1.nVersion = 1; dummyNode1.fSuccessfullyConnected = true; Misbehaving(dummyNode1.GetId(), 100); - SendMessages(&dummyNode1, *connman, interruptDummy); + peerLogic->SendMessages(&dummyNode1, interruptDummy); BOOST_CHECK(!connman->IsBanned(addr1)); Misbehaving(dummyNode1.GetId(), 10); - SendMessages(&dummyNode1, *connman, interruptDummy); + peerLogic->SendMessages(&dummyNode1, interruptDummy); BOOST_CHECK(!connman->IsBanned(addr1)); Misbehaving(dummyNode1.GetId(), 1); - SendMessages(&dummyNode1, *connman, interruptDummy); + peerLogic->SendMessages(&dummyNode1, interruptDummy); BOOST_CHECK(connman->IsBanned(addr1)); gArgs.ForceSetArg("-banscore", std::to_string(DEFAULT_BANSCORE_THRESHOLD)); } @@ -108,12 +108,12 @@ BOOST_AUTO_TEST_CASE(DoS_bantime) CAddress addr(ip(0xa0b0c001), NODE_NONE); CNode dummyNode(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr, 4, 4, CAddress(), "", true); dummyNode.SetSendVersion(PROTOCOL_VERSION); - GetNodeSignals().InitializeNode(&dummyNode, *connman); + peerLogic->InitializeNode(&dummyNode); dummyNode.nVersion = 1; dummyNode.fSuccessfullyConnected = true; Misbehaving(dummyNode.GetId(), 100); - SendMessages(&dummyNode, *connman, interruptDummy); + peerLogic->SendMessages(&dummyNode, interruptDummy); BOOST_CHECK(connman->IsBanned(addr)); SetMockTime(nStartTime+60*60); diff --git a/src/test/README.md b/src/test/README.md index eeb04c6ffa..dbaa9c27f3 100644 --- a/src/test/README.md +++ b/src/test/README.md @@ -5,7 +5,10 @@ and tests weren't explicitly disabled. After configuring, they can be run with `make check`. -To run the bitcoind tests manually, launch `src/test/test_bitcoin`. +To run the bitcoind tests manually, launch `src/test/test_bitcoin`. To recompile +after a test file was modified, run `make` and then run the test again. If you +modify a non-test file, use `make -C src/test` to recompile only what's needed +to run the bitcoind tests. To add more bitcoind tests, add `BOOST_AUTO_TEST_CASE` functions to the existing .cpp files in the `test/` directory or add new .cpp files that diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp index ee633249e9..4829590c54 100644 --- a/src/test/base58_tests.cpp +++ b/src/test/base58_tests.cpp @@ -121,7 +121,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse) { UniValue tests = read_json(std::string(json_tests::base58_keys_valid, json_tests::base58_keys_valid + sizeof(json_tests::base58_keys_valid))); CBitcoinSecret secret; - CBitcoinAddress addr; + CTxDestination destination; SelectParams(CBaseChainParams::MAIN); for (unsigned int idx = 0; idx < tests.size(); idx++) { @@ -145,7 +145,6 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse) { bool isCompressed = find_value(metadata, "isCompressed").get_bool(); // Must be valid private key - // Note: CBitcoinSecret::SetString tests isValid, whereas CBitcoinAddress does not! BOOST_CHECK_MESSAGE(secret.SetString(exp_base58string), "!SetString:"+ strTest); BOOST_CHECK_MESSAGE(secret.IsValid(), "!IsValid:" + strTest); CKey privkey = secret.GetKey(); @@ -153,18 +152,17 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse) BOOST_CHECK_MESSAGE(privkey.size() == exp_payload.size() && std::equal(privkey.begin(), privkey.end(), exp_payload.begin()), "key mismatch:" + strTest); // Private key must be invalid public key - addr.SetString(exp_base58string); - BOOST_CHECK_MESSAGE(!addr.IsValid(), "IsValid privkey as pubkey:" + strTest); + destination = DecodeDestination(exp_base58string); + BOOST_CHECK_MESSAGE(!IsValidDestination(destination), "IsValid privkey as pubkey:" + strTest); } else { std::string exp_addrType = find_value(metadata, "addrType").get_str(); // "script" or "pubkey" // Must be valid public key - BOOST_CHECK_MESSAGE(addr.SetString(exp_base58string), "SetString:" + strTest); - BOOST_CHECK_MESSAGE(addr.IsValid(), "!IsValid:" + strTest); - BOOST_CHECK_MESSAGE(addr.IsScript() == (exp_addrType == "script"), "isScript mismatch" + strTest); - CTxDestination dest = addr.Get(); - BOOST_CHECK_MESSAGE(boost::apply_visitor(TestAddrTypeVisitor(exp_addrType), dest), "addrType mismatch" + strTest); + destination = DecodeDestination(exp_base58string); + BOOST_CHECK_MESSAGE(IsValidDestination(destination), "!IsValid:" + strTest); + BOOST_CHECK_MESSAGE((boost::get<CScriptID>(&destination) != nullptr) == (exp_addrType == "script"), "isScript mismatch" + strTest); + BOOST_CHECK_MESSAGE(boost::apply_visitor(TestAddrTypeVisitor(exp_addrType), destination), "addrType mismatch" + strTest); // Public key must be invalid private key secret.SetString(exp_base58string); @@ -226,17 +224,11 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen) BOOST_ERROR("Bad addrtype: " << strTest); continue; } - CBitcoinAddress addrOut; - BOOST_CHECK_MESSAGE(addrOut.Set(dest), "encode dest: " + strTest); - BOOST_CHECK_MESSAGE(addrOut.ToString() == exp_base58string, "mismatch: " + strTest); + std::string address = EncodeDestination(dest); + BOOST_CHECK_MESSAGE(address == exp_base58string, "mismatch: " + strTest); } } - // Visiting a CNoDestination must fail - CBitcoinAddress dummyAddr; - CTxDestination nodest = CNoDestination(); - BOOST_CHECK(!dummyAddr.Set(nodest)); - SelectParams(CBaseChainParams::MAIN); } @@ -245,7 +237,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_invalid) { UniValue tests = read_json(std::string(json_tests::base58_keys_invalid, json_tests::base58_keys_invalid + sizeof(json_tests::base58_keys_invalid))); // Negative testcases CBitcoinSecret secret; - CBitcoinAddress addr; + CTxDestination destination; for (unsigned int idx = 0; idx < tests.size(); idx++) { UniValue test = tests[idx]; @@ -258,8 +250,8 @@ BOOST_AUTO_TEST_CASE(base58_keys_invalid) std::string exp_base58string = test[0].get_str(); // must be invalid as public and as private key - addr.SetString(exp_base58string); - BOOST_CHECK_MESSAGE(!addr.IsValid(), "IsValid pubkey:" + strTest); + destination = DecodeDestination(exp_base58string); + BOOST_CHECK_MESSAGE(!IsValidDestination(destination), "IsValid pubkey:" + strTest); secret.SetString(exp_base58string); BOOST_CHECK_MESSAGE(!secret.IsValid(), "IsValid privkey:" + strTest); } diff --git a/src/test/bip32_tests.cpp b/src/test/bip32_tests.cpp index c851ab2849..e123c26ad0 100644 --- a/src/test/bip32_tests.cpp +++ b/src/test/bip32_tests.cpp @@ -91,7 +91,7 @@ void RunTest(const TestVector &test) { std::vector<unsigned char> seed = ParseHex(test.strHexMaster); CExtKey key; CExtPubKey pubkey; - key.SetMaster(&seed[0], seed.size()); + key.SetMaster(seed.data(), seed.size()); pubkey = key.Neuter(); for (const TestDerivation &derive : test.vDerive) { unsigned char data[74]; diff --git a/src/test/bloom_tests.cpp b/src/test/bloom_tests.cpp index 2085b5cb2b..9274ceefcb 100644 --- a/src/test/bloom_tests.cpp +++ b/src/test/bloom_tests.cpp @@ -154,8 +154,8 @@ BOOST_AUTO_TEST_CASE(bloom_match) COutPoint prevOutPoint(uint256S("0x90c122d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 0); { std::vector<unsigned char> data(32 + sizeof(unsigned int)); - memcpy(&data[0], prevOutPoint.hash.begin(), 32); - memcpy(&data[32], &prevOutPoint.n, sizeof(unsigned int)); + memcpy(data.data(), prevOutPoint.hash.begin(), 32); + memcpy(data.data()+32, &prevOutPoint.n, sizeof(unsigned int)); filter.insert(data); } BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match manually serialized COutPoint"); diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp index 391ad14ffa..c748b2448c 100644 --- a/src/test/crypto_tests.cpp +++ b/src/test/crypto_tests.cpp @@ -58,12 +58,12 @@ void TestRIPEMD160(const std::string &in, const std::string &hexout) { TestVecto void TestHMACSHA256(const std::string &hexkey, const std::string &hexin, const std::string &hexout) { std::vector<unsigned char> key = ParseHex(hexkey); - TestVector(CHMAC_SHA256(&key[0], key.size()), ParseHex(hexin), ParseHex(hexout)); + TestVector(CHMAC_SHA256(key.data(), key.size()), ParseHex(hexin), ParseHex(hexout)); } void TestHMACSHA512(const std::string &hexkey, const std::string &hexin, const std::string &hexout) { std::vector<unsigned char> key = ParseHex(hexkey); - TestVector(CHMAC_SHA512(&key[0], key.size()), ParseHex(hexin), ParseHex(hexout)); + TestVector(CHMAC_SHA512(key.data(), key.size()), ParseHex(hexin), ParseHex(hexout)); } void TestAES128(const std::string &hexkey, const std::string &hexin, const std::string &hexout) @@ -76,13 +76,13 @@ void TestAES128(const std::string &hexkey, const std::string &hexin, const std:: assert(key.size() == 16); assert(in.size() == 16); assert(correctout.size() == 16); - AES128Encrypt enc(&key[0]); + AES128Encrypt enc(key.data()); buf.resize(correctout.size()); buf2.resize(correctout.size()); - enc.Encrypt(&buf[0], &in[0]); + enc.Encrypt(buf.data(), in.data()); BOOST_CHECK_EQUAL(HexStr(buf), HexStr(correctout)); - AES128Decrypt dec(&key[0]); - dec.Decrypt(&buf2[0], &buf[0]); + AES128Decrypt dec(key.data()); + dec.Decrypt(buf2.data(), buf.data()); BOOST_CHECK_EQUAL(HexStr(buf2), HexStr(in)); } @@ -96,12 +96,12 @@ void TestAES256(const std::string &hexkey, const std::string &hexin, const std:: assert(key.size() == 32); assert(in.size() == 16); assert(correctout.size() == 16); - AES256Encrypt enc(&key[0]); + AES256Encrypt enc(key.data()); buf.resize(correctout.size()); - enc.Encrypt(&buf[0], &in[0]); + enc.Encrypt(buf.data(), in.data()); BOOST_CHECK(buf == correctout); - AES256Decrypt dec(&key[0]); - dec.Decrypt(&buf[0], &buf[0]); + AES256Decrypt dec(key.data()); + dec.Decrypt(buf.data(), buf.data()); BOOST_CHECK(buf == in); } @@ -114,16 +114,16 @@ void TestAES128CBC(const std::string &hexkey, const std::string &hexiv, bool pad std::vector<unsigned char> realout(in.size() + AES_BLOCKSIZE); // Encrypt the plaintext and verify that it equals the cipher - AES128CBCEncrypt enc(&key[0], &iv[0], pad); - int size = enc.Encrypt(&in[0], in.size(), &realout[0]); + AES128CBCEncrypt enc(key.data(), iv.data(), pad); + int size = enc.Encrypt(in.data(), in.size(), realout.data()); realout.resize(size); BOOST_CHECK(realout.size() == correctout.size()); BOOST_CHECK_MESSAGE(realout == correctout, HexStr(realout) + std::string(" != ") + hexout); // Decrypt the cipher and verify that it equals the plaintext std::vector<unsigned char> decrypted(correctout.size()); - AES128CBCDecrypt dec(&key[0], &iv[0], pad); - size = dec.Decrypt(&correctout[0], correctout.size(), &decrypted[0]); + AES128CBCDecrypt dec(key.data(), iv.data(), pad); + size = dec.Decrypt(correctout.data(), correctout.size(), decrypted.data()); decrypted.resize(size); BOOST_CHECK(decrypted.size() == in.size()); BOOST_CHECK_MESSAGE(decrypted == in, HexStr(decrypted) + std::string(" != ") + hexin); @@ -133,12 +133,12 @@ void TestAES128CBC(const std::string &hexkey, const std::string &hexiv, bool pad { std::vector<unsigned char> sub(i, in.end()); std::vector<unsigned char> subout(sub.size() + AES_BLOCKSIZE); - int _size = enc.Encrypt(&sub[0], sub.size(), &subout[0]); + int _size = enc.Encrypt(sub.data(), sub.size(), subout.data()); if (_size != 0) { subout.resize(_size); std::vector<unsigned char> subdecrypted(subout.size()); - _size = dec.Decrypt(&subout[0], subout.size(), &subdecrypted[0]); + _size = dec.Decrypt(subout.data(), subout.size(), subdecrypted.data()); subdecrypted.resize(_size); BOOST_CHECK(decrypted.size() == in.size()); BOOST_CHECK_MESSAGE(subdecrypted == sub, HexStr(subdecrypted) + std::string(" != ") + HexStr(sub)); @@ -155,16 +155,16 @@ void TestAES256CBC(const std::string &hexkey, const std::string &hexiv, bool pad std::vector<unsigned char> realout(in.size() + AES_BLOCKSIZE); // Encrypt the plaintext and verify that it equals the cipher - AES256CBCEncrypt enc(&key[0], &iv[0], pad); - int size = enc.Encrypt(&in[0], in.size(), &realout[0]); + AES256CBCEncrypt enc(key.data(), iv.data(), pad); + int size = enc.Encrypt(in.data(), in.size(), realout.data()); realout.resize(size); BOOST_CHECK(realout.size() == correctout.size()); BOOST_CHECK_MESSAGE(realout == correctout, HexStr(realout) + std::string(" != ") + hexout); // Decrypt the cipher and verify that it equals the plaintext std::vector<unsigned char> decrypted(correctout.size()); - AES256CBCDecrypt dec(&key[0], &iv[0], pad); - size = dec.Decrypt(&correctout[0], correctout.size(), &decrypted[0]); + AES256CBCDecrypt dec(key.data(), iv.data(), pad); + size = dec.Decrypt(correctout.data(), correctout.size(), decrypted.data()); decrypted.resize(size); BOOST_CHECK(decrypted.size() == in.size()); BOOST_CHECK_MESSAGE(decrypted == in, HexStr(decrypted) + std::string(" != ") + hexin); @@ -174,12 +174,12 @@ void TestAES256CBC(const std::string &hexkey, const std::string &hexiv, bool pad { std::vector<unsigned char> sub(i, in.end()); std::vector<unsigned char> subout(sub.size() + AES_BLOCKSIZE); - int _size = enc.Encrypt(&sub[0], sub.size(), &subout[0]); + int _size = enc.Encrypt(sub.data(), sub.size(), subout.data()); if (_size != 0) { subout.resize(_size); std::vector<unsigned char> subdecrypted(subout.size()); - _size = dec.Decrypt(&subout[0], subout.size(), &subdecrypted[0]); + _size = dec.Decrypt(subout.data(), subout.size(), subdecrypted.data()); subdecrypted.resize(_size); BOOST_CHECK(decrypted.size() == in.size()); BOOST_CHECK_MESSAGE(subdecrypted == sub, HexStr(subdecrypted) + std::string(" != ") + HexStr(sub)); diff --git a/src/test/getarg_tests.cpp b/src/test/getarg_tests.cpp index 18a7e59933..40f0ecd5f1 100644 --- a/src/test/getarg_tests.cpp +++ b/src/test/getarg_tests.cpp @@ -27,7 +27,7 @@ static void ResetArgs(const std::string& strArg) for (std::string& s : vecArg) vecChar.push_back(s.c_str()); - gArgs.ParseParameters(vecChar.size(), &vecChar[0]); + gArgs.ParseParameters(vecChar.size(), vecChar.data()); } BOOST_AUTO_TEST_CASE(boolarg) diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp index 559b3caf1c..91c0175412 100644 --- a/src/test/key_tests.cpp +++ b/src/test/key_tests.cpp @@ -16,17 +16,16 @@ #include <boost/test/unit_test.hpp> -static const std::string strSecret1 ("5HxWvvfubhXpYYpS3tJkw6fq9jE9j18THftkZjHHfmFiWtmAbrj"); -static const std::string strSecret2 ("5KC4ejrDjv152FGwP386VD1i2NYc5KkfSMyv1nGy1VGDxGHqVY3"); -static const std::string strSecret1C ("Kwr371tjA9u2rFSMZjTNun2PXXP3WPZu2afRHTcta6KxEUdm1vEw"); -static const std::string strSecret2C ("L3Hq7a8FEQwJkW1M2GNKDW28546Vp5miewcCzSqUD9kCAXrJdS3g"); -static const CBitcoinAddress addr1 ("1QFqqMUD55ZV3PJEJZtaKCsQmjLT6JkjvJ"); -static const CBitcoinAddress addr2 ("1F5y5E5FMc5YzdJtB9hLaUe43GDxEKXENJ"); -static const CBitcoinAddress addr1C("1NoJrossxPBKfCHuJXT4HadJrXRE9Fxiqs"); -static const CBitcoinAddress addr2C("1CRj2HyM1CXWzHAXLQtiGLyggNT9WQqsDs"); +static const std::string strSecret1 = "5HxWvvfubhXpYYpS3tJkw6fq9jE9j18THftkZjHHfmFiWtmAbrj"; +static const std::string strSecret2 = "5KC4ejrDjv152FGwP386VD1i2NYc5KkfSMyv1nGy1VGDxGHqVY3"; +static const std::string strSecret1C = "Kwr371tjA9u2rFSMZjTNun2PXXP3WPZu2afRHTcta6KxEUdm1vEw"; +static const std::string strSecret2C = "L3Hq7a8FEQwJkW1M2GNKDW28546Vp5miewcCzSqUD9kCAXrJdS3g"; +static const std::string addr1 = "1QFqqMUD55ZV3PJEJZtaKCsQmjLT6JkjvJ"; +static const std::string addr2 = "1F5y5E5FMc5YzdJtB9hLaUe43GDxEKXENJ"; +static const std::string addr1C = "1NoJrossxPBKfCHuJXT4HadJrXRE9Fxiqs"; +static const std::string addr2C = "1CRj2HyM1CXWzHAXLQtiGLyggNT9WQqsDs"; - -static const std::string strAddressBad("1HV9Lc3sNHZxwj4Zk6fB38tEmBryq2cBiF"); +static const std::string strAddressBad = "1HV9Lc3sNHZxwj4Zk6fB38tEmBryq2cBiF"; BOOST_FIXTURE_TEST_SUITE(key_tests, BasicTestingSetup) @@ -74,10 +73,10 @@ BOOST_AUTO_TEST_CASE(key_test1) BOOST_CHECK(!key2C.VerifyPubKey(pubkey2)); BOOST_CHECK(key2C.VerifyPubKey(pubkey2C)); - BOOST_CHECK(addr1.Get() == CTxDestination(pubkey1.GetID())); - BOOST_CHECK(addr2.Get() == CTxDestination(pubkey2.GetID())); - BOOST_CHECK(addr1C.Get() == CTxDestination(pubkey1C.GetID())); - BOOST_CHECK(addr2C.Get() == CTxDestination(pubkey2C.GetID())); + BOOST_CHECK(DecodeDestination(addr1) == CTxDestination(pubkey1.GetID())); + BOOST_CHECK(DecodeDestination(addr2) == CTxDestination(pubkey2.GetID())); + BOOST_CHECK(DecodeDestination(addr1C) == CTxDestination(pubkey1C.GetID())); + BOOST_CHECK(DecodeDestination(addr2C) == CTxDestination(pubkey2C.GetID())); for (int n=0; n<16; n++) { diff --git a/src/test/skiplist_tests.cpp b/src/test/skiplist_tests.cpp index e3654e67ad..164cbd873f 100644 --- a/src/test/skiplist_tests.cpp +++ b/src/test/skiplist_tests.cpp @@ -39,7 +39,7 @@ BOOST_AUTO_TEST_CASE(skiplist_test) BOOST_CHECK(vIndex[SKIPLIST_LENGTH - 1].GetAncestor(from) == &vIndex[from]); BOOST_CHECK(vIndex[from].GetAncestor(to) == &vIndex[to]); - BOOST_CHECK(vIndex[from].GetAncestor(0) == &vIndex[0]); + BOOST_CHECK(vIndex[from].GetAncestor(0) == vIndex.data()); } } @@ -64,7 +64,7 @@ BOOST_AUTO_TEST_CASE(getlocator_test) for (unsigned int i=0; i<vBlocksSide.size(); i++) { vHashSide[i] = ArithToUint256(i + 50000 + (arith_uint256(1) << 128)); // Add 1<<128 to the hashes, so GetLow64() still returns the height. vBlocksSide[i].nHeight = i + 50000; - vBlocksSide[i].pprev = i ? &vBlocksSide[i - 1] : &vBlocksMain[49999]; + vBlocksSide[i].pprev = i ? &vBlocksSide[i - 1] : (vBlocksMain.data()+49999); vBlocksSide[i].phashBlock = &vHashSide[i]; vBlocksSide[i].BuildSkip(); BOOST_CHECK_EQUAL((int)UintToArith256(vBlocksSide[i].GetBlockHash()).GetLow64(), vBlocksSide[i].nHeight); diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index 194f62ca11..045655983c 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -48,7 +48,6 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName) BasicTestingSetup::~BasicTestingSetup() { ECC_Stop(); - g_connman.reset(); } TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(chainName) @@ -86,16 +85,17 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha threadGroup.create_thread(&ThreadScriptCheck); g_connman = std::unique_ptr<CConnman>(new CConnman(0x1337, 0x1337)); // Deterministic randomness for tests. connman = g_connman.get(); - RegisterNodeSignals(GetNodeSignals()); + peerLogic.reset(new PeerLogicValidation(connman)); } TestingSetup::~TestingSetup() { - UnregisterNodeSignals(GetNodeSignals()); threadGroup.interrupt_all(); threadGroup.join_all(); GetMainSignals().FlushBackgroundCallbacks(); GetMainSignals().UnregisterBackgroundSignalScheduler(); + g_connman.reset(); + peerLogic.reset(); UnloadBlockIndex(); delete pcoinsTip; delete pcoinsdbview; diff --git a/src/test/test_bitcoin.h b/src/test/test_bitcoin.h index 2ddac2f076..6ada96f887 100644 --- a/src/test/test_bitcoin.h +++ b/src/test/test_bitcoin.h @@ -49,12 +49,14 @@ struct BasicTestingSetup { * Included are data directory, coins database, script check threads setup. */ class CConnman; +class PeerLogicValidation; struct TestingSetup: public BasicTestingSetup { CCoinsViewDB *pcoinsdbview; fs::path pathTemp; boost::thread_group threadGroup; CConnman* connman; CScheduler scheduler; + std::unique_ptr<PeerLogicValidation> peerLogic; explicit TestingSetup(const std::string& chainName = CBaseChainParams::MAIN); ~TestingSetup(); diff --git a/src/test/test_bitcoin_fuzzy.cpp b/src/test/test_bitcoin_fuzzy.cpp index de14251601..50e4076d07 100644 --- a/src/test/test_bitcoin_fuzzy.cpp +++ b/src/test/test_bitcoin_fuzzy.cpp @@ -67,7 +67,7 @@ int do_fuzz() if (buffer.size() < sizeof(uint32_t)) return 0; uint32_t test_id = 0xffffffff; - memcpy(&test_id, &buffer[0], sizeof(uint32_t)); + memcpy(&test_id, buffer.data(), sizeof(uint32_t)); buffer.erase(buffer.begin(), buffer.begin() + sizeof(uint32_t)); if (test_id >= TEST_ID_END) return 0; diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index 5679086969..6ec544290d 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -253,6 +253,31 @@ BOOST_AUTO_TEST_CASE(util_IsHex) BOOST_CHECK(!IsHex("0x0000")); } +BOOST_AUTO_TEST_CASE(util_IsHexNumber) +{ + BOOST_CHECK(IsHexNumber("0x0")); + BOOST_CHECK(IsHexNumber("0")); + BOOST_CHECK(IsHexNumber("0x10")); + BOOST_CHECK(IsHexNumber("10")); + BOOST_CHECK(IsHexNumber("0xff")); + BOOST_CHECK(IsHexNumber("ff")); + BOOST_CHECK(IsHexNumber("0xFfa")); + BOOST_CHECK(IsHexNumber("Ffa")); + BOOST_CHECK(IsHexNumber("0x00112233445566778899aabbccddeeffAABBCCDDEEFF")); + BOOST_CHECK(IsHexNumber("00112233445566778899aabbccddeeffAABBCCDDEEFF")); + + BOOST_CHECK(!IsHexNumber("")); // empty string not allowed + BOOST_CHECK(!IsHexNumber("0x")); // empty string after prefix not allowed + BOOST_CHECK(!IsHexNumber("0x0 ")); // no spaces at end, + BOOST_CHECK(!IsHexNumber(" 0x0")); // or beginning, + BOOST_CHECK(!IsHexNumber("0x 0")); // or middle, + BOOST_CHECK(!IsHexNumber(" ")); // etc. + BOOST_CHECK(!IsHexNumber("0x0ga")); // invalid character + BOOST_CHECK(!IsHexNumber("x0")); // broken prefix + BOOST_CHECK(!IsHexNumber("0x0x00")); // two prefixes not allowed + +} + BOOST_AUTO_TEST_CASE(util_seed_insecure_rand) { SeedInsecureRand(true); diff --git a/src/txdb.cpp b/src/txdb.cpp index 797ae5713f..134bb8721b 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -371,9 +371,9 @@ bool CCoinsViewDB::Upgrade() { int64_t count = 0; LogPrintf("Upgrading utxo-set database...\n"); LogPrintf("[0%%]..."); + uiInterface.ShowProgress(_("Upgrading UTXO database"), 0, true); size_t batch_size = 1 << 24; CDBBatch batch(db); - uiInterface.SetProgressBreakAction(StartShutdown); int reportDone = 0; std::pair<unsigned char, uint256> key; std::pair<unsigned char, uint256> prev_key = {DB_COINS, uint256()}; @@ -386,7 +386,7 @@ bool CCoinsViewDB::Upgrade() { if (count++ % 256 == 0) { uint32_t high = 0x100 * *key.second.begin() + *(key.second.begin() + 1); int percentageDone = (int)(high * 100.0 / 65536.0 + 0.5); - uiInterface.ShowProgress(_("Upgrading UTXO database") + "\n"+ _("(press q to shutdown and continue later)") + "\n", percentageDone); + uiInterface.ShowProgress(_("Upgrading UTXO database"), percentageDone, true); if (reportDone < percentageDone/10) { // report max. every 10% step LogPrintf("[%d%%]...", percentageDone); @@ -420,7 +420,7 @@ bool CCoinsViewDB::Upgrade() { } db.WriteBatch(batch); db.CompactRange({DB_COINS, uint256()}, key); - uiInterface.SetProgressBreakAction(std::function<void(void)>()); + uiInterface.ShowProgress("", 100, false); LogPrintf("[%s].\n", ShutdownRequested() ? "CANCELLED" : "DONE"); return !ShutdownRequested(); } diff --git a/src/ui_interface.h b/src/ui_interface.h index 762dd19b19..7f68c578ee 100644 --- a/src/ui_interface.h +++ b/src/ui_interface.h @@ -94,11 +94,11 @@ public: /** A wallet has been loaded. */ boost::signals2::signal<void (CWallet* wallet)> LoadWallet; - /** Show progress e.g. for verifychain */ - boost::signals2::signal<void (const std::string &title, int nProgress)> ShowProgress; - - /** Set progress break action (possible "cancel button" triggers that action) */ - boost::signals2::signal<void (std::function<void(void)> action)> SetProgressBreakAction; + /** + * Show progress e.g. for verifychain. + * resume_possible indicates shutting down now will result in the current progress action resuming upon restart. + */ + boost::signals2::signal<void (const std::string &title, int nProgress, bool resume_possible)> ShowProgress; /** New block has been accepted */ boost::signals2::signal<void (bool, const CBlockIndex *)> NotifyBlockTip; diff --git a/src/uint256.cpp b/src/uint256.cpp index c4c7b716fe..736a0d4fe2 100644 --- a/src/uint256.cpp +++ b/src/uint256.cpp @@ -14,7 +14,7 @@ template <unsigned int BITS> base_blob<BITS>::base_blob(const std::vector<unsigned char>& vch) { assert(vch.size() == sizeof(data)); - memcpy(data, &vch[0], sizeof(data)); + memcpy(data, vch.data(), sizeof(data)); } template <unsigned int BITS> diff --git a/src/utilstrencodings.cpp b/src/utilstrencodings.cpp index fd233f6757..741680e93f 100644 --- a/src/utilstrencodings.cpp +++ b/src/utilstrencodings.cpp @@ -65,6 +65,19 @@ bool IsHex(const std::string& str) return (str.size() > 0) && (str.size()%2 == 0); } +bool IsHexNumber(const std::string& str) +{ + size_t starting_location = 0; + if (str.size() > 2 && *str.begin() == '0' && *(str.begin()+1) == 'x') { + starting_location = 2; + } + for (auto c : str.substr(starting_location)) { + if (HexDigit(c) < 0) return false; + } + // Return false for empty string or "0x". + return (str.size() > starting_location); +} + std::vector<unsigned char> ParseHex(const char* psz) { // convert hex dump to vector diff --git a/src/utilstrencodings.h b/src/utilstrencodings.h index 53da60e8f1..192f33fb29 100644 --- a/src/utilstrencodings.h +++ b/src/utilstrencodings.h @@ -38,7 +38,13 @@ std::string SanitizeString(const std::string& str, int rule = SAFE_CHARS_DEFAULT std::vector<unsigned char> ParseHex(const char* psz); std::vector<unsigned char> ParseHex(const std::string& str); signed char HexDigit(char c); +/* Returns true if each character in str is a hex character, and has an even + * number of hex digits.*/ bool IsHex(const std::string& str); +/** +* Return true if the string is a hex number, optionally prefixed with "0x" +*/ +bool IsHexNumber(const std::string& str); std::vector<unsigned char> DecodeBase64(const char* p, bool* pfInvalid = nullptr); std::string DecodeBase64(const std::string& str); std::string EncodeBase64(const unsigned char* pch, size_t len); diff --git a/src/validation.cpp b/src/validation.cpp index 939921d677..85a6af8585 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -83,6 +83,7 @@ int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE; bool fEnableReplacement = DEFAULT_ENABLE_REPLACEMENT; uint256 hashAssumeValid; +arith_uint256 nMinimumChainWork; CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE); CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE; @@ -218,7 +219,7 @@ bool CheckFinalTx(const CTransaction &tx, int flags) // IsFinalTx() with one more than chainActive.Height(). const int nBlockHeight = chainActive.Height() + 1; - // BIP113 will require that time-locked transactions have nLockTime set to + // BIP113 requires that time-locked transactions have nLockTime set to // less than the median time of the previous block they're contained in. // When the next block is created its previous block will be the current // chain tip, so we use that to calculate the median time passed to @@ -254,6 +255,8 @@ bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp, bool AssertLockHeld(mempool.cs); CBlockIndex* tip = chainActive.Tip(); + assert(tip != nullptr); + CBlockIndex index; index.pprev = tip; // CheckSequenceLocks() uses chainActive.Height()+1 to evaluate @@ -1035,8 +1038,6 @@ CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams) bool IsInitialBlockDownload() { - const CChainParams& chainParams = Params(); - // Once this function has returned false, it must remain false. static std::atomic<bool> latchToFalse{false}; // Optimization: pre-test latch before taking the lock. @@ -1050,7 +1051,7 @@ bool IsInitialBlockDownload() return true; if (chainActive.Tip() == nullptr) return true; - if (chainActive.Tip()->nChainWork < UintToArith256(chainParams.GetConsensus().nMinimumChainWork)) + if (chainActive.Tip()->nChainWork < nMinimumChainWork) return true; if (chainActive.Tip()->GetBlockTime() < (GetTime() - nMaxTipAge)) return true; @@ -1670,7 +1671,7 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd if (it != mapBlockIndex.end()) { if (it->second->GetAncestor(pindex->nHeight) == pindex && pindexBestHeader->GetAncestor(pindex->nHeight) == pindex && - pindexBestHeader->nChainWork >= UintToArith256(chainparams.GetConsensus().nMinimumChainWork)) { + pindexBestHeader->nChainWork >= nMinimumChainWork) { // This block is a member of the assumed verified chain and an ancestor of the best header. // The equivalent time check discourages hash power from extorting the network via DOS attack // into accepting an invalid block through telling users they must manually set assumevalid. @@ -3571,12 +3572,12 @@ bool LoadChainTip(const CChainParams& chainparams) CVerifyDB::CVerifyDB() { - uiInterface.ShowProgress(_("Verifying blocks..."), 0); + uiInterface.ShowProgress(_("Verifying blocks..."), 0, false); } CVerifyDB::~CVerifyDB() { - uiInterface.ShowProgress("", 100); + uiInterface.ShowProgress("", 100, false); } bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, int nCheckLevel, int nCheckDepth) @@ -3606,7 +3607,7 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, LogPrintf("[%d%%]...", percentageDone); reportDone = percentageDone/10; } - uiInterface.ShowProgress(_("Verifying blocks..."), percentageDone); + uiInterface.ShowProgress(_("Verifying blocks..."), percentageDone, false); if (pindex->nHeight < chainActive.Height()-nCheckDepth) break; if (fPruneMode && !(pindex->nStatus & BLOCK_HAVE_DATA)) { @@ -3657,7 +3658,7 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, CBlockIndex *pindex = pindexState; while (pindex != chainActive.Tip()) { boost::this_thread::interruption_point(); - uiInterface.ShowProgress(_("Verifying blocks..."), std::max(1, std::min(99, 100 - (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * 50)))); + uiInterface.ShowProgress(_("Verifying blocks..."), std::max(1, std::min(99, 100 - (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * 50))), false); pindex = chainActive.Next(pindex); CBlock block; if (!ReadBlockFromDisk(block, pindex, chainparams.GetConsensus())) @@ -3704,7 +3705,7 @@ bool ReplayBlocks(const CChainParams& params, CCoinsView* view) if (hashHeads.empty()) return true; // We're already in a consistent state. if (hashHeads.size() != 2) return error("ReplayBlocks(): unknown inconsistent state"); - uiInterface.ShowProgress(_("Replaying blocks..."), 0); + uiInterface.ShowProgress(_("Replaying blocks..."), 0, false); LogPrintf("Replaying blocks\n"); const CBlockIndex* pindexOld = nullptr; // Old tip during the interrupted flush. @@ -3755,7 +3756,7 @@ bool ReplayBlocks(const CChainParams& params, CCoinsView* view) cache.SetBestBlock(pindexNew->GetBlockHash()); cache.Flush(); - uiInterface.ShowProgress("", 100); + uiInterface.ShowProgress("", 100, false); return true; } @@ -4334,7 +4335,7 @@ bool LoadMempool(void) return true; } -void DumpMempool(void) +bool DumpMempool(void) { int64_t start = GetTimeMicros(); @@ -4354,7 +4355,7 @@ void DumpMempool(void) try { FILE* filestr = fsbridge::fopen(GetDataDir() / "mempool.dat.new", "wb"); if (!filestr) { - return; + return false; } CAutoFile file(filestr, SER_DISK, CLIENT_VERSION); @@ -4378,7 +4379,9 @@ void DumpMempool(void) LogPrintf("Dumped mempool: %gs to copy, %gs to dump\n", (mid-start)*MICRO, (last-mid)*MICRO); } catch (const std::exception& e) { LogPrintf("Failed to dump mempool: %s. Continuing anyway.\n", e.what()); + return false; } + return true; } //! Guess how far we are in the verification process at the given block index diff --git a/src/validation.h b/src/validation.h index d0f6cdc135..6a77fe56be 100644 --- a/src/validation.h +++ b/src/validation.h @@ -45,9 +45,9 @@ struct ChainTxData; struct PrecomputedTransactionData; struct LockPoints; -/** Default for DEFAULT_WHITELISTRELAY. */ +/** Default for -whitelistrelay. */ static const bool DEFAULT_WHITELISTRELAY = true; -/** Default for DEFAULT_WHITELISTFORCERELAY. */ +/** Default for -whitelistforcerelay. */ static const bool DEFAULT_WHITELISTFORCERELAY = true; /** Default for -minrelaytxfee, minimum relay fee for transactions */ static const unsigned int DEFAULT_MIN_RELAY_TX_FEE = 1000; @@ -94,8 +94,8 @@ static const int MAX_CMPCTBLOCK_DEPTH = 5; static const int MAX_BLOCKTXN_DEPTH = 10; /** Size of the "block download window": how far ahead of our current height do we fetch? * Larger windows tolerate larger download speed differences between peer, but increase the potential - * degree of disordering of blocks on disk (which make reindexing and in the future perhaps pruning - * harder). We'll probably want to make this a per-peer adaptive value at some point. */ + * degree of disordering of blocks on disk (which make reindexing and pruning harder). We'll probably + * want to make this a per-peer adaptive value at some point. */ static const unsigned int BLOCK_DOWNLOAD_WINDOW = 1024; /** Time to wait (in seconds) between writing blocks/block index to disk. */ static const unsigned int DATABASE_WRITE_INTERVAL = 60 * 60; @@ -161,7 +161,6 @@ extern CTxMemPool mempool; typedef std::unordered_map<uint256, CBlockIndex*, BlockHasher> BlockMap; extern BlockMap mapBlockIndex; extern uint64_t nLastBlockTx; -extern uint64_t nLastBlockSize; extern uint64_t nLastBlockWeight; extern const std::string strMessageMagic; extern CWaitableCriticalSection csBestBlock; @@ -186,6 +185,9 @@ extern bool fEnableReplacement; /** Block hash whose ancestors we will assume to have valid scripts without checking them. */ extern uint256 hashAssumeValid; +/** Minimum work we will assume exists on some valid chain. */ +extern arith_uint256 nMinimumChainWork; + /** Best header we've seen so far (used for getheaders queries' starting points). */ extern CBlockIndex *pindexBestHeader; @@ -475,7 +477,7 @@ static const unsigned int REJECT_HIGHFEE = 0x100; CBlockFileInfo* GetBlockFileInfo(size_t n); /** Dump the mempool to disk. */ -void DumpMempool(); +bool DumpMempool(); /** Load the mempool from disk. */ bool LoadMempool(); diff --git a/src/wallet/crypter.cpp b/src/wallet/crypter.cpp index dcce88cedc..8db3bfd69c 100644 --- a/src/wallet/crypter.cpp +++ b/src/wallet/crypter.cpp @@ -27,8 +27,7 @@ int CCrypter::BytesToKeySHA512AES(const std::vector<unsigned char>& chSalt, cons CSHA512 di; di.Write((const unsigned char*)strKeyData.c_str(), strKeyData.size()); - if(chSalt.size()) - di.Write(&chSalt[0], chSalt.size()); + di.Write(chSalt.data(), chSalt.size()); di.Finalize(buf); for(int i = 0; i != count - 1; i++) @@ -82,7 +81,7 @@ bool CCrypter::Encrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned vchCiphertext.resize(vchPlaintext.size() + AES_BLOCKSIZE); AES256CBCEncrypt enc(vchKey.data(), vchIV.data(), true); - size_t nLen = enc.Encrypt(&vchPlaintext[0], vchPlaintext.size(), &vchCiphertext[0]); + size_t nLen = enc.Encrypt(&vchPlaintext[0], vchPlaintext.size(), vchCiphertext.data()); if(nLen < vchPlaintext.size()) return false; vchCiphertext.resize(nLen); @@ -101,7 +100,7 @@ bool CCrypter::Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingM vchPlaintext.resize(nLen); AES256CBCDecrypt dec(vchKey.data(), vchIV.data(), true); - nLen = dec.Decrypt(&vchCiphertext[0], vchCiphertext.size(), &vchPlaintext[0]); + nLen = dec.Decrypt(vchCiphertext.data(), vchCiphertext.size(), &vchPlaintext[0]); if(nLen == 0) return false; vchPlaintext.resize(nLen); @@ -113,7 +112,7 @@ static bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMateri { CCrypter cKeyCrypter; std::vector<unsigned char> chIV(WALLET_CRYPTO_IV_SIZE); - memcpy(&chIV[0], &nIV, WALLET_CRYPTO_IV_SIZE); + memcpy(chIV.data(), &nIV, WALLET_CRYPTO_IV_SIZE); if(!cKeyCrypter.SetKey(vMasterKey, chIV)) return false; return cKeyCrypter.Encrypt(*((const CKeyingMaterial*)&vchPlaintext), vchCiphertext); @@ -123,7 +122,7 @@ static bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<u { CCrypter cKeyCrypter; std::vector<unsigned char> chIV(WALLET_CRYPTO_IV_SIZE); - memcpy(&chIV[0], &nIV, WALLET_CRYPTO_IV_SIZE); + memcpy(chIV.data(), &nIV, WALLET_CRYPTO_IV_SIZE); if(!cKeyCrypter.SetKey(vMasterKey, chIV)) return false; return cKeyCrypter.Decrypt(vchCiphertext, *((CKeyingMaterial*)&vchPlaintext)); diff --git a/src/wallet/crypter.h b/src/wallet/crypter.h index f1e8a25650..eac258b287 100644 --- a/src/wallet/crypter.h +++ b/src/wallet/crypter.h @@ -16,13 +16,13 @@ const unsigned int WALLET_CRYPTO_IV_SIZE = 16; /** * Private key encryption is done based on a CMasterKey, * which holds a salt and random encryption key. - * + * * CMasterKeys are encrypted using AES-256-CBC using a key * derived using derivation method nDerivationMethod * (0 == EVP_sha512()) and derivation iterations nDeriveIterations. * vchOtherDerivationParameters is provided for alternative algorithms * which may require more parameters (such as scrypt). - * + * * Wallet Private Keys are then encrypted using AES-256-CBC * with the double-sha256 of the public key as the IV, and the * master key's key as the encryption key (see keystore.[ch]). @@ -162,28 +162,26 @@ public: { { LOCK(cs_KeyStore); - if (!IsCrypted()) + if (!IsCrypted()) { return CBasicKeyStore::HaveKey(address); + } return mapCryptedKeys.count(address) > 0; } return false; } bool GetKey(const CKeyID &address, CKey& keyOut) const override; bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const override; - void GetKeys(std::set<CKeyID> &setAddress) const override + std::set<CKeyID> GetKeys() const override { - if (!IsCrypted()) - { - CBasicKeyStore::GetKeys(setAddress); - return; + LOCK(cs_KeyStore); + if (!IsCrypted()) { + return CBasicKeyStore::GetKeys(); } - setAddress.clear(); - CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin(); - while (mi != mapCryptedKeys.end()) - { - setAddress.insert((*mi).first); - mi++; + std::set<CKeyID> set_address; + for (const auto& mi : mapCryptedKeys) { + set_address.insert(mi.first); } + return set_address; } /** diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp index d2fe4866fa..d66ba48421 100644 --- a/src/wallet/db.cpp +++ b/src/wallet/db.cpp @@ -558,7 +558,6 @@ bool CDB::Rewrite(CWalletDBWrapper& dbw, const char* pszSkip) } MilliSleep(100); } - return false; } @@ -684,7 +683,6 @@ bool CWalletDBWrapper::Backup(const std::string& strDest) } MilliSleep(100); } - return false; } void CWalletDBWrapper::Flush(bool shutdown) diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp index 18365b1b72..c984df1df8 100644 --- a/src/wallet/init.cpp +++ b/src/wallet/init.cpp @@ -10,6 +10,7 @@ #include "utilmoneystr.h" #include "validation.h" #include "wallet/wallet.h" +#include "wallet/rpcwallet.h" std::string GetWalletHelpString(bool showDebug) { @@ -29,7 +30,6 @@ std::string GetWalletHelpString(bool showDebug) strUsage += HelpMessageOpt("-salvagewallet", _("Attempt to recover private keys from a corrupt wallet on startup")); strUsage += HelpMessageOpt("-spendzeroconfchange", strprintf(_("Spend unconfirmed change when sending transactions (default: %u)"), DEFAULT_SPEND_ZEROCONF_CHANGE)); strUsage += HelpMessageOpt("-txconfirmtarget=<n>", strprintf(_("If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)"), DEFAULT_TX_CONFIRM_TARGET)); - strUsage += HelpMessageOpt("-usehd", _("Use hierarchical deterministic key generation (HD) after BIP32. Only has effect during wallet creation/first start") + " " + strprintf(_("(default: %u)"), DEFAULT_USE_HD_WALLET)); strUsage += HelpMessageOpt("-walletrbf", strprintf(_("Send transactions with full-RBF opt-in enabled (default: %u)"), DEFAULT_WALLET_RBF)); strUsage += HelpMessageOpt("-upgradewallet", _("Upgrade wallet to latest format on startup")); strUsage += HelpMessageOpt("-wallet=<file>", _("Specify wallet file (within data directory)") + " " + strprintf(_("(default: %s)"), DEFAULT_WALLET_DAT)); @@ -171,7 +171,14 @@ bool WalletParameterInteraction() return true; } -bool WalletVerify() +void RegisterWalletRPC(CRPCTable &t) +{ + if (gArgs.GetBoolArg("-disablewallet", false)) return; + + RegisterWalletRPCCommands(t); +} + +bool VerifyWallets() { if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) return true; @@ -228,7 +235,7 @@ bool WalletVerify() return true; } -bool InitLoadWallet() +bool OpenWallets() { if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) { LogPrintf("Wallet disabled!\n"); @@ -245,3 +252,28 @@ bool InitLoadWallet() return true; } + +void StartWallets(CScheduler& scheduler) { + for (CWalletRef pwallet : vpwallets) { + pwallet->postInitProcess(scheduler); + } +} + +void FlushWallets() { + for (CWalletRef pwallet : vpwallets) { + pwallet->Flush(false); + } +} + +void StopWallets() { + for (CWalletRef pwallet : vpwallets) { + pwallet->Flush(true); + } +} + +void CloseWallets() { + for (CWalletRef pwallet : vpwallets) { + delete pwallet; + } + vpwallets.clear(); +} diff --git a/src/wallet/init.h b/src/wallet/init.h index fa2251506d..0b3ee2dda2 100644 --- a/src/wallet/init.h +++ b/src/wallet/init.h @@ -8,18 +8,36 @@ #include <string> +class CRPCTable; +class CScheduler; + //! Return the wallets help message. std::string GetWalletHelpString(bool showDebug); //! Wallets parameter interaction bool WalletParameterInteraction(); +//! Register wallet RPCs. +void RegisterWalletRPC(CRPCTable &tableRPC); + //! Responsible for reading and validating the -wallet arguments and verifying the wallet database. // This function will perform salvage on the wallet if requested, as long as only one wallet is -// being loaded (CWallet::ParameterInteraction forbids -salvagewallet, -zapwallettxes or -upgradewallet with multiwallet). -bool WalletVerify(); +// being loaded (WalletParameterInteraction forbids -salvagewallet, -zapwallettxes or -upgradewallet with multiwallet). +bool VerifyWallets(); //! Load wallet databases. -bool InitLoadWallet(); +bool OpenWallets(); + +//! Complete startup of wallets. +void StartWallets(CScheduler& scheduler); + +//! Flush all wallets in preparation for shutdown. +void FlushWallets(); + +//! Stop all wallets. Wallets will be flushed first. +void StopWallets(); + +//! Close all wallets. +void CloseWallets(); #endif // BITCOIN_WALLET_INIT_H diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index db6f6b48ac..9539cc9f42 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -181,7 +181,7 @@ UniValue abortrescan(const JSONRPCRequest& request) return true; } -void ImportAddress(CWallet*, const CBitcoinAddress& address, const std::string& strLabel); +void ImportAddress(CWallet*, const CTxDestination& dest, const std::string& strLabel); void ImportScript(CWallet* const pwallet, const CScript& script, const std::string& strLabel, bool isRedeemScript) { if (!isRedeemScript && ::IsMine(*pwallet, script) == ISMINE_SPENDABLE) { @@ -198,7 +198,7 @@ void ImportScript(CWallet* const pwallet, const CScript& script, const std::stri if (!pwallet->HaveCScript(script) && !pwallet->AddCScript(script)) { throw JSONRPCError(RPC_WALLET_ERROR, "Error adding p2sh redeemScript to wallet"); } - ImportAddress(pwallet, CBitcoinAddress(CScriptID(script)), strLabel); + ImportAddress(pwallet, CScriptID(script), strLabel); } else { CTxDestination destination; if (ExtractDestination(script, destination)) { @@ -207,13 +207,13 @@ void ImportScript(CWallet* const pwallet, const CScript& script, const std::stri } } -void ImportAddress(CWallet* const pwallet, const CBitcoinAddress& address, const std::string& strLabel) +void ImportAddress(CWallet* const pwallet, const CTxDestination& dest, const std::string& strLabel) { - CScript script = GetScriptForDestination(address.Get()); + CScript script = GetScriptForDestination(dest); ImportScript(pwallet, script, strLabel, false); // add to address book or update label - if (address.IsValid()) - pwallet->SetAddressBook(address.Get(), strLabel, "receive"); + if (IsValidDestination(dest)) + pwallet->SetAddressBook(dest, strLabel, "receive"); } UniValue importaddress(const JSONRPCRequest& request) @@ -265,11 +265,12 @@ UniValue importaddress(const JSONRPCRequest& request) LOCK2(cs_main, pwallet->cs_wallet); - CBitcoinAddress address(request.params[0].get_str()); - if (address.IsValid()) { - if (fP2SH) + CTxDestination dest = DecodeDestination(request.params[0].get_str()); + if (IsValidDestination(dest)) { + if (fP2SH) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Cannot use the p2sh flag with an address - use a script instead"); - ImportAddress(pwallet, address, strLabel); + } + ImportAddress(pwallet, dest, strLabel); } else if (IsHex(request.params[0].get_str())) { std::vector<unsigned char> data(ParseHex(request.params[0].get_str())); ImportScript(pwallet, CScript(data.begin(), data.end()), strLabel, fP2SH); @@ -432,7 +433,7 @@ UniValue importpubkey(const JSONRPCRequest& request) LOCK2(cs_main, pwallet->cs_wallet); - ImportAddress(pwallet, CBitcoinAddress(pubKey.GetID()), strLabel); + ImportAddress(pwallet, pubKey.GetID(), strLabel); ImportScript(pwallet, GetScriptForRawPubKey(pubKey), strLabel, false); if (fRescan) @@ -506,7 +507,7 @@ UniValue importwallet(const JSONRPCRequest& request) assert(key.VerifyPubKey(pubkey)); CKeyID keyid = pubkey.GetID(); if (pwallet->HaveKey(keyid)) { - LogPrintf("Skipping import of %s (key already present)\n", CBitcoinAddress(keyid).ToString()); + LogPrintf("Skipping import of %s (key already present)\n", EncodeDestination(keyid)); continue; } int64_t nTime = DecodeDumpTime(vstr[1]); @@ -524,7 +525,7 @@ UniValue importwallet(const JSONRPCRequest& request) fLabel = true; } } - LogPrintf("Importing %s...\n", CBitcoinAddress(keyid).ToString()); + LogPrintf("Importing %s...\n", EncodeDestination(keyid)); if (!pwallet->AddKeyPubKey(key, pubkey)) { fGood = false; continue; @@ -573,14 +574,16 @@ UniValue dumpprivkey(const JSONRPCRequest& request) EnsureWalletIsUnlocked(pwallet); std::string strAddress = request.params[0].get_str(); - CBitcoinAddress address; - if (!address.SetString(strAddress)) + CTxDestination dest = DecodeDestination(strAddress); + if (!IsValidDestination(dest)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address"); - CKeyID keyID; - if (!address.GetKeyID(keyID)) + } + const CKeyID *keyID = boost::get<CKeyID>(&dest); + if (!keyID) { throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to a key"); + } CKey vchSecret; - if (!pwallet->GetKey(keyID, vchSecret)) { + if (!pwallet->GetKey(*keyID, vchSecret)) { throw JSONRPCError(RPC_WALLET_ERROR, "Private key for address " + strAddress + " is not known"); } return CBitcoinSecret(vchSecret).ToString(); @@ -659,7 +662,7 @@ UniValue dumpwallet(const JSONRPCRequest& request) for (std::vector<std::pair<int64_t, CKeyID> >::const_iterator it = vKeyBirth.begin(); it != vKeyBirth.end(); it++) { const CKeyID &keyid = it->second; std::string strTime = EncodeDumpTime(it->first); - std::string strAddr = CBitcoinAddress(keyid).ToString(); + std::string strAddr = EncodeDestination(keyid); CKey key; if (pwallet->GetKey(keyid, key)) { file << strprintf("%s %s ", CBitcoinSecret(key).ToString(), strTime); @@ -715,14 +718,14 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6 // Parse the output. CScript script; - CBitcoinAddress address; + CTxDestination dest; if (!isScript) { - address = CBitcoinAddress(output); - if (!address.IsValid()) { + dest = DecodeDestination(output); + if (!IsValidDestination(dest)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address"); } - script = GetScriptForDestination(address.Get()); + script = GetScriptForDestination(dest); } else { if (!IsHex(output)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid scriptPubKey"); @@ -780,8 +783,8 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6 throw JSONRPCError(RPC_WALLET_ERROR, "Error adding p2sh redeemScript to wallet"); } - CBitcoinAddress redeemAddress = CBitcoinAddress(CScriptID(redeemScript)); - CScript redeemDestination = GetScriptForDestination(redeemAddress.Get()); + CTxDestination redeem_dest = CScriptID(redeemScript); + CScript redeemDestination = GetScriptForDestination(redeem_dest); if (::IsMine(*pwallet, redeemDestination) == ISMINE_SPENDABLE) { throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script"); @@ -794,8 +797,8 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6 } // add to address book or update label - if (address.IsValid()) { - pwallet->SetAddressBook(address.Get(), label, "receive"); + if (IsValidDestination(dest)) { + pwallet->SetAddressBook(dest, label, "receive"); } // Import private keys. @@ -854,27 +857,25 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey is not a valid public key"); } - CBitcoinAddress pubKeyAddress = CBitcoinAddress(pubKey.GetID()); + CTxDestination pubkey_dest = pubKey.GetID(); // Consistency check. - if (!isScript && !(pubKeyAddress.Get() == address.Get())) { + if (!isScript && !(pubkey_dest == dest)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed"); } // Consistency check. if (isScript) { - CBitcoinAddress scriptAddress; CTxDestination destination; if (ExtractDestination(script, destination)) { - scriptAddress = CBitcoinAddress(destination); - if (!(scriptAddress.Get() == pubKeyAddress.Get())) { + if (!(destination == pubkey_dest)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed"); } } } - CScript pubKeyScript = GetScriptForDestination(pubKeyAddress.Get()); + CScript pubKeyScript = GetScriptForDestination(pubkey_dest); if (::IsMine(*pwallet, pubKeyScript) == ISMINE_SPENDABLE) { throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script"); @@ -887,8 +888,8 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6 } // add to address book or update label - if (pubKeyAddress.IsValid()) { - pwallet->SetAddressBook(pubKeyAddress.Get(), label, "receive"); + if (IsValidDestination(pubkey_dest)) { + pwallet->SetAddressBook(pubkey_dest, label, "receive"); } // TODO Is this necessary? @@ -927,21 +928,19 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6 CPubKey pubKey = key.GetPubKey(); assert(key.VerifyPubKey(pubKey)); - CBitcoinAddress pubKeyAddress = CBitcoinAddress(pubKey.GetID()); + CTxDestination pubkey_dest = pubKey.GetID(); // Consistency check. - if (!isScript && !(pubKeyAddress.Get() == address.Get())) { + if (!isScript && !(pubkey_dest == dest)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed"); } // Consistency check. if (isScript) { - CBitcoinAddress scriptAddress; CTxDestination destination; if (ExtractDestination(script, destination)) { - scriptAddress = CBitcoinAddress(destination); - if (!(scriptAddress.Get() == pubKeyAddress.Get())) { + if (!(destination == pubkey_dest)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed"); } } @@ -980,8 +979,8 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6 if (scriptPubKey.getType() == UniValue::VOBJ) { // add to address book or update label - if (address.IsValid()) { - pwallet->SetAddressBook(address.Get(), label, "receive"); + if (IsValidDestination(dest)) { + pwallet->SetAddressBook(dest, label, "receive"); } } diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index e3639e4682..ae89b3c0a1 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -170,18 +170,18 @@ UniValue getnewaddress(const JSONRPCRequest& request) pwallet->SetAddressBook(keyID, strAccount, "receive"); - return CBitcoinAddress(keyID).ToString(); + return EncodeDestination(keyID); } -CBitcoinAddress GetAccountAddress(CWallet* const pwallet, std::string strAccount, bool bForceNew=false) +CTxDestination GetAccountAddress(CWallet* const pwallet, std::string strAccount, bool bForceNew=false) { CPubKey pubKey; if (!pwallet->GetAccountPubkey(pubKey, strAccount, bForceNew)) { throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first"); } - return CBitcoinAddress(pubKey.GetID()); + return pubKey.GetID(); } UniValue getaccountaddress(const JSONRPCRequest& request) @@ -213,7 +213,7 @@ UniValue getaccountaddress(const JSONRPCRequest& request) UniValue ret(UniValue::VSTR); - ret = GetAccountAddress(pwallet, strAccount).ToString(); + ret = EncodeDestination(GetAccountAddress(pwallet, strAccount)); return ret; } @@ -252,7 +252,7 @@ UniValue getrawchangeaddress(const JSONRPCRequest& request) CKeyID keyID = vchPubKey.GetID(); - return CBitcoinAddress(keyID).ToString(); + return EncodeDestination(keyID); } @@ -277,24 +277,25 @@ UniValue setaccount(const JSONRPCRequest& request) LOCK2(cs_main, pwallet->cs_wallet); - CBitcoinAddress address(request.params[0].get_str()); - if (!address.IsValid()) + CTxDestination dest = DecodeDestination(request.params[0].get_str()); + if (!IsValidDestination(dest)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address"); + } std::string strAccount; if (!request.params[1].isNull()) strAccount = AccountFromValue(request.params[1]); // Only add the account if the address is yours. - if (IsMine(*pwallet, address.Get())) { + if (IsMine(*pwallet, dest)) { // Detect when changing the account of an address that is the 'unused current key' of another account: - if (pwallet->mapAddressBook.count(address.Get())) { - std::string strOldAccount = pwallet->mapAddressBook[address.Get()].name; - if (address == GetAccountAddress(pwallet, strOldAccount)) { + if (pwallet->mapAddressBook.count(dest)) { + std::string strOldAccount = pwallet->mapAddressBook[dest].name; + if (dest == GetAccountAddress(pwallet, strOldAccount)) { GetAccountAddress(pwallet, strOldAccount, true); } } - pwallet->SetAddressBook(address.Get(), strAccount, "receive"); + pwallet->SetAddressBook(dest, strAccount, "receive"); } else throw JSONRPCError(RPC_MISC_ERROR, "setaccount can only be used with own address"); @@ -325,12 +326,13 @@ UniValue getaccount(const JSONRPCRequest& request) LOCK2(cs_main, pwallet->cs_wallet); - CBitcoinAddress address(request.params[0].get_str()); - if (!address.IsValid()) + CTxDestination dest = DecodeDestination(request.params[0].get_str()); + if (!IsValidDestination(dest)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address"); + } std::string strAccount; - std::map<CTxDestination, CAddressBookData>::iterator mi = pwallet->mapAddressBook.find(address.Get()); + std::map<CTxDestination, CAddressBookData>::iterator mi = pwallet->mapAddressBook.find(dest); if (mi != pwallet->mapAddressBook.end() && !(*mi).second.name.empty()) { strAccount = (*mi).second.name; } @@ -367,11 +369,12 @@ UniValue getaddressesbyaccount(const JSONRPCRequest& request) // Find all addresses that have the given account UniValue ret(UniValue::VARR); - for (const std::pair<CBitcoinAddress, CAddressBookData>& item : pwallet->mapAddressBook) { - const CBitcoinAddress& address = item.first; + for (const std::pair<CTxDestination, CAddressBookData>& item : pwallet->mapAddressBook) { + const CTxDestination& dest = item.first; const std::string& strName = item.second.name; - if (strName == strAccount) - ret.push_back(address.ToString()); + if (strName == strAccount) { + ret.push_back(EncodeDestination(dest)); + } } return ret; } @@ -454,9 +457,10 @@ UniValue sendtoaddress(const JSONRPCRequest& request) ObserveSafeMode(); LOCK2(cs_main, pwallet->cs_wallet); - CBitcoinAddress address(request.params[0].get_str()); - if (!address.IsValid()) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address"); + CTxDestination dest = DecodeDestination(request.params[0].get_str()); + if (!IsValidDestination(dest)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address"); + } // Amount CAmount nAmount = AmountFromValue(request.params[1]); @@ -493,7 +497,7 @@ UniValue sendtoaddress(const JSONRPCRequest& request) EnsureWalletIsUnlocked(pwallet); - SendMoney(pwallet, address.Get(), nAmount, fSubtractFeeFromAmount, wtx, coin_control); + SendMoney(pwallet, dest, nAmount, fSubtractFeeFromAmount, wtx, coin_control); return wtx.GetHash().GetHex(); } @@ -533,16 +537,16 @@ UniValue listaddressgroupings(const JSONRPCRequest& request) UniValue jsonGroupings(UniValue::VARR); std::map<CTxDestination, CAmount> balances = pwallet->GetAddressBalances(); - for (std::set<CTxDestination> grouping : pwallet->GetAddressGroupings()) { + for (const std::set<CTxDestination>& grouping : pwallet->GetAddressGroupings()) { UniValue jsonGrouping(UniValue::VARR); - for (CTxDestination address : grouping) + for (const CTxDestination& address : grouping) { UniValue addressInfo(UniValue::VARR); - addressInfo.push_back(CBitcoinAddress(address).ToString()); + addressInfo.push_back(EncodeDestination(address)); addressInfo.push_back(ValueFromAmount(balances[address])); { - if (pwallet->mapAddressBook.find(CBitcoinAddress(address).Get()) != pwallet->mapAddressBook.end()) { - addressInfo.push_back(pwallet->mapAddressBook.find(CBitcoinAddress(address).Get())->second.name); + if (pwallet->mapAddressBook.find(address) != pwallet->mapAddressBook.end()) { + addressInfo.push_back(pwallet->mapAddressBook.find(address)->second.name); } } jsonGrouping.push_back(addressInfo); @@ -587,16 +591,18 @@ UniValue signmessage(const JSONRPCRequest& request) std::string strAddress = request.params[0].get_str(); std::string strMessage = request.params[1].get_str(); - CBitcoinAddress addr(strAddress); - if (!addr.IsValid()) + CTxDestination dest = DecodeDestination(strAddress); + if (!IsValidDestination(dest)) { throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address"); + } - CKeyID keyID; - if (!addr.GetKeyID(keyID)) + const CKeyID *keyID = boost::get<CKeyID>(&dest); + if (!keyID) { throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key"); + } CKey key; - if (!pwallet->GetKey(keyID, key)) { + if (!pwallet->GetKey(*keyID, key)) { throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available"); } @@ -608,7 +614,7 @@ UniValue signmessage(const JSONRPCRequest& request) if (!key.SignCompact(ss.GetHash(), vchSig)) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed"); - return EncodeBase64(&vchSig[0], vchSig.size()); + return EncodeBase64(vchSig.data(), vchSig.size()); } UniValue getreceivedbyaddress(const JSONRPCRequest& request) @@ -642,10 +648,11 @@ UniValue getreceivedbyaddress(const JSONRPCRequest& request) LOCK2(cs_main, pwallet->cs_wallet); // Bitcoin address - CBitcoinAddress address = CBitcoinAddress(request.params[0].get_str()); - if (!address.IsValid()) + CTxDestination dest = DecodeDestination(request.params[0].get_str()); + if (!IsValidDestination(dest)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address"); - CScript scriptPubKey = GetScriptForDestination(address.Get()); + } + CScript scriptPubKey = GetScriptForDestination(dest); if (!IsMine(*pwallet, scriptPubKey)) { return ValueFromAmount(0); } @@ -915,9 +922,10 @@ UniValue sendfrom(const JSONRPCRequest& request) LOCK2(cs_main, pwallet->cs_wallet); std::string strAccount = AccountFromValue(request.params[0]); - CBitcoinAddress address(request.params[1].get_str()); - if (!address.IsValid()) + CTxDestination dest = DecodeDestination(request.params[1].get_str()); + if (!IsValidDestination(dest)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address"); + } CAmount nAmount = AmountFromValue(request.params[2]); if (nAmount <= 0) throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send"); @@ -940,7 +948,7 @@ UniValue sendfrom(const JSONRPCRequest& request) throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds"); CCoinControl no_coin_control; // This is a deprecated API - SendMoney(pwallet, address.Get(), nAmount, false, wtx, no_coin_control); + SendMoney(pwallet, dest, nAmount, false, wtx, no_coin_control); return wtx.GetHash().GetHex(); } @@ -1032,22 +1040,23 @@ UniValue sendmany(const JSONRPCRequest& request) } } - std::set<CBitcoinAddress> setAddress; + std::set<CTxDestination> destinations; std::vector<CRecipient> vecSend; CAmount totalAmount = 0; std::vector<std::string> keys = sendTo.getKeys(); - for (const std::string& name_ : keys) - { - CBitcoinAddress address(name_); - if (!address.IsValid()) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ")+name_); + for (const std::string& name_ : keys) { + CTxDestination dest = DecodeDestination(name_); + if (!IsValidDestination(dest)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ") + name_); + } - if (setAddress.count(address)) - throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ")+name_); - setAddress.insert(address); + if (destinations.count(dest)) { + throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + name_); + } + destinations.insert(dest); - CScript scriptPubKey = GetScriptForDestination(address.Get()); + CScript scriptPubKey = GetScriptForDestination(dest); CAmount nAmount = AmountFromValue(sendTo[name_]); if (nAmount <= 0) throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send"); @@ -1138,7 +1147,7 @@ UniValue addmultisigaddress(const JSONRPCRequest& request) pwallet->AddCScript(inner); pwallet->SetAddressBook(innerID, strAccount, "send"); - return CBitcoinAddress(innerID).ToString(); + return EncodeDestination(innerID); } class Witnessifier : public boost::static_visitor<bool> @@ -1226,12 +1235,12 @@ UniValue addwitnessaddress(const JSONRPCRequest& request) } } - CBitcoinAddress address(request.params[0].get_str()); - if (!address.IsValid()) + CTxDestination dest = DecodeDestination(request.params[0].get_str()); + if (!IsValidDestination(dest)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address"); + } Witnessifier w(pwallet); - CTxDestination dest = address.Get(); bool ret = boost::apply_visitor(w, dest); if (!ret) { throw JSONRPCError(RPC_WALLET_ERROR, "Public key or redeemscript not known to wallet, or the key is uncompressed"); @@ -1239,7 +1248,7 @@ UniValue addwitnessaddress(const JSONRPCRequest& request) pwallet->SetAddressBook(w.result, "", "receive"); - return CBitcoinAddress(w.result).ToString(); + return EncodeDestination(w.result); } struct tallyitem @@ -1274,7 +1283,7 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA filter = filter | ISMINE_WATCH_ONLY; // Tally - std::map<CBitcoinAddress, tallyitem> mapTally; + std::map<CTxDestination, tallyitem> mapTally; for (const std::pair<uint256, CWalletTx>& pairWtx : pwallet->mapWallet) { const CWalletTx& wtx = pairWtx.second; @@ -1307,10 +1316,10 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA // Reply UniValue ret(UniValue::VARR); std::map<std::string, tallyitem> mapAccountTally; - for (const std::pair<CBitcoinAddress, CAddressBookData>& item : pwallet->mapAddressBook) { - const CBitcoinAddress& address = item.first; + for (const std::pair<CTxDestination, CAddressBookData>& item : pwallet->mapAddressBook) { + const CTxDestination& dest = item.first; const std::string& strAccount = item.second.name; - std::map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address); + std::map<CTxDestination, tallyitem>::iterator it = mapTally.find(dest); if (it == mapTally.end() && !fIncludeEmpty) continue; @@ -1336,7 +1345,7 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA UniValue obj(UniValue::VOBJ); if(fIsWatchonly) obj.push_back(Pair("involvesWatchonly", true)); - obj.push_back(Pair("address", address.ToString())); + obj.push_back(Pair("address", EncodeDestination(dest))); obj.push_back(Pair("account", strAccount)); obj.push_back(Pair("amount", ValueFromAmount(nAmount))); obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf))); @@ -1461,9 +1470,9 @@ UniValue listreceivedbyaccount(const JSONRPCRequest& request) static void MaybePushAddress(UniValue & entry, const CTxDestination &dest) { - CBitcoinAddress addr; - if (addr.Set(dest)) - entry.push_back(Pair("address", addr.ToString())); + if (IsValidDestination(dest)) { + entry.push_back(Pair("address", EncodeDestination(dest))); + } } /** @@ -2717,18 +2726,19 @@ UniValue listunspent(const JSONRPCRequest& request) nMaxDepth = request.params[1].get_int(); } - std::set<CBitcoinAddress> setAddress; + std::set<CTxDestination> destinations; if (!request.params[2].isNull()) { RPCTypeCheckArgument(request.params[2], UniValue::VARR); UniValue inputs = request.params[2].get_array(); for (unsigned int idx = 0; idx < inputs.size(); idx++) { const UniValue& input = inputs[idx]; - CBitcoinAddress address(input.get_str()); - if (!address.IsValid()) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ")+input.get_str()); - if (setAddress.count(address)) - throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ")+input.get_str()); - setAddress.insert(address); + CTxDestination dest = DecodeDestination(input.get_str()); + if (!IsValidDestination(dest)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ") + input.get_str()); + } + if (!destinations.insert(dest).second) { + throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + input.get_str()); + } } } @@ -2770,7 +2780,7 @@ UniValue listunspent(const JSONRPCRequest& request) const CScript& scriptPubKey = out.tx->tx->vout[out.i].scriptPubKey; bool fValidAddress = ExtractDestination(scriptPubKey, address); - if (setAddress.size() && (!fValidAddress || !setAddress.count(address))) + if (destinations.size() && (!fValidAddress || !destinations.count(address))) continue; UniValue entry(UniValue::VOBJ); @@ -2778,7 +2788,7 @@ UniValue listunspent(const JSONRPCRequest& request) entry.push_back(Pair("vout", out.i)); if (fValidAddress) { - entry.push_back(Pair("address", CBitcoinAddress(address).ToString())); + entry.push_back(Pair("address", EncodeDestination(address))); if (pwallet->mapAddressBook.count(address)) { entry.push_back(Pair("account", pwallet->mapAddressBook[address].name)); @@ -2901,12 +2911,13 @@ UniValue fundrawtransaction(const JSONRPCRequest& request) true, true); if (options.exists("changeAddress")) { - CBitcoinAddress address(options["changeAddress"].get_str()); + CTxDestination dest = DecodeDestination(options["changeAddress"].get_str()); - if (!address.IsValid()) + if (!IsValidDestination(dest)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "changeAddress must be a valid bitcoin address"); + } - coinControl.destChange = address.Get(); + coinControl.destChange = dest; } if (options.exists("changePosition")) @@ -3239,9 +3250,6 @@ static const CRPCCommand commands[] = void RegisterWalletRPCCommands(CRPCTable &t) { - if (gArgs.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/rpcwallet.h b/src/wallet/rpcwallet.h index db0808b93b..14e51610d9 100644 --- a/src/wallet/rpcwallet.h +++ b/src/wallet/rpcwallet.h @@ -5,7 +5,10 @@ #ifndef BITCOIN_WALLET_RPCWALLET_H #define BITCOIN_WALLET_RPCWALLET_H +#include <string> + class CRPCTable; +class CWallet; class JSONRPCRequest; void RegisterWalletRPCCommands(CRPCTable &t); diff --git a/src/wallet/test/crypto_tests.cpp b/src/wallet/test/crypto_tests.cpp index cbd74b6f96..f4dabc50c0 100644 --- a/src/wallet/test/crypto_tests.cpp +++ b/src/wallet/test/crypto_tests.cpp @@ -80,7 +80,7 @@ BOOST_AUTO_TEST_CASE(passphrase) { std::string hash(GetRandHash().ToString()); std::vector<unsigned char> vchSalt(8); - GetRandBytes(&vchSalt[0], vchSalt.size()); + GetRandBytes(vchSalt.data(), vchSalt.size()); uint32_t rounds = InsecureRand32(); if (rounds > 30000) rounds = 30000; diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 36d6ce0007..fd2c1dfbe7 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -307,7 +307,7 @@ bool CWallet::LoadCScript(const CScript& redeemScript) * these. Do not add them to the wallet and warn. */ if (redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE) { - std::string strAddr = CBitcoinAddress(CScriptID(redeemScript)).ToString(); + std::string strAddr = EncodeDestination(CScriptID(redeemScript)); LogPrintf("%s: Warning: This wallet contains a redeemScript of size %i which exceeds maximum size %i thus can never be redeemed. Do not use address %s.\n", __func__, redeemScript.size(), MAX_SCRIPT_ELEMENT_SIZE, strAddr); return true; @@ -3073,9 +3073,9 @@ bool CWallet::SetAddressBook(const CTxDestination& address, const std::string& s } NotifyAddressBookChanged(this, address, strName, ::IsMine(*this, address) != ISMINE_NO, strPurpose, (fUpdated ? CT_UPDATED : CT_NEW) ); - if (!strPurpose.empty() && !CWalletDB(*dbw).WritePurpose(CBitcoinAddress(address).ToString(), strPurpose)) + if (!strPurpose.empty() && !CWalletDB(*dbw).WritePurpose(EncodeDestination(address), strPurpose)) return false; - return CWalletDB(*dbw).WriteName(CBitcoinAddress(address).ToString(), strName); + return CWalletDB(*dbw).WriteName(EncodeDestination(address), strName); } bool CWallet::DelAddressBook(const CTxDestination& address) @@ -3084,7 +3084,7 @@ bool CWallet::DelAddressBook(const CTxDestination& address) LOCK(cs_wallet); // mapAddressBook // Delete destdata tuples associated with address - std::string strAddress = CBitcoinAddress(address).ToString(); + std::string strAddress = EncodeDestination(address); for (const std::pair<std::string, std::string> &item : mapAddressBook[address].destdata) { CWalletDB(*dbw).EraseDestData(strAddress, item.first); @@ -3094,8 +3094,8 @@ bool CWallet::DelAddressBook(const CTxDestination& address) NotifyAddressBookChanged(this, address, "", ::IsMine(*this, address) != ISMINE_NO, "", CT_DELETED); - CWalletDB(*dbw).ErasePurpose(CBitcoinAddress(address).ToString()); - return CWalletDB(*dbw).EraseName(CBitcoinAddress(address).ToString()); + CWalletDB(*dbw).ErasePurpose(EncodeDestination(address)); + return CWalletDB(*dbw).EraseName(EncodeDestination(address)); } const std::string& CWallet::GetAccountName(const CScript& scriptPubKey) const @@ -3601,13 +3601,10 @@ void CWallet::GetKeyBirthTimes(std::map<CTxDestination, int64_t> &mapKeyBirth) c // map in which we'll infer heights of other keys CBlockIndex *pindexMax = chainActive[std::max(0, chainActive.Height() - 144)]; // the tip can be reorganized; use a 144-block safety margin std::map<CKeyID, CBlockIndex*> mapKeyFirstBlock; - std::set<CKeyID> setKeys; - GetKeys(setKeys); - for (const CKeyID &keyid : setKeys) { + for (const CKeyID &keyid : GetKeys()) { if (mapKeyBirth.count(keyid) == 0) mapKeyFirstBlock[keyid] = pindexMax; } - setKeys.clear(); // if there are no such keys, we're done if (mapKeyFirstBlock.empty()) @@ -3712,14 +3709,14 @@ bool CWallet::AddDestData(const CTxDestination &dest, const std::string &key, co return false; mapAddressBook[dest].destdata.insert(std::make_pair(key, value)); - return CWalletDB(*dbw).WriteDestData(CBitcoinAddress(dest).ToString(), key, value); + return CWalletDB(*dbw).WriteDestData(EncodeDestination(dest), key, value); } bool CWallet::EraseDestData(const CTxDestination &dest, const std::string &key) { if (!mapAddressBook[dest].destdata.erase(key)) return false; - return CWalletDB(*dbw).EraseDestData(CBitcoinAddress(dest).ToString(), key); + return CWalletDB(*dbw).EraseDestData(EncodeDestination(dest), key); } bool CWallet::LoadDestData(const CTxDestination &dest, const std::string &key, const std::string &value) @@ -3830,17 +3827,17 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile) if (fFirstRun) { - // Create new keyUser and set as default key - if (gArgs.GetBoolArg("-usehd", DEFAULT_USE_HD_WALLET) && !walletInstance->IsHDEnabled()) { - - // ensure this wallet.dat can only be opened by clients supporting HD with chain split - walletInstance->SetMinVersion(FEATURE_HD_SPLIT); - - // generate a new master key - CPubKey masterPubKey = walletInstance->GenerateNewHDMasterKey(); - if (!walletInstance->SetHDMasterKey(masterPubKey)) - throw std::runtime_error(std::string(__func__) + ": Storing master key failed"); + // ensure this wallet.dat can only be opened by clients supporting HD with chain split and expects no default key + if (!gArgs.GetBoolArg("-usehd", true)) { + InitError(strprintf(_("Error creating %s: You can't create non-HD wallets with this version."), walletFile)); + return nullptr; } + walletInstance->SetMinVersion(FEATURE_NO_DEFAULT_KEY); + + // generate a new master key + CPubKey masterPubKey = walletInstance->GenerateNewHDMasterKey(); + if (!walletInstance->SetHDMasterKey(masterPubKey)) + throw std::runtime_error(std::string(__func__) + ": Storing master key failed"); // Top up the keypool if (!walletInstance->TopUpKeyPool()) { @@ -3851,7 +3848,7 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile) walletInstance->SetBestChain(chainActive.GetLocator()); } else if (gArgs.IsArgSet("-usehd")) { - bool useHD = gArgs.GetBoolArg("-usehd", DEFAULT_USE_HD_WALLET); + bool useHD = gArgs.GetBoolArg("-usehd", true); if (walletInstance->IsHDEnabled() && !useHD) { InitError(strprintf(_("Error loading %s: You can't disable HD on an already existing HD wallet"), walletFile)); return nullptr; diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 73ad3bdeca..c4af192f36 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -65,8 +65,6 @@ static const unsigned int DEFAULT_TX_CONFIRM_TARGET = 6; static const bool DEFAULT_WALLET_RBF = false; 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; extern const char * DEFAULT_WALLET_DAT; @@ -87,7 +85,7 @@ enum class FeeEstimateMode; /** (client) version numbers for particular wallet features */ enum WalletFeature { - FEATURE_BASE = 10500, // the earliest version new wallets supports (only useful for getinfo's clientversion output) + FEATURE_BASE = 10500, // the earliest version new wallets supports (only useful for getwalletinfo's clientversion output) FEATURE_WALLETCRYPT = 40000, // wallet encryption FEATURE_COMPRPUBKEY = 60000, // compressed public keys @@ -96,6 +94,8 @@ enum WalletFeature FEATURE_HD_SPLIT = 139900, // Wallet with HD chain split (change outputs will use m/0'/1'/k) + FEATURE_NO_DEFAULT_KEY = 159900, // Wallet without a default key written + FEATURE_LATEST = FEATURE_COMPRPUBKEY // HD is optional, use FEATURE_COMPRPUBKEY as latest version }; diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 12da3cce64..52370a8eb5 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -253,13 +253,13 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, { std::string strAddress; ssKey >> strAddress; - ssValue >> pwallet->mapAddressBook[CBitcoinAddress(strAddress).Get()].name; + ssValue >> pwallet->mapAddressBook[DecodeDestination(strAddress)].name; } else if (strType == "purpose") { std::string strAddress; ssKey >> strAddress; - ssValue >> pwallet->mapAddressBook[CBitcoinAddress(strAddress).Get()].purpose; + ssValue >> pwallet->mapAddressBook[DecodeDestination(strAddress)].purpose; } else if (strType == "tx") { @@ -493,7 +493,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, ssKey >> strAddress; ssKey >> strKey; ssValue >> strValue; - if (!pwallet->LoadDestData(CBitcoinAddress(strAddress).Get(), strKey, strValue)) + if (!pwallet->LoadDestData(DecodeDestination(strAddress), strKey, strValue)) { strErr = "Error reading wallet database: LoadDestData failed"; return false; diff --git a/test/functional/assumevalid.py b/test/functional/assumevalid.py index beaf8c7055..65685c48b7 100755 --- a/test/functional/assumevalid.py +++ b/test/functional/assumevalid.py @@ -68,6 +68,8 @@ class AssumeValidTest(BitcoinTestFramework): def send_blocks_until_disconnected(self, node): """Keep sending blocks to the node until we're disconnected.""" for i in range(len(self.blocks)): + if not node.connection: + break try: node.send_message(msg_block(self.blocks[i])) except IOError as e: diff --git a/test/functional/bitcoin_cli.py b/test/functional/bitcoin_cli.py index 7acfede3f7..ffed5b0d33 100755 --- a/test/functional/bitcoin_cli.py +++ b/test/functional/bitcoin_cli.py @@ -4,7 +4,7 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test bitcoin-cli""" from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import assert_equal +from test_framework.util import assert_equal, assert_raises_process_error, get_auth_cookie class TestBitcoinCli(BitcoinTestFramework): @@ -15,11 +15,25 @@ class TestBitcoinCli(BitcoinTestFramework): def run_test(self): """Main test logic""" - self.log.info("Compare responses from getinfo RPC and `bitcoin-cli getinfo`") - cli_get_info = self.nodes[0].cli.getinfo() - rpc_get_info = self.nodes[0].getinfo() + self.log.info("Compare responses from gewalletinfo RPC and `bitcoin-cli getwalletinfo`") + cli_response = self.nodes[0].cli.getwalletinfo() + rpc_response = self.nodes[0].getwalletinfo() + assert_equal(cli_response, rpc_response) - assert_equal(cli_get_info, rpc_get_info) + self.log.info("Compare responses from getblockchaininfo RPC and `bitcoin-cli getblockchaininfo`") + cli_response = self.nodes[0].cli.getblockchaininfo() + rpc_response = self.nodes[0].getblockchaininfo() + assert_equal(cli_response, rpc_response) + + user, password = get_auth_cookie(self.nodes[0].datadir) + + self.log.info("Test -stdinrpcpass option") + assert_equal(0, self.nodes[0].cli('-rpcuser=%s' % user, '-stdinrpcpass', input=password).getblockcount()) + assert_raises_process_error(1, "incorrect rpcuser or rpcpassword", self.nodes[0].cli('-rpcuser=%s' % user, '-stdinrpcpass', input="foo").echo) + + self.log.info("Test -stdin and -stdinrpcpass") + assert_equal(["foo", "bar"], self.nodes[0].cli('-rpcuser=%s' % user, '-stdin', '-stdinrpcpass', input=password + "\nfoo\nbar").echo()) + assert_raises_process_error(1, "incorrect rpcuser or rpcpassword", self.nodes[0].cli('-rpcuser=%s' % user, '-stdin', '-stdinrpcpass', input="foo").echo) if __name__ == '__main__': TestBitcoinCli().main() diff --git a/test/functional/blockchain.py b/test/functional/blockchain.py index 5d04de9940..50be9262e4 100755 --- a/test/functional/blockchain.py +++ b/test/functional/blockchain.py @@ -21,7 +21,7 @@ from decimal import Decimal import http.client import subprocess -from test_framework.test_framework import (BitcoinTestFramework, BITCOIND_PROC_WAIT_TIMEOUT) +from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, assert_raises, @@ -141,7 +141,7 @@ class BlockchainTest(BitcoinTestFramework): except (ConnectionError, http.client.BadStatusLine): pass # The node already shut down before response self.log.debug('Node should stop at this height...') - self.nodes[0].process.wait(timeout=BITCOIND_PROC_WAIT_TIMEOUT) + self.nodes[0].wait_until_stopped() self.start_node(0) assert_equal(self.nodes[0].getblockcount(), 207) diff --git a/test/functional/dbcrash.py b/test/functional/dbcrash.py index 71424f641b..24b9765b4e 100755 --- a/test/functional/dbcrash.py +++ b/test/functional/dbcrash.py @@ -64,7 +64,7 @@ class ChainstateWriteCrashTest(BitcoinTestFramework): def setup_network(self): # Need a bit of extra time for the nodes to start up for this test - self.add_nodes(self.num_nodes, timewait=90) + self.add_nodes(self.num_nodes, extra_args=self.extra_args, timewait=90) self.start_nodes() # Leave them unconnected, we'll use submitblock directly in this test diff --git a/test/functional/fundrawtransaction.py b/test/functional/fundrawtransaction.py index 75a0dc5f9d..71e88009b6 100755 --- a/test/functional/fundrawtransaction.py +++ b/test/functional/fundrawtransaction.py @@ -4,7 +4,7 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test the fundrawtransaction RPC.""" -from test_framework.test_framework import BitcoinTestFramework, BITCOIND_PROC_WAIT_TIMEOUT +from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * diff --git a/test/functional/keypool-topup.py b/test/functional/keypool-topup.py index b87433a9c5..160a0f7ae5 100755 --- a/test/functional/keypool-topup.py +++ b/test/functional/keypool-topup.py @@ -23,7 +23,7 @@ class KeypoolRestoreTest(BitcoinTestFramework): def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 2 - self.extra_args = [['-usehd=0'], ['-usehd=1', '-keypool=100', '-keypoolmin=20']] + self.extra_args = [[], ['-keypool=100', '-keypoolmin=20']] def run_test(self): self.tmpdir = self.options.tmpdir diff --git a/test/functional/mempool_persist.py b/test/functional/mempool_persist.py index 01f65b1373..149a01870d 100755 --- a/test/functional/mempool_persist.py +++ b/test/functional/mempool_persist.py @@ -28,8 +28,14 @@ Test is as follows: - Restart node0 with -persistmempool. Verify that it has 5 transactions in its mempool. This tests that -persistmempool=0 does not overwrite a previously valid mempool stored on disk. + - Remove node0 mempool.dat and verify savemempool RPC recreates it + and verify that node1 can load it and has 5 transaction in its + mempool. + - Verify that savemempool throws when the RPC is called if + node1 can't write to disk. """ +import os import time from test_framework.test_framework import BitcoinTestFramework @@ -78,5 +84,27 @@ class MempoolPersistTest(BitcoinTestFramework): self.start_node(0) wait_until(lambda: len(self.nodes[0].getrawmempool()) == 5) + mempooldat0 = os.path.join(self.options.tmpdir, 'node0', 'regtest', 'mempool.dat') + mempooldat1 = os.path.join(self.options.tmpdir, 'node1', 'regtest', 'mempool.dat') + self.log.debug("Remove the mempool.dat file. Verify that savemempool to disk via RPC re-creates it") + os.remove(mempooldat0) + self.nodes[0].savemempool() + assert os.path.isfile(mempooldat0) + + self.log.debug("Stop nodes, make node1 use mempool.dat from node0. Verify it has 5 transactions") + os.rename(mempooldat0, mempooldat1) + self.stop_nodes() + self.start_node(1, extra_args=[]) + wait_until(lambda: len(self.nodes[1].getrawmempool()) == 5) + + self.log.debug("Prevent bitcoind from writing mempool.dat to disk. Verify that `savemempool` fails") + # to test the exception we are setting bad permissions on a tmp file called mempool.dat.new + # which is an implementation detail that could change and break this test + mempooldotnew1 = mempooldat1 + '.new' + with os.fdopen(os.open(mempooldotnew1, os.O_CREAT, 0o000), 'w'): + pass + assert_raises_jsonrpc(-1, "Unable to dump mempool to disk", self.nodes[1].savemempool) + os.remove(mempooldotnew1) + if __name__ == '__main__': MempoolPersistTest().main() diff --git a/test/functional/minchainwork.py b/test/functional/minchainwork.py new file mode 100755 index 0000000000..c7579d2548 --- /dev/null +++ b/test/functional/minchainwork.py @@ -0,0 +1,81 @@ +#!/usr/bin/env python3 +# Copyright (c) 2017 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 logic for setting nMinimumChainWork on command line. + +Nodes don't consider themselves out of "initial block download" until +their active chain has more work than nMinimumChainWork. + +Nodes don't download blocks from a peer unless the peer's best known block +has more work than nMinimumChainWork. + +While in initial block download, nodes won't relay blocks to their peers, so +test that this parameter functions as intended by verifying that block relay +only succeeds past a given node once its nMinimumChainWork has been exceeded. +""" + +import time + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import sync_blocks, connect_nodes, assert_equal + +# 2 hashes required per regtest block (with no difficulty adjustment) +REGTEST_WORK_PER_BLOCK = 2 + +class MinimumChainWorkTest(BitcoinTestFramework): + def set_test_params(self): + self.setup_clean_chain = True + self.num_nodes = 3 + self.extra_args = [[], ["-minimumchainwork=0x65"], ["-minimumchainwork=0x65"]] + self.node_min_work = [0, 101, 101] + + def setup_network(self): + # This test relies on the chain setup being: + # node0 <- node1 <- node2 + # Before leaving IBD, nodes prefer to download blocks from outbound + # peers, so ensure that we're mining on an outbound peer and testing + # block relay to inbound peers. + self.setup_nodes() + for i in range(self.num_nodes-1): + connect_nodes(self.nodes[i+1], i) + + def run_test(self): + # Start building a chain on node0. node2 shouldn't be able to sync until node1's + # minchainwork is exceeded + starting_chain_work = REGTEST_WORK_PER_BLOCK # Genesis block's work + self.log.info("Testing relay across node %d (minChainWork = %d)", 1, self.node_min_work[1]) + + starting_blockcount = self.nodes[2].getblockcount() + + num_blocks_to_generate = int((self.node_min_work[1] - starting_chain_work) / REGTEST_WORK_PER_BLOCK) + self.log.info("Generating %d blocks on node0", num_blocks_to_generate) + hashes = self.nodes[0].generate(num_blocks_to_generate) + + self.log.info("Node0 current chain work: %s", self.nodes[0].getblockheader(hashes[-1])['chainwork']) + + # Sleep a few seconds and verify that node2 didn't get any new blocks + # or headers. We sleep, rather than sync_blocks(node0, node1) because + # it's reasonable either way for node1 to get the blocks, or not get + # them (since they're below node1's minchainwork). + time.sleep(3) + + self.log.info("Verifying node 2 has no more blocks than before") + self.log.info("Blockcounts: %s", [n.getblockcount() for n in self.nodes]) + # Node2 shouldn't have any new headers yet, because node1 should not + # have relayed anything. + assert_equal(len(self.nodes[2].getchaintips()), 1) + assert_equal(self.nodes[2].getchaintips()[0]['height'], 0) + + assert self.nodes[1].getbestblockhash() != self.nodes[0].getbestblockhash() + assert_equal(self.nodes[2].getblockcount(), starting_blockcount) + + self.log.info("Generating one more block") + self.nodes[0].generate(1) + + self.log.info("Verifying nodes are all synced") + self.sync_all() + self.log.info("Blockcounts: %s", [n.getblockcount() for n in self.nodes]) + +if __name__ == '__main__': + MinimumChainWorkTest().main() diff --git a/test/functional/mining.py b/test/functional/mining.py index 93f9838896..c8fb1062b7 100755 --- a/test/functional/mining.py +++ b/test/functional/mining.py @@ -38,7 +38,6 @@ class MiningTest(BitcoinTestFramework): mining_info = node.getmininginfo() assert_equal(mining_info['blocks'], 200) assert_equal(mining_info['chain'], 'regtest') - assert_equal(mining_info['currentblocksize'], 0) assert_equal(mining_info['currentblocktx'], 0) assert_equal(mining_info['currentblockweight'], 0) assert_equal(mining_info['difficulty'], Decimal('4.656542373906925E-10')) diff --git a/test/functional/multiwallet.py b/test/functional/multiwallet.py index e5453e9aad..b4e15a3322 100755 --- a/test/functional/multiwallet.py +++ b/test/functional/multiwallet.py @@ -18,6 +18,8 @@ class MultiWalletTest(BitcoinTestFramework): self.extra_args = [['-wallet=w1', '-wallet=w2', '-wallet=w3']] def run_test(self): + assert_equal(set(self.nodes[0].listwallets()), {"w1", "w2", "w3"}) + self.stop_node(0) # should not initialize if there are duplicate wallets diff --git a/test/functional/p2p-leaktests.py b/test/functional/p2p-leaktests.py index f27086c97e..1dc8f72cd6 100755 --- a/test/functional/p2p-leaktests.py +++ b/test/functional/p2p-leaktests.py @@ -139,6 +139,9 @@ class P2PLeakTest(BitcoinTestFramework): [conn.disconnect_node() for conn in connections] + # Wait until all connections are closed + wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 0) + # Make sure no unexpected messages came in assert(no_version_bannode.unexpected_msg == False) assert(no_version_idlenode.unexpected_msg == False) @@ -157,8 +160,10 @@ class P2PLeakTest(BitcoinTestFramework): allowed_service_bit5_node.add_connection(connections[5]) allowed_service_bit7_node.add_connection(connections[6]) - wait_until(lambda: allowed_service_bit5_node.message_count["verack"], timeout=10, lock=mininode_lock) - wait_until(lambda: allowed_service_bit7_node.message_count["verack"], timeout=10, lock=mininode_lock) + NetworkThread().start() # Network thread stopped when all previous NodeConnCBs disconnected. Restart it + + wait_until(lambda: allowed_service_bit5_node.message_count["verack"], lock=mininode_lock) + wait_until(lambda: allowed_service_bit7_node.message_count["verack"], lock=mininode_lock) if __name__ == '__main__': P2PLeakTest().main() diff --git a/test/functional/p2p-versionbits-warning.py b/test/functional/p2p-versionbits-warning.py index 5dfac6dd10..0848fcde64 100755 --- a/test/functional/p2p-versionbits-warning.py +++ b/test/functional/p2p-versionbits-warning.py @@ -87,7 +87,6 @@ class VersionBitsWarningTest(BitcoinTestFramework): self.nodes[0].generate(VB_PERIOD - VB_THRESHOLD + 1) # Check that we're not getting any versionbit-related errors in # get*info() - assert(not VB_PATTERN.match(self.nodes[0].getinfo()["errors"])) assert(not VB_PATTERN.match(self.nodes[0].getmininginfo()["errors"])) assert(not VB_PATTERN.match(self.nodes[0].getnetworkinfo()["warnings"])) @@ -99,7 +98,6 @@ class VersionBitsWarningTest(BitcoinTestFramework): # have gotten a different alert due to more than 51/100 blocks # being of unexpected version. # Check that get*info() shows some kind of error. - assert(WARN_UNKNOWN_RULES_MINED in self.nodes[0].getinfo()["errors"]) assert(WARN_UNKNOWN_RULES_MINED in self.nodes[0].getmininginfo()["errors"]) assert(WARN_UNKNOWN_RULES_MINED in self.nodes[0].getnetworkinfo()["warnings"]) @@ -115,7 +113,6 @@ class VersionBitsWarningTest(BitcoinTestFramework): # Connecting one block should be enough to generate an error. self.nodes[0].generate(1) - assert(WARN_UNKNOWN_RULES_ACTIVE in self.nodes[0].getinfo()["errors"]) assert(WARN_UNKNOWN_RULES_ACTIVE in self.nodes[0].getmininginfo()["errors"]) assert(WARN_UNKNOWN_RULES_ACTIVE in self.nodes[0].getnetworkinfo()["warnings"]) self.stop_nodes() diff --git a/test/functional/rpcnamedargs.py b/test/functional/rpcnamedargs.py index da61cc66e6..b3cc681dad 100755 --- a/test/functional/rpcnamedargs.py +++ b/test/functional/rpcnamedargs.py @@ -16,10 +16,10 @@ class NamedArgumentTest(BitcoinTestFramework): def run_test(self): node = self.nodes[0] - h = node.help(command='getinfo') - assert(h.startswith('getinfo\n')) + h = node.help(command='getblockchaininfo') + assert(h.startswith('getblockchaininfo\n')) - assert_raises_jsonrpc(-8, 'Unknown named parameter', node.help, random='getinfo') + assert_raises_jsonrpc(-8, 'Unknown named parameter', node.help, random='getblockchaininfo') h = node.getblockhash(height=0) node.getblock(blockhash=h) diff --git a/test/functional/segwit.py b/test/functional/segwit.py index 609c592ed3..f465c1683b 100755 --- a/test/functional/segwit.py +++ b/test/functional/segwit.py @@ -279,6 +279,9 @@ class SegWitTest(BitcoinTestFramework): assert(txid2 in template_txids) assert(txid3 in template_txids) + # Check that wtxid is properly reported in mempool entry + assert_equal(int(self.nodes[0].getmempoolentry(txid3)["wtxid"], 16), tx.calc_sha256(True)) + # Mine a block to clear the gbt cache again. self.nodes[0].generate(1) diff --git a/test/functional/test_framework/mininode.py b/test/functional/test_framework/mininode.py index 2607b9b07c..abed661f37 100755 --- a/test/functional/test_framework/mininode.py +++ b/test/functional/test_framework/mininode.py @@ -1654,6 +1654,7 @@ class NodeConn(asyncore.dispatcher): self.dstaddr = dstaddr self.dstport = dstport self.create_socket(socket.AF_INET, socket.SOCK_STREAM) + self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) self.sendbuf = b"" self.recvbuf = b"" self.ver_send = 209 @@ -1792,7 +1793,14 @@ class NodeConn(asyncore.dispatcher): tmsg += h[:4] tmsg += data with mininode_lock: - self.sendbuf += tmsg + if (len(self.sendbuf) == 0 and not pushbuf): + try: + sent = self.send(tmsg) + self.sendbuf = tmsg[sent:] + except BlockingIOError: + self.sendbuf = tmsg + else: + self.sendbuf += tmsg self.last_sent = time.time() def got_message(self, message): @@ -1830,6 +1838,7 @@ class NetworkThread(Thread): disconnected.append(obj) [ obj.handle_close() for obj in disconnected ] asyncore.loop(0.1, use_poll=True, map=mininode_socket_map, count=1) + logger.debug("Network thread closing") # An exception we can raise if we detect a potential disconnect diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index 103651f175..a53eb51799 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -43,8 +43,6 @@ TEST_EXIT_PASSED = 0 TEST_EXIT_FAILED = 1 TEST_EXIT_SKIPPED = 77 -BITCOIND_PROC_WAIT_TIMEOUT = 60 - class BitcoinTestFramework(object): """Base class for a bitcoin test script. @@ -263,8 +261,7 @@ class BitcoinTestFramework(object): def stop_node(self, i): """Stop a bitcoind test node""" self.nodes[i].stop_node() - while not self.nodes[i].is_node_stopped(): - time.sleep(0.1) + self.nodes[i].wait_until_stopped() def stop_nodes(self): """Stop multiple bitcoind test nodes""" @@ -274,8 +271,7 @@ class BitcoinTestFramework(object): for node in self.nodes: # Wait for nodes to stop - while not node.is_node_stopped(): - time.sleep(0.1) + node.wait_until_stopped() def assert_start_raises_init_error(self, i, extra_args=None, expected_msg=None): with tempfile.SpooledTemporaryFile(max_size=2**16) as log_stderr: diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index efb3ac9d16..12dab57a02 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -17,9 +17,12 @@ from .util import ( assert_equal, get_rpc_proxy, rpc_url, + wait_until, ) from .authproxy import JSONRPCException +BITCOIND_PROC_WAIT_TIMEOUT = 60 + class TestNode(): """A class for representing a bitcoind node under test. @@ -125,14 +128,20 @@ class TestNode(): if not self.running: return True return_code = self.process.poll() - if return_code is not None: - # process has stopped. Assert that it didn't return an error code. - assert_equal(return_code, 0) - self.running = False - self.process = None - self.log.debug("Node stopped") - return True - return False + if return_code is None: + return False + + # process has stopped. Assert that it didn't return an error code. + assert_equal(return_code, 0) + self.running = False + self.process = None + self.rpc_connected = False + self.rpc = None + self.log.debug("Node stopped") + return True + + def wait_until_stopped(self, timeout=BITCOIND_PROC_WAIT_TIMEOUT): + wait_until(self.is_node_stopped, timeout=timeout) def node_encrypt_wallet(self, passphrase): """"Encrypts the wallet. @@ -140,17 +149,22 @@ class TestNode(): This causes bitcoind to shutdown, so this method takes care of cleaning up resources.""" self.encryptwallet(passphrase) - while not self.is_node_stopped(): - time.sleep(0.1) - self.rpc = None - self.rpc_connected = False + self.wait_until_stopped() class TestNodeCLI(): """Interface to bitcoin-cli for an individual node""" def __init__(self, binary, datadir): + self.args = [] self.binary = binary self.datadir = datadir + self.input = None + + def __call__(self, *args, input=None): + # TestNodeCLI is callable with bitcoin-cli command-line args + self.args = [str(arg) for arg in args] + self.input = input + return self def __getattr__(self, command): def dispatcher(*args, **kwargs): @@ -163,9 +177,14 @@ class TestNodeCLI(): pos_args = [str(arg) for arg in args] named_args = [str(key) + "=" + str(value) for (key, value) in kwargs.items()] assert not (pos_args and named_args), "Cannot use positional arguments and named arguments in the same bitcoin-cli call" - p_args = [self.binary, "-datadir=" + self.datadir] + p_args = [self.binary, "-datadir=" + self.datadir] + self.args if named_args: p_args += ["-named"] p_args += [command] + pos_args + named_args - cli_output = subprocess.check_output(p_args, universal_newlines=True) - return json.loads(cli_output, parse_float=decimal.Decimal) + process = subprocess.Popen(p_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) + cli_stdout, cli_stderr = process.communicate(input=self.input) + returncode = process.poll() + if returncode: + # Ignore cli_stdout, raise with cli_stderr + raise subprocess.CalledProcessError(returncode, self.binary, output=cli_stderr) + return json.loads(cli_stdout, parse_float=decimal.Decimal) diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py index a14cda07d0..b2d8199d12 100644 --- a/test/functional/test_framework/util.py +++ b/test/functional/test_framework/util.py @@ -12,6 +12,7 @@ import logging import os import random import re +from subprocess import CalledProcessError import time from . import coverage @@ -57,18 +58,42 @@ def assert_raises_message(exc, message, fun, *args, **kwds): else: raise AssertionError("No exception raised") +def assert_raises_process_error(returncode, output, fun, *args, **kwds): + """Execute a process and asserts the process return code and output. + + Calls function `fun` with arguments `args` and `kwds`. Catches a CalledProcessError + and verifies that the return code and output are as expected. Throws AssertionError if + no CalledProcessError was raised or if the return code and output are not as expected. + + Args: + returncode (int): the process return code. + output (string): [a substring of] the process output. + fun (function): the function to call. This should execute a process. + args*: positional arguments for the function. + kwds**: named arguments for the function. + """ + try: + fun(*args, **kwds) + except CalledProcessError as e: + if returncode != e.returncode: + raise AssertionError("Unexpected returncode %i" % e.returncode) + if output not in e.output: + raise AssertionError("Expected substring not found:" + e.output) + else: + raise AssertionError("No exception raised") + def assert_raises_jsonrpc(code, message, fun, *args, **kwds): """Run an RPC and verify that a specific JSONRPC exception code and message is raised. Calls function `fun` with arguments `args` and `kwds`. Catches a JSONRPCException and verifies that the error code and message are as expected. Throws AssertionError if - no JSONRPCException was returned or if the error code/message are not as expected. + no JSONRPCException was raised or if the error code/message are not as expected. Args: code (int), optional: the error code returned by the RPC call (defined in src/rpc/protocol.h). Set to None if checking the error code is not required. message (string), optional: [a substring of] the error string returned by the - RPC call. Set to None if checking the error string is not required + RPC call. Set to None if checking the error string is not required. fun (function): the function to call. This should be the name of an RPC. args*: positional arguments for the function. kwds**: named arguments for the function. diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index 59c236ce15..8dbe6247ee 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -121,6 +121,7 @@ BASE_SCRIPTS= [ 'bip65-cltv-p2p.py', 'uptime.py', 'resendwallettransactions.py', + 'minchainwork.py', ] EXTENDED_SCRIPTS = [ diff --git a/test/functional/wallet-encryption.py b/test/functional/wallet-encryption.py index f63bb2ea5e..ce1e7744e9 100755 --- a/test/functional/wallet-encryption.py +++ b/test/functional/wallet-encryption.py @@ -6,7 +6,7 @@ import time -from test_framework.test_framework import BitcoinTestFramework, BITCOIND_PROC_WAIT_TIMEOUT +from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, assert_raises_jsonrpc, diff --git a/test/functional/wallet-hd.py b/test/functional/wallet-hd.py index a6b96b7455..5ef3bf5bff 100755 --- a/test/functional/wallet-hd.py +++ b/test/functional/wallet-hd.py @@ -15,7 +15,7 @@ class WalletHDTest(BitcoinTestFramework): def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 2 - self.extra_args = [['-usehd=0'], ['-usehd=1', '-keypool=0']] + self.extra_args = [[], ['-keypool=0']] def run_test (self): tmpdir = self.options.tmpdir diff --git a/test/functional/wallet.py b/test/functional/wallet.py index 27089e8845..a643684c7f 100755 --- a/test/functional/wallet.py +++ b/test/functional/wallet.py @@ -10,10 +10,9 @@ class WalletTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 4 self.setup_clean_chain = True - self.extra_args = [['-usehd={:d}'.format(i%2==0)] for i in range(4)] def setup_network(self): - self.add_nodes(4, self.extra_args) + self.add_nodes(4) self.start_node(0) self.start_node(1) self.start_node(2) diff --git a/test/functional/zapwallettxes.py b/test/functional/zapwallettxes.py index c001517a6d..83b11035c8 100755 --- a/test/functional/zapwallettxes.py +++ b/test/functional/zapwallettxes.py @@ -15,9 +15,11 @@ been zapped. """ from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import (assert_equal, - assert_raises_jsonrpc, - ) +from test_framework.util import ( + assert_equal, + assert_raises_jsonrpc, + wait_until, +) class ZapWalletTXesTest (BitcoinTestFramework): def set_test_params(self): @@ -56,6 +58,8 @@ class ZapWalletTXesTest (BitcoinTestFramework): self.stop_node(0) self.start_node(0, ["-persistmempool=1", "-zapwallettxes=2"]) + wait_until(lambda: self.nodes[0].getmempoolinfo()['size'] == 1, timeout=3) + assert_equal(self.nodes[0].gettransaction(txid1)['txid'], txid1) assert_equal(self.nodes[0].gettransaction(txid2)['txid'], txid2) |