aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml2
-rwxr-xr-x.travis/test_04_install.sh2
-rw-r--r--CONTRIBUTING.md3
-rw-r--r--COPYING4
-rw-r--r--build_msvc/README.md15
-rw-r--r--configure.ac2
-rw-r--r--contrib/debian/copyright2
-rwxr-xr-xcontrib/macdeploy/custom_dsstore.py2
-rw-r--r--doc/build-netbsd.md52
-rw-r--r--doc/man/bitcoin-cli.143
-rw-r--r--doc/man/bitcoin-qt.168
-rw-r--r--doc/man/bitcoin-tx.119
-rw-r--r--doc/man/bitcoind.169
-rw-r--r--doc/psbt.md2
-rw-r--r--doc/release-notes-14060.md21
-rw-r--r--doc/release-notes-14477.md5
-rw-r--r--doc/release-notes-pr13381.md29
-rw-r--r--doc/release-notes.md107
-rw-r--r--doc/release-notes/release-notes-0.17.1.md168
-rw-r--r--src/amount.h2
-rw-r--r--src/bench/block_assemble.cpp2
-rw-r--r--src/bench/gcs_filter.cpp4
-rw-r--r--src/blockfilter.cpp62
-rw-r--r--src/blockfilter.h54
-rw-r--r--src/compat.h9
-rw-r--r--src/consensus/tx_verify.cpp2
-rw-r--r--src/fs.h2
-rw-r--r--src/init.cpp14
-rw-r--r--src/key_io.cpp2
-rw-r--r--src/net.cpp176
-rw-r--r--src/net.h2
-rw-r--r--src/netbase.cpp21
-rw-r--r--src/noui.h2
-rw-r--r--src/policy/fees.cpp17
-rw-r--r--src/policy/fees.h40
-rw-r--r--src/qt/bitcoingui.cpp15
-rw-r--r--src/qt/clientmodel.cpp14
-rw-r--r--src/qt/forms/optionsdialog.ui2
-rw-r--r--src/qt/splashscreen.cpp7
-rw-r--r--src/qt/transactiontablemodel.cpp5
-rw-r--r--src/qt/walletframe.h2
-rw-r--r--src/qt/walletmodel.cpp12
-rw-r--r--src/rpc/rawtransaction.cpp4
-rw-r--r--src/rpc/server.cpp7
-rw-r--r--src/scheduler.cpp5
-rw-r--r--src/scheduler.h2
-rw-r--r--src/test/blockfilter_tests.cpp26
-rw-r--r--src/test/key_io_tests.cpp2
-rw-r--r--src/test/scheduler_tests.cpp17
-rw-r--r--src/test/test_bitcoin.cpp2
-rw-r--r--src/test/transaction_tests.cpp2
-rw-r--r--src/test/txvalidation_tests.cpp2
-rw-r--r--src/threadinterrupt.h2
-rw-r--r--src/torcontrol.cpp23
-rw-r--r--src/validation.cpp33
-rw-r--r--src/validationinterface.cpp61
-rw-r--r--src/wallet/rpcdump.cpp379
-rw-r--r--test/functional/data/invalid_txs.py180
-rwxr-xr-xtest/functional/feature_assumevalid.py2
-rwxr-xr-xtest/functional/feature_block.py66
-rwxr-xr-xtest/functional/feature_dbcrash.py2
-rwxr-xr-xtest/functional/feature_pruning.py4
-rwxr-xr-xtest/functional/mempool_accept.py2
-rwxr-xr-xtest/functional/p2p_invalid_locator.py2
-rwxr-xr-xtest/functional/p2p_invalid_tx.py24
-rwxr-xr-xtest/functional/p2p_timeouts.py6
-rwxr-xr-xtest/functional/rpc_bind.py2
-rwxr-xr-xtest/functional/rpc_fundrawtransaction.py2
-rwxr-xr-xtest/functional/rpc_net.py4
-rwxr-xr-xtest/functional/rpc_rawtransaction.py2
-rw-r--r--test/functional/test_framework/blocktools.py2
-rwxr-xr-xtest/functional/test_framework/test_framework.py40
-rwxr-xr-xtest/functional/wallet_backup.py2
-rwxr-xr-xtest/functional/wallet_dump.py2
-rwxr-xr-xtest/functional/wallet_groups.py2
-rwxr-xr-xtest/functional/wallet_importmulti.py110
-rwxr-xr-xtest/functional/wallet_listtransactions.py3
-rwxr-xr-xtest/lint/lint-format-strings.py5
-rwxr-xr-xtest/lint/lint-includes.sh1
-rwxr-xr-xtest/lint/lint-python-dead-code.sh2
80 files changed, 1417 insertions, 700 deletions
diff --git a/.travis.yml b/.travis.yml
index b38c7e21c8..6181726fb6 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,4 +1,4 @@
-dist: trusty
+dist: xenial
os: linux
language: minimal
cache:
diff --git a/.travis/test_04_install.sh b/.travis/test_04_install.sh
index 3f74158117..a111387f10 100755
--- a/.travis/test_04_install.sh
+++ b/.travis/test_04_install.sh
@@ -15,6 +15,8 @@ export UBSAN_OPTIONS="suppressions=${TRAVIS_BUILD_DIR}/test/sanitizer_suppressio
env | grep -E '^(BITCOIN_CONFIG|CCACHE_|WINEDEBUG|LC_ALL|BOOST_TEST_RANDOM|CONFIG_SHELL|(ASAN|LSAN|TSAN|UBSAN)_OPTIONS)' | tee /tmp/env
if [[ $HOST = *-mingw32 ]]; then
DOCKER_ADMIN="--cap-add SYS_ADMIN"
+elif [[ $BITCOIN_CONFIG = *--with-sanitizers=*address* ]]; then # If ran with (ASan + LSan), Docker needs access to ptrace (https://github.com/google/sanitizers/issues/764)
+ DOCKER_ADMIN="--cap-add SYS_PTRACE"
fi
DOCKER_ID=$(docker run $DOCKER_ADMIN -idt --mount type=bind,src=$TRAVIS_BUILD_DIR,dst=$TRAVIS_BUILD_DIR --mount type=bind,src=$CCACHE_DIR,dst=$CCACHE_DIR -w $TRAVIS_BUILD_DIR --env-file /tmp/env $DOCKER_NAME_TAG)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 08b2fa609e..139fe7dc52 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -25,7 +25,8 @@ Most communication about Bitcoin Core development happens on IRC, in the
#bitcoin-core-dev channel on Freenode. The easiest way to participate on IRC is
with the web client, [webchat.freenode.net](https://webchat.freenode.net/). Chat
history logs can be found
-on [botbot.me](https://botbot.me/freenode/bitcoin-core-dev/).
+on [http://www.erisian.com.au/bitcoin-core-dev/](http://www.erisian.com.au/bitcoin-core-dev/)
+and [http://gnusha.org/bitcoin-core-dev/](http://gnusha.org/bitcoin-core-dev/).
Discussion about code base improvements happens in GitHub issues and on pull
requests.
diff --git a/COPYING b/COPYING
index 9704b9c94c..9d54ecbde1 100644
--- a/COPYING
+++ b/COPYING
@@ -1,7 +1,7 @@
The MIT License (MIT)
-Copyright (c) 2009-2018 The Bitcoin Core developers
-Copyright (c) 2009-2018 Bitcoin Developers
+Copyright (c) 2009-2019 The Bitcoin Core developers
+Copyright (c) 2009-2019 Bitcoin Developers
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/build_msvc/README.md b/build_msvc/README.md
index 5fb08df8d7..63c5babf35 100644
--- a/build_msvc/README.md
+++ b/build_msvc/README.md
@@ -31,20 +31,13 @@ Additional dependencies required from the [bitcoin-core](https://github.com/bitc
Building
---------------------
-The instructions below use vcpkg to install the dependencies.
+The instructions below use `vcpkg` to install the dependencies.
-- Clone and vcpkg from the [github repository](https://github.com/Microsoft/vcpkg) and install as per the instructions in the main README.md.
+- Clone `vcpkg` from the [github repository](https://github.com/Microsoft/vcpkg) and install as per the instructions in the main README.md.
- Install the required packages (replace x64 with x86 as required):
-- Install the required dependencies with vcpkg:
```
- PS >.\vcpkg install boost:x64-windows-static `
- libevent:x64-windows-static `
- openssl:x64-windows-static `
- zeromq:x64-windows-static `
- berkeleydb:x64-windows-static `
- secp256k1:x64-windows-static `
- leveldb:x64-windows-static
+ PS >.\vcpkg install --triplet x64-windows-static boost-filesystem boost-signals2 boost-test libevent openssl zeromq berkeleydb secp256k1 leveldb
```
- Use Python to generate *.vcxproj from Makefile
@@ -53,4 +46,4 @@ The instructions below use vcpkg to install the dependencies.
PS >python msvc-autogen.py
```
-- Build in Visual Studio. \ No newline at end of file
+- Build in Visual Studio.
diff --git a/configure.ac b/configure.ac
index 2d34b83047..4b34082270 100644
--- a/configure.ac
+++ b/configure.ac
@@ -6,7 +6,7 @@ define(_CLIENT_VERSION_REVISION, 99)
define(_CLIENT_VERSION_BUILD, 0)
define(_CLIENT_VERSION_RC, 0)
define(_CLIENT_VERSION_IS_RELEASE, false)
-define(_COPYRIGHT_YEAR, 2018)
+define(_COPYRIGHT_YEAR, 2019)
define(_COPYRIGHT_HOLDERS,[The %s developers])
define(_COPYRIGHT_HOLDERS_SUBSTITUTION,[[Bitcoin Core]])
AC_INIT([Bitcoin Core],m4_join([.], _CLIENT_VERSION_MAJOR, _CLIENT_VERSION_MINOR, _CLIENT_VERSION_REVISION, m4_if(_CLIENT_VERSION_BUILD, [0], [], _CLIENT_VERSION_BUILD))m4_if(_CLIENT_VERSION_RC, [0], [], [rc]_CLIENT_VERSION_RC),[https://github.com/bitcoin/bitcoin/issues],[bitcoin],[https://bitcoincore.org/])
diff --git a/contrib/debian/copyright b/contrib/debian/copyright
index e5b9cbaa40..2d5b0188d2 100644
--- a/contrib/debian/copyright
+++ b/contrib/debian/copyright
@@ -5,7 +5,7 @@ Upstream-Contact: Satoshi Nakamoto <satoshin@gmx.com>
Source: https://github.com/bitcoin/bitcoin
Files: *
-Copyright: 2009-2018, Bitcoin Core Developers
+Copyright: 2009-2019, Bitcoin Core Developers
License: Expat
Comment: The Bitcoin Core Developers encompasses the current developers listed on bitcoin.org,
as well as the numerous contributors to the project.
diff --git a/contrib/macdeploy/custom_dsstore.py b/contrib/macdeploy/custom_dsstore.py
index c29f83a91e..dc1c1882dd 100755
--- a/contrib/macdeploy/custom_dsstore.py
+++ b/contrib/macdeploy/custom_dsstore.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2013-2017 The Bitcoin Core developers
+# Copyright (c) 2013-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
import biplist
diff --git a/doc/build-netbsd.md b/doc/build-netbsd.md
index 5bf2d6b59b..ab422f6aa7 100644
--- a/doc/build-netbsd.md
+++ b/doc/build-netbsd.md
@@ -1,6 +1,6 @@
NetBSD build guide
======================
-(updated for NetBSD 7.0)
+(updated for NetBSD 8.0)
This guide describes how to build bitcoind and command-line utilities on NetBSD.
@@ -15,21 +15,38 @@ You will need the following modules, which can be installed via pkgsrc or pkgin:
autoconf
automake
boost
-db4
git
gmake
libevent
libtool
-python27
-```
+pkg-config
+python37
-Download the source code:
-```
-git clone https://github.com/bitcoin/bitcoin
+git clone https://github.com/bitcoin/bitcoin.git
```
See [dependencies.md](dependencies.md) for a complete overview.
+### Building BerkeleyDB
+
+BerkeleyDB is only necessary for the wallet functionality. To skip this, pass
+`--disable-wallet` to `./configure` and skip to the next section.
+
+It is recommended to use Berkeley DB 4.8. You cannot use the BerkeleyDB library
+from ports, for the same reason as boost above (g++/libstd++ incompatibility).
+If you have to build it yourself, you can use [the installation script included
+in contrib/](/contrib/install_db4.sh) like so:
+
+```shell
+./contrib/install_db4.sh `pwd`
+```
+
+from the root of the repository. Then set `BDB_PREFIX` for the next section:
+
+```shell
+export BDB_PREFIX="$PWD/db4"
+```
+
### Building Bitcoin Core
**Important**: Use `gmake` (the non-GNU `make` will exit with an error).
@@ -37,13 +54,26 @@ See [dependencies.md](dependencies.md) for a complete overview.
With wallet:
```
./autogen.sh
-./configure CPPFLAGS="-I/usr/pkg/include" LDFLAGS="-L/usr/pkg/lib" BOOST_CPPFLAGS="-I/usr/pkg/include" BOOST_LDFLAGS="-L/usr/pkg/lib"
-gmake
+./configure --with-gui=no CPPFLAGS="-I/usr/pkg/include" \
+ LDFLAGS="-L/usr/pkg/lib" \
+ BOOST_CPPFLAGS="-I/usr/pkg/include" \
+ BOOST_LDFLAGS="-L/usr/pkg/lib" \
+ BDB_LIBS="-L${BDB_PREFIX}/lib -ldb_cxx-4.8" \
+ BDB_CFLAGS="-I${BDB_PREFIX}/include"
```
Without wallet:
```
./autogen.sh
-./configure --disable-wallet CPPFLAGS="-I/usr/pkg/include" LDFLAGS="-L/usr/pkg/lib" BOOST_CPPFLAGS="-I/usr/pkg/include" BOOST_LDFLAGS="-L/usr/pkg/lib"
-gmake
+./configure --with-gui=no --disable-wallet \
+ CPPFLAGS="-I/usr/pkg/include" \
+ LDFLAGS="-L/usr/pkg/lib" \
+ BOOST_CPPFLAGS="-I/usr/pkg/include" \
+ BOOST_LDFLAGS="-L/usr/pkg/lib"
+```
+
+Build and run the tests:
+```bash
+gmake # use -jX here for parallelism
+gmake check
```
diff --git a/doc/man/bitcoin-cli.1 b/doc/man/bitcoin-cli.1
index bf24d929bc..553addfa84 100644
--- a/doc/man/bitcoin-cli.1
+++ b/doc/man/bitcoin-cli.1
@@ -1,17 +1,21 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.6.
-.TH BITCOIN-CLI "1" "July 2018" "bitcoin-cli v0.16.99.0" "User Commands"
+.TH BITCOIN-CLI "1" "December 2018" "bitcoin-cli v0.17.99.0" "User Commands"
.SH NAME
-bitcoin-cli \- manual page for bitcoin-cli v0.16.99.0
+bitcoin-cli \- manual page for bitcoin-cli v0.17.99.0
+.SH SYNOPSIS
+.B bitcoin-cli
+[\fI\,options\/\fR] \fI\,<command> \/\fR[\fI\,params\/\fR] \fI\,Send command to Bitcoin Core\/\fR
+.br
+.B bitcoin-cli
+[\fI\,options\/\fR] \fI\,-named <command> \/\fR[\fI\,name=value\/\fR]... \fI\,Send command to Bitcoin Core (with named arguments)\/\fR
+.br
+.B bitcoin-cli
+[\fI\,options\/\fR] \fI\,help List commands\/\fR
+.br
+.B bitcoin-cli
+[\fI\,options\/\fR] \fI\,help <command> Get help for a command\/\fR
.SH DESCRIPTION
-Bitcoin Core RPC client version v0.16.99.0
-.SS "Usage:"
-.TP
-bitcoin\-cli [options] <command> [params]
-Send command to Bitcoin Core
-.IP
-bitcoin\-cli [options] \fB\-named\fR <command> [name=value] ... Send command to Bitcoin Core (with named arguments)
-bitcoin\-cli [options] help List commands
-bitcoin\-cli [options] help <command> Get help for a command
+Bitcoin Core RPC client version v0.17.99.0
.SH OPTIONS
.HP
\-?
@@ -59,7 +63,8 @@ Password for JSON\-RPC connections
.HP
\fB\-rpcport=\fR<port>
.IP
-Connect to JSON\-RPC on <port> (default: 8332 or testnet: 18332)
+Connect to JSON\-RPC on <port> (default: 8332, testnet: 18332, regtest:
+18443)
.HP
\fB\-rpcuser=\fR<user>
.IP
@@ -72,20 +77,20 @@ Wait for RPC server to start
\fB\-rpcwallet=\fR<walletname>
.IP
Send RPC for non\-default wallet on RPC server (needs to exactly match
-corresponding \fB\-wallet\fR option passed to bitcoind)
+corresponding \fB\-wallet\fR option passed to bitcoind). This changes
+the RPC endpoint used, e.g.
+http://127.0.0.1:8332/wallet/<walletname>
.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).
-When combined with \fB\-stdinrpcpass\fR, the first line from standard
-input is used for the RPC password.
+(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\-stdinrpcpass\fR
-.TP
-Read RPC password from standard input as a single line.
-When combined
.IP
+Read RPC password from standard input as a single line. When combined
with \fB\-stdin\fR, the first line from standard input is used for the
RPC password.
.HP
diff --git a/doc/man/bitcoin-qt.1 b/doc/man/bitcoin-qt.1
index 3a18c9f49f..1d87acd3de 100644
--- a/doc/man/bitcoin-qt.1
+++ b/doc/man/bitcoin-qt.1
@@ -1,12 +1,12 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.6.
-.TH BITCOIN-QT "1" "July 2018" "bitcoin-qt v0.16.99.0" "User Commands"
+.TH BITCOIN-QT "1" "December 2018" "bitcoin-qt v0.17.99.0" "User Commands"
.SH NAME
-bitcoin-qt \- manual page for bitcoin-qt v0.16.99.0
+bitcoin-qt \- manual page for bitcoin-qt v0.17.99.0
+.SH SYNOPSIS
+.B bitcoin-qt
+[\fI\,command-line options\/\fR]
.SH DESCRIPTION
-Bitcoin Core version v0.16.99.0 (64\-bit)
-Usage:
-.IP
-bitcoin\-qt [command\-line options]
+Bitcoin Core version v0.17.99.0 (64\-bit)
.SH OPTIONS
.HP
\-?
@@ -23,9 +23,9 @@ long fork (%s in cmd is replaced by message)
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:
-0000000000000000005214481d2d96f898e3d5416e43359c145944a909d242e0,
+0000000000000000002e63058c023a9a1de233554f28c7b21380b6c9003f36a8,
testnet:
-0000000002e9e7b00e1f6dc5123a04aad68dd0f0968d8c7aa45f6640795c37b1)
+0000000000000037a8cd3e06cd5edbfe9dd1dbcc5dacab279376ef7cfc2b4c75)
.HP
\fB\-blocknotify=\fR<cmd>
.IP
@@ -61,7 +61,8 @@ Set database cache size in megabytes (4 to 16384, default: 450)
\fB\-debuglogfile=\fR<file>
.IP
Specify location of debug log file. Relative paths will be prefixed by a
-net\-specific datadir location. (0 to disable; default: debug.log)
+net\-specific datadir location. (\fB\-nodebuglogfile\fR to disable;
+default: debug.log)
.HP
\fB\-includeconf=\fR<file>
.IP
@@ -108,7 +109,7 @@ blocks if a target size in MiB is provided. This mode is
incompatible with \fB\-txindex\fR and \fB\-rescan\fR. Warning: Reverting this
setting requires re\-downloading the entire blockchain. (default:
0 = disable pruning blocks, 1 = allow manual pruning via RPC,
->550 = automatically prune block files to stay under the
+>=550 = automatically prune block files to stay under the
specified target size in MiB)
.HP
\fB\-reindex\fR
@@ -117,7 +118,9 @@ Rebuild chain state and block index from the blk*.dat files on disk
.HP
\fB\-reindex\-chainstate\fR
.IP
-Rebuild chain state from the currently indexed blocks
+Rebuild chain state from the currently indexed blocks. When in pruning
+mode or if blocks on disk might be corrupted, use full \fB\-reindex\fR
+instead.
.HP
\fB\-sysperms\fR
.IP
@@ -157,7 +160,7 @@ for IPv6
.HP
\fB\-connect=\fR<ip>
.IP
-Connect only to the specified node; \fB\-connect\fR=\fI\,0\/\fR disables automatic
+Connect only to the specified node; \fB\-noconnect\fR disables automatic
connections (the rules for this peer are the same as for
\fB\-addnode\fR). This option can be specified multiple times to connect
to multiple nodes.
@@ -178,7 +181,7 @@ unless \fB\-connect\fR used)
.HP
\fB\-enablebip61\fR
.IP
-Send reject messages per BIP61 (default: 1)
+Send reject messages per BIP61 (default: 0)
.HP
\fB\-externalip=\fR<ip>
.IP
@@ -221,8 +224,8 @@ Tries to keep outbound traffic under the given target (in MiB per 24h),
.HP
\fB\-onion=\fR<ip:port>
.IP
-Use separate SOCKS5 proxy to reach peers via Tor hidden services
-(default: \fB\-proxy\fR)
+Use separate SOCKS5 proxy to reach peers via Tor hidden services, set
+\fB\-noonion\fR to disable (default: \fB\-proxy\fR)
.HP
\fB\-onlynet=\fR<net>
.IP
@@ -242,11 +245,13 @@ Relay non\-P2SH multisig (default: 1)
.HP
\fB\-port=\fR<port>
.IP
-Listen for connections on <port> (default: 8333 or testnet: 18333)
+Listen for connections on <port> (default: 8333, testnet: 18333,
+regtest: 18444)
.HP
\fB\-proxy=\fR<ip:port>
.IP
-Connect through SOCKS5 proxy
+Connect through SOCKS5 proxy, set \fB\-noproxy\fR to disable (default:
+disabled)
.HP
\fB\-proxyrandomize\fR
.IP
@@ -393,8 +398,7 @@ Send transactions with full\-RBF opt\-in enabled (RPC only, default: 0)
.IP
Delete all wallet transactions and only recover those parts of the
blockchain through \fB\-rescan\fR on startup (1 = keep tx meta data e.g.
-account owner and payment request information, 2 = drop tx meta
-data)
+payment request information, 2 = drop tx meta data)
.PP
ZeroMQ notification options:
.HP
@@ -418,7 +422,7 @@ Debugging/Testing options:
.HP
\fB\-debug=\fR<category>
.IP
-Output debugging information (default: 0, supplying <category> is
+Output debugging information (default: \fB\-nodebug\fR, supplying <category> is
optional). If <category> is not supplied or if <category> = 1,
output all debugging information. <category> can be: net, tor,
mempool, http, bench, zmq, db, rpc, estimatefee, addrman,
@@ -433,7 +437,7 @@ or more specified categories.
.HP
\fB\-help\-debug\fR
.IP
-Show all debugging options (usage: \fB\-\-help\fR \fB\-help\-debug\fR)
+Print help message with debugging options and exit
.HP
\fB\-logips\fR
.IP
@@ -452,7 +456,7 @@ transaction; setting this too low may abort large transactions
\fB\-printtoconsole\fR
.IP
Send trace/debug info to console (default: 1 when no \fB\-daemon\fR. To disable
-logging to file, set debuglogfile=0)
+logging to file, set \fB\-nodebuglogfile\fR)
.HP
\fB\-shrinkdebugfile\fR
.IP
@@ -529,8 +533,8 @@ option can be specified multiple times
.HP
\fB\-rpcauth=\fR<userpw>
.IP
-Username and hashed password for JSON\-RPC connections. The field
-<userpw> comes in the format: <USERNAME>:<SALT>$<HASH>. A
+Username and HMAC\-SHA\-256 hashed password for JSON\-RPC connections. The
+field <userpw> comes in the format: <USERNAME>:<SALT>$<HASH>. A
canonical python script is included in share/rpcauth. The client
then connects normally using the
rpcuser=<USERNAME>/rpcpassword=<PASSWORD> pair of arguments. This
@@ -538,12 +542,12 @@ option can be specified multiple times
.HP
\fB\-rpcbind=\fR<addr>[:port]
.IP
-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)
+Bind to given address to listen for JSON\-RPC connections. Do not expose
+the RPC server to untrusted networks such as the public internet!
+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)
.HP
\fB\-rpccookiefile=\fR<loc>
.IP
@@ -556,8 +560,8 @@ Password for JSON\-RPC connections
.HP
\fB\-rpcport=\fR<port>
.IP
-Listen for JSON\-RPC connections on <port> (default: 8332 or testnet:
-18332)
+Listen for JSON\-RPC connections on <port> (default: 8332, testnet:
+18332, regtest: 18443)
.HP
\fB\-rpcserialversion\fR
.IP
diff --git a/doc/man/bitcoin-tx.1 b/doc/man/bitcoin-tx.1
index e1b81bad6c..f16c68ca14 100644
--- a/doc/man/bitcoin-tx.1
+++ b/doc/man/bitcoin-tx.1
@@ -1,16 +1,15 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.6.
-.TH BITCOIN-TX "1" "July 2018" "bitcoin-tx v0.16.99.0" "User Commands"
+.TH BITCOIN-TX "1" "December 2018" "bitcoin-tx v0.17.99.0" "User Commands"
.SH NAME
-bitcoin-tx \- manual page for bitcoin-tx v0.16.99.0
+bitcoin-tx \- manual page for bitcoin-tx v0.17.99.0
+.SH SYNOPSIS
+.B bitcoin-tx
+[\fI\,options\/\fR] \fI\,<hex-tx> \/\fR[\fI\,commands\/\fR] \fI\,Update hex-encoded bitcoin transaction\/\fR
+.br
+.B bitcoin-tx
+[\fI\,options\/\fR] \fI\,-create \/\fR[\fI\,commands\/\fR] \fI\,Create hex-encoded bitcoin transaction\/\fR
.SH DESCRIPTION
-Bitcoin Core bitcoin\-tx utility version v0.16.99.0
-.SS "Usage:"
-.TP
-bitcoin\-tx [options] <hex\-tx> [commands]
-Update hex\-encoded bitcoin transaction
-.TP
-bitcoin\-tx [options] \fB\-create\fR [commands]
-Create hex\-encoded bitcoin transaction
+Bitcoin Core bitcoin\-tx utility version v0.17.99.0
.SH OPTIONS
.HP
\-?
diff --git a/doc/man/bitcoind.1 b/doc/man/bitcoind.1
index d0ba131cde..5c4b1cd03b 100644
--- a/doc/man/bitcoind.1
+++ b/doc/man/bitcoind.1
@@ -1,13 +1,12 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.6.
-.TH BITCOIND "1" "July 2018" "bitcoind v0.16.99.0" "User Commands"
+.TH BITCOIND "1" "December 2018" "bitcoind v0.17.99.0" "User Commands"
.SH NAME
-bitcoind \- manual page for bitcoind v0.16.99.0
+bitcoind \- manual page for bitcoind v0.17.99.0
+.SH SYNOPSIS
+.B bitcoind
+[\fI\,options\/\fR] \fI\,Start Bitcoin Core Daemon\/\fR
.SH DESCRIPTION
-Bitcoin Core Daemon version v0.16.99.0
-.SS "Usage:"
-.TP
-bitcoind [options]
-Start Bitcoin Core Daemon
+Bitcoin Core Daemon version v0.17.99.0
.SH OPTIONS
.HP
\-?
@@ -24,9 +23,9 @@ long fork (%s in cmd is replaced by message)
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:
-0000000000000000005214481d2d96f898e3d5416e43359c145944a909d242e0,
+0000000000000000002e63058c023a9a1de233554f28c7b21380b6c9003f36a8,
testnet:
-0000000002e9e7b00e1f6dc5123a04aad68dd0f0968d8c7aa45f6640795c37b1)
+0000000000000037a8cd3e06cd5edbfe9dd1dbcc5dacab279376ef7cfc2b4c75)
.HP
\fB\-blocknotify=\fR<cmd>
.IP
@@ -62,7 +61,8 @@ Set database cache size in megabytes (4 to 16384, default: 450)
\fB\-debuglogfile=\fR<file>
.IP
Specify location of debug log file. Relative paths will be prefixed by a
-net\-specific datadir location. (0 to disable; default: debug.log)
+net\-specific datadir location. (\fB\-nodebuglogfile\fR to disable;
+default: debug.log)
.HP
\fB\-includeconf=\fR<file>
.IP
@@ -109,7 +109,7 @@ blocks if a target size in MiB is provided. This mode is
incompatible with \fB\-txindex\fR and \fB\-rescan\fR. Warning: Reverting this
setting requires re\-downloading the entire blockchain. (default:
0 = disable pruning blocks, 1 = allow manual pruning via RPC,
->550 = automatically prune block files to stay under the
+>=550 = automatically prune block files to stay under the
specified target size in MiB)
.HP
\fB\-reindex\fR
@@ -118,7 +118,9 @@ Rebuild chain state and block index from the blk*.dat files on disk
.HP
\fB\-reindex\-chainstate\fR
.IP
-Rebuild chain state from the currently indexed blocks
+Rebuild chain state from the currently indexed blocks. When in pruning
+mode or if blocks on disk might be corrupted, use full \fB\-reindex\fR
+instead.
.HP
\fB\-sysperms\fR
.IP
@@ -158,7 +160,7 @@ for IPv6
.HP
\fB\-connect=\fR<ip>
.IP
-Connect only to the specified node; \fB\-connect\fR=\fI\,0\/\fR disables automatic
+Connect only to the specified node; \fB\-noconnect\fR disables automatic
connections (the rules for this peer are the same as for
\fB\-addnode\fR). This option can be specified multiple times to connect
to multiple nodes.
@@ -179,7 +181,7 @@ unless \fB\-connect\fR used)
.HP
\fB\-enablebip61\fR
.IP
-Send reject messages per BIP61 (default: 1)
+Send reject messages per BIP61 (default: 0)
.HP
\fB\-externalip=\fR<ip>
.IP
@@ -222,8 +224,8 @@ Tries to keep outbound traffic under the given target (in MiB per 24h),
.HP
\fB\-onion=\fR<ip:port>
.IP
-Use separate SOCKS5 proxy to reach peers via Tor hidden services
-(default: \fB\-proxy\fR)
+Use separate SOCKS5 proxy to reach peers via Tor hidden services, set
+\fB\-noonion\fR to disable (default: \fB\-proxy\fR)
.HP
\fB\-onlynet=\fR<net>
.IP
@@ -243,11 +245,13 @@ Relay non\-P2SH multisig (default: 1)
.HP
\fB\-port=\fR<port>
.IP
-Listen for connections on <port> (default: 8333 or testnet: 18333)
+Listen for connections on <port> (default: 8333, testnet: 18333,
+regtest: 18444)
.HP
\fB\-proxy=\fR<ip:port>
.IP
-Connect through SOCKS5 proxy
+Connect through SOCKS5 proxy, set \fB\-noproxy\fR to disable (default:
+disabled)
.HP
\fB\-proxyrandomize\fR
.IP
@@ -394,8 +398,7 @@ Send transactions with full\-RBF opt\-in enabled (RPC only, default: 0)
.IP
Delete all wallet transactions and only recover those parts of the
blockchain through \fB\-rescan\fR on startup (1 = keep tx meta data e.g.
-account owner and payment request information, 2 = drop tx meta
-data)
+payment request information, 2 = drop tx meta data)
.PP
ZeroMQ notification options:
.HP
@@ -419,7 +422,7 @@ Debugging/Testing options:
.HP
\fB\-debug=\fR<category>
.IP
-Output debugging information (default: 0, supplying <category> is
+Output debugging information (default: \fB\-nodebug\fR, supplying <category> is
optional). If <category> is not supplied or if <category> = 1,
output all debugging information. <category> can be: net, tor,
mempool, http, bench, zmq, db, rpc, estimatefee, addrman,
@@ -434,7 +437,7 @@ or more specified categories.
.HP
\fB\-help\-debug\fR
.IP
-Show all debugging options (usage: \fB\-\-help\fR \fB\-help\-debug\fR)
+Print help message with debugging options and exit
.HP
\fB\-logips\fR
.IP
@@ -453,7 +456,7 @@ transaction; setting this too low may abort large transactions
\fB\-printtoconsole\fR
.IP
Send trace/debug info to console (default: 1 when no \fB\-daemon\fR. To disable
-logging to file, set debuglogfile=0)
+logging to file, set \fB\-nodebuglogfile\fR)
.HP
\fB\-shrinkdebugfile\fR
.IP
@@ -530,8 +533,8 @@ option can be specified multiple times
.HP
\fB\-rpcauth=\fR<userpw>
.IP
-Username and hashed password for JSON\-RPC connections. The field
-<userpw> comes in the format: <USERNAME>:<SALT>$<HASH>. A
+Username and HMAC\-SHA\-256 hashed password for JSON\-RPC connections. The
+field <userpw> comes in the format: <USERNAME>:<SALT>$<HASH>. A
canonical python script is included in share/rpcauth. The client
then connects normally using the
rpcuser=<USERNAME>/rpcpassword=<PASSWORD> pair of arguments. This
@@ -539,12 +542,12 @@ option can be specified multiple times
.HP
\fB\-rpcbind=\fR<addr>[:port]
.IP
-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)
+Bind to given address to listen for JSON\-RPC connections. Do not expose
+the RPC server to untrusted networks such as the public internet!
+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)
.HP
\fB\-rpccookiefile=\fR<loc>
.IP
@@ -557,8 +560,8 @@ Password for JSON\-RPC connections
.HP
\fB\-rpcport=\fR<port>
.IP
-Listen for JSON\-RPC connections on <port> (default: 8332 or testnet:
-18332)
+Listen for JSON\-RPC connections on <port> (default: 8332, testnet:
+18332, regtest: 18443)
.HP
\fB\-rpcserialversion\fR
.IP
diff --git a/doc/psbt.md b/doc/psbt.md
index 7e6a93714d..560b45ef31 100644
--- a/doc/psbt.md
+++ b/doc/psbt.md
@@ -124,7 +124,7 @@ does not need to be involved.
- Finally anyone can broadcast the transaction using `sendrawtransaction "T"`.
In case there are more signers, it may be advantageous to let them all sign in
-parallel, rather passing the PSBT from one signer to the next one. In the
+parallel, rather than passing the PSBT from one signer to the next one. In the
above example this would translate to Carol handing a copy of *P* to each signer
separately. They can then all invoke `walletprocesspsbt "P"`, and end up with
their individually-signed PSBT structures. They then all send those back to
diff --git a/doc/release-notes-14060.md b/doc/release-notes-14060.md
deleted file mode 100644
index 2cc5ab49fb..0000000000
--- a/doc/release-notes-14060.md
+++ /dev/null
@@ -1,21 +0,0 @@
-Configuration
--------------
-
-The outbound message high water mark of the ZMQ PUB sockets are now
-configurable via the options:
-
-`-zmqpubhashtxhwm=n`
-
-`-zmqpubhashblockhwm=n`
-
-`-zmqpubrawblockhwm=n`
-
-`-zmqpubrawtxhwm=n`
-
-Each high water mark value must be an integer greater than or equal to 0.
-The high water mark limits the maximum number of messages that ZMQ will
-queue in memory for any single subscriber. A value of 0 means no limit.
-When not specified, the default value continues to be 1000.
-When a ZMQ PUB socket reaches its high water mark for a subscriber, then
-additional messages to the subscriber are dropped until the number of
-queued messages again falls below the high water mark value.
diff --git a/doc/release-notes-14477.md b/doc/release-notes-14477.md
deleted file mode 100644
index bb8c0a623e..0000000000
--- a/doc/release-notes-14477.md
+++ /dev/null
@@ -1,5 +0,0 @@
-Miscellaneous RPC changes
-------------
-
-- `getaddressinfo` now reports `solvable`, a boolean indicating whether all information necessary for signing is present in the wallet (ignoring private keys).
-- `getaddressinfo`, `listunspent`, and `scantxoutset` have a new output field `desc`, an output descriptor that encapsulates all signing information and key paths for the address (only available when `solvable` is true for `getaddressinfo` and `listunspent`).
diff --git a/doc/release-notes-pr13381.md b/doc/release-notes-pr13381.md
deleted file mode 100644
index 75faad9906..0000000000
--- a/doc/release-notes-pr13381.md
+++ /dev/null
@@ -1,29 +0,0 @@
-RPC importprivkey: new label behavior
--------------------------------------
-
-Previously, `importprivkey` automatically added the default empty label
-("") to all addresses associated with the imported private key. Now it
-defaults to using any existing label for those addresses. For example:
-
-- Old behavior: you import a watch-only address with the label "cold
- wallet". Later, you import the corresponding private key using the
- default settings. The address's label is changed from "cold wallet"
- to "".
-
-- New behavior: you import a watch-only address with the label "cold
- wallet". Later, you import the corresponding private key using the
- default settings. The address's label remains "cold wallet".
-
-In both the previous and current case, if you directly specify a label
-during the import, that label will override whatever previous label the
-addresses may have had. Also in both cases, if none of the addresses
-previously had a label, they will still receive the default empty label
-(""). Examples:
-
-- You import a watch-only address with the label "temporary". Later you
- import the corresponding private key with the label "final". The
- address's label will be changed to "final".
-
-- You use the default settings to import a private key for an address that
- was not previously in the wallet. Its addresses will receive the default
- empty label ("").
diff --git a/doc/release-notes.md b/doc/release-notes.md
index 9465258310..53b5a2119f 100644
--- a/doc/release-notes.md
+++ b/doc/release-notes.md
@@ -47,8 +47,9 @@ processing the entire blockchain.
Compatibility
==============
-Bitcoin Core is extensively tested on multiple operating systems using
-the Linux kernel, macOS 10.10+, and Windows 7 and newer (Windows XP is not supported).
+Bitcoin Core is supported and extensively tested on operating systems using
+the Linux kernel, macOS 10.10+, and Windows 7 and newer. It is not recommended
+to use Bitcoin Core on unsupported systems.
Bitcoin Core should also work on most other Unix-like systems but is not
frequently tested on them.
@@ -71,16 +72,44 @@ Mining
- Calls to `getblocktemplate` will fail if the segwit rule is not specified.
Calling `getblocktemplate` without segwit specified is almost certainly
a misconfiguration since doing so results in lower rewards for the miner.
-
-Command line option changes
----------------------------
-
-The `-enablebip61` command line option (introduced in Bitcoin Core 0.17.0) is
-used to toggle sending of BIP 61 reject messages. Reject messages have no use
-case on the P2P network and are only logged for debugging by most network
-nodes. The option will now by default be off for improved privacy and security
-as well as reduced upload usage. The option can explicitly be turned on for
-local-network debugging purposes.
+ Failed calls will produce an error message describing how to enable the
+ segwit rule.
+
+Configuration option changes
+----------------------------
+
+- A warning is printed if an unrecognized section name is used in the
+ configuration file. Recognized sections are `[test]`, `[main]`, and
+ `[regtest]`.
+
+- Four new options are available for configuring the maximum number of
+ messages that ZMQ will queue in memory (the "high water mark") before
+ dropping additional messages. The default value is 1,000, the same as
+ was used for previous releases. See the [ZMQ
+ documentation](https://github.com/bitcoin/bitcoin/blob/master/doc/zmq.md#usage)
+ for details.
+
+- The `enablebip61` option (introduced in Bitcoin Core 0.17.0) is
+ used to toggle sending of BIP 61 reject messages. Reject messages have no use
+ case on the P2P network and are only logged for debugging by most network
+ nodes. The option will now by default be off for improved privacy and security
+ as well as reduced upload usage. The option can explicitly be turned on for
+ local-network debugging purposes.
+
+- The `rpcallowip` option can no longer be used to automatically listen
+ on all network interfaces. Instead, the `rpcbind` parameter must also
+ be used to specify the IP addresses to listen on. Listening for RPC
+ commands over a public network connection is insecure and should be
+ disabled, so a warning is now printed if a user selects such a
+ configuration. If you need to expose RPC in order to use a tool
+ like Docker, ensure you only bind RPC to your localhost, e.g. `docker
+ run [...] -p 127.0.0.1:8332:8332` (this is an extra `:8332` over the
+ normal Docker port specification).
+
+- The `rpcpassword` option now causes a startup error if the password
+ set in the configuration file contains a hash character (#), as it's
+ ambiguous whether the hash character is meant for the password or as a
+ comment.
Documentation
-------------
@@ -167,7 +196,7 @@ Updated RPCs
Note: some low-level RPC changes mainly useful for testing are described
in the Low-level Changes section below.
-- The `getpeerinfo` RPC now returns an additional "minfeefilter" field
+- The `getpeerinfo` RPC now returns an additional `minfeefilter` field
set to the peer's BIP133 fee filter. You can use this to detect that
you have peers that are willing to accept transactions below the
default minimum relay fee.
@@ -189,8 +218,50 @@ in the Low-level Changes section below.
P2SH-P2WPKH, and P2SH-P2WSH. Requests for P2WSH and P2SH-P2WSH accept
an additional `witnessscript` parameter.
+- The `importmulti` RPC now returns an additional `warnings` field for
+ each request with an array of strings explaining when fields are being
+ ignored or are inconsistent, if there are any.
+
+- The `getaddressinfo` RPC now returns an additional `solvable` boolean
+ field when Bitcoin Core knows enough about the address's scriptPubKey,
+ optional redeemScript, and optional witnessScript in order for the
+ wallet to be able to generate an unsigned input spending funds sent to
+ that address.
+
+- The `getaddressinfo`, `listunspent`, and `scantxoutset` RPCs now
+ return an additional `desc` field that contains an output descriptor
+ containing all key paths and signing information for the address
+ (except for the private key). The `desc` field is only returned for
+ `getaddressinfo` and `listunspent` when the address is solvable.
+
+- The `importprivkey` RPC will preserve previously-set labels for
+ addresses or public keys corresponding to the private key being
+ imported. For example, if you imported a watch-only address with the
+ label "cold wallet" in earlier releases of Bitcoin Core, subsequently
+ importing the private key would default to resetting the address's
+ label to the default empty-string label (""). In this release, the
+ previous label of "cold wallet" will be retained. If you optionally
+ specify any label besides the default when calling `importprivkey`,
+ the new label will be applied to the address.
+
- See the [Mining](#mining) section for changes to `getblocktemplate`.
+Graphical User Interface (GUI)
+------------------------------
+
+- A new Window menu is added alongside the existing File, Settings, and
+ Help menus. Several items from the other menus that opened new
+ windows have been moved to this new Window menu.
+
+- In the Send tab, the checkbox for "pay only the required fee"
+ has been removed. Instead, the user can simply decrease the value in
+ the Custom Feerate field all the way down to the node's configured
+ minimum relay fee.
+
+- In the Overview tab, the watch-only balance will be the only
+ balance shown if the wallet was created using the `createwallet` RPC
+ and the `disable_private_keys` parameter was set to true.
+
Low-level changes
=================
@@ -215,6 +286,16 @@ Configuration
deterministic wallets. This release makes specifying `-usehd` an
invalid configuration option.
+Changes for particular platforms
+--------------------------------
+
+- On macOS, Bitcoin Core now opts out of application CPU throttling
+ ("app nap") during initial blockchain download, when catching up from
+ over 100 blocks behind the current chain tip, or when reindexing chain
+ data. This helps prevent these operations from taking an excessively
+ long time because the operating system is attempting to conserve
+ power.
+
Credits
=======
diff --git a/doc/release-notes/release-notes-0.17.1.md b/doc/release-notes/release-notes-0.17.1.md
new file mode 100644
index 0000000000..b1e50e0391
--- /dev/null
+++ b/doc/release-notes/release-notes-0.17.1.md
@@ -0,0 +1,168 @@
+Bitcoin Core version 0.17.1 is now available from:
+
+ <https://bitcoincore.org/bin/bitcoin-core-0.17.1/>
+
+or through BitTorrent:
+
+ magnet:?xt=urn:btih:c56c87ccfaa8e6fbccc90d549121e61efd97cb6f&dn=bitcoin-core-0.17.1&tr=udp%3A%2F%2Ftracker.openbittorrent.com%3A80&tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337&tr=udp%3A%2F%2Ftracker.coppersurfer.tk%3A6969&tr=udp%3A%2F%2Ftracker.leechers-paradise.org%3A6969&tr=udp%3A%2F%2Fzer0day.ch%3A1337&tr=udp%3A%2F%2Fexplodie.org%3A6969
+
+This is a new minor version release, with 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).
+
+If your node has a txindex, the txindex db will be migrated the first time you run 0.17.0 or newer, which may take up to a few hours. Your node will not be functional until this migration completes.
+
+The first time you run version 0.15.0 or newer, 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.
+
+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.10+, and Windows 7 and newer (Windows XP is not supported).
+
+Bitcoin Core should also work on most other Unix-like systems but is not
+frequently tested on them.
+
+From 0.17.0 onwards macOS <10.10 is no longer supported. 0.17.0 is built using Qt 5.9.x, which doesn't
+support versions of macOS older than 10.10.
+
+Notable changes
+===============
+
+`listtransactions` label support
+--------------------------------
+
+The `listtransactions` RPC `account` parameter which was deprecated in 0.17.0
+and renamed to `dummy` has been un-deprecated and renamed again to `label`.
+
+When bitcoin is configured with the `-deprecatedrpc=accounts` setting, specifying
+a label/account/dummy argument will return both outgoing and incoming
+transactions. Without the `-deprecatedrpc=accounts` setting, it will only return
+incoming transactions (because it used to be possible to create transactions
+spending from specific accounts, but this is no longer possible with labels).
+
+When `-deprecatedrpc=accounts` is set, it's possible to pass the empty string ""
+to list transactions that don't have any label. Without
+`-deprecatedrpc=accounts`, passing the empty string is an error because returning
+only non-labeled transactions is not generally useful behavior and can cause
+confusion.
+
+0.17.1 change log
+=================
+
+### P2P protocol and network code
+- #14685 `9406502` Fix a deserialization overflow edge case (kazcw)
+- #14728 `b901578` Fix uninitialized read when stringifying an addrLocal (kazcw)
+
+### Wallet
+- #14441 `5150acc` Restore ability to list incoming transactions by label (jnewbery)
+- #13546 `91fa15a` Fix use of uninitialized value `bnb_used` in CWallet::CreateTransaction(…) (practicalswift)
+- #14310 `bb90695` Ensure wallet is unlocked before signing (gustavonalle)
+- #14690 `5782fdc` Throw error if CPubKey is invalid during PSBT keypath serialization (instagibbs)
+- #14852 `2528443` backport: [tests] Add `wallet_balance.py` (MarcoFalke)
+- #14196 `3362a95` psbt: always drop the unnecessary utxo and convert non-witness utxo to witness when necessary (achow101)
+- #14588 `70ee1f8` Refactor PSBT signing logic to enforce invariant and fix signing bug (gwillen)
+- #14424 `89a9a9d` Stop requiring imported pubkey to sign non-PKH schemes (sipa, MeshCollider)
+
+### RPC and other APIs
+- #14417 `fb9ad04` Fix listreceivedbyaddress not taking address as a string (etscrivner)
+- #14596 `de5e48a` Bugfix: RPC: Add `address_type` named param for createmultisig (luke-jr)
+- #14618 `9666dba` Make HTTP RPC debug logging more informative (practicalswift)
+- #14197 `7bee414` [psbt] Convert non-witness UTXOs to witness if witness sig created (achow101)
+- #14377 `a3fe125` Check that a separator is found for psbt inputs, outputs, and global map (achow101)
+- #14356 `7a590d8` Fix converttopsbt permitsigdata arg, add basic test (instagibbs)
+- #14453 `75b5d8c` Fix wallet unload during walletpassphrase timeout (promag)
+
+### GUI
+- #14403 `0242b5a` Revert "Force TLS1.0+ for SSL connections" (real-or-random)
+- #14593 `df5131b` Explicitly disable "Dark Mode" appearance on macOS (fanquake)
+
+### Build system
+- #14647 `7edebed` Remove illegal spacing in darwin.mk (ch4ot1c)
+- #14698 `ec71f06` Add bitcoin-tx.exe into Windows installer (ken2812221)
+
+### Tests and QA
+- #13965 `29899ec` Fix extended functional tests fail (ken2812221)
+- #14011 `9461f98` Disable wallet and address book Qt tests on macOS minimal platform (ryanofsky)
+- #14180 `86fadee` Run all tests even if wallet is not compiled (MarcoFalke)
+- #14122 `8bc1bad` Test `rpc_help.py` failed: Check whether ZMQ is enabled or not (Kvaciral)
+- #14101 `96dc936` Use named args in validation acceptance tests (MarcoFalke)
+- #14020 `24d796a` Add tests for RPC help (promag)
+- #14052 `7ff32a6` Add some actual witness in `rpc_rawtransaction` (MarcoFalke)
+- #14215 `b72fbab` Use correct python index slices in example test (sdaftuar)
+- #14024 `06544fa` Add `TestNode::assert_debug_log` (MarcoFalke)
+- #14658 `60f7a97` Add test to ensure node can generate all rpc help texts at runtime (MarcoFalke)
+- #14632 `96f15e8` Fix a comment (fridokus)
+- #14700 `f9db08e` Avoid race in `p2p_invalid_block` by waiting for the block request (MarcoFalke)
+- #14845 `67225e2` Add `wallet_balance.py` (jnewbery)
+
+### Documentation
+- #14161 `5f51fd6` doc/descriptors.md tweaks (ryanofsky)
+- #14276 `85aacc4` Add autogen.sh in ARM Cross-compilation (walterwhite81)
+
+Credits
+=======
+
+Thanks to everyone who directly contributed to this release:
+
+- Andrew Chow
+- Chun Kuan Lee
+- David A. Harding
+- Eric Scrivner
+- fanquake
+- fridokus
+- Glenn Willen
+- Gregory Sanders
+- gustavonalle
+- John Newbery
+- Jon Layton
+- Jonas Schnelli
+- João Barbosa
+- Kaz Wesley
+- Kvaciral
+- Luke Dashjr
+- MarcoFalke
+- MeshCollider
+- Pieter Wuille
+- practicalswift
+- Russell Yanofsky
+- Sjors Provoost
+- Suhas Daftuar
+- Tim Ruffing
+- Walter
+- 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/amount.h b/src/amount.h
index 449fd1b15f..47968e80b1 100644
--- a/src/amount.h
+++ b/src/amount.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2016 The Bitcoin Core developers
+// Copyright (c) 2009-2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/bench/block_assemble.cpp b/src/bench/block_assemble.cpp
index 7cf27f9f5b..8133fd9d65 100644
--- a/src/bench/block_assemble.cpp
+++ b/src/bench/block_assemble.cpp
@@ -78,7 +78,7 @@ static void AssembleBlock(benchmark::State& state)
::pcoinsTip.reset(new CCoinsViewCache(pcoinsdbview.get()));
const CChainParams& chainparams = Params();
- thread_group.create_thread(boost::bind(&CScheduler::serviceQueue, &scheduler));
+ thread_group.create_thread(std::bind(&CScheduler::serviceQueue, &scheduler));
GetMainSignals().RegisterBackgroundSignalScheduler(scheduler);
LoadGenesisBlock(chainparams);
CValidationState state;
diff --git a/src/bench/gcs_filter.cpp b/src/bench/gcs_filter.cpp
index 6f4e384e3b..535ad35571 100644
--- a/src/bench/gcs_filter.cpp
+++ b/src/bench/gcs_filter.cpp
@@ -17,7 +17,7 @@ static void ConstructGCSFilter(benchmark::State& state)
uint64_t siphash_k0 = 0;
while (state.KeepRunning()) {
- GCSFilter filter(siphash_k0, 0, 20, 1 << 20, elements);
+ GCSFilter filter({siphash_k0, 0, 20, 1 << 20}, elements);
siphash_k0++;
}
@@ -32,7 +32,7 @@ static void MatchGCSFilter(benchmark::State& state)
element[1] = static_cast<unsigned char>(i >> 8);
elements.insert(std::move(element));
}
- GCSFilter filter(0, 0, 20, 1 << 20, elements);
+ GCSFilter filter({0, 0, 20, 1 << 20}, elements);
while (state.KeepRunning()) {
filter.Match(GCSFilter::Element());
diff --git a/src/blockfilter.cpp b/src/blockfilter.cpp
index 163e2a52ef..bcf24047ff 100644
--- a/src/blockfilter.cpp
+++ b/src/blockfilter.cpp
@@ -79,7 +79,7 @@ static uint64_t MapIntoRange(uint64_t x, uint64_t n)
uint64_t GCSFilter::HashToRange(const Element& element) const
{
- uint64_t hash = CSipHasher(m_siphash_k0, m_siphash_k1)
+ uint64_t hash = CSipHasher(m_params.m_siphash_k0, m_params.m_siphash_k1)
.Write(element.data(), element.size())
.Finalize();
return MapIntoRange(hash, m_F);
@@ -96,16 +96,13 @@ std::vector<uint64_t> GCSFilter::BuildHashedSet(const ElementSet& elements) cons
return hashed_elements;
}
-GCSFilter::GCSFilter(uint64_t siphash_k0, uint64_t siphash_k1, uint8_t P, uint32_t M)
- : m_siphash_k0(siphash_k0), m_siphash_k1(siphash_k1), m_P(P), m_M(M), m_N(0), m_F(0)
+GCSFilter::GCSFilter(const Params& params)
+ : m_params(params), m_N(0), m_F(0), m_encoded{0}
{}
-GCSFilter::GCSFilter(uint64_t siphash_k0, uint64_t siphash_k1, uint8_t P, uint32_t M,
- std::vector<unsigned char> encoded_filter)
- : GCSFilter(siphash_k0, siphash_k1, P, M)
+GCSFilter::GCSFilter(const Params& params, std::vector<unsigned char> encoded_filter)
+ : m_params(params), m_encoded(std::move(encoded_filter))
{
- m_encoded = std::move(encoded_filter);
-
VectorReader stream(GCS_SER_TYPE, GCS_SER_VERSION, m_encoded, 0);
uint64_t N = ReadCompactSize(stream);
@@ -113,29 +110,28 @@ GCSFilter::GCSFilter(uint64_t siphash_k0, uint64_t siphash_k1, uint8_t P, uint32
if (m_N != N) {
throw std::ios_base::failure("N must be <2^32");
}
- m_F = static_cast<uint64_t>(m_N) * static_cast<uint64_t>(m_M);
+ m_F = static_cast<uint64_t>(m_N) * static_cast<uint64_t>(m_params.m_M);
// Verify that the encoded filter contains exactly N elements. If it has too much or too little
// data, a std::ios_base::failure exception will be raised.
BitStreamReader<VectorReader> bitreader(stream);
for (uint64_t i = 0; i < m_N; ++i) {
- GolombRiceDecode(bitreader, m_P);
+ GolombRiceDecode(bitreader, m_params.m_P);
}
if (!stream.empty()) {
throw std::ios_base::failure("encoded_filter contains excess data");
}
}
-GCSFilter::GCSFilter(uint64_t siphash_k0, uint64_t siphash_k1, uint8_t P, uint32_t M,
- const ElementSet& elements)
- : GCSFilter(siphash_k0, siphash_k1, P, M)
+GCSFilter::GCSFilter(const Params& params, const ElementSet& elements)
+ : m_params(params)
{
size_t N = elements.size();
m_N = static_cast<uint32_t>(N);
if (m_N != N) {
throw std::invalid_argument("N must be <2^32");
}
- m_F = static_cast<uint64_t>(m_N) * static_cast<uint64_t>(m_M);
+ m_F = static_cast<uint64_t>(m_N) * static_cast<uint64_t>(m_params.m_M);
CVectorWriter stream(GCS_SER_TYPE, GCS_SER_VERSION, m_encoded, 0);
@@ -150,7 +146,7 @@ GCSFilter::GCSFilter(uint64_t siphash_k0, uint64_t siphash_k1, uint8_t P, uint32
uint64_t last_value = 0;
for (uint64_t value : BuildHashedSet(elements)) {
uint64_t delta = value - last_value;
- GolombRiceEncode(bitwriter, m_P, delta);
+ GolombRiceEncode(bitwriter, m_params.m_P, delta);
last_value = value;
}
@@ -170,7 +166,7 @@ bool GCSFilter::MatchInternal(const uint64_t* element_hashes, size_t size) const
uint64_t value = 0;
size_t hashes_index = 0;
for (uint32_t i = 0; i < m_N; ++i) {
- uint64_t delta = GolombRiceDecode(bitreader, m_P);
+ uint64_t delta = GolombRiceDecode(bitreader, m_params.m_P);
value += delta;
while (true) {
@@ -225,19 +221,39 @@ static GCSFilter::ElementSet BasicFilterElements(const CBlock& block,
return elements;
}
+BlockFilter::BlockFilter(BlockFilterType filter_type, const uint256& block_hash,
+ std::vector<unsigned char> filter)
+ : m_filter_type(filter_type), m_block_hash(block_hash)
+{
+ GCSFilter::Params params;
+ if (!BuildParams(params)) {
+ throw std::invalid_argument("unknown filter_type");
+ }
+ m_filter = GCSFilter(params, std::move(filter));
+}
+
BlockFilter::BlockFilter(BlockFilterType filter_type, const CBlock& block, const CBlockUndo& block_undo)
: m_filter_type(filter_type), m_block_hash(block.GetHash())
{
+ GCSFilter::Params params;
+ if (!BuildParams(params)) {
+ throw std::invalid_argument("unknown filter_type");
+ }
+ m_filter = GCSFilter(params, BasicFilterElements(block, block_undo));
+}
+
+bool BlockFilter::BuildParams(GCSFilter::Params& params) const
+{
switch (m_filter_type) {
case BlockFilterType::BASIC:
- m_filter = GCSFilter(m_block_hash.GetUint64(0), m_block_hash.GetUint64(1),
- BASIC_FILTER_P, BASIC_FILTER_M,
- BasicFilterElements(block, block_undo));
- break;
-
- default:
- throw std::invalid_argument("unknown filter_type");
+ params.m_siphash_k0 = m_block_hash.GetUint64(0);
+ params.m_siphash_k1 = m_block_hash.GetUint64(1);
+ params.m_P = BASIC_FILTER_P;
+ params.m_M = BASIC_FILTER_M;
+ return true;
}
+
+ return false;
}
uint256 BlockFilter::GetHash() const
diff --git a/src/blockfilter.h b/src/blockfilter.h
index 871be11769..4d1f51dd60 100644
--- a/src/blockfilter.h
+++ b/src/blockfilter.h
@@ -25,11 +25,20 @@ public:
typedef std::vector<unsigned char> Element;
typedef std::unordered_set<Element, ByteVectorHash> ElementSet;
+ struct Params
+ {
+ uint64_t m_siphash_k0;
+ uint64_t m_siphash_k1;
+ uint8_t m_P; //!< Golomb-Rice coding parameter
+ uint32_t m_M; //!< Inverse false positive rate
+
+ Params(uint64_t siphash_k0 = 0, uint64_t siphash_k1 = 0, uint8_t P = 0, uint32_t M = 1)
+ : m_siphash_k0(siphash_k0), m_siphash_k1(siphash_k1), m_P(P), m_M(M)
+ {}
+ };
+
private:
- uint64_t m_siphash_k0;
- uint64_t m_siphash_k1;
- uint8_t m_P; //!< Golomb-Rice coding parameter
- uint32_t m_M; //!< Inverse false positive rate
+ Params m_params;
uint32_t m_N; //!< Number of elements in the filter
uint64_t m_F; //!< Range of element hashes, F = N * M
std::vector<unsigned char> m_encoded;
@@ -45,19 +54,16 @@ private:
public:
/** Constructs an empty filter. */
- GCSFilter(uint64_t siphash_k0 = 0, uint64_t siphash_k1 = 0, uint8_t P = 0, uint32_t M = 0);
+ explicit GCSFilter(const Params& params = Params());
/** Reconstructs an already-created filter from an encoding. */
- GCSFilter(uint64_t siphash_k0, uint64_t siphash_k1, uint8_t P, uint32_t M,
- std::vector<unsigned char> encoded_filter);
+ GCSFilter(const Params& params, std::vector<unsigned char> encoded_filter);
/** Builds a new filter from the params and set of elements. */
- GCSFilter(uint64_t siphash_k0, uint64_t siphash_k1, uint8_t P, uint32_t M,
- const ElementSet& elements);
+ GCSFilter(const Params& params, const ElementSet& elements);
- uint8_t GetP() const { return m_P; }
uint32_t GetN() const { return m_N; }
- uint32_t GetM() const { return m_M; }
+ const Params& GetParams() const { return m_params; }
const std::vector<unsigned char>& GetEncoded() const { return m_encoded; }
/**
@@ -93,13 +99,21 @@ private:
uint256 m_block_hash;
GCSFilter m_filter;
+ bool BuildParams(GCSFilter::Params& params) const;
+
public:
- // Construct a new BlockFilter of the specified type from a block.
+ BlockFilter() = default;
+
+ //! Reconstruct a BlockFilter from parts.
+ BlockFilter(BlockFilterType filter_type, const uint256& block_hash,
+ std::vector<unsigned char> filter);
+
+ //! Construct a new BlockFilter of the specified type from a block.
BlockFilter(BlockFilterType filter_type, const CBlock& block, const CBlockUndo& block_undo);
BlockFilterType GetFilterType() const { return m_filter_type; }
-
+ const uint256& GetBlockHash() const { return m_block_hash; }
const GCSFilter& GetFilter() const { return m_filter; }
const std::vector<unsigned char>& GetEncodedFilter() const
@@ -107,10 +121,10 @@ public:
return m_filter.GetEncoded();
}
- // Compute the filter hash.
+ //! Compute the filter hash.
uint256 GetHash() const;
- // Compute the filter header given the previous one.
+ //! Compute the filter header given the previous one.
uint256 ComputeHeader(const uint256& prev_header) const;
template <typename Stream>
@@ -131,15 +145,11 @@ public:
m_filter_type = static_cast<BlockFilterType>(filter_type);
- switch (m_filter_type) {
- case BlockFilterType::BASIC:
- m_filter = GCSFilter(m_block_hash.GetUint64(0), m_block_hash.GetUint64(1),
- BASIC_FILTER_P, BASIC_FILTER_M, std::move(encoded_filter));
- break;
-
- default:
+ GCSFilter::Params params;
+ if (!BuildParams(params)) {
throw std::ios_base::failure("unknown filter_type");
}
+ m_filter = GCSFilter(params, std::move(encoded_filter));
}
};
diff --git a/src/compat.h b/src/compat.h
index 049579c365..7b164d5630 100644
--- a/src/compat.h
+++ b/src/compat.h
@@ -92,8 +92,15 @@ typedef void* sockopt_arg_type;
typedef char* sockopt_arg_type;
#endif
+// Note these both should work with the current usage of poll, but best to be safe
+// WIN32 poll is broken https://daniel.haxx.se/blog/2012/10/10/wsapoll-is-broken/
+// __APPLE__ poll is broke https://github.com/bitcoin/bitcoin/pull/14336#issuecomment-437384408
+#if defined(__linux__)
+#define USE_POLL
+#endif
+
bool static inline IsSelectableSocket(const SOCKET& s) {
-#ifdef WIN32
+#if defined(USE_POLL) || defined(WIN32)
return true;
#else
return (s < FD_SETSIZE);
diff --git a/src/consensus/tx_verify.cpp b/src/consensus/tx_verify.cpp
index b17a8bb31d..0a7eacfb91 100644
--- a/src/consensus/tx_verify.cpp
+++ b/src/consensus/tx_verify.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2017 The Bitcoin Core developers
+// Copyright (c) 2017-2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/fs.h b/src/fs.h
index bdccb15232..8af81f173b 100644
--- a/src/fs.h
+++ b/src/fs.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017 The Bitcoin Core developers
+// Copyright (c) 2017-2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/init.cpp b/src/init.cpp
index 8ecd79197f..18c145a023 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -59,7 +59,6 @@
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/algorithm/string/split.hpp>
-#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include <openssl/crypto.h>
@@ -954,8 +953,13 @@ bool AppInitParameterInteraction()
// Trim requested connection counts, to fit into system limitations
// <int> in std::min<int>(...) to work around FreeBSD compilation issue described in #2695
- nMaxConnections = std::max(std::min<int>(nMaxConnections, FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS - MAX_ADDNODE_CONNECTIONS), 0);
nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS + MAX_ADDNODE_CONNECTIONS);
+#ifdef USE_POLL
+ int fd_max = nFD;
+#else
+ int fd_max = FD_SETSIZE;
+#endif
+ nMaxConnections = std::max(std::min<int>(nMaxConnections, fd_max - nBind - MIN_CORE_FILEDESCRIPTORS - MAX_ADDNODE_CONNECTIONS), 0);
if (nFD < MIN_CORE_FILEDESCRIPTORS)
return InitError(_("Not enough file descriptors available."));
nMaxConnections = std::min(nFD - MIN_CORE_FILEDESCRIPTORS - MAX_ADDNODE_CONNECTIONS, nMaxConnections);
@@ -1237,8 +1241,8 @@ bool AppInitMain(InitInterfaces& interfaces)
}
// Start the lightweight task scheduler thread
- CScheduler::Function serviceLoop = boost::bind(&CScheduler::serviceQueue, &scheduler);
- threadGroup.create_thread(boost::bind(&TraceThread<CScheduler::Function>, "scheduler", serviceLoop));
+ CScheduler::Function serviceLoop = std::bind(&CScheduler::serviceQueue, &scheduler);
+ threadGroup.create_thread(std::bind(&TraceThread<CScheduler::Function>, "scheduler", serviceLoop));
GetMainSignals().RegisterBackgroundSignalScheduler(scheduler);
GetMainSignals().RegisterWithMempoolSignals(mempool);
@@ -1646,7 +1650,7 @@ bool AppInitMain(InitInterfaces& interfaces)
vImportFiles.push_back(strFile);
}
- threadGroup.create_thread(boost::bind(&ThreadImport, vImportFiles));
+ threadGroup.create_thread(std::bind(&ThreadImport, vImportFiles));
// Wait for genesis block to be processed
{
diff --git a/src/key_io.cpp b/src/key_io.cpp
index 282385f50d..d998089535 100644
--- a/src/key_io.cpp
+++ b/src/key_io.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2017 The Bitcoin Core developers
+// Copyright (c) 2014-2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/net.cpp b/src/net.cpp
index e595fb0b0b..a288c6e81e 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -26,6 +26,10 @@
#include <fcntl.h>
#endif
+#ifdef USE_POLL
+#include <poll.h>
+#endif
+
#ifdef USE_UPNP
#include <miniupnpc/miniupnpc.h>
#include <miniupnpc/miniwget.h>
@@ -33,6 +37,7 @@
#include <miniupnpc/upnperrors.h>
#endif
+#include <unordered_map>
#include <math.h>
@@ -71,6 +76,10 @@ enum BindFlags {
BF_WHITELIST = (1U << 2),
};
+// The set of sockets cannot be modified while waiting
+// The sleep time needs to be small to avoid new sockets stalling
+static const uint64_t SELECT_TIMEOUT_MILLISECONDS = 50;
+
const static std::string NET_MESSAGE_COMMAND_OTHER = "*other*";
static const uint64_t RANDOMIZER_ID_NETGROUP = 0x6c0edd8036ef4036ULL; // SHA256("netgroup")[0:8]
@@ -1258,28 +1267,10 @@ void CConnman::InactivityCheck(CNode *pnode)
}
}
-void CConnman::SocketHandler()
+bool CConnman::GenerateSelectSet(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set)
{
- //
- // Find which sockets have data to receive
- //
- struct timeval timeout;
- timeout.tv_sec = 0;
- timeout.tv_usec = 50000; // frequency to poll pnode->vSend
-
- fd_set fdsetRecv;
- fd_set fdsetSend;
- fd_set fdsetError;
- FD_ZERO(&fdsetRecv);
- FD_ZERO(&fdsetSend);
- FD_ZERO(&fdsetError);
- SOCKET hSocketMax = 0;
- bool have_fds = false;
-
for (const ListenSocket& hListenSocket : vhListenSocket) {
- FD_SET(hListenSocket.socket, &fdsetRecv);
- hSocketMax = std::max(hSocketMax, hListenSocket.socket);
- have_fds = true;
+ recv_set.insert(hListenSocket.socket);
}
{
@@ -1308,46 +1299,151 @@ void CConnman::SocketHandler()
if (pnode->hSocket == INVALID_SOCKET)
continue;
- FD_SET(pnode->hSocket, &fdsetError);
- hSocketMax = std::max(hSocketMax, pnode->hSocket);
- have_fds = true;
-
+ error_set.insert(pnode->hSocket);
if (select_send) {
- FD_SET(pnode->hSocket, &fdsetSend);
+ send_set.insert(pnode->hSocket);
continue;
}
if (select_recv) {
- FD_SET(pnode->hSocket, &fdsetRecv);
+ recv_set.insert(pnode->hSocket);
}
}
}
- int nSelect = select(have_fds ? hSocketMax + 1 : 0,
- &fdsetRecv, &fdsetSend, &fdsetError, &timeout);
+ return !recv_set.empty() || !send_set.empty() || !error_set.empty();
+}
+
+#ifdef USE_POLL
+void CConnman::SocketEvents(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set)
+{
+ std::set<SOCKET> recv_select_set, send_select_set, error_select_set;
+ if (!GenerateSelectSet(recv_select_set, send_select_set, error_select_set)) {
+ interruptNet.sleep_for(std::chrono::milliseconds(SELECT_TIMEOUT_MILLISECONDS));
+ return;
+ }
+
+ std::unordered_map<SOCKET, struct pollfd> pollfds;
+ for (SOCKET socket_id : recv_select_set) {
+ pollfds[socket_id].fd = socket_id;
+ pollfds[socket_id].events |= POLLIN;
+ }
+
+ for (SOCKET socket_id : send_select_set) {
+ pollfds[socket_id].fd = socket_id;
+ pollfds[socket_id].events |= POLLOUT;
+ }
+
+ for (SOCKET socket_id : error_select_set) {
+ pollfds[socket_id].fd = socket_id;
+ // These flags are ignored, but we set them for clarity
+ pollfds[socket_id].events |= POLLERR|POLLHUP;
+ }
+
+ std::vector<struct pollfd> vpollfds;
+ vpollfds.reserve(pollfds.size());
+ for (auto it : pollfds) {
+ vpollfds.push_back(std::move(it.second));
+ }
+
+ if (poll(vpollfds.data(), vpollfds.size(), SELECT_TIMEOUT_MILLISECONDS) < 0) return;
+
+ if (interruptNet) return;
+
+ for (struct pollfd pollfd_entry : vpollfds) {
+ if (pollfd_entry.revents & POLLIN) recv_set.insert(pollfd_entry.fd);
+ if (pollfd_entry.revents & POLLOUT) send_set.insert(pollfd_entry.fd);
+ if (pollfd_entry.revents & (POLLERR|POLLHUP)) error_set.insert(pollfd_entry.fd);
+ }
+}
+#else
+void CConnman::SocketEvents(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set)
+{
+ std::set<SOCKET> recv_select_set, send_select_set, error_select_set;
+ if (!GenerateSelectSet(recv_select_set, send_select_set, error_select_set)) {
+ interruptNet.sleep_for(std::chrono::milliseconds(SELECT_TIMEOUT_MILLISECONDS));
+ return;
+ }
+
+ //
+ // Find which sockets have data to receive
+ //
+ struct timeval timeout;
+ timeout.tv_sec = 0;
+ timeout.tv_usec = SELECT_TIMEOUT_MILLISECONDS * 1000; // frequency to poll pnode->vSend
+
+ fd_set fdsetRecv;
+ fd_set fdsetSend;
+ fd_set fdsetError;
+ FD_ZERO(&fdsetRecv);
+ FD_ZERO(&fdsetSend);
+ FD_ZERO(&fdsetError);
+ SOCKET hSocketMax = 0;
+
+ for (SOCKET hSocket : recv_select_set) {
+ FD_SET(hSocket, &fdsetRecv);
+ hSocketMax = std::max(hSocketMax, hSocket);
+ }
+
+ for (SOCKET hSocket : send_select_set) {
+ FD_SET(hSocket, &fdsetSend);
+ hSocketMax = std::max(hSocketMax, hSocket);
+ }
+
+ for (SOCKET hSocket : error_select_set) {
+ FD_SET(hSocket, &fdsetError);
+ hSocketMax = std::max(hSocketMax, hSocket);
+ }
+
+ int nSelect = select(hSocketMax + 1, &fdsetRecv, &fdsetSend, &fdsetError, &timeout);
+
if (interruptNet)
return;
if (nSelect == SOCKET_ERROR)
{
- if (have_fds)
- {
- int nErr = WSAGetLastError();
- LogPrintf("socket select error %s\n", NetworkErrorString(nErr));
- for (unsigned int i = 0; i <= hSocketMax; i++)
- FD_SET(i, &fdsetRecv);
- }
+ int nErr = WSAGetLastError();
+ LogPrintf("socket select error %s\n", NetworkErrorString(nErr));
+ for (unsigned int i = 0; i <= hSocketMax; i++)
+ FD_SET(i, &fdsetRecv);
FD_ZERO(&fdsetSend);
FD_ZERO(&fdsetError);
- if (!interruptNet.sleep_for(std::chrono::milliseconds(timeout.tv_usec/1000)))
+ if (!interruptNet.sleep_for(std::chrono::milliseconds(SELECT_TIMEOUT_MILLISECONDS)))
return;
}
+ for (SOCKET hSocket : recv_select_set) {
+ if (FD_ISSET(hSocket, &fdsetRecv)) {
+ recv_set.insert(hSocket);
+ }
+ }
+
+ for (SOCKET hSocket : send_select_set) {
+ if (FD_ISSET(hSocket, &fdsetSend)) {
+ send_set.insert(hSocket);
+ }
+ }
+
+ for (SOCKET hSocket : error_select_set) {
+ if (FD_ISSET(hSocket, &fdsetError)) {
+ error_set.insert(hSocket);
+ }
+ }
+}
+#endif
+
+void CConnman::SocketHandler()
+{
+ std::set<SOCKET> recv_set, send_set, error_set;
+ SocketEvents(recv_set, send_set, error_set);
+
+ if (interruptNet) return;
+
//
// Accept new connections
//
for (const ListenSocket& hListenSocket : vhListenSocket)
{
- if (hListenSocket.socket != INVALID_SOCKET && FD_ISSET(hListenSocket.socket, &fdsetRecv))
+ if (hListenSocket.socket != INVALID_SOCKET && recv_set.count(hListenSocket.socket) > 0)
{
AcceptConnection(hListenSocket);
}
@@ -1378,9 +1474,9 @@ void CConnman::SocketHandler()
LOCK(pnode->cs_hSocket);
if (pnode->hSocket == INVALID_SOCKET)
continue;
- recvSet = FD_ISSET(pnode->hSocket, &fdsetRecv);
- sendSet = FD_ISSET(pnode->hSocket, &fdsetSend);
- errorSet = FD_ISSET(pnode->hSocket, &fdsetError);
+ recvSet = recv_set.count(pnode->hSocket) > 0;
+ sendSet = send_set.count(pnode->hSocket) > 0;
+ errorSet = error_set.count(pnode->hSocket) > 0;
}
if (recvSet || errorSet)
{
diff --git a/src/net.h b/src/net.h
index 775d0c8099..915a8e5b35 100644
--- a/src/net.h
+++ b/src/net.h
@@ -346,6 +346,8 @@ private:
void DisconnectNodes();
void NotifyNumConnectionsChanged();
void InactivityCheck(CNode *pnode);
+ bool GenerateSelectSet(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set);
+ void SocketEvents(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set);
void SocketHandler();
void ThreadSocketHandler();
void ThreadDNSAddressSeed();
diff --git a/src/netbase.cpp b/src/netbase.cpp
index 1c043fc981..355e21d4e6 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -21,6 +21,10 @@
#include <codecvt>
#endif
+#ifdef USE_POLL
+#include <poll.h>
+#endif
+
#if !defined(MSG_NOSIGNAL)
#define MSG_NOSIGNAL 0
#endif
@@ -264,11 +268,19 @@ static IntrRecvError InterruptibleRecv(uint8_t* data, size_t len, int timeout, c
if (!IsSelectableSocket(hSocket)) {
return IntrRecvError::NetworkError;
}
- struct timeval tval = MillisToTimeval(std::min(endTime - curTime, maxWait));
+ int timeout_ms = std::min(endTime - curTime, maxWait);
+#ifdef USE_POLL
+ struct pollfd pollfd = {};
+ pollfd.fd = hSocket;
+ pollfd.events = POLLIN | POLLOUT;
+ int nRet = poll(&pollfd, 1, timeout_ms);
+#else
+ struct timeval tval = MillisToTimeval(timeout_ms);
fd_set fdset;
FD_ZERO(&fdset);
FD_SET(hSocket, &fdset);
int nRet = select(hSocket + 1, &fdset, nullptr, nullptr, &tval);
+#endif
if (nRet == SOCKET_ERROR) {
return IntrRecvError::NetworkError;
}
@@ -499,11 +511,18 @@ bool ConnectSocketDirectly(const CService &addrConnect, const SOCKET& hSocket, i
// WSAEINVAL is here because some legacy version of winsock uses it
if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK || nErr == WSAEINVAL)
{
+#ifdef USE_POLL
+ struct pollfd pollfd = {};
+ pollfd.fd = hSocket;
+ pollfd.events = POLLIN | POLLOUT;
+ int nRet = poll(&pollfd, 1, nTimeout);
+#else
struct timeval timeout = MillisToTimeval(nTimeout);
fd_set fdset;
FD_ZERO(&fdset);
FD_SET(hSocket, &fdset);
int nRet = select(hSocket + 1, nullptr, &fdset, nullptr, &timeout);
+#endif
if (nRet == 0)
{
LogPrint(BCLog::NET, "connection to %s timeout\n", addrConnect.ToString());
diff --git a/src/noui.h b/src/noui.h
index 169c2bbd7f..79a79a9af2 100644
--- a/src/noui.h
+++ b/src/noui.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2013-2014 The Bitcoin Core developers
+// Copyright (c) 2013-2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp
index 3afe6fe1b7..c49b9fa36b 100644
--- a/src/policy/fees.cpp
+++ b/src/policy/fees.cpp
@@ -511,7 +511,7 @@ void TxConfirmStats::removeTx(unsigned int entryHeight, unsigned int nBestSeenHe
// of no harm to try to remove them again.
bool CBlockPolicyEstimator::removeTx(uint256 hash, bool inBlock)
{
- LOCK(cs_feeEstimator);
+ LOCK(m_cs_fee_estimator);
std::map<uint256, TxStatsInfo>::iterator pos = mapMemPoolTxs.find(hash);
if (pos != mapMemPoolTxs.end()) {
feeStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex, inBlock);
@@ -548,7 +548,7 @@ CBlockPolicyEstimator::~CBlockPolicyEstimator()
void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, bool validFeeEstimate)
{
- LOCK(cs_feeEstimator);
+ LOCK(m_cs_fee_estimator);
unsigned int txHeight = entry.GetHeight();
uint256 hash = entry.GetTx().GetHash();
if (mapMemPoolTxs.count(hash)) {
@@ -615,7 +615,7 @@ bool CBlockPolicyEstimator::processBlockTx(unsigned int nBlockHeight, const CTxM
void CBlockPolicyEstimator::processBlock(unsigned int nBlockHeight,
std::vector<const CTxMemPoolEntry*>& entries)
{
- LOCK(cs_feeEstimator);
+ LOCK(m_cs_fee_estimator);
if (nBlockHeight <= nBestSeenHeight) {
// Ignore side chains and re-orgs; assuming they are random
// they don't affect the estimate.
@@ -693,7 +693,7 @@ CFeeRate CBlockPolicyEstimator::estimateRawFee(int confTarget, double successThr
}
}
- LOCK(cs_feeEstimator);
+ LOCK(m_cs_fee_estimator);
// Return failure if trying to analyze a target we're not tracking
if (confTarget <= 0 || (unsigned int)confTarget > stats->GetMaxConfirms())
return CFeeRate(0);
@@ -710,6 +710,7 @@ CFeeRate CBlockPolicyEstimator::estimateRawFee(int confTarget, double successThr
unsigned int CBlockPolicyEstimator::HighestTargetTracked(FeeEstimateHorizon horizon) const
{
+ LOCK(m_cs_fee_estimator);
switch (horizon) {
case FeeEstimateHorizon::SHORT_HALFLIFE: {
return shortStats->GetMaxConfirms();
@@ -819,7 +820,7 @@ double CBlockPolicyEstimator::estimateConservativeFee(unsigned int doubleTarget,
*/
CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, FeeCalculation *feeCalc, bool conservative) const
{
- LOCK(cs_feeEstimator);
+ LOCK(m_cs_fee_estimator);
if (feeCalc) {
feeCalc->desiredTarget = confTarget;
@@ -899,7 +900,7 @@ CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, FeeCalculation
bool CBlockPolicyEstimator::Write(CAutoFile& fileout) const
{
try {
- LOCK(cs_feeEstimator);
+ LOCK(m_cs_fee_estimator);
fileout << 149900; // version required to read: 0.14.99 or later
fileout << CLIENT_VERSION; // version that wrote the file
fileout << nBestSeenHeight;
@@ -924,7 +925,7 @@ bool CBlockPolicyEstimator::Write(CAutoFile& fileout) const
bool CBlockPolicyEstimator::Read(CAutoFile& filein)
{
try {
- LOCK(cs_feeEstimator);
+ LOCK(m_cs_fee_estimator);
int nVersionRequired, nVersionThatWrote;
filein >> nVersionRequired >> nVersionThatWrote;
if (nVersionRequired > CLIENT_VERSION)
@@ -983,7 +984,7 @@ bool CBlockPolicyEstimator::Read(CAutoFile& filein)
void CBlockPolicyEstimator::FlushUnconfirmed() {
int64_t startclear = GetTimeMicros();
- LOCK(cs_feeEstimator);
+ LOCK(m_cs_fee_estimator);
size_t num_entries = mapMemPoolTxs.size();
// Remove every entry in mapMemPoolTxs
while (!mapMemPoolTxs.empty()) {
diff --git a/src/policy/fees.h b/src/policy/fees.h
index 90f159b48c..c8472a12f5 100644
--- a/src/policy/fees.h
+++ b/src/policy/fees.h
@@ -228,10 +228,12 @@ public:
unsigned int HighestTargetTracked(FeeEstimateHorizon horizon) const;
private:
- unsigned int nBestSeenHeight;
- unsigned int firstRecordedHeight;
- unsigned int historicalFirst;
- unsigned int historicalBest;
+ mutable CCriticalSection m_cs_fee_estimator;
+
+ unsigned int nBestSeenHeight GUARDED_BY(m_cs_fee_estimator);
+ unsigned int firstRecordedHeight GUARDED_BY(m_cs_fee_estimator);
+ unsigned int historicalFirst GUARDED_BY(m_cs_fee_estimator);
+ unsigned int historicalBest GUARDED_BY(m_cs_fee_estimator);
struct TxStatsInfo
{
@@ -241,34 +243,32 @@ private:
};
// map of txids to information about that transaction
- std::map<uint256, TxStatsInfo> mapMemPoolTxs;
+ std::map<uint256, TxStatsInfo> mapMemPoolTxs GUARDED_BY(m_cs_fee_estimator);
/** Classes to track historical data on transaction confirmations */
- std::unique_ptr<TxConfirmStats> feeStats;
- std::unique_ptr<TxConfirmStats> shortStats;
- std::unique_ptr<TxConfirmStats> longStats;
-
- unsigned int trackedTxs;
- unsigned int untrackedTxs;
+ std::unique_ptr<TxConfirmStats> feeStats PT_GUARDED_BY(m_cs_fee_estimator);
+ std::unique_ptr<TxConfirmStats> shortStats PT_GUARDED_BY(m_cs_fee_estimator);
+ std::unique_ptr<TxConfirmStats> longStats PT_GUARDED_BY(m_cs_fee_estimator);
- std::vector<double> buckets; // The upper-bound of the range for the bucket (inclusive)
- std::map<double, unsigned int> bucketMap; // Map of bucket upper-bound to index into all vectors by bucket
+ unsigned int trackedTxs GUARDED_BY(m_cs_fee_estimator);
+ unsigned int untrackedTxs GUARDED_BY(m_cs_fee_estimator);
- mutable CCriticalSection cs_feeEstimator;
+ std::vector<double> buckets GUARDED_BY(m_cs_fee_estimator); // The upper-bound of the range for the bucket (inclusive)
+ std::map<double, unsigned int> bucketMap GUARDED_BY(m_cs_fee_estimator); // Map of bucket upper-bound to index into all vectors by bucket
/** Process a transaction confirmed in a block*/
- bool processBlockTx(unsigned int nBlockHeight, const CTxMemPoolEntry* entry);
+ bool processBlockTx(unsigned int nBlockHeight, const CTxMemPoolEntry* entry) EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator);
/** Helper for estimateSmartFee */
- double estimateCombinedFee(unsigned int confTarget, double successThreshold, bool checkShorterHorizon, EstimationResult *result) const;
+ double estimateCombinedFee(unsigned int confTarget, double successThreshold, bool checkShorterHorizon, EstimationResult *result) const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator);
/** Helper for estimateSmartFee */
- double estimateConservativeFee(unsigned int doubleTarget, EstimationResult *result) const;
+ double estimateConservativeFee(unsigned int doubleTarget, EstimationResult *result) const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator);
/** Number of blocks of data recorded while fee estimates have been running */
- unsigned int BlockSpan() const;
+ unsigned int BlockSpan() const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator);
/** Number of blocks of recorded fee estimate data represented in saved data file */
- unsigned int HistoricalBlockSpan() const;
+ unsigned int HistoricalBlockSpan() const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator);
/** Calculation of highest target that reasonable estimate can be provided for */
- unsigned int MaxUsableEstimate() const;
+ unsigned int MaxUsableEstimate() const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator);
};
class FeeFilterRounder
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index d7056ddd89..70255e058a 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -58,7 +58,6 @@
#include <QVBoxLayout>
#include <QWindow>
-#include <boost/bind.hpp>
const std::string BitcoinGUI::DEFAULT_UIPLATFORM =
#if defined(Q_OS_MAC)
@@ -130,6 +129,7 @@ BitcoinGUI::BitcoinGUI(interfaces::Node& node, const PlatformStyle *_platformSty
if (QSystemTrayIcon::isSystemTrayAvailable()) {
createTrayIcon(networkStyle);
}
+ notificator = new Notificator(QApplication::applicationName(), trayIcon, this);
// Create status bar
statusBar();
@@ -537,8 +537,7 @@ void BitcoinGUI::setClientModel(ClientModel *_clientModel)
unitDisplayControl->setOptionsModel(_clientModel->getOptionsModel());
OptionsModel* optionsModel = _clientModel->getOptionsModel();
- if(optionsModel)
- {
+ if (optionsModel && trayIcon) {
// be aware of the tray icon disable state change reported by the OptionsModel object.
connect(optionsModel, &OptionsModel::hideTrayIconChanged, this, &BitcoinGUI::setTrayIconVisible);
@@ -643,14 +642,10 @@ void BitcoinGUI::createTrayIcon(const NetworkStyle *networkStyle)
assert(QSystemTrayIcon::isSystemTrayAvailable());
#ifndef Q_OS_MAC
- trayIcon = new QSystemTrayIcon(this);
+ trayIcon = new QSystemTrayIcon(networkStyle->getTrayAndWindowIcon(), this);
QString toolTip = tr("%1 client").arg(tr(PACKAGE_NAME)) + " " + networkStyle->getTitleAddText();
trayIcon->setToolTip(toolTip);
- trayIcon->setIcon(networkStyle->getTrayAndWindowIcon());
- trayIcon->hide();
#endif
-
- notificator = new Notificator(QApplication::applicationName(), trayIcon, this);
}
void BitcoinGUI::createTrayIconMenu()
@@ -1294,8 +1289,8 @@ static bool ThreadSafeMessageBox(BitcoinGUI* gui, const std::string& message, co
void BitcoinGUI::subscribeToCoreSignals()
{
// Connect signals to client
- m_handler_message_box = m_node.handleMessageBox(boost::bind(ThreadSafeMessageBox, this, _1, _2, _3));
- m_handler_question = m_node.handleQuestion(boost::bind(ThreadSafeMessageBox, this, _1, _3, _4));
+ m_handler_message_box = m_node.handleMessageBox(std::bind(ThreadSafeMessageBox, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
+ m_handler_question = m_node.handleQuestion(std::bind(ThreadSafeMessageBox, this, std::placeholders::_1, std::placeholders::_3, std::placeholders::_4));
}
void BitcoinGUI::unsubscribeFromCoreSignals()
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index 75012b279c..217326f818 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -252,13 +252,13 @@ static void BlockTipChanged(ClientModel *clientmodel, bool initialSync, int heig
void ClientModel::subscribeToCoreSignals()
{
// Connect signals to client
- m_handler_show_progress = m_node.handleShowProgress(boost::bind(ShowProgress, this, _1, _2));
- m_handler_notify_num_connections_changed = m_node.handleNotifyNumConnectionsChanged(boost::bind(NotifyNumConnectionsChanged, this, _1));
- m_handler_notify_network_active_changed = m_node.handleNotifyNetworkActiveChanged(boost::bind(NotifyNetworkActiveChanged, this, _1));
- m_handler_notify_alert_changed = m_node.handleNotifyAlertChanged(boost::bind(NotifyAlertChanged, this));
- m_handler_banned_list_changed = m_node.handleBannedListChanged(boost::bind(BannedListChanged, this));
- m_handler_notify_block_tip = m_node.handleNotifyBlockTip(boost::bind(BlockTipChanged, this, _1, _2, _3, _4, false));
- m_handler_notify_header_tip = m_node.handleNotifyHeaderTip(boost::bind(BlockTipChanged, this, _1, _2, _3, _4, true));
+ m_handler_show_progress = m_node.handleShowProgress(std::bind(ShowProgress, this, std::placeholders::_1, std::placeholders::_2));
+ m_handler_notify_num_connections_changed = m_node.handleNotifyNumConnectionsChanged(std::bind(NotifyNumConnectionsChanged, this, std::placeholders::_1));
+ m_handler_notify_network_active_changed = m_node.handleNotifyNetworkActiveChanged(std::bind(NotifyNetworkActiveChanged, this, std::placeholders::_1));
+ m_handler_notify_alert_changed = m_node.handleNotifyAlertChanged(std::bind(NotifyAlertChanged, this));
+ m_handler_banned_list_changed = m_node.handleBannedListChanged(std::bind(BannedListChanged, this));
+ m_handler_notify_block_tip = m_node.handleNotifyBlockTip(std::bind(BlockTipChanged, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, false));
+ m_handler_notify_header_tip = m_node.handleNotifyHeaderTip(std::bind(BlockTipChanged, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, true));
}
void ClientModel::unsubscribeFromCoreSignals()
diff --git a/src/qt/forms/optionsdialog.ui b/src/qt/forms/optionsdialog.ui
index 8f34e6bc82..507d195b72 100644
--- a/src/qt/forms/optionsdialog.ui
+++ b/src/qt/forms/optionsdialog.ui
@@ -714,7 +714,7 @@
<item>
<widget class="QLabel" name="overriddenByCommandLineInfoLabel">
<property name="text">
- <string>Active command-line options that override above options:</string>
+ <string>Options set in this dialog are overridden by the command line or in the configuration file:</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp
index 7b952f9fd7..b109a08b1c 100644
--- a/src/qt/splashscreen.cpp
+++ b/src/qt/splashscreen.cpp
@@ -24,7 +24,6 @@
#include <QPainter>
#include <QRadialGradient>
-#include <boost/bind.hpp>
SplashScreen::SplashScreen(interfaces::Node& node, Qt::WindowFlags f, const NetworkStyle *networkStyle) :
QWidget(0, f), curAlignment(0), m_node(node)
@@ -174,7 +173,7 @@ static void ShowProgress(SplashScreen *splash, const std::string &title, int nPr
#ifdef ENABLE_WALLET
void SplashScreen::ConnectWallet(std::unique_ptr<interfaces::Wallet> wallet)
{
- m_connected_wallet_handlers.emplace_back(wallet->handleShowProgress(boost::bind(ShowProgress, this, _1, _2, false)));
+ m_connected_wallet_handlers.emplace_back(wallet->handleShowProgress(std::bind(ShowProgress, this, std::placeholders::_1, std::placeholders::_2, false)));
m_connected_wallets.emplace_back(std::move(wallet));
}
#endif
@@ -182,8 +181,8 @@ void SplashScreen::ConnectWallet(std::unique_ptr<interfaces::Wallet> wallet)
void SplashScreen::subscribeToCoreSignals()
{
// Connect signals to client
- m_handler_init_message = m_node.handleInitMessage(boost::bind(InitMessage, this, _1));
- m_handler_show_progress = m_node.handleShowProgress(boost::bind(ShowProgress, this, _1, _2, _3));
+ m_handler_init_message = m_node.handleInitMessage(std::bind(InitMessage, this, std::placeholders::_1));
+ m_handler_show_progress = m_node.handleShowProgress(std::bind(ShowProgress, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
#ifdef ENABLE_WALLET
m_handler_load_wallet = m_node.handleLoadWallet([this](std::unique_ptr<interfaces::Wallet> wallet) { ConnectWallet(std::move(wallet)); });
#endif
diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp
index 1983c3bc92..01722146c5 100644
--- a/src/qt/transactiontablemodel.cpp
+++ b/src/qt/transactiontablemodel.cpp
@@ -27,7 +27,6 @@
#include <QIcon>
#include <QList>
-#include <boost/bind.hpp>
// Amount column is right-aligned it contains numbers
static int column_alignments[] = {
@@ -745,8 +744,8 @@ static void ShowProgress(TransactionTableModel *ttm, const std::string &title, i
void TransactionTableModel::subscribeToCoreSignals()
{
// Connect signals to wallet
- m_handler_transaction_changed = walletModel->wallet().handleTransactionChanged(boost::bind(NotifyTransactionChanged, this, _1, _2));
- m_handler_show_progress = walletModel->wallet().handleShowProgress(boost::bind(ShowProgress, this, _1, _2));
+ m_handler_transaction_changed = walletModel->wallet().handleTransactionChanged(std::bind(NotifyTransactionChanged, this, std::placeholders::_1, std::placeholders::_2));
+ m_handler_show_progress = walletModel->wallet().handleShowProgress(std::bind(ShowProgress, this, std::placeholders::_1, std::placeholders::_2));
}
void TransactionTableModel::unsubscribeFromCoreSignals()
diff --git a/src/qt/walletframe.h b/src/qt/walletframe.h
index 05ca569d7a..1963e89b24 100644
--- a/src/qt/walletframe.h
+++ b/src/qt/walletframe.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2017 The Bitcoin Core developers
+// Copyright (c) 2011-2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index 353da0c9b4..ba16fdd5e1 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -428,12 +428,12 @@ static void NotifyWatchonlyChanged(WalletModel *walletmodel, bool fHaveWatchonly
void WalletModel::subscribeToCoreSignals()
{
// Connect signals to wallet
- m_handler_unload = m_wallet->handleUnload(boost::bind(&NotifyUnload, this));
- m_handler_status_changed = m_wallet->handleStatusChanged(boost::bind(&NotifyKeyStoreStatusChanged, this));
- m_handler_address_book_changed = m_wallet->handleAddressBookChanged(boost::bind(NotifyAddressBookChanged, this, _1, _2, _3, _4, _5));
- m_handler_transaction_changed = m_wallet->handleTransactionChanged(boost::bind(NotifyTransactionChanged, this, _1, _2));
- m_handler_show_progress = m_wallet->handleShowProgress(boost::bind(ShowProgress, this, _1, _2));
- m_handler_watch_only_changed = m_wallet->handleWatchOnlyChanged(boost::bind(NotifyWatchonlyChanged, this, _1));
+ m_handler_unload = m_wallet->handleUnload(std::bind(&NotifyUnload, this));
+ m_handler_status_changed = m_wallet->handleStatusChanged(std::bind(&NotifyKeyStoreStatusChanged, this));
+ m_handler_address_book_changed = m_wallet->handleAddressBookChanged(std::bind(NotifyAddressBookChanged, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5));
+ m_handler_transaction_changed = m_wallet->handleTransactionChanged(std::bind(NotifyTransactionChanged, this, std::placeholders::_1, std::placeholders::_2));
+ m_handler_show_progress = m_wallet->handleShowProgress(std::bind(ShowProgress, this, std::placeholders::_1, std::placeholders::_2));
+ m_handler_watch_only_changed = m_wallet->handleWatchOnlyChanged(std::bind(NotifyWatchonlyChanged, this, std::placeholders::_1));
}
void WalletModel::unsubscribeFromCoreSignals()
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index 370ae8e4d7..bf00870107 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -130,8 +130,8 @@ static UniValue getrawtransaction(const JSONRPCRequest& request)
" ],\n"
" \"blockhash\" : \"hash\", (string) the block hash\n"
" \"confirmations\" : n, (numeric) The confirmations\n"
- " \"time\" : ttt, (numeric) The transaction time in seconds since epoch (Jan 1 1970 GMT)\n"
" \"blocktime\" : ttt (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\n"
+ " \"time\" : ttt, (numeric) Same as \"blocktime\"\n"
"}\n"
"\nExamples:\n"
@@ -1135,7 +1135,7 @@ static UniValue testmempoolaccept(const JSONRPCRequest& request)
"Sign the transaction, and get back the hex\n"
+ HelpExampleCli("signrawtransactionwithwallet", "\"myhex\"") +
"\nTest acceptance of the transaction (signed hex)\n"
- + HelpExampleCli("testmempoolaccept", "\"signedhex\"") +
+ + HelpExampleCli("testmempoolaccept", "[\"signedhex\"]") +
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("testmempoolaccept", "[\"signedhex\"]")
);
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
index 03e1c81132..e7e047334e 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -15,7 +15,6 @@
#include <util/strencodings.h>
#include <util/system.h>
-#include <boost/bind.hpp>
#include <boost/signals2/signal.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>
@@ -504,11 +503,7 @@ UniValue CRPCTable::execute(const JSONRPCRequest &request) const
std::vector<std::string> CRPCTable::listCommands() const
{
std::vector<std::string> commandList;
- typedef std::map<std::string, const CRPCCommand*> commandMap;
-
- std::transform( mapCommands.begin(), mapCommands.end(),
- std::back_inserter(commandList),
- boost::bind(&commandMap::value_type::first,_1) );
+ for (const auto& i : mapCommands) commandList.emplace_back(i.first);
return commandList;
}
diff --git a/src/scheduler.cpp b/src/scheduler.cpp
index 552391d7d0..b2da62fc75 100644
--- a/src/scheduler.cpp
+++ b/src/scheduler.cpp
@@ -8,7 +8,6 @@
#include <reverselock.h>
#include <assert.h>
-#include <boost/bind.hpp>
#include <utility>
CScheduler::CScheduler() : nThreadsServicingQueue(0), stopRequested(false), stopWhenEmpty(false)
@@ -120,12 +119,12 @@ void CScheduler::scheduleFromNow(CScheduler::Function f, int64_t deltaMilliSecon
static void Repeat(CScheduler* s, CScheduler::Function f, int64_t deltaMilliSeconds)
{
f();
- s->scheduleFromNow(boost::bind(&Repeat, s, f, deltaMilliSeconds), deltaMilliSeconds);
+ s->scheduleFromNow(std::bind(&Repeat, s, f, deltaMilliSeconds), deltaMilliSeconds);
}
void CScheduler::scheduleEvery(CScheduler::Function f, int64_t deltaMilliSeconds)
{
- scheduleFromNow(boost::bind(&Repeat, this, f, deltaMilliSeconds), deltaMilliSeconds);
+ scheduleFromNow(std::bind(&Repeat, this, f, deltaMilliSeconds), deltaMilliSeconds);
}
size_t CScheduler::getQueueInfo(boost::chrono::system_clock::time_point &first,
diff --git a/src/scheduler.h b/src/scheduler.h
index 6c45f508ec..6d7f42cf9f 100644
--- a/src/scheduler.h
+++ b/src/scheduler.h
@@ -25,7 +25,7 @@
// CScheduler* s = new CScheduler();
// s->scheduleFromNow(doSomething, 11); // Assuming a: void doSomething() { }
// s->scheduleFromNow(std::bind(Class::func, this, argument), 3);
-// boost::thread* t = new boost::thread(boost::bind(CScheduler::serviceQueue, s));
+// boost::thread* t = new boost::thread(std::bind(CScheduler::serviceQueue, s));
//
// ... then at program shutdown, clean up the thread running serviceQueue:
// t->interrupt();
diff --git a/src/test/blockfilter_tests.cpp b/src/test/blockfilter_tests.cpp
index 2144202b8d..625362f446 100644
--- a/src/test/blockfilter_tests.cpp
+++ b/src/test/blockfilter_tests.cpp
@@ -29,7 +29,7 @@ BOOST_AUTO_TEST_CASE(gcsfilter_test)
excluded_elements.insert(std::move(element2));
}
- GCSFilter filter(0, 0, 10, 1 << 10, included_elements);
+ GCSFilter filter({0, 0, 10, 1 << 10}, included_elements);
for (const auto& element : included_elements) {
BOOST_CHECK(filter.Match(element));
@@ -39,6 +39,19 @@ BOOST_AUTO_TEST_CASE(gcsfilter_test)
}
}
+BOOST_AUTO_TEST_CASE(gcsfilter_default_constructor)
+{
+ GCSFilter filter;
+ BOOST_CHECK_EQUAL(filter.GetN(), 0);
+ BOOST_CHECK_EQUAL(filter.GetEncoded().size(), 1);
+
+ const GCSFilter::Params& params = filter.GetParams();
+ BOOST_CHECK_EQUAL(params.m_siphash_k0, 0);
+ BOOST_CHECK_EQUAL(params.m_siphash_k1, 0);
+ BOOST_CHECK_EQUAL(params.m_P, 0);
+ BOOST_CHECK_EQUAL(params.m_M, 1);
+}
+
BOOST_AUTO_TEST_CASE(blockfilter_basic_test)
{
CScript included_scripts[5], excluded_scripts[3];
@@ -88,6 +101,17 @@ BOOST_AUTO_TEST_CASE(blockfilter_basic_test)
for (const CScript& script : excluded_scripts) {
BOOST_CHECK(!filter.Match(GCSFilter::Element(script.begin(), script.end())));
}
+
+ // Test serialization/unserialization.
+ BlockFilter block_filter2;
+
+ CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
+ stream << block_filter;
+ stream >> block_filter2;
+
+ BOOST_CHECK_EQUAL(block_filter.GetFilterType(), block_filter2.GetFilterType());
+ BOOST_CHECK_EQUAL(block_filter.GetBlockHash(), block_filter2.GetBlockHash());
+ BOOST_CHECK(block_filter.GetEncodedFilter() == block_filter2.GetEncodedFilter());
}
BOOST_AUTO_TEST_CASE(blockfilters_json_test)
diff --git a/src/test/key_io_tests.cpp b/src/test/key_io_tests.cpp
index 1abaabd658..bf295042de 100644
--- a/src/test/key_io_tests.cpp
+++ b/src/test/key_io_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2017 The Bitcoin Core developers
+// Copyright (c) 2011-2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/scheduler_tests.cpp b/src/test/scheduler_tests.cpp
index 12ec00ce02..100d65b779 100644
--- a/src/test/scheduler_tests.cpp
+++ b/src/test/scheduler_tests.cpp
@@ -7,7 +7,6 @@
#include <test/test_bitcoin.h>
-#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include <boost/test/unit_test.hpp>
@@ -21,7 +20,7 @@ static void microTask(CScheduler& s, boost::mutex& mutex, int& counter, int delt
}
boost::chrono::system_clock::time_point noTime = boost::chrono::system_clock::time_point::min();
if (rescheduleTime != noTime) {
- CScheduler::Function f = boost::bind(&microTask, boost::ref(s), boost::ref(mutex), boost::ref(counter), -delta + 1, noTime);
+ CScheduler::Function f = std::bind(&microTask, std::ref(s), std::ref(mutex), std::ref(counter), -delta + 1, noTime);
s.schedule(f, rescheduleTime);
}
}
@@ -69,8 +68,8 @@ BOOST_AUTO_TEST_CASE(manythreads)
boost::chrono::system_clock::time_point t = now + boost::chrono::microseconds(randomMsec(rng));
boost::chrono::system_clock::time_point tReschedule = now + boost::chrono::microseconds(500 + randomMsec(rng));
int whichCounter = zeroToNine(rng);
- CScheduler::Function f = boost::bind(&microTask, boost::ref(microTasks),
- boost::ref(counterMutex[whichCounter]), boost::ref(counter[whichCounter]),
+ CScheduler::Function f = std::bind(&microTask, std::ref(microTasks),
+ std::ref(counterMutex[whichCounter]), std::ref(counter[whichCounter]),
randomDelta(rng), tReschedule);
microTasks.schedule(f, t);
}
@@ -82,20 +81,20 @@ BOOST_AUTO_TEST_CASE(manythreads)
// As soon as these are created they will start running and servicing the queue
boost::thread_group microThreads;
for (int i = 0; i < 5; i++)
- microThreads.create_thread(boost::bind(&CScheduler::serviceQueue, &microTasks));
+ microThreads.create_thread(std::bind(&CScheduler::serviceQueue, &microTasks));
MicroSleep(600);
now = boost::chrono::system_clock::now();
// More threads and more tasks:
for (int i = 0; i < 5; i++)
- microThreads.create_thread(boost::bind(&CScheduler::serviceQueue, &microTasks));
+ microThreads.create_thread(std::bind(&CScheduler::serviceQueue, &microTasks));
for (int i = 0; i < 100; i++) {
boost::chrono::system_clock::time_point t = now + boost::chrono::microseconds(randomMsec(rng));
boost::chrono::system_clock::time_point tReschedule = now + boost::chrono::microseconds(500 + randomMsec(rng));
int whichCounter = zeroToNine(rng);
- CScheduler::Function f = boost::bind(&microTask, boost::ref(microTasks),
- boost::ref(counterMutex[whichCounter]), boost::ref(counter[whichCounter]),
+ CScheduler::Function f = std::bind(&microTask, std::ref(microTasks),
+ std::ref(counterMutex[whichCounter]), std::ref(counter[whichCounter]),
randomDelta(rng), tReschedule);
microTasks.schedule(f, t);
}
@@ -126,7 +125,7 @@ BOOST_AUTO_TEST_CASE(singlethreadedscheduler_ordered)
// if they don't we'll get out of order behaviour
boost::thread_group threads;
for (int i = 0; i < 5; ++i) {
- threads.create_thread(boost::bind(&CScheduler::serviceQueue, &scheduler));
+ threads.create_thread(std::bind(&CScheduler::serviceQueue, &scheduler));
}
// these are not atomic, if SinglethreadedSchedulerClient prevents
diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp
index a3201de385..858bb512fc 100644
--- a/src/test/test_bitcoin.cpp
+++ b/src/test/test_bitcoin.cpp
@@ -89,7 +89,7 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha
// We have to run a scheduler thread to prevent ActivateBestChain
// from blocking due to queue overrun.
- threadGroup.create_thread(boost::bind(&CScheduler::serviceQueue, &scheduler));
+ threadGroup.create_thread(std::bind(&CScheduler::serviceQueue, &scheduler));
GetMainSignals().RegisterBackgroundSignalScheduler(scheduler);
mempool.setSanityCheck(1.0);
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index c68b6bbb4d..d952054483 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -467,7 +467,7 @@ BOOST_AUTO_TEST_CASE(test_big_witness_transaction) {
CCheckQueueControl<CScriptCheck> control(&scriptcheckqueue);
for (int i=0; i<20; i++)
- threadGroup.create_thread(boost::bind(&CCheckQueue<CScriptCheck>::Thread, boost::ref(scriptcheckqueue)));
+ threadGroup.create_thread(std::bind(&CCheckQueue<CScriptCheck>::Thread, std::ref(scriptcheckqueue)));
std::vector<Coin> coins;
for(uint32_t i = 0; i < mtx.vin.size(); i++) {
diff --git a/src/test/txvalidation_tests.cpp b/src/test/txvalidation_tests.cpp
index 473ec5addf..c2777cd6d1 100644
--- a/src/test/txvalidation_tests.cpp
+++ b/src/test/txvalidation_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017 The Bitcoin Core developers
+// Copyright (c) 2017-2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/threadinterrupt.h b/src/threadinterrupt.h
index 9c6fccfcde..2743571379 100644
--- a/src/threadinterrupt.h
+++ b/src/threadinterrupt.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2017 The Bitcoin Core developers
+// Copyright (c) 2016-2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp
index 229cc7d553..c9ee6f9f81 100644
--- a/src/torcontrol.cpp
+++ b/src/torcontrol.cpp
@@ -15,7 +15,6 @@
#include <set>
#include <stdlib.h>
-#include <boost/bind.hpp>
#include <boost/signals2/signal.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
@@ -459,8 +458,8 @@ TorController::TorController(struct event_base* _base, const std::string& _targe
if (!reconnect_ev)
LogPrintf("tor: Failed to create event for reconnection: out of memory?\n");
// Start connection attempts immediately
- if (!conn.Connect(_target, boost::bind(&TorController::connected_cb, this, _1),
- boost::bind(&TorController::disconnected_cb, this, _1) )) {
+ if (!conn.Connect(_target, std::bind(&TorController::connected_cb, this, std::placeholders::_1),
+ std::bind(&TorController::disconnected_cb, this, std::placeholders::_1) )) {
LogPrintf("tor: Initiating connection to Tor control port %s failed\n", _target);
}
// Read service private key if cached
@@ -538,7 +537,7 @@ void TorController::auth_cb(TorControlConnection& _conn, const TorControlReply&
// Note that the 'virtual' port doesn't have to be the same as our internal port, but this is just a convenient
// choice. TODO; refactor the shutdown sequence some day.
_conn.Command(strprintf("ADD_ONION %s Port=%i,127.0.0.1:%i", private_key, GetListenPort(), GetListenPort()),
- boost::bind(&TorController::add_onion_cb, this, _1, _2));
+ std::bind(&TorController::add_onion_cb, this, std::placeholders::_1, std::placeholders::_2));
} else {
LogPrintf("tor: Authentication failed\n");
}
@@ -597,7 +596,7 @@ void TorController::authchallenge_cb(TorControlConnection& _conn, const TorContr
}
std::vector<uint8_t> computedClientHash = ComputeResponse(TOR_SAFE_CLIENTKEY, cookie, clientNonce, serverNonce);
- _conn.Command("AUTHENTICATE " + HexStr(computedClientHash), boost::bind(&TorController::auth_cb, this, _1, _2));
+ _conn.Command("AUTHENTICATE " + HexStr(computedClientHash), std::bind(&TorController::auth_cb, this, std::placeholders::_1, std::placeholders::_2));
} else {
LogPrintf("tor: Invalid reply to AUTHCHALLENGE\n");
}
@@ -646,23 +645,23 @@ void TorController::protocolinfo_cb(TorControlConnection& _conn, const TorContro
if (methods.count("HASHEDPASSWORD")) {
LogPrint(BCLog::TOR, "tor: Using HASHEDPASSWORD authentication\n");
boost::replace_all(torpassword, "\"", "\\\"");
- _conn.Command("AUTHENTICATE \"" + torpassword + "\"", boost::bind(&TorController::auth_cb, this, _1, _2));
+ _conn.Command("AUTHENTICATE \"" + torpassword + "\"", std::bind(&TorController::auth_cb, this, std::placeholders::_1, std::placeholders::_2));
} else {
LogPrintf("tor: Password provided with -torpassword, but HASHEDPASSWORD authentication is not available\n");
}
} else if (methods.count("NULL")) {
LogPrint(BCLog::TOR, "tor: Using NULL authentication\n");
- _conn.Command("AUTHENTICATE", boost::bind(&TorController::auth_cb, this, _1, _2));
+ _conn.Command("AUTHENTICATE", std::bind(&TorController::auth_cb, this, std::placeholders::_1, std::placeholders::_2));
} else if (methods.count("SAFECOOKIE")) {
// Cookie: hexdump -e '32/1 "%02x""\n"' ~/.tor/control_auth_cookie
LogPrint(BCLog::TOR, "tor: Using SAFECOOKIE authentication, reading cookie authentication from %s\n", cookiefile);
std::pair<bool,std::string> status_cookie = ReadBinaryFile(cookiefile, TOR_COOKIE_SIZE);
if (status_cookie.first && status_cookie.second.size() == TOR_COOKIE_SIZE) {
- // _conn.Command("AUTHENTICATE " + HexStr(status_cookie.second), boost::bind(&TorController::auth_cb, this, _1, _2));
+ // _conn.Command("AUTHENTICATE " + HexStr(status_cookie.second), std::bind(&TorController::auth_cb, this, std::placeholders::_1, std::placeholders::_2));
cookie = std::vector<uint8_t>(status_cookie.second.begin(), status_cookie.second.end());
clientNonce = std::vector<uint8_t>(TOR_NONCE_SIZE, 0);
GetRandBytes(clientNonce.data(), TOR_NONCE_SIZE);
- _conn.Command("AUTHCHALLENGE SAFECOOKIE " + HexStr(clientNonce), boost::bind(&TorController::authchallenge_cb, this, _1, _2));
+ _conn.Command("AUTHCHALLENGE SAFECOOKIE " + HexStr(clientNonce), std::bind(&TorController::authchallenge_cb, this, std::placeholders::_1, std::placeholders::_2));
} else {
if (status_cookie.first) {
LogPrintf("tor: Authentication cookie %s is not exactly %i bytes, as is required by the spec\n", cookiefile, TOR_COOKIE_SIZE);
@@ -684,7 +683,7 @@ void TorController::connected_cb(TorControlConnection& _conn)
{
reconnect_timeout = RECONNECT_TIMEOUT_START;
// First send a PROTOCOLINFO command to figure out what authentication is expected
- if (!_conn.Command("PROTOCOLINFO 1", boost::bind(&TorController::protocolinfo_cb, this, _1, _2)))
+ if (!_conn.Command("PROTOCOLINFO 1", std::bind(&TorController::protocolinfo_cb, this, std::placeholders::_1, std::placeholders::_2)))
LogPrintf("tor: Error sending initial protocolinfo command\n");
}
@@ -711,8 +710,8 @@ void TorController::Reconnect()
/* Try to reconnect and reestablish if we get booted - for example, Tor
* may be restarting.
*/
- if (!conn.Connect(target, boost::bind(&TorController::connected_cb, this, _1),
- boost::bind(&TorController::disconnected_cb, this, _1) )) {
+ if (!conn.Connect(target, std::bind(&TorController::connected_cb, this, std::placeholders::_1),
+ std::bind(&TorController::disconnected_cb, this, std::placeholders::_1) )) {
LogPrintf("tor: Re-initiating connection to Tor control port %s failed\n", target);
}
}
diff --git a/src/validation.cpp b/src/validation.cpp
index 5696684ed6..00d7a60cb7 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -2366,14 +2366,11 @@ class ConnectTrace {
private:
std::vector<PerBlockConnectTrace> blocksConnected;
CTxMemPool &pool;
+ boost::signals2::scoped_connection m_connNotifyEntryRemoved;
public:
explicit ConnectTrace(CTxMemPool &_pool) : blocksConnected(1), pool(_pool) {
- pool.NotifyEntryRemoved.connect(boost::bind(&ConnectTrace::NotifyEntryRemoved, this, _1, _2));
- }
-
- ~ConnectTrace() {
- pool.NotifyEntryRemoved.disconnect(boost::bind(&ConnectTrace::NotifyEntryRemoved, this, _1, _2));
+ m_connNotifyEntryRemoved = pool.NotifyEntryRemoved.connect(std::bind(&ConnectTrace::NotifyEntryRemoved, this, std::placeholders::_1, std::placeholders::_2));
}
void BlockConnected(CBlockIndex* pindex, std::shared_ptr<const CBlock> pblock) {
@@ -3374,10 +3371,30 @@ bool CChainState::AcceptBlockHeader(const CBlockHeader& block, CValidationState&
if (!ContextualCheckBlockHeader(block, state, chainparams, pindexPrev, GetAdjustedTime()))
return error("%s: Consensus::ContextualCheckBlockHeader: %s, %s", __func__, hash.ToString(), FormatStateMessage(state));
- // If the previous block index isn't valid, determine if it descends from any block which
- // has been found invalid (m_failed_blocks), then mark pindexPrev and any blocks
- // between them as failed.
+ /* Determine if this block descends from any block which has been found
+ * invalid (m_failed_blocks), then mark pindexPrev and any blocks between
+ * them as failed. For example:
+ *
+ * D3
+ * /
+ * B2 - C2
+ * / \
+ * A D2 - E2 - F2
+ * \
+ * B1 - C1 - D1 - E1
+ *
+ * In the case that we attempted to reorg from E1 to F2, only to find
+ * C2 to be invalid, we would mark D2, E2, and F2 as BLOCK_FAILED_CHILD
+ * but NOT D3 (it was not in any of our candidate sets at the time).
+ *
+ * In any case D3 will also be marked as BLOCK_FAILED_CHILD at restart
+ * in LoadBlockIndex.
+ */
if (!pindexPrev->IsValid(BLOCK_VALID_SCRIPTS)) {
+ // The above does not mean "invalid": it checks if the previous block
+ // hasn't been validated up to BLOCK_VALID_SCRIPTS. This is a performance
+ // optimization, in the common case of adding a new block to the tip,
+ // we don't need to iterate over the failed blocks list.
for (const CBlockIndex* failedit : m_failed_blocks) {
if (pindexPrev->GetAncestor(failedit->nHeight) == failedit) {
assert(failedit->nStatus & BLOCK_FAILED_VALID);
diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp
index 214a9ffba9..533d412888 100644
--- a/src/validationinterface.cpp
+++ b/src/validationinterface.cpp
@@ -17,6 +17,18 @@
#include <boost/signals2/signal.hpp>
+struct ValidationInterfaceConnections {
+ boost::signals2::scoped_connection UpdatedBlockTip;
+ boost::signals2::scoped_connection TransactionAddedToMempool;
+ boost::signals2::scoped_connection BlockConnected;
+ boost::signals2::scoped_connection BlockDisconnected;
+ boost::signals2::scoped_connection TransactionRemovedFromMempool;
+ boost::signals2::scoped_connection ChainStateFlushed;
+ boost::signals2::scoped_connection Broadcast;
+ boost::signals2::scoped_connection BlockChecked;
+ boost::signals2::scoped_connection NewPoWValidBlock;
+};
+
struct MainSignalsInstance {
boost::signals2::signal<void (const CBlockIndex *, const CBlockIndex *, bool fInitialDownload)> UpdatedBlockTip;
boost::signals2::signal<void (const CTransactionRef &)> TransactionAddedToMempool;
@@ -32,12 +44,18 @@ struct MainSignalsInstance {
// but must ensure all callbacks happen in-order, so we end up creating
// our own queue here :(
SingleThreadedSchedulerClient m_schedulerClient;
+ std::unordered_map<CValidationInterface*, ValidationInterfaceConnections> m_connMainSignals;
explicit MainSignalsInstance(CScheduler *pscheduler) : m_schedulerClient(pscheduler) {}
};
static CMainSignals g_signals;
+// This map has to a separate global instead of a member of MainSignalsInstance,
+// because RegisterWithMempoolSignals is currently called before RegisterBackgroundSignalScheduler,
+// so MainSignalsInstance hasn't been created yet.
+static std::unordered_map<CTxMemPool*, boost::signals2::scoped_connection> g_connNotifyEntryRemoved;
+
void CMainSignals::RegisterBackgroundSignalScheduler(CScheduler& scheduler) {
assert(!m_internals);
m_internals.reset(new MainSignalsInstance(&scheduler));
@@ -59,11 +77,11 @@ size_t CMainSignals::CallbacksPending() {
}
void CMainSignals::RegisterWithMempoolSignals(CTxMemPool& pool) {
- pool.NotifyEntryRemoved.connect(boost::bind(&CMainSignals::MempoolEntryRemoved, this, _1, _2));
+ g_connNotifyEntryRemoved.emplace(&pool, pool.NotifyEntryRemoved.connect(std::bind(&CMainSignals::MempoolEntryRemoved, this, std::placeholders::_1, std::placeholders::_2)));
}
void CMainSignals::UnregisterWithMempoolSignals(CTxMemPool& pool) {
- pool.NotifyEntryRemoved.disconnect(boost::bind(&CMainSignals::MempoolEntryRemoved, this, _1, _2));
+ g_connNotifyEntryRemoved.erase(&pool);
}
CMainSignals& GetMainSignals()
@@ -72,42 +90,27 @@ CMainSignals& GetMainSignals()
}
void RegisterValidationInterface(CValidationInterface* pwalletIn) {
- g_signals.m_internals->UpdatedBlockTip.connect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1, _2, _3));
- g_signals.m_internals->TransactionAddedToMempool.connect(boost::bind(&CValidationInterface::TransactionAddedToMempool, pwalletIn, _1));
- g_signals.m_internals->BlockConnected.connect(boost::bind(&CValidationInterface::BlockConnected, pwalletIn, _1, _2, _3));
- g_signals.m_internals->BlockDisconnected.connect(boost::bind(&CValidationInterface::BlockDisconnected, pwalletIn, _1));
- g_signals.m_internals->TransactionRemovedFromMempool.connect(boost::bind(&CValidationInterface::TransactionRemovedFromMempool, pwalletIn, _1));
- g_signals.m_internals->ChainStateFlushed.connect(boost::bind(&CValidationInterface::ChainStateFlushed, pwalletIn, _1));
- g_signals.m_internals->Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1, _2));
- g_signals.m_internals->BlockChecked.connect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));
- g_signals.m_internals->NewPoWValidBlock.connect(boost::bind(&CValidationInterface::NewPoWValidBlock, pwalletIn, _1, _2));
+ ValidationInterfaceConnections& conns = g_signals.m_internals->m_connMainSignals[pwalletIn];
+ conns.UpdatedBlockTip = g_signals.m_internals->UpdatedBlockTip.connect(std::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
+ conns.TransactionAddedToMempool = g_signals.m_internals->TransactionAddedToMempool.connect(std::bind(&CValidationInterface::TransactionAddedToMempool, pwalletIn, std::placeholders::_1));
+ conns.BlockConnected = g_signals.m_internals->BlockConnected.connect(std::bind(&CValidationInterface::BlockConnected, pwalletIn, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
+ conns.BlockDisconnected = g_signals.m_internals->BlockDisconnected.connect(std::bind(&CValidationInterface::BlockDisconnected, pwalletIn, std::placeholders::_1));
+ conns.TransactionRemovedFromMempool = g_signals.m_internals->TransactionRemovedFromMempool.connect(std::bind(&CValidationInterface::TransactionRemovedFromMempool, pwalletIn, std::placeholders::_1));
+ conns.ChainStateFlushed = g_signals.m_internals->ChainStateFlushed.connect(std::bind(&CValidationInterface::ChainStateFlushed, pwalletIn, std::placeholders::_1));
+ conns.Broadcast = g_signals.m_internals->Broadcast.connect(std::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, std::placeholders::_1, std::placeholders::_2));
+ conns.BlockChecked = g_signals.m_internals->BlockChecked.connect(std::bind(&CValidationInterface::BlockChecked, pwalletIn, std::placeholders::_1, std::placeholders::_2));
+ conns.NewPoWValidBlock = g_signals.m_internals->NewPoWValidBlock.connect(std::bind(&CValidationInterface::NewPoWValidBlock, pwalletIn, std::placeholders::_1, std::placeholders::_2));
}
void UnregisterValidationInterface(CValidationInterface* pwalletIn) {
- g_signals.m_internals->BlockChecked.disconnect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));
- g_signals.m_internals->Broadcast.disconnect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1, _2));
- g_signals.m_internals->ChainStateFlushed.disconnect(boost::bind(&CValidationInterface::ChainStateFlushed, pwalletIn, _1));
- g_signals.m_internals->TransactionAddedToMempool.disconnect(boost::bind(&CValidationInterface::TransactionAddedToMempool, pwalletIn, _1));
- g_signals.m_internals->BlockConnected.disconnect(boost::bind(&CValidationInterface::BlockConnected, pwalletIn, _1, _2, _3));
- g_signals.m_internals->BlockDisconnected.disconnect(boost::bind(&CValidationInterface::BlockDisconnected, pwalletIn, _1));
- g_signals.m_internals->TransactionRemovedFromMempool.disconnect(boost::bind(&CValidationInterface::TransactionRemovedFromMempool, pwalletIn, _1));
- g_signals.m_internals->UpdatedBlockTip.disconnect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1, _2, _3));
- g_signals.m_internals->NewPoWValidBlock.disconnect(boost::bind(&CValidationInterface::NewPoWValidBlock, pwalletIn, _1, _2));
+ g_signals.m_internals->m_connMainSignals.erase(pwalletIn);
}
void UnregisterAllValidationInterfaces() {
if (!g_signals.m_internals) {
return;
}
- g_signals.m_internals->BlockChecked.disconnect_all_slots();
- g_signals.m_internals->Broadcast.disconnect_all_slots();
- g_signals.m_internals->ChainStateFlushed.disconnect_all_slots();
- g_signals.m_internals->TransactionAddedToMempool.disconnect_all_slots();
- g_signals.m_internals->BlockConnected.disconnect_all_slots();
- g_signals.m_internals->BlockDisconnected.disconnect_all_slots();
- g_signals.m_internals->TransactionRemovedFromMempool.disconnect_all_slots();
- g_signals.m_internals->UpdatedBlockTip.disconnect_all_slots();
- g_signals.m_internals->NewPoWValidBlock.disconnect_all_slots();
+ g_signals.m_internals->m_connMainSignals.clear();
}
void CallFunctionInValidationInterfaceQueue(std::function<void ()> func) {
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index 647af3eb86..ed1e2d3940 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -836,9 +836,98 @@ UniValue dumpwallet(const JSONRPCRequest& request)
return reply;
}
+struct ImportData
+{
+ // Input data
+ std::unique_ptr<CScript> redeemscript; //!< Provided redeemScript; will be moved to `import_scripts` if relevant.
+ std::unique_ptr<CScript> witnessscript; //!< Provided witnessScript; will be moved to `import_scripts` if relevant.
+
+ // Output data
+ std::set<CScript> import_scripts;
+ std::map<CKeyID, bool> used_keys; //!< Import these private keys if available (the value indicates whether if the key is required for solvability)
+};
+
+enum class ScriptContext
+{
+ TOP, //! Top-level scriptPubKey
+ P2SH, //! P2SH redeemScript
+ WITNESS_V0, //! P2WSH witnessScript
+};
+
+// Analyse the provided scriptPubKey, determining which keys and which redeem scripts from the ImportData struct are needed to spend it, and mark them as used.
+// Returns an error string, or the empty string for success.
+static std::string RecurseImportData(const CScript& script, ImportData& import_data, const ScriptContext script_ctx)
+{
+ // Use Solver to obtain script type and parsed pubkeys or hashes:
+ std::vector<std::vector<unsigned char>> solverdata;
+ txnouttype script_type = Solver(script, solverdata);
+
+ switch (script_type) {
+ case TX_PUBKEY: {
+ CPubKey pubkey(solverdata[0].begin(), solverdata[0].end());
+ import_data.used_keys.emplace(pubkey.GetID(), false);
+ return "";
+ }
+ case TX_PUBKEYHASH: {
+ CKeyID id = CKeyID(uint160(solverdata[0]));
+ import_data.used_keys[id] = true;
+ return "";
+ }
+ case TX_SCRIPTHASH: {
+ if (script_ctx == ScriptContext::P2SH) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Trying to nest P2SH inside another P2SH");
+ if (script_ctx == ScriptContext::WITNESS_V0) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Trying to nest P2SH inside a P2WSH");
+ assert(script_ctx == ScriptContext::TOP);
+ CScriptID id = CScriptID(uint160(solverdata[0]));
+ auto subscript = std::move(import_data.redeemscript); // Remove redeemscript from import_data to check for superfluous script later.
+ if (!subscript) return "missing redeemscript";
+ if (CScriptID(*subscript) != id) return "redeemScript does not match the scriptPubKey";
+ import_data.import_scripts.emplace(*subscript);
+ return RecurseImportData(*subscript, import_data, ScriptContext::P2SH);
+ }
+ case TX_MULTISIG: {
+ for (size_t i = 1; i + 1< solverdata.size(); ++i) {
+ CPubKey pubkey(solverdata[i].begin(), solverdata[i].end());
+ import_data.used_keys.emplace(pubkey.GetID(), false);
+ }
+ return "";
+ }
+ case TX_WITNESS_V0_SCRIPTHASH: {
+ if (script_ctx == ScriptContext::WITNESS_V0) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Trying to nest P2WSH inside another P2WSH");
+ uint256 fullid(solverdata[0]);
+ CScriptID id;
+ CRIPEMD160().Write(fullid.begin(), fullid.size()).Finalize(id.begin());
+ auto subscript = std::move(import_data.witnessscript); // Remove redeemscript from import_data to check for superfluous script later.
+ if (!subscript) return "missing witnessscript";
+ if (CScriptID(*subscript) != id) return "witnessScript does not match the scriptPubKey or redeemScript";
+ if (script_ctx == ScriptContext::TOP) {
+ import_data.import_scripts.emplace(script); // Special rule for IsMine: native P2WSH requires the TOP script imported (see script/ismine.cpp)
+ }
+ import_data.import_scripts.emplace(*subscript);
+ return RecurseImportData(*subscript, import_data, ScriptContext::WITNESS_V0);
+ }
+ case TX_WITNESS_V0_KEYHASH: {
+ if (script_ctx == ScriptContext::WITNESS_V0) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Trying to nest P2WPKH inside P2WSH");
+ CKeyID id = CKeyID(uint160(solverdata[0]));
+ import_data.used_keys[id] = true;
+ if (script_ctx == ScriptContext::TOP) {
+ import_data.import_scripts.emplace(script); // Special rule for IsMine: native P2WPKH requires the TOP script imported (see script/ismine.cpp)
+ }
+ return "";
+ }
+ case TX_NULL_DATA:
+ return "unspendable script";
+ case TX_NONSTANDARD:
+ case TX_WITNESS_UNKNOWN:
+ default:
+ return "unrecognized script";
+ }
+}
static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
{
+ UniValue warnings(UniValue::VARR);
+ UniValue result(UniValue::VOBJ);
+
try {
// First ensure scriptPubKey has either a script or JSON with "address" string
const UniValue& scriptPubKey = data["scriptPubKey"];
@@ -860,18 +949,16 @@ static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, con
// Generate the script and destination for the scriptPubKey provided
CScript script;
CTxDestination dest;
-
if (!isScript) {
dest = DecodeDestination(output);
if (!IsValidDestination(dest)) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address \"" + output + "\"");
}
script = GetScriptForDestination(dest);
} else {
if (!IsHex(output)) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid scriptPubKey");
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid scriptPubKey \"" + output + "\"");
}
-
std::vector<unsigned char> vData(ParseHex(output));
script = CScript(vData.begin(), vData.end());
if (!ExtractDestination(script, dest) && !internal) {
@@ -879,203 +966,161 @@ static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, con
}
}
- // Watchonly and private keys
- if (watchOnly && keys.size()) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Watch-only addresses should not include private keys");
- }
-
- // Internal addresses should not have a label
- if (internal && data.exists("label")) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Internal addresses should not have a label");
- }
-
- // Force users to provide the witness script in its field rather than redeemscript
- if (!strRedeemScript.empty() && script.IsPayToWitnessScriptHash()) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "P2WSH addresses have an empty redeemscript. Please provide the witnessscript instead.");
- }
-
- CScript scriptpubkey_script = script;
- CTxDestination scriptpubkey_dest = dest;
- bool allow_p2wpkh = true;
-
- // P2SH
- if (!strRedeemScript.empty() && script.IsPayToScriptHash()) {
- // Check the redeemScript is valid
+ // Parse all arguments
+ ImportData import_data;
+ if (strRedeemScript.size()) {
if (!IsHex(strRedeemScript)) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid redeem script: must be hex string");
- }
-
- // Import redeem script.
- std::vector<unsigned char> vData(ParseHex(strRedeemScript));
- CScript redeemScript = CScript(vData.begin(), vData.end());
- CScriptID redeem_id(redeemScript);
-
- // Check that the redeemScript and scriptPubKey match
- if (GetScriptForDestination(redeem_id) != script) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "The redeemScript does not match the scriptPubKey");
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid redeem script \"" + strRedeemScript + "\": must be hex string");
}
-
- pwallet->MarkDirty();
-
- if (!pwallet->AddWatchOnly(redeemScript, timestamp)) {
- throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
- }
-
- if (!pwallet->HaveCScript(redeem_id) && !pwallet->AddCScript(redeemScript)) {
- throw JSONRPCError(RPC_WALLET_ERROR, "Error adding p2sh redeemScript to wallet");
- }
-
- // Now set script to the redeemScript so we parse the inner script as P2WSH or P2WPKH below
- script = redeemScript;
- ExtractDestination(script, dest);
+ auto parsed_redeemscript = ParseHex(strRedeemScript);
+ import_data.redeemscript = MakeUnique<CScript>(parsed_redeemscript.begin(), parsed_redeemscript.end());
}
-
- // (P2SH-)P2WSH
- if (!witness_script_hex.empty() && script.IsPayToWitnessScriptHash()) {
+ if (witness_script_hex.size()) {
if (!IsHex(witness_script_hex)) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid witness script: must be hex string");
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid witness script \"" + witness_script_hex + "\": must be hex string");
}
-
- // Generate the scripts
- std::vector<unsigned char> witness_script_parsed(ParseHex(witness_script_hex));
- CScript witness_script = CScript(witness_script_parsed.begin(), witness_script_parsed.end());
- CScriptID witness_id(witness_script);
-
- // Check that the witnessScript and scriptPubKey match
- if (GetScriptForDestination(WitnessV0ScriptHash(witness_script)) != script) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "The witnessScript does not match the scriptPubKey or redeemScript");
+ auto parsed_witnessscript = ParseHex(witness_script_hex);
+ import_data.witnessscript = MakeUnique<CScript>(parsed_witnessscript.begin(), parsed_witnessscript.end());
+ }
+ std::map<CKeyID, CPubKey> pubkey_map;
+ for (size_t i = 0; i < pubKeys.size(); ++i) {
+ const auto& str = pubKeys[i].get_str();
+ if (!IsHex(str)) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey \"" + str + "\" must be a hex string");
}
-
- // Add the witness script as watch only only if it is not for P2SH-P2WSH
- if (!scriptpubkey_script.IsPayToScriptHash() && !pwallet->AddWatchOnly(witness_script, timestamp)) {
- throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
+ auto parsed_pubkey = ParseHex(str);
+ CPubKey pubkey(parsed_pubkey.begin(), parsed_pubkey.end());
+ if (!pubkey.IsFullyValid()) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey \"" + str + "\" is not a valid public key");
}
-
- if (!pwallet->HaveCScript(witness_id) && !pwallet->AddCScript(witness_script)) {
- throw JSONRPCError(RPC_WALLET_ERROR, "Error adding p2wsh witnessScript to wallet");
+ pubkey_map.emplace(pubkey.GetID(), pubkey);
+ }
+ std::map<CKeyID, CKey> privkey_map;
+ for (size_t i = 0; i < keys.size(); ++i) {
+ const auto& str = keys[i].get_str();
+ CKey key = DecodeSecret(str);
+ if (!key.IsValid()) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key encoding");
}
+ CPubKey pubkey = key.GetPubKey();
+ CKeyID id = pubkey.GetID();
+ if (pubkey_map.count(id)) {
+ pubkey_map.erase(id);
+ }
+ privkey_map.emplace(id, key);
+ }
- // Now set script to the witnessScript so we parse the inner script as P2PK or P2PKH below
- script = witness_script;
- ExtractDestination(script, dest);
- allow_p2wpkh = false; // P2WPKH cannot be embedded in P2WSH
+ // Internal addresses should not have a label
+ if (internal && data.exists("label")) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Internal addresses should not have a label");
}
- // (P2SH-)P2PK/P2PKH/P2WPKH
- if (dest.type() == typeid(CKeyID) || dest.type() == typeid(WitnessV0KeyHash)) {
- if (!allow_p2wpkh && dest.type() == typeid(WitnessV0KeyHash)) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "P2WPKH cannot be embedded in P2WSH");
- }
- if (keys.size() > 1 || pubKeys.size() > 1) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "More than one key given for one single-key address");
- }
- CPubKey pubkey;
- if (keys.size()) {
- pubkey = DecodeSecret(keys[0].get_str()).GetPubKey();
+ // Verify and process input data
+ bool have_solving_data = import_data.redeemscript || import_data.witnessscript || pubkey_map.size() || privkey_map.size();
+ if (have_solving_data) {
+ // Match up data in import_data with the scriptPubKey in script.
+ auto error = RecurseImportData(script, import_data, ScriptContext::TOP);
+
+ // Verify whether the watchonly option corresponds to the availability of private keys.
+ bool spendable = std::all_of(import_data.used_keys.begin(), import_data.used_keys.end(), [&](const std::pair<CKeyID, bool>& used_key){ return privkey_map.count(used_key.first) > 0; });
+ if (!watchOnly && !spendable) {
+ warnings.push_back("Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag.");
}
- if (pubKeys.size()) {
- const std::string& strPubKey = pubKeys[0].get_str();
- if (!IsHex(strPubKey)) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey must be a hex string");
- }
- std::vector<unsigned char> vData(ParseHex(pubKeys[0].get_str()));
- CPubKey pubkey_temp(vData.begin(), vData.end());
- if (pubkey.size() && pubkey_temp != pubkey) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Private key does not match public key for address");
- }
- pubkey = pubkey_temp;
+ if (watchOnly && spendable) {
+ warnings.push_back("All private keys are provided, outputs will be considered spendable. If this is intentional, do not specify the watchonly flag.");
}
- if (pubkey.size() > 0) {
- if (!pubkey.IsFullyValid()) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey is not a valid public key");
- }
- // Check the key corresponds to the destination given
- std::vector<CTxDestination> destinations = GetAllDestinationsForKey(pubkey);
- if (std::find(destinations.begin(), destinations.end(), dest) == destinations.end()) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Key does not match address destination");
+ // Check that all required keys for solvability are provided.
+ if (error.empty()) {
+ for (const auto& require_key : import_data.used_keys) {
+ if (!require_key.second) continue; // Not a required key
+ if (pubkey_map.count(require_key.first) == 0 && privkey_map.count(require_key.first) == 0) {
+ error = "some required keys are missing";
+ }
}
+ }
- // This is necessary to force the wallet to import the pubKey
- CScript scriptRawPubKey = GetScriptForRawPubKey(pubkey);
-
- if (::IsMine(*pwallet, scriptRawPubKey) == ISMINE_SPENDABLE) {
- throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script");
+ if (!error.empty()) {
+ warnings.push_back("Importing as non-solvable: " + error + ". If this is intentional, don't provide any keys, pubkeys, witnessscript, or redeemscript.");
+ import_data = ImportData();
+ pubkey_map.clear();
+ privkey_map.clear();
+ have_solving_data = false;
+ } else {
+ // RecurseImportData() removes any relevant redeemscript/witnessscript from import_data, so we can use that to discover if a superfluous one was provided.
+ if (import_data.redeemscript) warnings.push_back("Ignoring redeemscript as this is not a P2SH script.");
+ if (import_data.witnessscript) warnings.push_back("Ignoring witnessscript as this is not a (P2SH-)P2WSH script.");
+ for (auto it = privkey_map.begin(); it != privkey_map.end(); ) {
+ auto oldit = it++;
+ if (import_data.used_keys.count(oldit->first) == 0) {
+ warnings.push_back("Ignoring irrelevant private key.");
+ privkey_map.erase(oldit);
+ }
}
-
- pwallet->MarkDirty();
-
- if (!pwallet->AddWatchOnly(scriptRawPubKey, timestamp)) {
- throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
+ for (auto it = pubkey_map.begin(); it != pubkey_map.end(); ) {
+ auto oldit = it++;
+ auto key_data_it = import_data.used_keys.find(oldit->first);
+ if (key_data_it == import_data.used_keys.end() || !key_data_it->second) {
+ warnings.push_back("Ignoring public key \"" + HexStr(oldit->first) + "\" as it doesn't appear inside P2PKH or P2WPKH.");
+ pubkey_map.erase(oldit);
+ }
}
}
}
- // Import the address
- if (::IsMine(*pwallet, scriptpubkey_script) == ISMINE_SPENDABLE) {
+ // Check whether we have any work to do
+ if (::IsMine(*pwallet, script) & ISMINE_SPENDABLE) {
throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script");
}
+ // All good, time to import
pwallet->MarkDirty();
-
- if (!pwallet->AddWatchOnly(scriptpubkey_script, timestamp)) {
- throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
- }
-
- if (!watchOnly && !pwallet->HaveCScript(CScriptID(scriptpubkey_script)) && !pwallet->AddCScript(scriptpubkey_script)) {
- throw JSONRPCError(RPC_WALLET_ERROR, "Error adding scriptPubKey script to wallet");
- }
-
- // if not internal add to address book or update label
- if (!internal) {
- assert(IsValidDestination(scriptpubkey_dest));
- pwallet->SetAddressBook(scriptpubkey_dest, label, "receive");
- }
-
- // Import private keys.
- for (size_t i = 0; i < keys.size(); i++) {
- const std::string& strPrivkey = keys[i].get_str();
-
- // Checks.
- CKey key = DecodeSecret(strPrivkey);
-
- if (!key.IsValid()) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key encoding");
+ for (const auto& entry : import_data.import_scripts) {
+ if (!pwallet->HaveCScript(CScriptID(entry)) && !pwallet->AddCScript(entry)) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Error adding script to wallet");
}
-
- CPubKey pubKey = key.GetPubKey();
- assert(key.VerifyPubKey(pubKey));
-
- CKeyID vchAddress = pubKey.GetID();
- pwallet->MarkDirty();
-
- if (pwallet->HaveKey(vchAddress)) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Already have this key");
- }
-
- pwallet->mapKeyMetadata[vchAddress].nCreateTime = timestamp;
-
- if (!pwallet->AddKeyPubKey(key, pubKey)) {
+ }
+ for (const auto& entry : privkey_map) {
+ const CKey& key = entry.second;
+ CPubKey pubkey = key.GetPubKey();
+ const CKeyID& id = entry.first;
+ assert(key.VerifyPubKey(pubkey));
+ pwallet->mapKeyMetadata[id].nCreateTime = timestamp;
+ // If the private key is not present in the wallet, insert it.
+ if (!pwallet->HaveKey(id) && !pwallet->AddKeyPubKey(key, pubkey)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
}
-
pwallet->UpdateTimeFirstKey(timestamp);
}
+ for (const auto& entry : pubkey_map) {
+ const CPubKey& pubkey = entry.second;
+ const CKeyID& id = entry.first;
+ CPubKey temp;
+ if (!pwallet->GetPubKey(id, temp) && !pwallet->AddWatchOnly(GetScriptForRawPubKey(pubkey), timestamp)) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
+ }
+ }
+ if (!have_solving_data || !::IsMine(*pwallet, script)) { // Always call AddWatchOnly for non-solvable watch-only, so that watch timestamp gets updated
+ if (!pwallet->AddWatchOnly(script, timestamp)) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
+ }
+ }
+ if (!internal) {
+ assert(IsValidDestination(dest));
+ pwallet->SetAddressBook(dest, label, "receive");
+ }
- UniValue result = UniValue(UniValue::VOBJ);
result.pushKV("success", UniValue(true));
- return result;
} catch (const UniValue& e) {
- UniValue result = UniValue(UniValue::VOBJ);
result.pushKV("success", UniValue(false));
result.pushKV("error", e);
- return result;
} catch (...) {
- UniValue result = UniValue(UniValue::VOBJ);
result.pushKV("success", UniValue(false));
+
result.pushKV("error", JSONRPCError(RPC_MISC_ERROR, "Missing required fields"));
- return result;
}
+ if (warnings.size()) result.pushKV("warnings", warnings);
+ return result;
}
static int64_t GetImportTimestamp(const UniValue& data, int64_t now)
@@ -1122,18 +1167,18 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
},
{"redeemscript", RPCArg::Type::STR, /* opt */ true, /* default_val */ "omitted", "Allowed only if the scriptPubKey is a P2SH or P2SH-P2WSH address/scriptPubKey"},
{"witnessscript", RPCArg::Type::STR, /* opt */ true, /* default_val */ "omitted", "Allowed only if the scriptPubKey is a P2SH-P2WSH or P2WSH address/scriptPubKey"},
- {"pubkeys", RPCArg::Type::ARR, /* opt */ true, /* default_val */ "empty array", "Array of strings giving pubkeys that must occur in the output or redeemscript",
+ {"pubkeys", RPCArg::Type::ARR, /* opt */ true, /* default_val */ "empty array", "Array of strings giving pubkeys to import. They must occur in P2PKH or P2WPKH scripts. They are not required when the private key is also provided (see the \"keys\" argument).",
{
{"pubKey", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", ""},
}
},
- {"keys", RPCArg::Type::ARR, /* opt */ true, /* default_val */ "empty array", "Array of strings giving private keys whose corresponding public keys must occur in the output or redeemscript",
+ {"keys", RPCArg::Type::ARR, /* opt */ true, /* default_val */ "empty array", "Array of strings giving private keys to import. The corresponding public keys must occur in the output or redeemscript.",
{
{"key", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", ""},
}
},
- {"internal", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Stating whether matching outputs should be treated as not incoming payments aka change"},
- {"watchonly", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Stating whether matching outputs should be considered watched even when they're not spendable, only allowed if keys are empty"},
+ {"internal", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Stating whether matching outputs should be treated as not incoming payments (also known as change)"},
+ {"watchonly", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Stating whether matching outputs should be considered watched even when not all private keys are provided."},
{"label", RPCArg::Type::STR, /* opt */ true, /* default_val */ "''", "Label to assign to the address, only allowed with internal=false"},
},
},
@@ -1154,7 +1199,7 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
HelpExampleCli("importmulti", "'[{ \"scriptPubKey\": { \"address\": \"<my address>\" }, \"timestamp\":1455191478 }]' '{ \"rescan\": false}'") +
"\nResponse is an array with the same size as the input that has the execution result :\n"
- " [{ \"success\": true } , { \"success\": false, \"error\": { \"code\": -1, \"message\": \"Internal Server Error\"} }, ... ]\n");
+ " [{\"success\": true}, {\"success\": true, \"warnings\": [\"Ignoring irrelevant private key\"]}, {\"success\": false, \"error\": {\"code\": -1, \"message\": \"Internal Server Error\"}}, ...]\n");
RPCTypeCheck(mainRequest.params, {UniValue::VARR, UniValue::VOBJ});
diff --git a/test/functional/data/invalid_txs.py b/test/functional/data/invalid_txs.py
new file mode 100644
index 0000000000..02deae92f3
--- /dev/null
+++ b/test/functional/data/invalid_txs.py
@@ -0,0 +1,180 @@
+#!/usr/bin/env python3
+# Copyright (c) 2015-2018 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""
+Templates for constructing various sorts of invalid transactions.
+
+These templates (or an iterator over all of them) can be reused in different
+contexts to test using a number of invalid transaction types.
+
+Hopefully this makes it easier to get coverage of a full variety of tx
+validation checks through different interfaces (AcceptBlock, AcceptToMemPool,
+etc.) without repeating ourselves.
+
+Invalid tx cases not covered here can be found by running:
+
+ $ diff \
+ <(grep -IREho "bad-txns[a-zA-Z-]+" src | sort -u) \
+ <(grep -IEho "bad-txns[a-zA-Z-]+" test/functional/data/invalid_txs.py | sort -u)
+
+"""
+import abc
+
+from test_framework.messages import CTransaction, CTxIn, CTxOut, COutPoint
+from test_framework import script as sc
+from test_framework.blocktools import create_tx_with_script, MAX_BLOCK_SIGOPS
+
+basic_p2sh = sc.CScript([sc.OP_HASH160, sc.hash160(sc.CScript([sc.OP_0])), sc.OP_EQUAL])
+
+
+class BadTxTemplate:
+ """Allows simple construction of a certain kind of invalid tx. Base class to be subclassed."""
+ __metaclass__ = abc.ABCMeta
+
+ # The expected error code given by bitcoind upon submission of the tx.
+ reject_reason = ""
+
+ # Only specified if it differs from mempool acceptance error.
+ block_reject_reason = ""
+
+ # Do we expect to be disconnected after submitting this tx?
+ expect_disconnect = False
+
+ # Is this tx considered valid when included in a block, but not for acceptance into
+ # the mempool (i.e. does it violate policy but not consensus)?
+ valid_in_block = False
+
+ def __init__(self, *, spend_tx=None, spend_block=None):
+ self.spend_tx = spend_block.vtx[0] if spend_block else spend_tx
+ self.spend_avail = sum(o.nValue for o in self.spend_tx.vout)
+ self.valid_txin = CTxIn(COutPoint(self.spend_tx.sha256, 0), b"", 0xffffffff)
+
+ @abc.abstractmethod
+ def get_tx(self, *args, **kwargs):
+ """Return a CTransaction that is invalid per the subclass."""
+ pass
+
+
+class OutputMissing(BadTxTemplate):
+ reject_reason = "bad-txns-vout-empty"
+ expect_disconnect = False
+
+ def get_tx(self):
+ tx = CTransaction()
+ tx.vin.append(self.valid_txin)
+ tx.calc_sha256()
+ return tx
+
+
+class InputMissing(BadTxTemplate):
+ reject_reason = "bad-txns-vin-empty"
+ expect_disconnect = False
+
+ def get_tx(self):
+ tx = CTransaction()
+ tx.vout.append(CTxOut(0, sc.CScript([sc.OP_TRUE] * 100)))
+ tx.calc_sha256()
+ return tx
+
+
+class SizeTooSmall(BadTxTemplate):
+ reject_reason = "tx-size-small"
+ expect_disconnect = False
+ valid_in_block = True
+
+ def get_tx(self):
+ tx = CTransaction()
+ tx.vin.append(self.valid_txin)
+ tx.vout.append(CTxOut(0, sc.CScript([sc.OP_TRUE])))
+ tx.calc_sha256()
+ return tx
+
+
+class BadInputOutpointIndex(BadTxTemplate):
+ # Won't be rejected - nonexistent outpoint index is treated as an orphan since the coins
+ # database can't distinguish between spent outpoints and outpoints which never existed.
+ reject_reason = None
+ expect_disconnect = False
+
+ def get_tx(self):
+ num_indices = len(self.spend_tx.vin)
+ bad_idx = num_indices + 100
+
+ tx = CTransaction()
+ tx.vin.append(CTxIn(COutPoint(self.spend_tx.sha256, bad_idx), b"", 0xffffffff))
+ tx.vout.append(CTxOut(0, basic_p2sh))
+ tx.calc_sha256()
+ return tx
+
+
+class DuplicateInput(BadTxTemplate):
+ reject_reason = 'bad-txns-inputs-duplicate'
+ expect_disconnect = True
+
+ def get_tx(self):
+ tx = CTransaction()
+ tx.vin.append(self.valid_txin)
+ tx.vin.append(self.valid_txin)
+ tx.vout.append(CTxOut(1, basic_p2sh))
+ tx.calc_sha256()
+ return tx
+
+
+class NonexistentInput(BadTxTemplate):
+ reject_reason = None # Added as an orphan tx.
+ expect_disconnect = False
+
+ def get_tx(self):
+ tx = CTransaction()
+ tx.vin.append(CTxIn(COutPoint(self.spend_tx.sha256 + 1, 0), b"", 0xffffffff))
+ tx.vin.append(self.valid_txin)
+ tx.vout.append(CTxOut(1, basic_p2sh))
+ tx.calc_sha256()
+ return tx
+
+
+class SpendTooMuch(BadTxTemplate):
+ reject_reason = 'bad-txns-in-belowout'
+ expect_disconnect = True
+
+ def get_tx(self):
+ return create_tx_with_script(
+ self.spend_tx, 0, script_pub_key=basic_p2sh, amount=(self.spend_avail + 1))
+
+
+class SpendNegative(BadTxTemplate):
+ reject_reason = 'bad-txns-vout-negative'
+ expect_disconnect = True
+
+ def get_tx(self):
+ return create_tx_with_script(self.spend_tx, 0, amount=-1)
+
+
+class InvalidOPIFConstruction(BadTxTemplate):
+ reject_reason = "mandatory-script-verify-flag-failed (Invalid OP_IF construction)"
+ expect_disconnect = True
+ valid_in_block = True
+
+ def get_tx(self):
+ return create_tx_with_script(
+ self.spend_tx, 0, script_sig=b'\x64' * 35,
+ amount=(self.spend_avail // 2))
+
+
+class TooManySigops(BadTxTemplate):
+ reject_reason = "bad-txns-too-many-sigops"
+ block_reject_reason = "bad-blk-sigops, out-of-bounds SigOpCount"
+ expect_disconnect = False
+
+ def get_tx(self):
+ lotsa_checksigs = sc.CScript([sc.OP_CHECKSIG] * (MAX_BLOCK_SIGOPS))
+ return create_tx_with_script(
+ self.spend_tx, 0,
+ script_pub_key=lotsa_checksigs,
+ amount=1)
+
+
+def iter_all_templates():
+ """Iterate through all bad transaction template types."""
+ return BadTxTemplate.__subclasses__()
diff --git a/test/functional/feature_assumevalid.py b/test/functional/feature_assumevalid.py
index 3d0467038d..12a4ce9aff 100755
--- a/test/functional/feature_assumevalid.py
+++ b/test/functional/feature_assumevalid.py
@@ -180,7 +180,7 @@ class AssumeValidTest(BitcoinTestFramework):
for i in range(2202):
p2p1.send_message(msg_block(self.blocks[i]))
# Syncing 2200 blocks can take a while on slow systems. Give it plenty of time to sync.
- p2p1.sync_with_ping(120)
+ p2p1.sync_with_ping(150)
assert_equal(self.nodes[1].getblock(self.nodes[1].getbestblockhash())['height'], 2202)
# Send blocks to node2. Block 102 will be rejected.
diff --git a/test/functional/feature_block.py b/test/functional/feature_block.py
index b741339351..697a0b19ac 100755
--- a/test/functional/feature_block.py
+++ b/test/functional/feature_block.py
@@ -7,7 +7,13 @@ import copy
import struct
import time
-from test_framework.blocktools import create_block, create_coinbase, create_tx_with_script, get_legacy_sigopcount_block
+from test_framework.blocktools import (
+ create_block,
+ create_coinbase,
+ create_tx_with_script,
+ get_legacy_sigopcount_block,
+ MAX_BLOCK_SIGOPS,
+)
from test_framework.key import CECKey
from test_framework.messages import (
CBlock,
@@ -45,8 +51,7 @@ from test_framework.script import (
)
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
-
-MAX_BLOCK_SIGOPS = 20000
+from data import invalid_txs
# Use this class for tests that require behavior other than normal "mininode" behavior.
# For now, it is used to serialize a bloated varint (b64).
@@ -95,16 +100,21 @@ class FullBlockTest(BitcoinTestFramework):
self.save_spendable_output()
self.sync_blocks([b0])
+ # These constants chosen specifically to trigger an immature coinbase spend
+ # at a certain time below.
+ NUM_BUFFER_BLOCKS_TO_GENERATE = 99
+ NUM_OUTPUTS_TO_COLLECT = 33
+
# Allow the block to mature
blocks = []
- for i in range(99):
- blocks.append(self.next_block(5000 + i))
+ for i in range(NUM_BUFFER_BLOCKS_TO_GENERATE):
+ blocks.append(self.next_block("maturitybuffer.{}".format(i)))
self.save_spendable_output()
self.sync_blocks(blocks)
# collect spendable outputs now to avoid cluttering the code later on
out = []
- for i in range(33):
+ for i in range(NUM_OUTPUTS_TO_COLLECT):
out.append(self.get_spendable_output())
# Start by building a couple of blocks on top (which output is spent is
@@ -116,7 +126,39 @@ class FullBlockTest(BitcoinTestFramework):
b2 = self.next_block(2, spend=out[1])
self.save_spendable_output()
- self.sync_blocks([b1, b2])
+ self.sync_blocks([b1, b2], timeout=4)
+
+ # Select a txn with an output eligible for spending. This won't actually be spent,
+ # since we're testing submission of a series of blocks with invalid txns.
+ attempt_spend_tx = out[2]
+
+ # Submit blocks for rejection, each of which contains a single transaction
+ # (aside from coinbase) which should be considered invalid.
+ for TxTemplate in invalid_txs.iter_all_templates():
+ template = TxTemplate(spend_tx=attempt_spend_tx)
+
+ # Something about the serialization code for missing inputs creates
+ # a different hash in the test client than on bitcoind, resulting
+ # in a mismatching merkle root during block validation.
+ # Skip until we figure out what's going on.
+ if TxTemplate == invalid_txs.InputMissing:
+ continue
+ if template.valid_in_block:
+ continue
+
+ self.log.info("Reject block with invalid tx: %s", TxTemplate.__name__)
+ blockname = "for_invalid.%s" % TxTemplate.__name__
+ badblock = self.next_block(blockname)
+ badtx = template.get_tx()
+ self.sign_tx(badtx, attempt_spend_tx)
+ badtx.rehash()
+ badblock = self.update_block(blockname, [badtx])
+ self.sync_blocks(
+ [badblock], success=False,
+ reject_reason=(template.block_reject_reason or template.reject_reason),
+ reconnect=True, timeout=2)
+
+ self.move_tip(2)
# Fork like this:
#
@@ -1288,7 +1330,7 @@ class FullBlockTest(BitcoinTestFramework):
self.blocks[block_number] = block
return block
- def bootstrap_p2p(self):
+ def bootstrap_p2p(self, timeout=10):
"""Add a P2P connection to the node.
Helper to connect and wait for version handshake."""
@@ -1299,15 +1341,15 @@ class FullBlockTest(BitcoinTestFramework):
# an INV for the next block and receive two getheaders - one for the
# IBD and one for the INV. We'd respond to both and could get
# unexpectedly disconnected if the DoS score for that error is 50.
- self.nodes[0].p2p.wait_for_getheaders(timeout=5)
+ self.nodes[0].p2p.wait_for_getheaders(timeout=timeout)
- def reconnect_p2p(self):
+ def reconnect_p2p(self, timeout=60):
"""Tear down and bootstrap the P2P connection to the node.
The node gets disconnected several times in this test. This helper
method reconnects the p2p and restarts the network thread."""
self.nodes[0].disconnect_p2ps()
- self.bootstrap_p2p()
+ self.bootstrap_p2p(timeout=timeout)
def sync_blocks(self, blocks, success=True, reject_reason=None, force_send=False, reconnect=False, timeout=60):
"""Sends blocks to test node. Syncs and verifies that tip has advanced to most recent block.
@@ -1316,7 +1358,7 @@ class FullBlockTest(BitcoinTestFramework):
self.nodes[0].p2p.send_blocks_and_test(blocks, self.nodes[0], success=success, reject_reason=reject_reason, force_send=force_send, timeout=timeout, expect_disconnect=reconnect)
if reconnect:
- self.reconnect_p2p()
+ self.reconnect_p2p(timeout=timeout)
if __name__ == '__main__':
diff --git a/test/functional/feature_dbcrash.py b/test/functional/feature_dbcrash.py
index 70d67aa53a..8b06cc7372 100755
--- a/test/functional/feature_dbcrash.py
+++ b/test/functional/feature_dbcrash.py
@@ -46,7 +46,7 @@ class ChainstateWriteCrashTest(BitcoinTestFramework):
self.num_nodes = 4
self.setup_clean_chain = False
# Need a bit of extra time for the nodes to start up for this test
- self.rpc_timewait = 90
+ self.rpc_timeout = 90
# Set -maxmempool=0 to turn off mempool memory sharing with dbcache
# Set -rpcservertimeout=900 to reduce socket disconnects in this
diff --git a/test/functional/feature_pruning.py b/test/functional/feature_pruning.py
index c162f46d63..9a3f4fae45 100755
--- a/test/functional/feature_pruning.py
+++ b/test/functional/feature_pruning.py
@@ -29,7 +29,7 @@ class PruneTest(BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 6
- self.rpc_timewait = 900
+ self.rpc_timeout = 900
# Create nodes 0 and 1 to mine.
# Create node 2 to test pruning.
@@ -191,6 +191,8 @@ class PruneTest(BitcoinTestFramework):
def reorg_back(self):
# Verify that a block on the old main chain fork has been pruned away
assert_raises_rpc_error(-1, "Block not available (pruned data)", self.nodes[2].getblock, self.forkhash)
+ with self.nodes[2].assert_debug_log(expected_msgs=['block verification stopping at height', '(pruning, no data)']):
+ self.nodes[2].verifychain(checklevel=4, nblocks=0)
self.log.info("Will need to redownload block %d" % self.forkheight)
# Verify that we have enough history to reorg back to the fork point
diff --git a/test/functional/mempool_accept.py b/test/functional/mempool_accept.py
index 02f1cc4391..e2a219b85a 100755
--- a/test/functional/mempool_accept.py
+++ b/test/functional/mempool_accept.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017 The Bitcoin Core developers
+# Copyright (c) 2017-2018 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 mempool acceptance of raw transactions."""
diff --git a/test/functional/p2p_invalid_locator.py b/test/functional/p2p_invalid_locator.py
index c8c752d1f7..33b7060060 100755
--- a/test/functional/p2p_invalid_locator.py
+++ b/test/functional/p2p_invalid_locator.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2017 The Bitcoin Core developers
+# Copyright (c) 2015-2018 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 node responses to invalid locators.
diff --git a/test/functional/p2p_invalid_tx.py b/test/functional/p2p_invalid_tx.py
index 58e129b57d..1b18dd3e58 100755
--- a/test/functional/p2p_invalid_tx.py
+++ b/test/functional/p2p_invalid_tx.py
@@ -5,7 +5,7 @@
"""Test node responses to invalid transactions.
In this test we connect to one node over p2p, and test tx requests."""
-from test_framework.blocktools import create_block, create_coinbase, create_tx_with_script
+from test_framework.blocktools import create_block, create_coinbase
from test_framework.messages import (
COIN,
COutPoint,
@@ -19,6 +19,7 @@ from test_framework.util import (
assert_equal,
wait_until,
)
+from data import invalid_txs
class InvalidTxRequestTest(BitcoinTestFramework):
@@ -63,12 +64,21 @@ class InvalidTxRequestTest(BitcoinTestFramework):
self.log.info("Mature the block.")
self.nodes[0].generatetoaddress(100, self.nodes[0].get_deterministic_priv_key().address)
- # b'\x64' is OP_NOTIF
- # Transaction will be rejected with code 16 (REJECT_INVALID)
- # and we get disconnected immediately
- self.log.info('Test a transaction that is rejected')
- tx1 = create_tx_with_script(block1.vtx[0], 0, script_sig=b'\x64' * 35, amount=50 * COIN - 12000)
- node.p2p.send_txs_and_test([tx1], node, success=False, expect_disconnect=True)
+ # Iterate through a list of known invalid transaction types, ensuring each is
+ # rejected. Some are consensus invalid and some just violate policy.
+ for BadTxTemplate in invalid_txs.iter_all_templates():
+ self.log.info("Testing invalid transaction: %s", BadTxTemplate.__name__)
+ template = BadTxTemplate(spend_block=block1)
+ tx = template.get_tx()
+ node.p2p.send_txs_and_test(
+ [tx], node, success=False,
+ expect_disconnect=template.expect_disconnect,
+ reject_reason=template.reject_reason,
+ )
+
+ if template.expect_disconnect:
+ self.log.info("Reconnecting to peer")
+ self.reconnect_p2p()
# Make two p2p connections to provide the node with orphans
# * p2ps[0] will send valid orphan txs (one with low fee)
diff --git a/test/functional/p2p_timeouts.py b/test/functional/p2p_timeouts.py
index ffed853033..02ceec3dc1 100755
--- a/test/functional/p2p_timeouts.py
+++ b/test/functional/p2p_timeouts.py
@@ -72,7 +72,11 @@ class TimeoutsTest(BitcoinTestFramework):
]
with self.nodes[0].assert_debug_log(expected_msgs=expected_timeout_logs):
- sleep(2)
+ sleep(3)
+ # By now, we waited a total of 5 seconds. Off-by-two for two
+ # reasons:
+ # * The internal precision is one second
+ # * Account for network delay
assert not no_verack_node.is_connected
assert not no_version_node.is_connected
assert not no_send_node.is_connected
diff --git a/test/functional/rpc_bind.py b/test/functional/rpc_bind.py
index c23aa13685..3938ca98dd 100755
--- a/test/functional/rpc_bind.py
+++ b/test/functional/rpc_bind.py
@@ -70,7 +70,7 @@ class RPCBindTest(BitcoinTestFramework):
self.log.info("Check for ipv6")
have_ipv6 = test_ipv6_local()
- if not have_ipv6 and not self.options.run_ipv4:
+ if not have_ipv6 and not (self.options.run_ipv4 or self.options.run_nonloopback):
raise SkipTest("This test requires ipv6 support.")
self.log.info("Check for non-loopback interface")
diff --git a/test/functional/rpc_fundrawtransaction.py b/test/functional/rpc_fundrawtransaction.py
index 0c61e9ab62..4f350953b2 100755
--- a/test/functional/rpc_fundrawtransaction.py
+++ b/test/functional/rpc_fundrawtransaction.py
@@ -32,7 +32,7 @@ class RawTransactionsTest(BitcoinTestFramework):
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
- def setup_network(self, split=False):
+ def setup_network(self):
self.setup_nodes()
connect_nodes_bi(self.nodes, 0, 1)
diff --git a/test/functional/rpc_net.py b/test/functional/rpc_net.py
index 0affddcf05..b12eb1d9ec 100755
--- a/test/functional/rpc_net.py
+++ b/test/functional/rpc_net.py
@@ -67,8 +67,8 @@ class NetTest(BitcoinTestFramework):
peer_info_after_ping = self.nodes[0].getpeerinfo()
for before, after in zip(peer_info, peer_info_after_ping):
- assert_greater_than_or_equal(after['bytesrecv_per_msg']['pong'], before['bytesrecv_per_msg']['pong'] + 32)
- assert_greater_than_or_equal(after['bytessent_per_msg']['ping'], before['bytessent_per_msg']['ping'] + 32)
+ assert_greater_than_or_equal(after['bytesrecv_per_msg'].get('pong', 0), before['bytesrecv_per_msg'].get('pong', 0) + 32)
+ assert_greater_than_or_equal(after['bytessent_per_msg'].get('ping', 0), before['bytessent_per_msg'].get('ping', 0) + 32)
def _test_getnetworkinginfo(self):
assert_equal(self.nodes[0].getnetworkinfo()['networkactive'], True)
diff --git a/test/functional/rpc_rawtransaction.py b/test/functional/rpc_rawtransaction.py
index fc012e6e3a..5b9dbef68d 100755
--- a/test/functional/rpc_rawtransaction.py
+++ b/test/functional/rpc_rawtransaction.py
@@ -47,7 +47,7 @@ class RawTransactionsTest(BitcoinTestFramework):
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
- def setup_network(self, split=False):
+ def setup_network(self):
super().setup_network()
connect_nodes_bi(self.nodes, 0, 2)
diff --git a/test/functional/test_framework/blocktools.py b/test/functional/test_framework/blocktools.py
index 81cce1167b..7679ea5398 100644
--- a/test/functional/test_framework/blocktools.py
+++ b/test/functional/test_framework/blocktools.py
@@ -41,6 +41,8 @@ from .script import (
from .util import assert_equal
from io import BytesIO
+MAX_BLOCK_SIGOPS = 20000
+
# From BIP141
WITNESS_COMMITMENT_HEADER = b"\xaa\x21\xa9\xed"
diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py
index 21bf35597e..352fa32b5b 100755
--- a/test/functional/test_framework/test_framework.py
+++ b/test/functional/test_framework/test_framework.py
@@ -95,7 +95,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
self.nodes = []
self.network_thread = None
self.mocktime = 0
- self.rpc_timewait = 60 # Wait for up to 60 seconds for the RPC server to respond
+ self.rpc_timeout = 60 # Wait for up to 60 seconds for the RPC server to respond
self.supports_cli = False
self.bind_to_localhost_only = True
self.set_test_params()
@@ -301,7 +301,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
i,
get_datadir_path(self.options.tmpdir, i),
rpchost=rpchost,
- timewait=self.rpc_timewait,
+ timewait=self.rpc_timeout,
bitcoind=binary[i],
bitcoin_cli=self.options.bitcoincli,
mocktime=self.mocktime,
@@ -388,21 +388,6 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
sync_blocks(group)
sync_mempools(group)
- def enable_mocktime(self):
- """Enable mocktime for the script.
-
- mocktime may be needed for scripts that use the cached version of the
- blockchain. If the cached version of the blockchain is used without
- mocktime then the mempools will not sync due to IBD.
-
- For backward compatibility of the python scripts with previous
- versions of the cache, this helper function sets mocktime to Jan 1,
- 2014 + (201 * 10 * 60)"""
- self.mocktime = 1388534400 + (201 * 10 * 60)
-
- def disable_mocktime(self):
- self.mocktime = 0
-
# Private helper methods. These should not be accessed by the subclass test scripts.
def _start_logging(self):
@@ -460,7 +445,18 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
args = [self.options.bitcoind, "-datadir=" + datadir, '-disablewallet']
if i > 0:
args.append("-connect=127.0.0.1:" + str(p2p_port(0)))
- self.nodes.append(TestNode(i, get_datadir_path(self.options.cachedir, i), extra_conf=["bind=127.0.0.1"], extra_args=[], rpchost=None, timewait=self.rpc_timewait, bitcoind=self.options.bitcoind, bitcoin_cli=self.options.bitcoincli, mocktime=self.mocktime, coverage_dir=None))
+ self.nodes.append(TestNode(
+ i,
+ get_datadir_path(self.options.cachedir, i),
+ extra_conf=["bind=127.0.0.1"],
+ extra_args=[],
+ rpchost=None,
+ timewait=self.rpc_timeout,
+ bitcoind=self.options.bitcoind,
+ bitcoin_cli=self.options.bitcoincli,
+ mocktime=self.mocktime,
+ coverage_dir=None,
+ ))
self.nodes[i].args = args
self.start_node(i)
@@ -468,6 +464,11 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
for node in self.nodes:
node.wait_for_rpc_connection()
+ # For backward compatibility of the python scripts with previous
+ # versions of the cache, set mocktime to Jan 1,
+ # 2014 + (201 * 10 * 60)"""
+ self.mocktime = 1388534400 + (201 * 10 * 60)
+
# Create a 200-block-long chain; each of the 4 first nodes
# gets 25 mature blocks and 25 immature.
# Note: To preserve compatibility with older versions of
@@ -475,7 +476,6 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
#
# blocks are created with timestamps 10 minutes apart
# starting from 2010 minutes in the past
- self.enable_mocktime()
block_time = self.mocktime - (201 * 10 * 60)
for i in range(2):
for peer in range(4):
@@ -489,7 +489,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
# Shut them down, and clean up cache directories:
self.stop_nodes()
self.nodes = []
- self.disable_mocktime()
+ self.mocktime = 0
def cache_path(n, *paths):
return os.path.join(get_datadir_path(self.options.cachedir, n), "regtest", *paths)
diff --git a/test/functional/wallet_backup.py b/test/functional/wallet_backup.py
index 32ec385fa1..dd3750203a 100755
--- a/test/functional/wallet_backup.py
+++ b/test/functional/wallet_backup.py
@@ -48,7 +48,7 @@ class WalletBackupTest(BitcoinTestFramework):
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
- def setup_network(self, split=False):
+ def setup_network(self):
self.setup_nodes()
connect_nodes(self.nodes[0], 3)
connect_nodes(self.nodes[1], 3)
diff --git a/test/functional/wallet_dump.py b/test/functional/wallet_dump.py
index 20cb816ee8..3f39654bb8 100755
--- a/test/functional/wallet_dump.py
+++ b/test/functional/wallet_dump.py
@@ -94,7 +94,7 @@ class WalletDumpTest(BitcoinTestFramework):
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
- def setup_network(self, split=False):
+ def setup_network(self):
self.add_nodes(self.num_nodes, extra_args=self.extra_args)
self.start_nodes()
diff --git a/test/functional/wallet_groups.py b/test/functional/wallet_groups.py
index 9d61483868..5452433acf 100755
--- a/test/functional/wallet_groups.py
+++ b/test/functional/wallet_groups.py
@@ -21,7 +21,7 @@ class WalletGroupTest(BitcoinTestFramework):
self.setup_clean_chain = True
self.num_nodes = 3
self.extra_args = [[], [], ['-avoidpartialspends']]
- self.rpc_timewait = 120
+ self.rpc_timeout = 120
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
diff --git a/test/functional/wallet_importmulti.py b/test/functional/wallet_importmulti.py
index a163f7018c..3492075694 100755
--- a/test/functional/wallet_importmulti.py
+++ b/test/functional/wallet_importmulti.py
@@ -119,9 +119,13 @@ class ImportMultiTest(BitcoinTestFramework):
CScript([OP_HASH160, witness_script, OP_EQUAL]).hex(), # p2sh-p2wsh
script_to_p2sh_p2wsh(script_code)) # p2sh-p2wsh addr
- def test_importmulti(self, req, success, error_code=None, error_message=None):
+ def test_importmulti(self, req, success, error_code=None, error_message=None, warnings=[]):
"""Run importmulti and assert success"""
result = self.nodes[1].importmulti([req])
+ observed_warnings = []
+ if 'warnings' in result[0]:
+ observed_warnings = result[0]['warnings']
+ assert_equal("\n".join(sorted(warnings)), "\n".join(sorted(observed_warnings)))
assert_equal(result[0]['success'], success)
if error_code is not None:
assert_equal(result[0]['error']['code'], error_code)
@@ -178,7 +182,7 @@ class ImportMultiTest(BitcoinTestFramework):
"timestamp": "now"},
False,
error_code=-5,
- error_message='Invalid address')
+ error_message='Invalid address \"not valid address\"')
# ScriptPubKey + internal
self.log.info("Should import a scriptPubKey with internal flag")
@@ -227,7 +231,8 @@ class ImportMultiTest(BitcoinTestFramework):
"timestamp": "now",
"pubkeys": [key.pubkey],
"internal": False},
- True)
+ True,
+ warnings=["Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."])
self.test_address(address,
iswatchonly=True,
ismine=False,
@@ -241,7 +246,8 @@ class ImportMultiTest(BitcoinTestFramework):
"timestamp": "now",
"pubkeys": [key.pubkey],
"internal": True},
- True)
+ True,
+ warnings=["Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."])
self.test_address(address,
iswatchonly=True,
ismine=False,
@@ -284,20 +290,19 @@ class ImportMultiTest(BitcoinTestFramework):
error_message='The wallet already contains the private key for this address or script')
# Address + Private key + watchonly
- self.log.info("Should not import an address with private key and with watchonly")
+ self.log.info("Should import an address with private key and with watchonly")
key = self.get_key()
address = key.p2pkh_addr
self.test_importmulti({"scriptPubKey": {"address": address},
"timestamp": "now",
"keys": [key.privkey],
"watchonly": True},
- False,
- error_code=-8,
- error_message='Watch-only addresses should not include private keys')
+ True,
+ warnings=["All private keys are provided, outputs will be considered spendable. If this is intentional, do not specify the watchonly flag."])
self.test_address(address,
iswatchonly=False,
- ismine=False,
- timestamp=None)
+ ismine=True,
+ timestamp=timestamp)
# ScriptPubKey + Private key + internal
self.log.info("Should import a scriptPubKey with internal and with private key")
@@ -358,8 +363,9 @@ class ImportMultiTest(BitcoinTestFramework):
self.test_importmulti({"scriptPubKey": {"address": multisig.p2sh_addr},
"timestamp": "now",
"redeemscript": multisig.redeem_script},
- True)
- self.test_address(multisig.p2sh_addr, timestamp=timestamp)
+ True,
+ warnings=["Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."])
+ self.test_address(multisig.p2sh_addr, timestamp=timestamp, iswatchonly=True, ismine=False, solvable=True)
p2shunspent = self.nodes[1].listunspent(0, 999999, [multisig.p2sh_addr])[0]
assert_equal(p2shunspent['spendable'], False)
@@ -377,9 +383,13 @@ class ImportMultiTest(BitcoinTestFramework):
"timestamp": "now",
"redeemscript": multisig.redeem_script,
"keys": multisig.privkeys[0:2]},
- True)
+ True,
+ warnings=["Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."])
self.test_address(multisig.p2sh_addr,
- timestamp=timestamp)
+ timestamp=timestamp,
+ ismine=False,
+ iswatchonly=True,
+ solvable=True)
p2shunspent = self.nodes[1].listunspent(0, 999999, [multisig.p2sh_addr])[0]
assert_equal(p2shunspent['spendable'], False)
@@ -398,28 +408,31 @@ class ImportMultiTest(BitcoinTestFramework):
"redeemscript": multisig.redeem_script,
"keys": multisig.privkeys[0:2],
"watchonly": True},
- False,
- error_code=-8,
- error_message='Watch-only addresses should not include private keys')
+ True)
+ self.test_address(multisig.p2sh_addr,
+ iswatchonly=True,
+ ismine=False,
+ solvable=True,
+ timestamp=timestamp)
# Address + Public key + !Internal + Wrong pubkey
- self.log.info("Should not import an address with a wrong public key")
+ self.log.info("Should not import an address with the wrong public key as non-solvable")
key = self.get_key()
address = key.p2pkh_addr
wrong_key = self.get_key().pubkey
self.test_importmulti({"scriptPubKey": {"address": address},
"timestamp": "now",
"pubkeys": [wrong_key]},
- False,
- error_code=-5,
- error_message='Key does not match address destination')
+ True,
+ warnings=["Importing as non-solvable: some required keys are missing. If this is intentional, don't provide any keys, pubkeys, witnessscript, or redeemscript.", "Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."])
self.test_address(address,
- iswatchonly=False,
+ iswatchonly=True,
ismine=False,
- timestamp=None)
+ solvable=False,
+ timestamp=timestamp)
# ScriptPubKey + Public key + internal + Wrong pubkey
- self.log.info("Should not import a scriptPubKey with internal and with a wrong public key")
+ self.log.info("Should import a scriptPubKey with internal and with a wrong public key as non-solvable")
key = self.get_key()
address = key.p2pkh_addr
wrong_key = self.get_key().pubkey
@@ -427,32 +440,32 @@ class ImportMultiTest(BitcoinTestFramework):
"timestamp": "now",
"pubkeys": [wrong_key],
"internal": True},
- False,
- error_code=-5,
- error_message='Key does not match address destination')
+ True,
+ warnings=["Importing as non-solvable: some required keys are missing. If this is intentional, don't provide any keys, pubkeys, witnessscript, or redeemscript.", "Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."])
self.test_address(address,
- iswatchonly=False,
+ iswatchonly=True,
ismine=False,
- timestamp=None)
+ solvable=False,
+ timestamp=timestamp)
# Address + Private key + !watchonly + Wrong private key
- self.log.info("Should not import an address with a wrong private key")
+ self.log.info("Should import an address with a wrong private key as non-solvable")
key = self.get_key()
address = key.p2pkh_addr
wrong_privkey = self.get_key().privkey
self.test_importmulti({"scriptPubKey": {"address": address},
"timestamp": "now",
"keys": [wrong_privkey]},
- False,
- error_code=-5,
- error_message='Key does not match address destination')
+ True,
+ warnings=["Importing as non-solvable: some required keys are missing. If this is intentional, don't provide any keys, pubkeys, witnessscript, or redeemscript.", "Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."])
self.test_address(address,
- iswatchonly=False,
+ iswatchonly=True,
ismine=False,
- timestamp=None)
+ solvable=False,
+ timestamp=timestamp)
# ScriptPubKey + Private key + internal + Wrong private key
- self.log.info("Should not import a scriptPubKey with internal and with a wrong private key")
+ self.log.info("Should import a scriptPubKey with internal and with a wrong private key as non-solvable")
key = self.get_key()
address = key.p2pkh_addr
wrong_privkey = self.get_key().privkey
@@ -460,13 +473,13 @@ class ImportMultiTest(BitcoinTestFramework):
"timestamp": "now",
"keys": [wrong_privkey],
"internal": True},
- False,
- error_code=-5,
- error_message='Key does not match address destination')
+ True,
+ warnings=["Importing as non-solvable: some required keys are missing. If this is intentional, don't provide any keys, pubkeys, witnessscript, or redeemscript.", "Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."])
self.test_address(address,
- iswatchonly=False,
+ iswatchonly=True,
ismine=False,
- timestamp=None)
+ solvable=False,
+ timestamp=timestamp)
# Importing existing watch only address with new timestamp should replace saved timestamp.
assert_greater_than(timestamp, watchonly_timestamp)
@@ -516,7 +529,8 @@ class ImportMultiTest(BitcoinTestFramework):
self.test_importmulti({"scriptPubKey": {"address": address},
"timestamp": "now",
"pubkeys": [key.pubkey]},
- True)
+ True,
+ warnings=["Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."])
self.test_address(address,
ismine=False,
solvable=True)
@@ -571,7 +585,8 @@ class ImportMultiTest(BitcoinTestFramework):
"timestamp": "now",
"redeemscript": key.p2sh_p2wpkh_redeem_script,
"pubkeys": [key.pubkey]},
- True)
+ True,
+ warnings=["Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."])
self.test_address(address,
solvable=True,
ismine=False)
@@ -591,14 +606,17 @@ class ImportMultiTest(BitcoinTestFramework):
# P2SH-P2WSH multisig + redeemscript with no private key
multisig = self.get_multisig()
+ address = multisig.p2sh_p2wsh_addr
self.log.info("Should import a p2sh-p2wsh with respective redeem script but no private key")
- self.test_importmulti({"scriptPubKey": {"address": multisig.p2sh_p2wsh_addr},
+ self.test_importmulti({"scriptPubKey": {"address": address},
"timestamp": "now",
"redeemscript": multisig.p2wsh_script,
"witnessscript": multisig.redeem_script},
- True)
+ True,
+ warnings=["Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."])
self.test_address(address,
- solvable=True)
+ solvable=True,
+ ismine=False)
if __name__ == '__main__':
ImportMultiTest().main()
diff --git a/test/functional/wallet_listtransactions.py b/test/functional/wallet_listtransactions.py
index 8ca0387268..17f044bf65 100755
--- a/test/functional/wallet_listtransactions.py
+++ b/test/functional/wallet_listtransactions.py
@@ -25,12 +25,13 @@ def tx_from_hex(hexstring):
class ListTransactionsTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
- self.enable_mocktime()
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
def run_test(self):
+ self.nodes[0].generate(1) # Get out of IBD
+ self.sync_all()
# Simple send, 0 to 1:
txid = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.1)
self.sync_all()
diff --git a/test/lint/lint-format-strings.py b/test/lint/lint-format-strings.py
index 5caebf3739..f5d4780b6d 100755
--- a/test/lint/lint-format-strings.py
+++ b/test/lint/lint-format-strings.py
@@ -241,12 +241,11 @@ def count_format_specifiers(format_string):
4
"""
assert(type(format_string) is str)
+ format_string = format_string.replace('%%', 'X')
n = 0
in_specifier = False
for i, char in enumerate(format_string):
- if format_string[i - 1:i + 1] == "%%" or format_string[i:i + 2] == "%%":
- pass
- elif char == "%":
+ if char == "%":
in_specifier = True
n += 1
elif char in "aAcdeEfFgGinopsuxX":
diff --git a/test/lint/lint-includes.sh b/test/lint/lint-includes.sh
index f6d0fd382b..4b9e2615b6 100755
--- a/test/lint/lint-includes.sh
+++ b/test/lint/lint-includes.sh
@@ -50,7 +50,6 @@ EXPECTED_BOOST_INCLUDES=(
boost/algorithm/string/classification.hpp
boost/algorithm/string/replace.hpp
boost/algorithm/string/split.hpp
- boost/bind.hpp
boost/chrono/chrono.hpp
boost/date_time/posix_time/posix_time.hpp
boost/filesystem.hpp
diff --git a/test/lint/lint-python-dead-code.sh b/test/lint/lint-python-dead-code.sh
index 4561b0db30..1b897cd131 100755
--- a/test/lint/lint-python-dead-code.sh
+++ b/test/lint/lint-python-dead-code.sh
@@ -16,4 +16,4 @@ fi
vulture \
--min-confidence 60 \
--ignore-names "argtypes,connection_lost,connection_made,converter,data_received,daemon,errcheck,get_ecdh_key,get_privkey,is_compressed,is_fullyvalid,msg_generic,on_*,optionxform,restype,set_privkey" \
- $(git ls-files -- "*.py" ":(exclude)contrib/")
+ $(git ls-files -- "*.py" ":(exclude)contrib/" ":(exclude)test/functional/data/invalid_txs.py")