aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml12
-rw-r--r--CONTRIBUTING.md8
-rw-r--r--Makefile.am4
-rwxr-xr-xautogen.sh1
-rw-r--r--build-aux/m4/bitcoin_qt.m4237
-rw-r--r--configure.ac50
-rwxr-xr-xcontrib/devtools/circular-dependencies.py2
-rwxr-xr-xcontrib/devtools/clang-format-diff.py2
-rwxr-xr-xcontrib/devtools/copyright_header.py6
-rwxr-xr-xcontrib/devtools/gen-manpages.sh3
-rwxr-xr-xcontrib/devtools/github-merge.py2
-rwxr-xr-xcontrib/devtools/test-security-check.py2
-rwxr-xr-xcontrib/devtools/update-translations.py10
-rwxr-xr-xcontrib/filter-lcov.py4
-rwxr-xr-xcontrib/gitian-build.sh3
-rw-r--r--contrib/gitian-descriptors/gitian-linux.yml6
-rw-r--r--contrib/gitian-descriptors/gitian-osx-signer.yml2
-rw-r--r--contrib/gitian-descriptors/gitian-osx.yml4
-rw-r--r--contrib/gitian-descriptors/gitian-win.yml8
-rw-r--r--contrib/init/bitcoind.init2
-rwxr-xr-xcontrib/install_db4.sh1
-rwxr-xr-xcontrib/linearize/linearize-data.py4
-rwxr-xr-xcontrib/linearize/linearize-hashes.py4
-rwxr-xr-xcontrib/macdeploy/detached-sig-apply.sh1
-rwxr-xr-xcontrib/macdeploy/detached-sig-create.sh1
-rwxr-xr-xcontrib/macdeploy/extract-osx-sdk.sh3
-rw-r--r--contrib/qos/tc.sh1
-rwxr-xr-xcontrib/seeds/generate-seeds.py4
-rw-r--r--contrib/verify-commits/README.md10
-rw-r--r--contrib/verify-commits/allow-incorrect-sha512-commits2
-rw-r--r--contrib/verify-commits/allow-unclean-merge-commits4
-rwxr-xr-xcontrib/verify-commits/gpg.sh3
-rwxr-xr-xcontrib/verify-commits/pre-push-hook.sh7
-rwxr-xr-xcontrib/verify-commits/verify-commits.py155
-rwxr-xr-xcontrib/verify-commits/verify-commits.sh153
-rwxr-xr-xcontrib/verifybinaries/verify.sh3
-rwxr-xr-xcontrib/windeploy/detached-sig-create.sh1
-rw-r--r--doc/build-freebsd.md2
-rw-r--r--doc/build-osx.md2
-rw-r--r--doc/build-unix.md25
-rw-r--r--doc/dependencies.md2
-rw-r--r--doc/developer-notes.md10
-rw-r--r--doc/release-notes-pr10740.md3
-rw-r--r--doc/release-notes-pr12892.md2
-rw-r--r--doc/release-notes.md5
-rw-r--r--doc/release-notes/release-notes-0.16.1.md145
-rwxr-xr-xshare/genbuild.sh1
-rwxr-xr-xshare/qt/extract_strings_qt.py2
-rw-r--r--src/Makefile.am40
-rw-r--r--src/Makefile.bench.include5
-rw-r--r--src/Makefile.qt.include2
-rw-r--r--src/Makefile.qttest.include2
-rw-r--r--src/Makefile.test.include6
-rw-r--r--src/bench/block_assemble.cpp116
-rw-r--r--src/bench/examples.cpp (renamed from src/bench/Examples.cpp)0
-rw-r--r--src/bench/merkle_root.cpp8
-rw-r--r--src/bitcoin-tx.cpp2
-rw-r--r--src/bitcoind.cpp3
-rw-r--r--src/core_io.h1
-rw-r--r--src/core_read.cpp8
-rw-r--r--src/crypto/sha256.cpp135
-rw-r--r--src/crypto/sha256_avx2.cpp4
-rw-r--r--src/crypto/sha256_sse41.cpp4
-rw-r--r--src/init.cpp54
-rw-r--r--src/interfaces/wallet.cpp4
-rw-r--r--src/interfaces/wallet.h4
-rw-r--r--src/miner.cpp4
-rw-r--r--src/net_processing.cpp2
-rw-r--r--src/policy/policy.cpp9
-rw-r--r--src/policy/policy.h4
-rw-r--r--src/primitives/transaction.h5
-rw-r--r--src/qt/README.md8
-rw-r--r--src/qt/addressbookpage.cpp5
-rw-r--r--src/qt/bantablemodel.cpp2
-rw-r--r--src/qt/bitcoin.cpp54
-rw-r--r--src/qt/bitcoingui.cpp92
-rw-r--r--src/qt/bitcoingui.h101
-rw-r--r--src/qt/coincontroldialog.cpp10
-rw-r--r--src/qt/forms/optionsdialog.ui67
-rw-r--r--src/qt/guiutil.cpp32
-rw-r--r--src/qt/guiutil.h2
-rw-r--r--src/qt/macdockiconhandler.mm8
-rw-r--r--src/qt/networkstyle.cpp4
-rw-r--r--src/qt/openuridialog.cpp2
-rw-r--r--src/qt/optionsdialog.cpp31
-rw-r--r--src/qt/optionsdialog.h1
-rw-r--r--src/qt/optionsmodel.cpp26
-rw-r--r--src/qt/optionsmodel.h2
-rw-r--r--src/qt/paymentrequestplus.cpp2
-rw-r--r--src/qt/paymentserver.cpp15
-rw-r--r--src/qt/peertablemodel.cpp2
-rw-r--r--src/qt/platformstyle.cpp2
-rw-r--r--src/qt/receiverequestdialog.cpp3
-rwxr-xr-xsrc/qt/res/movies/makespinner.sh1
-rw-r--r--src/qt/rpcconsole.cpp14
-rw-r--r--src/qt/rpcconsole.h1
-rw-r--r--src/qt/sendcoinsentry.cpp2
-rw-r--r--src/qt/signverifymessagedialog.cpp2
-rw-r--r--src/qt/test/test_main.cpp7
-rw-r--r--src/qt/test/wallettests.cpp13
-rw-r--r--src/qt/transactionview.cpp4
-rw-r--r--src/qt/walletframe.cpp1
-rw-r--r--src/qt/walletmodel.cpp8
-rw-r--r--src/qt/walletmodel.h4
-rw-r--r--src/qt/winshutdownmonitor.cpp2
-rw-r--r--src/qt/winshutdownmonitor.h2
-rw-r--r--src/rest.cpp2
-rw-r--r--src/rpc/blockchain.cpp8
-rw-r--r--src/rpc/client.cpp1
-rw-r--r--src/rpc/mining.cpp13
-rw-r--r--src/rpc/net.cpp2
-rw-r--r--src/test/blockchain_tests.cpp6
-rw-r--r--src/test/denialofservice_tests.cpp (renamed from src/test/DoS_tests.cpp)2
-rw-r--r--src/test/mempool_tests.cpp175
-rw-r--r--src/test/script_p2sh_tests.cpp (renamed from src/test/script_P2SH_tests.cpp)2
-rw-r--r--src/txmempool.cpp41
-rw-r--r--src/txmempool.h10
-rw-r--r--src/util.cpp7
-rw-r--r--src/util.h5
-rw-r--r--src/validation.cpp36
-rw-r--r--src/validation.h25
-rw-r--r--src/wallet/db.cpp5
-rw-r--r--src/wallet/init.cpp2
-rw-r--r--src/wallet/rpcdump.cpp2
-rw-r--r--src/wallet/rpcwallet.cpp195
-rw-r--r--src/wallet/test/coinselector_tests.cpp16
-rw-r--r--src/wallet/wallet.cpp58
-rw-r--r--src/wallet/wallet.h8
-rwxr-xr-xtest/functional/combine_logs.py2
-rwxr-xr-xtest/functional/feature_assumevalid.py4
-rwxr-xr-xtest/functional/feature_notifications.py6
-rwxr-xr-xtest/functional/feature_nulldummy.py2
-rwxr-xr-xtest/functional/feature_pruning.py7
-rwxr-xr-xtest/functional/feature_segwit.py31
-rwxr-xr-xtest/functional/p2p_compactblocks.py2
-rwxr-xr-xtest/functional/p2p_leak.py6
-rwxr-xr-xtest/functional/p2p_segwit.py160
-rwxr-xr-xtest/functional/p2p_sendheaders.py16
-rwxr-xr-xtest/functional/p2p_timeouts.py18
-rwxr-xr-xtest/functional/rpc_blockchain.py1
-rwxr-xr-xtest/functional/rpc_deprecated.py5
-rwxr-xr-xtest/functional/rpc_getblockstats.py4
-rwxr-xr-xtest/functional/test_framework/mininode.py68
-rwxr-xr-xtest/functional/test_framework/test_framework.py2
-rw-r--r--test/functional/test_framework/util.py2
-rwxr-xr-xtest/functional/test_runner.py12
-rwxr-xr-xtest/functional/wallet_basic.py9
-rwxr-xr-xtest/functional/wallet_bumpfee.py2
-rwxr-xr-xtest/functional/wallet_fallbackfee.py1
-rwxr-xr-xtest/functional/wallet_labels.py87
-rwxr-xr-xtest/functional/wallet_multiwallet.py29
-rwxr-xr-xtest/lint/check-doc.py2
-rwxr-xr-xtest/lint/check-rpc-mappings.py4
-rwxr-xr-xtest/lint/commit-script-check.sh1
-rwxr-xr-xtest/lint/git-subtree-check.sh1
-rwxr-xr-xtest/lint/lint-all.sh6
-rwxr-xr-xtest/lint/lint-filenames.sh24
-rwxr-xr-xtest/lint/lint-include-guards.sh3
-rwxr-xr-xtest/lint/lint-includes.sh16
-rwxr-xr-xtest/lint/lint-locale-dependence.sh3
-rwxr-xr-xtest/lint/lint-logs.sh4
-rwxr-xr-xtest/lint/lint-python-shebang.sh4
-rwxr-xr-xtest/lint/lint-python-utf8-encoding.sh20
-rwxr-xr-xtest/lint/lint-python.sh2
-rwxr-xr-xtest/lint/lint-shell-locale.sh24
-rwxr-xr-xtest/lint/lint-shell.sh6
-rwxr-xr-xtest/lint/lint-tests.sh3
-rwxr-xr-xtest/lint/lint-whitespace.sh3
-rwxr-xr-xtest/util/bitcoin-util-test.py8
-rwxr-xr-xtest/util/rpcauth-test.py2
170 files changed, 1925 insertions, 1186 deletions
diff --git a/.travis.yml b/.travis.yml
index 7cbe0b83f1..9332160926 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -35,17 +35,17 @@ env:
- HOST=i686-pc-linux-gnu PACKAGES="g++-multilib python3-zmq" DEP_OPTS="NO_QT=1" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-zmq --enable-glibc-back-compat --enable-reduce-exports LDFLAGS=-static-libstdc++" CONFIG_SHELL="/bin/dash"
# x86_64 Linux (uses qt5 dev package instead of depends Qt to speed up build and avoid timeout)
- HOST=x86_64-unknown-linux-gnu PACKAGES="python3-zmq qtbase5-dev qttools5-dev-tools protobuf-compiler libdbus-1-dev libharfbuzz-dev libprotobuf-dev" DEP_OPTS="NO_QT=1 NO_UPNP=1 DEBUG=1 ALLOW_HOST_PACKAGES=1" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-zmq --with-gui=qt5 --enable-glibc-back-compat --enable-reduce-exports CPPFLAGS=-DDEBUG_LOCKORDER"
-# Qt4 & system libs
- - HOST=x86_64-unknown-linux-gnu PACKAGES="python3-zmq qt4-dev-tools libssl1.0-dev libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-program-options-dev libboost-test-dev libboost-thread-dev libdb5.3++-dev libminiupnpc-dev libzmq3-dev libprotobuf-dev protobuf-compiler libqrencode-dev xvfb libqt4-dev" NO_DEPENDS=1 NEED_XVFB=1 RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-zmq --with-incompatible-bdb --enable-glibc-back-compat --enable-reduce-exports --with-gui=qt4 CPPFLAGS=-DDEBUG_LOCKORDER" DISPLAY=:99.0
+# x86_64 Linux (Qt5 & system libs)
+ - HOST=x86_64-unknown-linux-gnu PACKAGES="python3-zmq qtbase5-dev qttools5-dev-tools libssl1.0-dev libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-program-options-dev libboost-test-dev libboost-thread-dev libdb5.3++-dev libminiupnpc-dev libzmq3-dev libprotobuf-dev protobuf-compiler libqrencode-dev" NO_DEPENDS=1 RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-zmq --with-incompatible-bdb --enable-glibc-back-compat --enable-reduce-exports --with-gui=qt5 CPPFLAGS=-DDEBUG_LOCKORDER"
# x86_64 Linux, No wallet
- HOST=x86_64-unknown-linux-gnu PACKAGES="python3" DEP_OPTS="NO_WALLET=1" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports"
# Cross-Mac
- - HOST=x86_64-apple-darwin11 PACKAGES="cmake imagemagick libcap-dev librsvg2-bin libz-dev libbz2-dev libtiff-tools python-dev python3-setuptools-git" BITCOIN_CONFIG="--enable-gui --enable-reduce-exports --enable-werror" OSX_SDK=10.11 GOAL="deploy"
+ - HOST=x86_64-apple-darwin11 PACKAGES="cmake imagemagick libcap-dev librsvg2-bin libz-dev libbz2-dev libtiff-tools python-dev python3-setuptools-git" BITCOIN_CONFIG="--enable-gui --enable-reduce-exports --enable-werror" OSX_SDK=10.11 GOAL="all deploy"
before_install:
- export PATH=$(echo $PATH | tr ':' "\n" | sed '/\/opt\/python/d' | tr "\n" ":" | sed "s|::|:|g")
install:
- - env | grep -E '^(CCACHE_|WINEDEBUG|DISPLAY|BOOST_TEST_RANDOM|CONFIG_SHELL)' | tee /tmp/env
+ - env | grep -E '^(CCACHE_|WINEDEBUG|BOOST_TEST_RANDOM|CONFIG_SHELL)' | tee /tmp/env
- if [[ $HOST = *-mingw32 ]]; then DOCKER_ADMIN="--cap-add SYS_ADMIN"; 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 ubuntu:18.04)
- DOCKER_EXEC () { docker exec $DOCKER_ID bash -c "cd $PWD && $*"; }
@@ -58,8 +58,6 @@ before_script:
- if [ -n "$OSX_SDK" -a -f depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz ]; then tar -C depends/SDKs -xf depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz; fi
- if [[ $HOST = *-mingw32 ]]; then DOCKER_EXEC update-alternatives --set $HOST-g++ \$\(which $HOST-g++-posix\); fi
- if [ -z "$NO_DEPENDS" ]; then DOCKER_EXEC CONFIG_SHELL= make $MAKEJOBS -C depends HOST=$HOST $DEP_OPTS; fi
- # Start xvfb if needed, as documented at https://docs.travis-ci.com/user/gui-and-headless-browsers/#Using-xvfb-to-Run-Tests-That-Require-a-GUI
- - if [ "$NEED_XVFB" = 1 ]; then DOCKER_EXEC /sbin/start-stop-daemon --start --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -ac; fi
script:
- export TRAVIS_COMMIT_LOG=`git log --format=fuller -1`
- OUTDIR=$BASE_OUTDIR/$TRAVIS_PULL_REQUEST/$TRAVIS_JOB_NUMBER-$HOST
@@ -104,5 +102,5 @@ jobs:
- test/lint/lint-all.sh
- if [ "$TRAVIS_REPO_SLUG" = "bitcoin/bitcoin" -a "$TRAVIS_EVENT_TYPE" = "cron" ]; then
while read LINE; do travis_retry gpg --keyserver hkp://subset.pool.sks-keyservers.net --recv-keys $LINE; done < contrib/verify-commits/trusted-keys &&
- travis_wait 30 contrib/verify-commits/verify-commits.sh;
+ travis_wait 50 contrib/verify-commits/verify-commits.py;
fi
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index c390595abf..3ee5a04796 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -127,10 +127,10 @@ before it will be merged. The basic squashing workflow is shown below.
git checkout your_branch_name
git rebase -i HEAD~n
- # n is normally the number of commits in the pull
- # set commits from 'pick' to 'squash', save and quit
- # on the next screen, edit/refine commit messages
- # save and quit
+ # n is normally the number of commits in the pull request.
+ # Set commits (except the one in the first line) from 'pick' to 'squash', save and quit.
+ # On the next screen, edit/refine commit messages.
+ # Save and quit.
git push -f # (force push to GitHub)
If you have problems with squashing (or other workflows with `git`), you can
diff --git a/Makefile.am b/Makefile.am
index 0ed3dd289a..f3f3302fce 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -95,9 +95,9 @@ $(OSX_APP)/Contents/Resources/bitcoin.icns: $(OSX_INSTALLER_ICONS)
$(MKDIR_P) $(@D)
$(INSTALL_DATA) $< $@
-$(OSX_APP)/Contents/MacOS/Bitcoin-Qt: $(BITCOIN_QT_BIN)
+$(OSX_APP)/Contents/MacOS/Bitcoin-Qt: all-recursive
$(MKDIR_P) $(@D)
- STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $< $@
+ STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $(BITCOIN_QT_BIN) $@
$(OSX_APP)/Contents/Resources/Base.lproj/InfoPlist.strings:
$(MKDIR_P) $(@D)
diff --git a/autogen.sh b/autogen.sh
index 27417daf76..0c05626ccc 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -3,6 +3,7 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+export LC_ALL=C
set -e
srcdir="$(dirname $0)"
cd "$srcdir"
diff --git a/build-aux/m4/bitcoin_qt.m4 b/build-aux/m4/bitcoin_qt.m4
index f41508336c..fe0cc6c36d 100644
--- a/build-aux/m4/bitcoin_qt.m4
+++ b/build-aux/m4/bitcoin_qt.m4
@@ -53,8 +53,8 @@ dnl CAUTION: Do not use this inside of a conditional.
AC_DEFUN([BITCOIN_QT_INIT],[
dnl enable qt support
AC_ARG_WITH([gui],
- [AS_HELP_STRING([--with-gui@<:@=no|qt4|qt5|auto@:>@],
- [build bitcoin-qt GUI (default=auto, qt5 tried first)])],
+ [AS_HELP_STRING([--with-gui@<:@=no|qt5|auto@:>@],
+ [build bitcoin-qt GUI (default=auto)])],
[
bitcoin_qt_want_version=$withval
if test "x$bitcoin_qt_want_version" = xyes; then
@@ -94,18 +94,17 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[
fi
if test "x$use_pkgconfig" = xyes; then
- BITCOIN_QT_CHECK([_BITCOIN_QT_FIND_LIBS_WITH_PKGCONFIG([$2])])
+ BITCOIN_QT_CHECK([_BITCOIN_QT_FIND_LIBS_WITH_PKGCONFIG])
else
BITCOIN_QT_CHECK([_BITCOIN_QT_FIND_LIBS_WITHOUT_PKGCONFIG])
fi
dnl This is ugly and complicated. Yuck. Works as follows:
- dnl We can't discern whether Qt4 builds are static or not. For Qt5, we can
- dnl check a header to find out. When Qt is built statically, some plugins must
- dnl be linked into the final binary as well. These plugins have changed between
- dnl Qt4 and Qt5. With Qt5, languages moved into core and the WindowsIntegration
- dnl plugin was added. Since we can't tell if Qt4 is static or not, it is
- dnl assumed for windows builds.
+ dnl For Qt5, we can check a header to find out whether Qt is build
+ dnl statically. When Qt is built statically, some plugins must be linked into
+ dnl the final binary as well.
+ dnl With Qt5, languages moved into core and the WindowsIntegration plugin was
+ dnl added.
dnl _BITCOIN_QT_CHECK_STATIC_PLUGINS does a quick link-check and appends the
dnl results to QT_LIBS.
BITCOIN_QT_CHECK([
@@ -113,53 +112,40 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[
TEMP_CXXFLAGS=$CXXFLAGS
CPPFLAGS="$QT_INCLUDES $CPPFLAGS"
CXXFLAGS="$PIC_FLAGS $CXXFLAGS"
- if test "x$bitcoin_qt_got_major_vers" = x5; then
- _BITCOIN_QT_IS_STATIC
- if test "x$bitcoin_cv_static_qt" = xyes; then
- _BITCOIN_QT_FIND_STATIC_PLUGINS
- AC_DEFINE(QT_STATICPLUGIN, 1, [Define this symbol if qt plugins are static])
- AC_CACHE_CHECK(for Qt < 5.4, bitcoin_cv_need_acc_widget,[
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
- #include <QtCore/qconfig.h>
- #ifndef QT_VERSION
- # include <QtCore/qglobal.h>
- #endif
- ]],
- [[
- #if QT_VERSION >= 0x050400
- choke
- #endif
- ]])],
- [bitcoin_cv_need_acc_widget=yes],
- [bitcoin_cv_need_acc_widget=no])
- ])
- if test "x$bitcoin_cv_need_acc_widget" = xyes; then
- _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(AccessibleFactory)], [-lqtaccessiblewidgets])
- fi
- _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QMinimalIntegrationPlugin)],[-lqminimal])
- AC_DEFINE(QT_QPA_PLATFORM_MINIMAL, 1, [Define this symbol if the minimal qt platform exists])
- if test "x$TARGET_OS" = xwindows; then
- _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin)],[-lqwindows])
- AC_DEFINE(QT_QPA_PLATFORM_WINDOWS, 1, [Define this symbol if the qt platform is windows])
- elif test "x$TARGET_OS" = xlinux; then
- _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QXcbIntegrationPlugin)],[-lqxcb -lxcb-static])
- AC_DEFINE(QT_QPA_PLATFORM_XCB, 1, [Define this symbol if the qt platform is xcb])
- elif test "x$TARGET_OS" = xdarwin; then
- AX_CHECK_LINK_FLAG([[-framework IOKit]],[QT_LIBS="$QT_LIBS -framework IOKit"],[AC_MSG_ERROR(could not iokit framework)])
- _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin)],[-lqcocoa])
- AC_DEFINE(QT_QPA_PLATFORM_COCOA, 1, [Define this symbol if the qt platform is cocoa])
- fi
+ _BITCOIN_QT_IS_STATIC
+ if test "x$bitcoin_cv_static_qt" = xyes; then
+ _BITCOIN_QT_FIND_STATIC_PLUGINS
+ AC_DEFINE(QT_STATICPLUGIN, 1, [Define this symbol if qt plugins are static])
+ AC_CACHE_CHECK(for Qt < 5.4, bitcoin_cv_need_acc_widget,[
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+ #include <QtCore/qconfig.h>
+ #ifndef QT_VERSION
+ # include <QtCore/qglobal.h>
+ #endif
+ ]],
+ [[
+ #if QT_VERSION >= 0x050400
+ choke
+ #endif
+ ]])],
+ [bitcoin_cv_need_acc_widget=yes],
+ [bitcoin_cv_need_acc_widget=no])
+ ])
+ if test "x$bitcoin_cv_need_acc_widget" = xyes; then
+ _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(AccessibleFactory)], [-lqtaccessiblewidgets])
fi
- else
+ _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QMinimalIntegrationPlugin)],[-lqminimal])
+ AC_DEFINE(QT_QPA_PLATFORM_MINIMAL, 1, [Define this symbol if the minimal qt platform exists])
if test "x$TARGET_OS" = xwindows; then
- AC_DEFINE(QT_STATICPLUGIN, 1, [Define this symbol if qt plugins are static])
- _BITCOIN_QT_CHECK_STATIC_PLUGINS([
- Q_IMPORT_PLUGIN(qcncodecs)
- Q_IMPORT_PLUGIN(qjpcodecs)
- Q_IMPORT_PLUGIN(qtwcodecs)
- Q_IMPORT_PLUGIN(qkrcodecs)
- Q_IMPORT_PLUGIN(AccessibleFactory)],
- [-lqcncodecs -lqjpcodecs -lqtwcodecs -lqkrcodecs -lqtaccessiblewidgets])
+ _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin)],[-lqwindows])
+ AC_DEFINE(QT_QPA_PLATFORM_WINDOWS, 1, [Define this symbol if the qt platform is windows])
+ elif test "x$TARGET_OS" = xlinux; then
+ _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QXcbIntegrationPlugin)],[-lqxcb -lxcb-static])
+ AC_DEFINE(QT_QPA_PLATFORM_XCB, 1, [Define this symbol if the qt platform is xcb])
+ elif test "x$TARGET_OS" = xdarwin; then
+ AX_CHECK_LINK_FLAG([[-framework IOKit]],[QT_LIBS="$QT_LIBS -framework IOKit"],[AC_MSG_ERROR(could not iokit framework)])
+ _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin)],[-lqcocoa])
+ AC_DEFINE(QT_QPA_PLATFORM_COCOA, 1, [Define this symbol if the qt platform is cocoa])
fi
fi
CPPFLAGS=$TEMP_CPPFLAGS
@@ -167,9 +153,7 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[
])
if test "x$use_pkgconfig$qt_bin_path" = xyes; then
- if test "x$bitcoin_qt_got_major_vers" = x5; then
- qt_bin_path="`$PKG_CONFIG --variable=host_bins Qt5Core 2>/dev/null`"
- fi
+ qt_bin_path="`$PKG_CONFIG --variable=host_bins Qt5Core 2>/dev/null`"
fi
if test "x$use_hardening" != xno; then
@@ -219,11 +203,11 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[
])
fi
- BITCOIN_QT_PATH_PROGS([MOC], [moc-qt${bitcoin_qt_got_major_vers} moc${bitcoin_qt_got_major_vers} moc], $qt_bin_path)
- BITCOIN_QT_PATH_PROGS([UIC], [uic-qt${bitcoin_qt_got_major_vers} uic${bitcoin_qt_got_major_vers} uic], $qt_bin_path)
- BITCOIN_QT_PATH_PROGS([RCC], [rcc-qt${bitcoin_qt_got_major_vers} rcc${bitcoin_qt_got_major_vers} rcc], $qt_bin_path)
- BITCOIN_QT_PATH_PROGS([LRELEASE], [lrelease-qt${bitcoin_qt_got_major_vers} lrelease${bitcoin_qt_got_major_vers} lrelease], $qt_bin_path)
- BITCOIN_QT_PATH_PROGS([LUPDATE], [lupdate-qt${bitcoin_qt_got_major_vers} lupdate${bitcoin_qt_got_major_vers} lupdate],$qt_bin_path, yes)
+ BITCOIN_QT_PATH_PROGS([MOC], [moc-qt5 moc5 moc], $qt_bin_path)
+ BITCOIN_QT_PATH_PROGS([UIC], [uic-qt5 uic5 uic], $qt_bin_path)
+ BITCOIN_QT_PATH_PROGS([RCC], [rcc-qt5 rcc5 rcc], $qt_bin_path)
+ BITCOIN_QT_PATH_PROGS([LRELEASE], [lrelease-qt5 lrelease5 lrelease], $qt_bin_path)
+ BITCOIN_QT_PATH_PROGS([LUPDATE], [lupdate-qt5 lupdate5 lupdate],$qt_bin_path, yes)
MOC_DEFS='-DHAVE_CONFIG_H -I$(srcdir)'
case $host in
@@ -262,7 +246,7 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[
],[
bitcoin_enable_qt=no
])
- AC_MSG_RESULT([$bitcoin_enable_qt (Qt${bitcoin_qt_got_major_vers})])
+ AC_MSG_RESULT([$bitcoin_enable_qt (Qt5)])
AC_SUBST(QT_PIE_FLAGS)
AC_SUBST(QT_INCLUDES)
@@ -272,7 +256,7 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[
AC_SUBST(QT_DBUS_LIBS)
AC_SUBST(QT_TEST_INCLUDES)
AC_SUBST(QT_TEST_LIBS)
- AC_SUBST(QT_SELECT, qt${bitcoin_qt_got_major_vers})
+ AC_SUBST(QT_SELECT, qt5)
AC_SUBST(MOC_DEFS)
])
@@ -301,7 +285,7 @@ AC_DEFUN([_BITCOIN_QT_CHECK_QT5],[
])])
dnl Internal. Check if the linked version of Qt was built as static libs.
-dnl Requires: Qt5. This check cannot determine if Qt4 is static.
+dnl Requires: Qt5.
dnl Requires: INCLUDES and LIBS must be populated as necessary.
dnl Output: bitcoin_cv_static_qt=yes|no
dnl Output: Defines QT_STATICPLUGIN if plugins are static.
@@ -346,58 +330,50 @@ AC_DEFUN([_BITCOIN_QT_CHECK_STATIC_PLUGINS],[
])
dnl Internal. Find paths necessary for linking qt static plugins
-dnl Inputs: bitcoin_qt_got_major_vers. 4 or 5.
dnl Inputs: qt_plugin_path. optional.
dnl Outputs: QT_LIBS is appended
AC_DEFUN([_BITCOIN_QT_FIND_STATIC_PLUGINS],[
- if test "x$bitcoin_qt_got_major_vers" = x5; then
- if test "x$qt_plugin_path" != x; then
- QT_LIBS="$QT_LIBS -L$qt_plugin_path/platforms"
- if test -d "$qt_plugin_path/accessible"; then
- QT_LIBS="$QT_LIBS -L$qt_plugin_path/accessible"
- fi
+ if test "x$qt_plugin_path" != x; then
+ QT_LIBS="$QT_LIBS -L$qt_plugin_path/platforms"
+ if test -d "$qt_plugin_path/accessible"; then
+ QT_LIBS="$QT_LIBS -L$qt_plugin_path/accessible"
fi
- if test "x$use_pkgconfig" = xyes; then
- : dnl
- m4_ifdef([PKG_CHECK_MODULES],[
- PKG_CHECK_MODULES([QTPLATFORM], [Qt5PlatformSupport], [QT_LIBS="$QTPLATFORM_LIBS $QT_LIBS"])
- if test "x$TARGET_OS" = xlinux; then
- PKG_CHECK_MODULES([X11XCB], [x11-xcb], [QT_LIBS="$X11XCB_LIBS $QT_LIBS"])
- if ${PKG_CONFIG} --exists "Qt5Core >= 5.5" 2>/dev/null; then
- PKG_CHECK_MODULES([QTXCBQPA], [Qt5XcbQpa], [QT_LIBS="$QTXCBQPA_LIBS $QT_LIBS"])
- fi
- elif test "x$TARGET_OS" = xdarwin; then
- PKG_CHECK_MODULES([QTPRINT], [Qt5PrintSupport], [QT_LIBS="$QTPRINT_LIBS $QT_LIBS"])
+ fi
+ if test "x$use_pkgconfig" = xyes; then
+ : dnl
+ m4_ifdef([PKG_CHECK_MODULES],[
+ PKG_CHECK_MODULES([QTPLATFORM], [Qt5PlatformSupport], [QT_LIBS="$QTPLATFORM_LIBS $QT_LIBS"])
+ if test "x$TARGET_OS" = xlinux; then
+ PKG_CHECK_MODULES([X11XCB], [x11-xcb], [QT_LIBS="$X11XCB_LIBS $QT_LIBS"])
+ if ${PKG_CONFIG} --exists "Qt5Core >= 5.5" 2>/dev/null; then
+ PKG_CHECK_MODULES([QTXCBQPA], [Qt5XcbQpa], [QT_LIBS="$QTXCBQPA_LIBS $QT_LIBS"])
fi
- ])
- else
- if test "x$TARGET_OS" = xwindows; then
- AC_CACHE_CHECK(for Qt >= 5.6, bitcoin_cv_need_platformsupport,[
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
- #include <QtCore/qconfig.h>
- #ifndef QT_VERSION
- # include <QtCore/qglobal.h>
- #endif
- ]],
- [[
- #if QT_VERSION < 0x050600
- choke
- #endif
- ]])],
- [bitcoin_cv_need_platformsupport=yes],
- [bitcoin_cv_need_platformsupport=no])
- ])
- if test "x$bitcoin_cv_need_platformsupport" = xyes; then
- BITCOIN_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}PlatformSupport],[main],,BITCOIN_QT_FAIL(lib${QT_LIB_PREFIX}PlatformSupport not found)))
- fi
+ elif test "x$TARGET_OS" = xdarwin; then
+ PKG_CHECK_MODULES([QTPRINT], [Qt5PrintSupport], [QT_LIBS="$QTPRINT_LIBS $QT_LIBS"])
+ fi
+ ])
+ else
+ if test "x$TARGET_OS" = xwindows; then
+ AC_CACHE_CHECK(for Qt >= 5.6, bitcoin_cv_need_platformsupport,[
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+ #include <QtCore/qconfig.h>
+ #ifndef QT_VERSION
+ # include <QtCore/qglobal.h>
+ #endif
+ ]],
+ [[
+ #if QT_VERSION < 0x050600
+ choke
+ #endif
+ ]])],
+ [bitcoin_cv_need_platformsupport=yes],
+ [bitcoin_cv_need_platformsupport=no])
+ ])
+ if test "x$bitcoin_cv_need_platformsupport" = xyes; then
+ BITCOIN_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}PlatformSupport],[main],,BITCOIN_QT_FAIL(lib${QT_LIB_PREFIX}PlatformSupport not found)))
fi
fi
- else
- if test "x$qt_plugin_path" != x; then
- QT_LIBS="$QT_LIBS -L$qt_plugin_path/accessible"
- QT_LIBS="$QT_LIBS -L$qt_plugin_path/codecs"
- fi
- fi
+ fi
])
dnl Internal. Find Qt libraries using pkg-config.
@@ -406,38 +382,14 @@ dnl first.
dnl Inputs: $1: If bitcoin_qt_want_version is "auto", check for this version
dnl first.
dnl Outputs: All necessary QT_* variables are set.
-dnl Outputs: bitcoin_qt_got_major_vers is set to "4" or "5".
dnl Outputs: have_qt_test and have_qt_dbus are set (if applicable) to yes|no.
AC_DEFUN([_BITCOIN_QT_FIND_LIBS_WITH_PKGCONFIG],[
m4_ifdef([PKG_CHECK_MODULES],[
- auto_priority_version=$1
- if test "x$auto_priority_version" = x; then
- auto_priority_version=qt5
- fi
- if test "x$bitcoin_qt_want_version" = xqt5 || ( test "x$bitcoin_qt_want_version" = xauto && test "x$auto_priority_version" = xqt5 ); then
- QT_LIB_PREFIX=Qt5
- bitcoin_qt_got_major_vers=5
- else
- QT_LIB_PREFIX=Qt
- bitcoin_qt_got_major_vers=4
- fi
+ QT_LIB_PREFIX=Qt5
qt5_modules="Qt5Core Qt5Gui Qt5Network Qt5Widgets"
- qt4_modules="QtCore QtGui QtNetwork"
BITCOIN_QT_CHECK([
- if test "x$bitcoin_qt_want_version" = xqt5 || ( test "x$bitcoin_qt_want_version" = xauto && test "x$auto_priority_version" = xqt5 ); then
- PKG_CHECK_MODULES([QT5], [$qt5_modules], [QT_INCLUDES="$QT5_CFLAGS"; QT_LIBS="$QT5_LIBS" have_qt=yes],[have_qt=no])
- elif test "x$bitcoin_qt_want_version" = xqt4 || ( test "x$bitcoin_qt_want_version" = xauto && test "x$auto_priority_version" = xqt4 ); then
- PKG_CHECK_MODULES([QT4], [$qt4_modules], [QT_INCLUDES="$QT4_CFLAGS"; QT_LIBS="$QT4_LIBS" ; have_qt=yes], [have_qt=no])
- fi
+ PKG_CHECK_MODULES([QT5], [$qt5_modules], [QT_INCLUDES="$QT5_CFLAGS"; QT_LIBS="$QT5_LIBS" have_qt=yes],[have_qt=no])
- dnl qt version is set to 'auto' and the preferred version wasn't found. Now try the other.
- if test "x$have_qt" = xno && test "x$bitcoin_qt_want_version" = xauto; then
- if test "x$auto_priority_version" = xqt5; then
- PKG_CHECK_MODULES([QT4], [$qt4_modules], [QT_INCLUDES="$QT4_CFLAGS"; QT_LIBS="$QT4_LIBS" ; have_qt=yes; QT_LIB_PREFIX=Qt; bitcoin_qt_got_major_vers=4], [have_qt=no])
- else
- PKG_CHECK_MODULES([QT5], [$qt5_modules], [QT_INCLUDES="$QT5_CFLAGS"; QT_LIBS="$QT5_LIBS" ; have_qt=yes; QT_LIB_PREFIX=Qt5; bitcoin_qt_got_major_vers=5], [have_qt=no])
- fi
- fi
if test "x$have_qt" != xyes; then
have_qt=no
BITCOIN_QT_FAIL([Qt dependencies not found])
@@ -458,7 +410,6 @@ dnl from the discovered headers.
dnl Inputs: bitcoin_qt_want_version (from --with-gui=). The version to use.
dnl If "auto", the version will be discovered by _BITCOIN_QT_CHECK_QT5.
dnl Outputs: All necessary QT_* variables are set.
-dnl Outputs: bitcoin_qt_got_major_vers is set to "4" or "5".
dnl Outputs: have_qt_test and have_qt_dbus are set (if applicable) to yes|no.
AC_DEFUN([_BITCOIN_QT_FIND_LIBS_WITHOUT_PKGCONFIG],[
TEMP_CPPFLAGS="$CPPFLAGS"
@@ -480,13 +431,7 @@ AC_DEFUN([_BITCOIN_QT_FIND_LIBS_WITHOUT_PKGCONFIG],[
if test "x$bitcoin_qt_want_version" = xauto; then
_BITCOIN_QT_CHECK_QT5
fi
- if test "x$bitcoin_cv_qt5" = xyes || test "x$bitcoin_qt_want_version" = xqt5; then
- QT_LIB_PREFIX=Qt5
- bitcoin_qt_got_major_vers=5
- else
- QT_LIB_PREFIX=Qt
- bitcoin_qt_got_major_vers=4
- fi
+ QT_LIB_PREFIX=Qt5
])
BITCOIN_QT_CHECK([
@@ -508,9 +453,7 @@ AC_DEFUN([_BITCOIN_QT_FIND_LIBS_WITHOUT_PKGCONFIG],[
BITCOIN_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}Core] ,[main],,BITCOIN_QT_FAIL(lib${QT_LIB_PREFIX}Core not found)))
BITCOIN_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}Gui] ,[main],,BITCOIN_QT_FAIL(lib${QT_LIB_PREFIX}Gui not found)))
BITCOIN_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}Network],[main],,BITCOIN_QT_FAIL(lib${QT_LIB_PREFIX}Network not found)))
- if test "x$bitcoin_qt_got_major_vers" = x5; then
- BITCOIN_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}Widgets],[main],,BITCOIN_QT_FAIL(lib${QT_LIB_PREFIX}Widgets not found)))
- fi
+ BITCOIN_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}Widgets],[main],,BITCOIN_QT_FAIL(lib${QT_LIB_PREFIX}Widgets not found)))
QT_LIBS="$LIBS"
LIBS="$TEMP_LIBS"
diff --git a/configure.ac b/configure.ac
index af60b28c71..ff7f1b39c8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -243,6 +243,10 @@ AC_LANG_PUSH([C++])
AX_CHECK_COMPILE_FLAG([-Werror],[CXXFLAG_WERROR="-Werror"],[CXXFLAG_WERROR=""])
if test "x$enable_debug" = xyes; then
+ # Clear default -g -O2 flags
+ if test "x$CXXFLAGS_overridden" = xno; then
+ CXXFLAGS=""
+ fi
# Prefer -Og, fall back to -O0 if that is unavailable.
AX_CHECK_COMPILE_FLAG(
[-Og],
@@ -297,6 +301,7 @@ if test "x$CXXFLAGS_overridden" = "xno"; then
AX_CHECK_COMPILE_FLAG([-Wvla],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wvla"],,[[$CXXFLAG_WERROR]])
AX_CHECK_COMPILE_FLAG([-Wformat-security],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wformat-security"],,[[$CXXFLAG_WERROR]])
AX_CHECK_COMPILE_FLAG([-Wthread-safety-analysis],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wthread-safety-analysis"],,[[$CXXFLAG_WERROR]])
+ AX_CHECK_COMPILE_FLAG([-Wrange-loop-analysis],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wrange-loop-analysis"],,[[$CXXFLAG_WERROR]])
## Some compilers (gcc) ignore unknown -Wno-* options, but warn about all
## unknown options if any other warning is produced. Test the -Wfoo case, and
@@ -403,25 +408,25 @@ case $host in
use_pkgconfig=no
TARGET_OS=windows
- AC_CHECK_LIB([mingwthrd], [main],, AC_MSG_ERROR(lib missing))
- AC_CHECK_LIB([kernel32], [main],, AC_MSG_ERROR(lib missing))
- AC_CHECK_LIB([user32], [main],, AC_MSG_ERROR(lib missing))
- AC_CHECK_LIB([gdi32], [main],, AC_MSG_ERROR(lib missing))
- AC_CHECK_LIB([comdlg32], [main],, AC_MSG_ERROR(lib missing))
- AC_CHECK_LIB([winspool], [main],, AC_MSG_ERROR(lib missing))
- AC_CHECK_LIB([winmm], [main],, AC_MSG_ERROR(lib missing))
- AC_CHECK_LIB([shell32], [main],, AC_MSG_ERROR(lib missing))
- AC_CHECK_LIB([comctl32], [main],, AC_MSG_ERROR(lib missing))
- AC_CHECK_LIB([ole32], [main],, AC_MSG_ERROR(lib missing))
- AC_CHECK_LIB([oleaut32], [main],, AC_MSG_ERROR(lib missing))
- AC_CHECK_LIB([uuid], [main],, AC_MSG_ERROR(lib missing))
- AC_CHECK_LIB([rpcrt4], [main],, AC_MSG_ERROR(lib missing))
- AC_CHECK_LIB([advapi32], [main],, AC_MSG_ERROR(lib missing))
- AC_CHECK_LIB([ws2_32], [main],, AC_MSG_ERROR(lib missing))
- AC_CHECK_LIB([mswsock], [main],, AC_MSG_ERROR(lib missing))
- AC_CHECK_LIB([shlwapi], [main],, AC_MSG_ERROR(lib missing))
- AC_CHECK_LIB([iphlpapi], [main],, AC_MSG_ERROR(lib missing))
- AC_CHECK_LIB([crypt32], [main],, AC_MSG_ERROR(lib missing))
+ AC_CHECK_LIB([mingwthrd], [main],, AC_MSG_ERROR(libmingwthrd missing))
+ AC_CHECK_LIB([kernel32], [main],, AC_MSG_ERROR(libkernel32 missing))
+ AC_CHECK_LIB([user32], [main],, AC_MSG_ERROR(libuser32 missing))
+ AC_CHECK_LIB([gdi32], [main],, AC_MSG_ERROR(libgdi32 missing))
+ AC_CHECK_LIB([comdlg32], [main],, AC_MSG_ERROR(libcomdlg32 missing))
+ AC_CHECK_LIB([winspool], [main],, AC_MSG_ERROR(libwinspool missing))
+ AC_CHECK_LIB([winmm], [main],, AC_MSG_ERROR(libwinmm missing))
+ AC_CHECK_LIB([shell32], [main],, AC_MSG_ERROR(libshell32 missing))
+ AC_CHECK_LIB([comctl32], [main],, AC_MSG_ERROR(libcomctl32 missing))
+ AC_CHECK_LIB([ole32], [main],, AC_MSG_ERROR(libole32 missing))
+ AC_CHECK_LIB([oleaut32], [main],, AC_MSG_ERROR(liboleaut32 missing))
+ AC_CHECK_LIB([uuid], [main],, AC_MSG_ERROR(libuuid missing))
+ AC_CHECK_LIB([rpcrt4], [main],, AC_MSG_ERROR(librpcrt4 missing))
+ AC_CHECK_LIB([advapi32], [main],, AC_MSG_ERROR(libadvapi32 missing))
+ AC_CHECK_LIB([ws2_32], [main],, AC_MSG_ERROR(libws2_32 missing))
+ AC_CHECK_LIB([mswsock], [main],, AC_MSG_ERROR(libmswsock missing))
+ AC_CHECK_LIB([shlwapi], [main],, AC_MSG_ERROR(libshlwapi missing))
+ AC_CHECK_LIB([iphlpapi], [main],, AC_MSG_ERROR(libiphlpapi missing))
+ AC_CHECK_LIB([crypt32], [main],, AC_MSG_ERROR(libcrypt32 missing))
# -static is interpreted by libtool, where it has a different meaning.
# In libtool-speak, it's -all-static.
@@ -620,7 +625,7 @@ if test x$use_glibc_compat != xno; then
#glibc absorbed clock_gettime in 2.17. librt (its previous location) is safe to link
#in anyway for back-compat.
- AC_CHECK_LIB([rt],[clock_gettime],, AC_MSG_ERROR(lib missing))
+ AC_CHECK_LIB([rt],[clock_gettime],, AC_MSG_ERROR(librt missing))
#__fdelt_chk's params and return type have changed from long unsigned int to long int.
# See which one is present here.
@@ -682,7 +687,7 @@ if test x$use_hardening != xno; then
case $host in
*mingw*)
- AC_CHECK_LIB([ssp], [main],, AC_MSG_ERROR(lib missing))
+ AC_CHECK_LIB([ssp], [main],, AC_MSG_ERROR(libssp missing))
;;
esac
fi
@@ -833,7 +838,7 @@ fi
BITCOIN_QT_INIT
dnl sets $bitcoin_enable_qt, $bitcoin_enable_qt_test, $bitcoin_enable_qt_dbus
-BITCOIN_QT_CONFIGURE([$use_pkgconfig], [qt5])
+BITCOIN_QT_CONFIGURE([$use_pkgconfig])
if test x$build_bitcoin_utils$build_bitcoind$bitcoin_enable_qt$use_tests$use_bench = xnonononono; then
use_boost=no
@@ -1418,7 +1423,6 @@ echo "Options used to compile and link:"
echo " with wallet = $enable_wallet"
echo " with gui / qt = $bitcoin_enable_qt"
if test x$bitcoin_enable_qt != xno; then
- echo " qt version = $bitcoin_qt_got_major_vers"
echo " with qr = $use_qr"
fi
echo " with zmq = $use_zmq"
diff --git a/contrib/devtools/circular-dependencies.py b/contrib/devtools/circular-dependencies.py
index d544d5c371..abfa5ed5ae 100755
--- a/contrib/devtools/circular-dependencies.py
+++ b/contrib/devtools/circular-dependencies.py
@@ -37,7 +37,7 @@ for arg in sys.argv[1:]:
# TODO: implement support for multiple include directories
for arg in sorted(files.keys()):
module = files[arg]
- with open(arg, 'r') as f:
+ with open(arg, 'r', encoding="utf8") as f:
for line in f:
match = RE.match(line)
if match:
diff --git a/contrib/devtools/clang-format-diff.py b/contrib/devtools/clang-format-diff.py
index 5402870fba..77e845a9b4 100755
--- a/contrib/devtools/clang-format-diff.py
+++ b/contrib/devtools/clang-format-diff.py
@@ -152,7 +152,7 @@ def main():
sys.exit(p.returncode)
if not args.i:
- with open(filename) as f:
+ with open(filename, encoding="utf8") as f:
code = f.readlines()
formatted_code = io.StringIO(stdout).readlines()
diff = difflib.unified_diff(code, formatted_code,
diff --git a/contrib/devtools/copyright_header.py b/contrib/devtools/copyright_header.py
index 82d3c19683..da7d74bdc4 100755
--- a/contrib/devtools/copyright_header.py
+++ b/contrib/devtools/copyright_header.py
@@ -146,7 +146,7 @@ def file_has_without_c_style_copyright_for_holder(contents, holder_name):
################################################################################
def read_file(filename):
- return open(os.path.abspath(filename), 'r').read()
+ return open(os.path.abspath(filename), 'r', encoding="utf8").read()
def gather_file_info(filename):
info = {}
@@ -325,13 +325,13 @@ def get_most_recent_git_change_year(filename):
################################################################################
def read_file_lines(filename):
- f = open(os.path.abspath(filename), 'r')
+ f = open(os.path.abspath(filename), 'r', encoding="utf8")
file_lines = f.readlines()
f.close()
return file_lines
def write_file_lines(filename, file_lines):
- f = open(os.path.abspath(filename), 'w')
+ f = open(os.path.abspath(filename), 'w', encoding="utf8")
f.write(''.join(file_lines))
f.close()
diff --git a/contrib/devtools/gen-manpages.sh b/contrib/devtools/gen-manpages.sh
index 27c80548c1..b5de5a395f 100755
--- a/contrib/devtools/gen-manpages.sh
+++ b/contrib/devtools/gen-manpages.sh
@@ -1,5 +1,6 @@
-#!/bin/bash
+#!/usr/bin/env bash
+export LC_ALL=C
TOPDIR=${TOPDIR:-$(git rev-parse --show-toplevel)}
BUILDDIR=${BUILDDIR:-$TOPDIR}
diff --git a/contrib/devtools/github-merge.py b/contrib/devtools/github-merge.py
index 187ef75fb7..4e90f85f50 100755
--- a/contrib/devtools/github-merge.py
+++ b/contrib/devtools/github-merge.py
@@ -191,7 +191,7 @@ def main():
merge_branch = 'pull/'+pull+'/merge'
local_merge_branch = 'pull/'+pull+'/local-merge'
- devnull = open(os.devnull,'w')
+ devnull = open(os.devnull, 'w', encoding="utf8")
try:
subprocess.check_call([GIT,'checkout','-q',branch])
except subprocess.CalledProcessError:
diff --git a/contrib/devtools/test-security-check.py b/contrib/devtools/test-security-check.py
index 307e057736..9b6d6bf665 100755
--- a/contrib/devtools/test-security-check.py
+++ b/contrib/devtools/test-security-check.py
@@ -9,7 +9,7 @@ import subprocess
import unittest
def write_testcode(filename):
- with open(filename, 'w') as f:
+ with open(filename, 'w', encoding="utf8") as f:
f.write('''
#include <stdio.h>
int main()
diff --git a/contrib/devtools/update-translations.py b/contrib/devtools/update-translations.py
index b36e6968bf..f0098cfcdf 100755
--- a/contrib/devtools/update-translations.py
+++ b/contrib/devtools/update-translations.py
@@ -30,6 +30,8 @@ SOURCE_LANG = 'bitcoin_en.ts'
LOCALE_DIR = 'src/qt/locale'
# Minimum number of messages for translation to be considered at all
MIN_NUM_MESSAGES = 10
+# Regexp to check for Bitcoin addresses
+ADDRESS_REGEXP = re.compile('([13]|bc1)[a-zA-Z0-9]{30,}')
def check_at_repository_root():
if not os.path.exists('.git'):
@@ -122,6 +124,12 @@ def escape_cdata(text):
text = text.replace('"', '&quot;')
return text
+def contains_bitcoin_addr(text, errors):
+ if text != None and ADDRESS_REGEXP.search(text) != None:
+ errors.append('Translation "%s" contains a bitcoin address. This will be removed.' % (text))
+ return True
+ return False
+
def postprocess_translations(reduce_diff_hacks=False):
print('Checking and postprocessing...')
@@ -160,7 +168,7 @@ def postprocess_translations(reduce_diff_hacks=False):
if translation is None:
continue
errors = []
- valid = check_format_specifiers(source, translation, errors, numerus)
+ valid = check_format_specifiers(source, translation, errors, numerus) and not contains_bitcoin_addr(translation, errors)
for error in errors:
print('%s: %s' % (filename, error))
diff --git a/contrib/filter-lcov.py b/contrib/filter-lcov.py
index 299377d691..df1db76e92 100755
--- a/contrib/filter-lcov.py
+++ b/contrib/filter-lcov.py
@@ -13,8 +13,8 @@ pattern = args.pattern
outfile = args.outfile
in_remove = False
-with open(tracefile, 'r') as f:
- with open(outfile, 'w') as wf:
+with open(tracefile, 'r', encoding="utf8") as f:
+ with open(outfile, 'w', encoding="utf8") as wf:
for line in f:
for p in pattern:
if line.startswith("SF:") and p in line:
diff --git a/contrib/gitian-build.sh b/contrib/gitian-build.sh
index 5a925f2282..05e7d6f4c6 100755
--- a/contrib/gitian-build.sh
+++ b/contrib/gitian-build.sh
@@ -1,8 +1,9 @@
-#!/bin/bash
+#!/usr/bin/env bash
# Copyright (c) 2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+export LC_ALL=C
# What to do
sign=false
verify=false
diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml
index 3e9ee0495a..f78eea73a3 100644
--- a/contrib/gitian-descriptors/gitian-linux.yml
+++ b/contrib/gitian-descriptors/gitian-linux.yml
@@ -56,7 +56,7 @@ script: |
function create_global_faketime_wrappers {
for prog in ${FAKETIME_PROGS}; do
- echo '#!/bin/bash' > ${WRAP_DIR}/${prog}
+ echo '#!/usr/bin/env bash' > ${WRAP_DIR}/${prog}
echo "REAL=\`which -a ${prog} | grep -v ${WRAP_DIR}/${prog} | head -1\`" >> ${WRAP_DIR}/${prog}
echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${prog}
echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${prog}
@@ -68,7 +68,7 @@ script: |
function create_per-host_faketime_wrappers {
for i in $HOSTS; do
for prog in ${FAKETIME_HOST_PROGS}; do
- echo '#!/bin/bash' > ${WRAP_DIR}/${i}-${prog}
+ echo '#!/usr/bin/env bash' > ${WRAP_DIR}/${i}-${prog}
echo "REAL=\`which -a ${i}-${prog} | grep -v ${WRAP_DIR}/${i}-${prog} | head -1\`" >> ${WRAP_DIR}/${i}-${prog}
echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${i}-${prog}
echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${i}-${prog}
@@ -98,7 +98,7 @@ script: |
for prog in gcc g++; do
rm -f ${WRAP_DIR}/${prog}
cat << EOF > ${WRAP_DIR}/${prog}
- #!/bin/bash
+ #!/usr/bin/env bash
REAL="`which -a ${prog} | grep -v ${WRAP_DIR}/${prog} | head -1`"
for var in "\$@"
do
diff --git a/contrib/gitian-descriptors/gitian-osx-signer.yml b/contrib/gitian-descriptors/gitian-osx-signer.yml
index f6e9414ab1..b5c863bb14 100644
--- a/contrib/gitian-descriptors/gitian-osx-signer.yml
+++ b/contrib/gitian-descriptors/gitian-osx-signer.yml
@@ -19,7 +19,7 @@ script: |
# Create global faketime wrappers
for prog in ${FAKETIME_PROGS}; do
- echo '#!/bin/bash' > ${WRAP_DIR}/${prog}
+ echo '#!/usr/bin/env bash' > ${WRAP_DIR}/${prog}
echo "REAL=\`which -a ${prog} | grep -v ${WRAP_DIR}/${prog} | head -1\`" >> ${WRAP_DIR}/${prog}
echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${prog}
echo "export FAKETIME=\"${REFERENCE_DATETIME}\"" >> ${WRAP_DIR}/${prog}
diff --git a/contrib/gitian-descriptors/gitian-osx.yml b/contrib/gitian-descriptors/gitian-osx.yml
index a84dce3e3a..2cc62d4ce7 100644
--- a/contrib/gitian-descriptors/gitian-osx.yml
+++ b/contrib/gitian-descriptors/gitian-osx.yml
@@ -55,7 +55,7 @@ script: |
function create_global_faketime_wrappers {
for prog in ${FAKETIME_PROGS}; do
- echo '#!/bin/bash' > ${WRAP_DIR}/${prog}
+ echo '#!/usr/bin/env bash' > ${WRAP_DIR}/${prog}
echo "REAL=\`which -a ${prog} | grep -v ${WRAP_DIR}/${prog} | head -1\`" >> ${WRAP_DIR}/${prog}
echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${prog}
echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${prog}
@@ -67,7 +67,7 @@ script: |
function create_per-host_faketime_wrappers {
for i in $HOSTS; do
for prog in ${FAKETIME_HOST_PROGS}; do
- echo '#!/bin/bash' > ${WRAP_DIR}/${i}-${prog}
+ echo '#!/usr/bin/env bash' > ${WRAP_DIR}/${i}-${prog}
echo "REAL=\`which -a ${i}-${prog} | grep -v ${WRAP_DIR}/${i}-${prog} | head -1\`" >> ${WRAP_DIR}/${i}-${prog}
echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${i}-${prog}
echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${i}-${prog}
diff --git a/contrib/gitian-descriptors/gitian-win.yml b/contrib/gitian-descriptors/gitian-win.yml
index 8a87d91754..f6eb1815f6 100644
--- a/contrib/gitian-descriptors/gitian-win.yml
+++ b/contrib/gitian-descriptors/gitian-win.yml
@@ -48,7 +48,7 @@ script: |
function create_global_faketime_wrappers {
for prog in ${FAKETIME_PROGS}; do
- echo '#!/bin/bash' > ${WRAP_DIR}/${prog}
+ echo '#!/usr/bin/env bash' > ${WRAP_DIR}/${prog}
echo "REAL=\`which -a ${prog} | grep -v ${WRAP_DIR}/${prog} | head -1\`" >> ${WRAP_DIR}/${prog}
echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${prog}
echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${prog}
@@ -60,7 +60,7 @@ script: |
function create_per-host_faketime_wrappers {
for i in $HOSTS; do
for prog in ${FAKETIME_HOST_PROGS}; do
- echo '#!/bin/bash' > ${WRAP_DIR}/${i}-${prog}
+ echo '#!/usr/bin/env bash' > ${WRAP_DIR}/${i}-${prog}
echo "REAL=\`which -a ${i}-${prog} | grep -v ${WRAP_DIR}/${i}-${prog} | head -1\`" >> ${WRAP_DIR}/${i}-${prog}
echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${i}-${prog}
echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${i}-${prog}
@@ -76,14 +76,14 @@ script: |
for i in $HOSTS; do
mkdir -p ${WRAP_DIR}/${i}
for prog in collect2; do
- echo '#!/bin/bash' > ${WRAP_DIR}/${i}/${prog}
+ echo '#!/usr/bin/env bash' > ${WRAP_DIR}/${i}/${prog}
REAL=$(${i}-gcc -print-prog-name=${prog})
echo "export MALLOC_PERTURB_=255" >> ${WRAP_DIR}/${i}/${prog}
echo "${REAL} \$@" >> $WRAP_DIR/${i}/${prog}
chmod +x ${WRAP_DIR}/${i}/${prog}
done
for prog in gcc g++; do
- echo '#!/bin/bash' > ${WRAP_DIR}/${i}-${prog}
+ echo '#!/usr/bin/env bash' > ${WRAP_DIR}/${i}-${prog}
echo "REAL=\`which -a ${i}-${prog} | grep -v ${WRAP_DIR}/${i}-${prog} | head -1\`" >> ${WRAP_DIR}/${i}-${prog}
echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${i}-${prog}
echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${i}-${prog}
diff --git a/contrib/init/bitcoind.init b/contrib/init/bitcoind.init
index db5061874b..0c95baf3a1 100644
--- a/contrib/init/bitcoind.init
+++ b/contrib/init/bitcoind.init
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
#
# bitcoind The bitcoin core server.
#
diff --git a/contrib/install_db4.sh b/contrib/install_db4.sh
index d315a7d3b7..4f74e67f2f 100755
--- a/contrib/install_db4.sh
+++ b/contrib/install_db4.sh
@@ -2,6 +2,7 @@
# Install libdb4.8 (Berkeley DB).
+export LC_ALL=C
set -e
if [ -z "${1}" ]; then
diff --git a/contrib/linearize/linearize-data.py b/contrib/linearize/linearize-data.py
index f8aea27342..b501388fd2 100755
--- a/contrib/linearize/linearize-data.py
+++ b/contrib/linearize/linearize-data.py
@@ -75,7 +75,7 @@ def get_blk_dt(blk_hdr):
# When getting the list of block hashes, undo any byte reversals.
def get_block_hashes(settings):
blkindex = []
- f = open(settings['hashlist'], "r")
+ f = open(settings['hashlist'], "r", encoding="utf8")
for line in f:
line = line.rstrip()
if settings['rev_hash_bytes'] == 'true':
@@ -261,7 +261,7 @@ if __name__ == '__main__':
print("Usage: linearize-data.py CONFIG-FILE")
sys.exit(1)
- f = open(sys.argv[1])
+ f = open(sys.argv[1], encoding="utf8")
for line in f:
# skip comment lines
m = re.search('^\s*#', line)
diff --git a/contrib/linearize/linearize-hashes.py b/contrib/linearize/linearize-hashes.py
index 8e1266ae0b..bfd2171947 100755
--- a/contrib/linearize/linearize-hashes.py
+++ b/contrib/linearize/linearize-hashes.py
@@ -96,7 +96,7 @@ def get_block_hashes(settings, max_blocks_per_call=10000):
def get_rpc_cookie():
# Open the cookie file
- with open(os.path.join(os.path.expanduser(settings['datadir']), '.cookie'), 'r') as f:
+ with open(os.path.join(os.path.expanduser(settings['datadir']), '.cookie'), 'r', encoding="ascii") as f:
combined = f.readline()
combined_split = combined.split(":")
settings['rpcuser'] = combined_split[0]
@@ -107,7 +107,7 @@ if __name__ == '__main__':
print("Usage: linearize-hashes.py CONFIG-FILE")
sys.exit(1)
- f = open(sys.argv[1])
+ f = open(sys.argv[1], encoding="utf8")
for line in f:
# skip comment lines
m = re.search('^\s*#', line)
diff --git a/contrib/macdeploy/detached-sig-apply.sh b/contrib/macdeploy/detached-sig-apply.sh
index 91674a92e6..f8503e4de8 100755
--- a/contrib/macdeploy/detached-sig-apply.sh
+++ b/contrib/macdeploy/detached-sig-apply.sh
@@ -3,6 +3,7 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+export LC_ALL=C
set -e
UNSIGNED="$1"
diff --git a/contrib/macdeploy/detached-sig-create.sh b/contrib/macdeploy/detached-sig-create.sh
index 3379a4599c..5281ebcc47 100755
--- a/contrib/macdeploy/detached-sig-create.sh
+++ b/contrib/macdeploy/detached-sig-create.sh
@@ -3,6 +3,7 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+export LC_ALL=C
set -e
ROOTDIR=dist
diff --git a/contrib/macdeploy/extract-osx-sdk.sh b/contrib/macdeploy/extract-osx-sdk.sh
index ff9fbd58df..4c175156f4 100755
--- a/contrib/macdeploy/extract-osx-sdk.sh
+++ b/contrib/macdeploy/extract-osx-sdk.sh
@@ -1,8 +1,9 @@
-#!/bin/bash
+#!/usr/bin/env bash
# Copyright (c) 2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+export LC_ALL=C
set -e
INPUTFILE="Xcode_7.3.1.dmg"
diff --git a/contrib/qos/tc.sh b/contrib/qos/tc.sh
index 0d1dd65b4f..738ea70dbe 100644
--- a/contrib/qos/tc.sh
+++ b/contrib/qos/tc.sh
@@ -2,6 +2,7 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+export LC_ALL=C
#network interface on which to limit traffic
IF="eth0"
#limit of the network interface in question
diff --git a/contrib/seeds/generate-seeds.py b/contrib/seeds/generate-seeds.py
index ace7d3534f..fe7cd1d597 100755
--- a/contrib/seeds/generate-seeds.py
+++ b/contrib/seeds/generate-seeds.py
@@ -127,10 +127,10 @@ def main():
g.write(' * Each line contains a 16-byte IPv6 address and a port.\n')
g.write(' * IPv4 as well as onion addresses are wrapped inside an IPv6 address accordingly.\n')
g.write(' */\n')
- with open(os.path.join(indir,'nodes_main.txt'),'r') as f:
+ with open(os.path.join(indir,'nodes_main.txt'), 'r', encoding="utf8") as f:
process_nodes(g, f, 'pnSeed6_main', 8333)
g.write('\n')
- with open(os.path.join(indir,'nodes_test.txt'),'r') as f:
+ with open(os.path.join(indir,'nodes_test.txt'), 'r', encoding="utf8") as f:
process_nodes(g, f, 'pnSeed6_test', 18333)
g.write('#endif // BITCOIN_CHAINPARAMSSEEDS_H\n')
diff --git a/contrib/verify-commits/README.md b/contrib/verify-commits/README.md
index fa492fdd27..aa805ad1b9 100644
--- a/contrib/verify-commits/README.md
+++ b/contrib/verify-commits/README.md
@@ -7,18 +7,18 @@ are PGP signed (nearly always merge commits), as well as a script to verify
commits against a trusted keys list.
-Using verify-commits.sh safely
+Using verify-commits.py safely
------------------------------
Remember that you can't use an untrusted script to verify itself. This means
-that checking out code, then running `verify-commits.sh` against `HEAD` is
-_not_ safe, because the version of `verify-commits.sh` that you just ran could
+that checking out code, then running `verify-commits.py` against `HEAD` is
+_not_ safe, because the version of `verify-commits.py` that you just ran could
be backdoored. Instead, you need to use a trusted version of verify-commits
prior to checkout to make sure you're checking out only code signed by trusted
keys:
git fetch origin && \
- ./contrib/verify-commits/verify-commits.sh origin/master && \
+ ./contrib/verify-commits/verify-commits.py origin/master && \
git checkout origin/master
Note that the above isn't a good UI/UX yet, and needs significant improvements
@@ -42,6 +42,6 @@ said key. In order to avoid bumping the root-of-trust `trusted-git-root`
file, individual commits which were signed by such a key can be added to the
`allow-revsig-commits` file. That way, the PGP signatures are still verified
but no new commits can be signed by any expired/revoked key. To easily build a
-list of commits which need to be added, verify-commits.sh can be edited to test
+list of commits which need to be added, verify-commits.py can be edited to test
each commit with BITCOIN_VERIFY_COMMITS_ALLOW_REVSIG set to both 1 and 0, and
those which need it set to 1 printed.
diff --git a/contrib/verify-commits/allow-incorrect-sha512-commits b/contrib/verify-commits/allow-incorrect-sha512-commits
new file mode 100644
index 0000000000..c572806f26
--- /dev/null
+++ b/contrib/verify-commits/allow-incorrect-sha512-commits
@@ -0,0 +1,2 @@
+f8feaa4636260b599294c7285bcf1c8b7737f74e
+8040ae6fc576e9504186f2ae3ff2c8125de1095c
diff --git a/contrib/verify-commits/allow-unclean-merge-commits b/contrib/verify-commits/allow-unclean-merge-commits
new file mode 100644
index 0000000000..7aab274b9a
--- /dev/null
+++ b/contrib/verify-commits/allow-unclean-merge-commits
@@ -0,0 +1,4 @@
+6052d509105790a26b3ad5df43dd61e7f1b24a12
+3798e5de334c3deb5f71302b782f6b8fbd5087f1
+326ffed09bfcc209a2efd6a2ebc69edf6bd200b5
+97d83739db0631be5d4ba86af3616014652c00ec
diff --git a/contrib/verify-commits/gpg.sh b/contrib/verify-commits/gpg.sh
index 8f3e4b8063..7a10ba7d7d 100755
--- a/contrib/verify-commits/gpg.sh
+++ b/contrib/verify-commits/gpg.sh
@@ -3,6 +3,7 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+export LC_ALL=C
INPUT=$(cat /dev/stdin)
VALID=false
REVSIG=false
@@ -57,7 +58,7 @@ if ! $VALID; then
exit 1
fi
if $VALID && $REVSIG; then
- printf '%s\n' "$INPUT" | gpg --trust-model always "$@" 2>/dev/null | grep "\[GNUPG:\] \(NEWSIG\|SIG_ID\|VALIDSIG\)"
+ printf '%s\n' "$INPUT" | gpg --trust-model always "$@" 2>/dev/null | grep "^\[GNUPG:\] \(NEWSIG\|SIG_ID\|VALIDSIG\)"
echo "$GOODREVSIG"
else
printf '%s\n' "$INPUT" | gpg --trust-model always "$@" 2>/dev/null
diff --git a/contrib/verify-commits/pre-push-hook.sh b/contrib/verify-commits/pre-push-hook.sh
index c21febb9e9..4db4a90853 100755
--- a/contrib/verify-commits/pre-push-hook.sh
+++ b/contrib/verify-commits/pre-push-hook.sh
@@ -1,8 +1,9 @@
-#!/bin/bash
+#!/usr/bin/env bash
# Copyright (c) 2014-2015 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+export LC_ALL=C
if ! [[ "$2" =~ ^(git@)?(www.)?github.com(:|/)bitcoin/bitcoin(.git)?$ ]]; then
exit 0
fi
@@ -12,9 +13,9 @@ while read LINE; do
if [ "$4" != "refs/heads/master" ]; then
continue
fi
- if ! ./contrib/verify-commits/verify-commits.sh $3 > /dev/null 2>&1; then
+ if ! ./contrib/verify-commits/verify-commits.py $3 > /dev/null 2>&1; then
echo "ERROR: A commit is not signed, can't push"
- ./contrib/verify-commits/verify-commits.sh
+ ./contrib/verify-commits/verify-commits.py
exit 1
fi
done < /dev/stdin
diff --git a/contrib/verify-commits/verify-commits.py b/contrib/verify-commits/verify-commits.py
new file mode 100755
index 0000000000..a9e4977715
--- /dev/null
+++ b/contrib/verify-commits/verify-commits.py
@@ -0,0 +1,155 @@
+#!/usr/bin/env python3
+# Copyright (c) 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.
+"""Verify commits against a trusted keys list."""
+import argparse
+import hashlib
+import os
+import subprocess
+import sys
+import time
+
+GIT = os.getenv('GIT', 'git')
+
+def tree_sha512sum(commit='HEAD'):
+ """Calculate the Tree-sha512 for the commit.
+
+ This is copied from github-merge.py."""
+
+ # request metadata for entire tree, recursively
+ files = []
+ blob_by_name = {}
+ for line in subprocess.check_output([GIT, 'ls-tree', '--full-tree', '-r', commit]).splitlines():
+ name_sep = line.index(b'\t')
+ metadata = line[:name_sep].split() # perms, 'blob', blobid
+ assert metadata[1] == b'blob'
+ name = line[name_sep + 1:]
+ files.append(name)
+ blob_by_name[name] = metadata[2]
+
+ files.sort()
+ # open connection to git-cat-file in batch mode to request data for all blobs
+ # this is much faster than launching it per file
+ p = subprocess.Popen([GIT, 'cat-file', '--batch'], stdout=subprocess.PIPE, stdin=subprocess.PIPE)
+ overall = hashlib.sha512()
+ for f in files:
+ blob = blob_by_name[f]
+ # request blob
+ p.stdin.write(blob + b'\n')
+ p.stdin.flush()
+ # read header: blob, "blob", size
+ reply = p.stdout.readline().split()
+ assert reply[0] == blob and reply[1] == b'blob'
+ size = int(reply[2])
+ # hash the blob data
+ intern = hashlib.sha512()
+ ptr = 0
+ while ptr < size:
+ bs = min(65536, size - ptr)
+ piece = p.stdout.read(bs)
+ if len(piece) == bs:
+ intern.update(piece)
+ else:
+ raise IOError('Premature EOF reading git cat-file output')
+ ptr += bs
+ dig = intern.hexdigest()
+ assert p.stdout.read(1) == b'\n' # ignore LF that follows blob data
+ # update overall hash with file hash
+ overall.update(dig.encode("utf-8"))
+ overall.update(" ".encode("utf-8"))
+ overall.update(f)
+ overall.update("\n".encode("utf-8"))
+ p.stdin.close()
+ if p.wait():
+ raise IOError('Non-zero return value executing git cat-file')
+ return overall.hexdigest()
+
+def main():
+ # Parse arguments
+ parser = argparse.ArgumentParser(usage='%(prog)s [options] [commit id]')
+ parser.add_argument('--disable-tree-check', action='store_false', dest='verify_tree', help='disable SHA-512 tree check')
+ parser.add_argument('--clean-merge', type=float, dest='clean_merge', default=float('inf'), help='Only check clean merge after <NUMBER> days ago (default: %(default)s)', metavar='NUMBER')
+ parser.add_argument('commit', nargs='?', default='HEAD', help='Check clean merge up to commit <commit>')
+ args = parser.parse_args()
+
+ # get directory of this program and read data files
+ dirname = os.path.dirname(os.path.abspath(__file__))
+ print("Using verify-commits data from " + dirname)
+ verified_root = open(dirname + "/trusted-git-root", "r", encoding="utf8").read().splitlines()[0]
+ verified_sha512_root = open(dirname + "/trusted-sha512-root-commit", "r", encoding="utf8").read().splitlines()[0]
+ revsig_allowed = open(dirname + "/allow-revsig-commits", "r", encoding="utf-8").read().splitlines()
+ unclean_merge_allowed = open(dirname + "/allow-unclean-merge-commits", "r", encoding="utf-8").read().splitlines()
+ incorrect_sha512_allowed = open(dirname + "/allow-incorrect-sha512-commits", "r", encoding="utf-8").read().splitlines()
+
+ # Set commit and branch and set variables
+ current_commit = args.commit
+ if ' ' in current_commit:
+ print("Commit must not contain spaces", file=sys.stderr)
+ sys.exit(1)
+ verify_tree = args.verify_tree
+ no_sha1 = True
+ prev_commit = ""
+ initial_commit = current_commit
+ branch = subprocess.check_output([GIT, 'show', '-s', '--format=%H', initial_commit], universal_newlines=True).splitlines()[0]
+
+ # Iterate through commits
+ while True:
+ if current_commit == verified_root:
+ print('There is a valid path from "{}" to {} where all commits are signed!'.format(initial_commit, verified_root))
+ sys.exit(0)
+ if current_commit == verified_sha512_root:
+ if verify_tree:
+ print("All Tree-SHA512s matched up to {}".format(verified_sha512_root), file=sys.stderr)
+ verify_tree = False
+ no_sha1 = False
+
+ os.environ['BITCOIN_VERIFY_COMMITS_ALLOW_SHA1'] = "0" if no_sha1 else "1"
+ os.environ['BITCOIN_VERIFY_COMMITS_ALLOW_REVSIG'] = "1" if current_commit in revsig_allowed else "0"
+
+ # Check that the commit (and parents) was signed with a trusted key
+ if subprocess.call([GIT, '-c', 'gpg.program={}/gpg.sh'.format(dirname), 'verify-commit', current_commit], stdout=subprocess.DEVNULL):
+ if prev_commit != "":
+ print("No parent of {} was signed with a trusted key!".format(prev_commit), file=sys.stderr)
+ print("Parents are:", file=sys.stderr)
+ parents = subprocess.check_output([GIT, 'show', '-s', '--format=format:%P', prev_commit], universal_newlines=True).splitlines()[0].split(' ')
+ for parent in parents:
+ subprocess.call([GIT, 'show', '-s', parent], stdout=sys.stderr)
+ else:
+ print("{} was not signed with a trusted key!".format(current_commit), file=sys.stderr)
+ sys.exit(1)
+
+ # Check the Tree-SHA512
+ if (verify_tree or prev_commit == "") and current_commit not in incorrect_sha512_allowed:
+ tree_hash = tree_sha512sum(current_commit)
+ if ("Tree-SHA512: {}".format(tree_hash)) not in subprocess.check_output([GIT, 'show', '-s', '--format=format:%B', current_commit], universal_newlines=True).splitlines():
+ print("Tree-SHA512 did not match for commit " + current_commit, file=sys.stderr)
+ sys.exit(1)
+
+ # Merge commits should only have two parents
+ parents = subprocess.check_output([GIT, 'show', '-s', '--format=format:%P', current_commit], universal_newlines=True).splitlines()[0].split(' ')
+ if len(parents) > 2:
+ print("Commit {} is an octopus merge".format(current_commit), file=sys.stderr)
+ sys.exit(1)
+
+ # Check that the merge commit is clean
+ commit_time = int(subprocess.check_output([GIT, 'show', '-s', '--format=format:%ct', current_commit], universal_newlines=True).splitlines()[0])
+ check_merge = commit_time > time.time() - args.clean_merge * 24 * 60 * 60 # Only check commits in clean_merge days
+ allow_unclean = current_commit in unclean_merge_allowed
+ if len(parents) == 2 and check_merge and not allow_unclean:
+ current_tree = subprocess.check_output([GIT, 'show', '--format=%T', current_commit], universal_newlines=True).splitlines()[0]
+ subprocess.call([GIT, 'checkout', '--force', '--quiet', parents[0]])
+ subprocess.call([GIT, 'merge', '--no-ff', '--quiet', parents[1]], stdout=subprocess.DEVNULL)
+ recreated_tree = subprocess.check_output([GIT, 'show', '--format=format:%T', 'HEAD'], universal_newlines=True).splitlines()[0]
+ if current_tree != recreated_tree:
+ print("Merge commit {} is not clean".format(current_commit), file=sys.stderr)
+ subprocess.call([GIT, 'diff', current_commit])
+ subprocess.call([GIT, 'checkout', '--force', '--quiet', branch])
+ sys.exit(1)
+ subprocess.call([GIT, 'checkout', '--force', '--quiet', branch])
+
+ prev_commit = current_commit
+ current_commit = parents[0]
+
+if __name__ == '__main__':
+ main()
diff --git a/contrib/verify-commits/verify-commits.sh b/contrib/verify-commits/verify-commits.sh
deleted file mode 100755
index 6415eea4d5..0000000000
--- a/contrib/verify-commits/verify-commits.sh
+++ /dev/null
@@ -1,153 +0,0 @@
-#!/bin/sh
-# Copyright (c) 2014-2016 The Bitcoin Core developers
-# Distributed under the MIT software license, see the accompanying
-# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-DIR=$(dirname "$0")
-[ "/${DIR#/}" != "$DIR" ] && DIR=$(dirname "$(pwd)/$0")
-
-echo "Using verify-commits data from ${DIR}"
-
-VERIFIED_ROOT=$(cat "${DIR}/trusted-git-root")
-VERIFIED_SHA512_ROOT=$(cat "${DIR}/trusted-sha512-root-commit")
-REVSIG_ALLOWED=$(cat "${DIR}/allow-revsig-commits")
-
-HAVE_GNU_SHA512=1
-[ ! -x "$(which sha512sum)" ] && HAVE_GNU_SHA512=0
-
-if [ x"$1" = "x" ]; then
- CURRENT_COMMIT="HEAD"
-else
- CURRENT_COMMIT="$1"
-fi
-
-if [ "${CURRENT_COMMIT#* }" != "$CURRENT_COMMIT" ]; then
- echo "Commit must not contain spaces?" > /dev/stderr
- exit 1
-fi
-
-VERIFY_TREE=0
-if [ x"$2" = "x--tree-checks" ]; then
- VERIFY_TREE=1
-fi
-
-NO_SHA1=1
-PREV_COMMIT=""
-INITIAL_COMMIT="${CURRENT_COMMIT}"
-
-BRANCH="$(git rev-parse --abbrev-ref HEAD)"
-
-while true; do
- if [ "$CURRENT_COMMIT" = $VERIFIED_ROOT ]; then
- echo "There is a valid path from \"$INITIAL_COMMIT\" to $VERIFIED_ROOT where all commits are signed!"
- exit 0
- fi
-
- if [ "$CURRENT_COMMIT" = $VERIFIED_SHA512_ROOT ]; then
- if [ "$VERIFY_TREE" = "1" ]; then
- echo "All Tree-SHA512s matched up to $VERIFIED_SHA512_ROOT" > /dev/stderr
- fi
- VERIFY_TREE=0
- NO_SHA1=0
- fi
-
- if [ "$NO_SHA1" = "1" ]; then
- export BITCOIN_VERIFY_COMMITS_ALLOW_SHA1=0
- else
- export BITCOIN_VERIFY_COMMITS_ALLOW_SHA1=1
- fi
-
- if [ "${REVSIG_ALLOWED#*$CURRENT_COMMIT}" != "$REVSIG_ALLOWED" ]; then
- export BITCOIN_VERIFY_COMMITS_ALLOW_REVSIG=1
- else
- export BITCOIN_VERIFY_COMMITS_ALLOW_REVSIG=0
- fi
-
- if ! git -c "gpg.program=${DIR}/gpg.sh" verify-commit "$CURRENT_COMMIT" > /dev/null; then
- if [ "$PREV_COMMIT" != "" ]; then
- echo "No parent of $PREV_COMMIT was signed with a trusted key!" > /dev/stderr
- echo "Parents are:" > /dev/stderr
- PARENTS=$(git show -s --format=format:%P $PREV_COMMIT)
- for PARENT in $PARENTS; do
- git show -s $PARENT > /dev/stderr
- done
- else
- echo "$CURRENT_COMMIT was not signed with a trusted key!" > /dev/stderr
- fi
- exit 1
- fi
-
- # We always verify the top of the tree
- if [ "$VERIFY_TREE" = 1 -o "$PREV_COMMIT" = "" ]; then
- IFS_CACHE="$IFS"
- IFS='
-'
- for LINE in $(git ls-tree --full-tree -r "$CURRENT_COMMIT"); do
- case "$LINE" in
- "12"*)
- echo "Repo contains symlinks" > /dev/stderr
- IFS="$IFS_CACHE"
- exit 1
- ;;
- esac
- done
- IFS="$IFS_CACHE"
-
- FILE_HASHES=""
- for FILE in $(git ls-tree --full-tree -r --name-only "$CURRENT_COMMIT" | LC_ALL=C sort); do
- if [ "$HAVE_GNU_SHA512" = 1 ]; then
- HASH=$(git cat-file blob "$CURRENT_COMMIT":"$FILE" | sha512sum | { read FIRST _; echo $FIRST; } )
- else
- HASH=$(git cat-file blob "$CURRENT_COMMIT":"$FILE" | shasum -a 512 | { read FIRST _; echo $FIRST; } )
- fi
- [ "$FILE_HASHES" != "" ] && FILE_HASHES="$FILE_HASHES"'
-'
- FILE_HASHES="$FILE_HASHES$HASH $FILE"
- done
-
- if [ "$HAVE_GNU_SHA512" = 1 ]; then
- TREE_HASH="$(echo "$FILE_HASHES" | sha512sum)"
- else
- TREE_HASH="$(echo "$FILE_HASHES" | shasum -a 512)"
- fi
- HASH_MATCHES=0
- MSG="$(git show -s --format=format:%B "$CURRENT_COMMIT" | tail -n1)"
-
- case "$MSG -" in
- "Tree-SHA512: $TREE_HASH")
- HASH_MATCHES=1;;
- esac
-
- if [ "$HASH_MATCHES" = "0" ]; then
- echo "Tree-SHA512 did not match for commit $CURRENT_COMMIT" > /dev/stderr
- exit 1
- fi
- fi
-
- PARENTS=$(git show -s --format=format:%P "$CURRENT_COMMIT")
- PARENT1=${PARENTS%% *}
- PARENT2=""
- if [ "x$PARENT1" != "x$PARENTS" ]; then
- PARENTX=${PARENTS#* }
- PARENT2=${PARENTX%% *}
- if [ "x$PARENT2" != "x$PARENTX" ]; then
- echo "Commit $CURRENT_COMMIT is an octopus merge" > /dev/stderr
- exit 1
- fi
- fi
- if [ "x$PARENT2" != "x" ]; then
- CURRENT_TREE="$(git show --format="%T" "$CURRENT_COMMIT")"
- git checkout --force --quiet "$PARENT1"
- git merge --no-ff --quiet "$PARENT2" >/dev/null
- RECREATED_TREE="$(git show --format="%T" HEAD)"
- if [ "$CURRENT_TREE" != "$RECREATED_TREE" ]; then
- echo "Merge commit $CURRENT_COMMIT is not clean" > /dev/stderr
- git diff "$CURRENT_COMMIT"
- git checkout --force --quiet "$BRANCH"
- exit 1
- fi
- git checkout --force --quiet "$BRANCH"
- fi
- PREV_COMMIT="$CURRENT_COMMIT"
- CURRENT_COMMIT="$PARENT1"
-done
diff --git a/contrib/verifybinaries/verify.sh b/contrib/verifybinaries/verify.sh
index e0266bf08a..fc7492ad3b 100755
--- a/contrib/verifybinaries/verify.sh
+++ b/contrib/verifybinaries/verify.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
# Copyright (c) 2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -11,6 +11,7 @@
### The script returns 0 if everything passes the checks. It returns 1 if either the
### signature check or the hash check doesn't pass. If an error occurs the return value is 2
+export LC_ALL=C
function clean_up {
for file in $*
do
diff --git a/contrib/windeploy/detached-sig-create.sh b/contrib/windeploy/detached-sig-create.sh
index bf4978d143..15f8108cf0 100755
--- a/contrib/windeploy/detached-sig-create.sh
+++ b/contrib/windeploy/detached-sig-create.sh
@@ -3,6 +3,7 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+export LC_ALL=C
if [ -z "$OSSLSIGNCODE" ]; then
OSSLSIGNCODE=osslsigncode
fi
diff --git a/doc/build-freebsd.md b/doc/build-freebsd.md
index c2e4e36dff..48746ce0c2 100644
--- a/doc/build-freebsd.md
+++ b/doc/build-freebsd.md
@@ -17,7 +17,7 @@ pkg install autoconf automake boost-libs git gmake libevent libtool openssl pkgc
For the wallet (optional):
```
./contrib/install_db4.sh `pwd`
-export BDB_PREFIX='$PWD/db4'
+export BDB_PREFIX="$PWD/db4"
```
See [dependencies.md](dependencies.md) for a complete overview.
diff --git a/doc/build-osx.md b/doc/build-osx.md
index abd305cf9a..a07dbd1e1d 100644
--- a/doc/build-osx.md
+++ b/doc/build-osx.md
@@ -24,8 +24,6 @@ If you want to build the disk image with `make deploy` (.dmg / optional), you ne
brew install librsvg
-NOTE: Building with Qt4 is still supported, however, could result in a broken UI. Building with Qt5 is recommended.
-
Berkeley DB
-----------
It is recommended to use Berkeley DB 4.8. If you have to build it yourself,
diff --git a/doc/build-unix.md b/doc/build-unix.md
index 60d888a297..e884c0ab67 100644
--- a/doc/build-unix.md
+++ b/doc/build-unix.md
@@ -70,19 +70,7 @@ tuned to conserve memory with additional CXXFLAGS:
Build requirements:
- sudo apt-get install build-essential libtool autotools-dev automake pkg-config libssl-dev libevent-dev bsdmainutils python3
-
-Options when installing required Boost library files:
-
-1. On at least Ubuntu 14.04+ and Debian 7+ there are generic names for the
-individual boost development packages, so the following can be used to only
-install necessary parts of boost:
-
- sudo apt-get install libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-program-options-dev libboost-test-dev libboost-thread-dev
-
-2. If that doesn't work, you can install all boost development packages with:
-
- sudo apt-get install libboost-all-dev
+ sudo apt-get install build-essential libtool autotools-dev automake pkg-config libssl-dev libevent-dev bsdmainutils python3 libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-program-options-dev libboost-test-dev libboost-thread-dev
BerkeleyDB is required for the wallet.
@@ -112,18 +100,13 @@ ZMQ dependencies (provides ZMQ API 4.x):
#### Dependencies for the GUI
If you want to build Bitcoin-Qt, make sure that the required packages for Qt development
-are installed. Either Qt 5 or Qt 4 are necessary to build the GUI.
-If both Qt 4 and Qt 5 are installed, Qt 5 will be used. Pass `--with-gui=qt4` to configure to choose Qt4.
+are installed. Qt 5 is necessary to build the GUI.
To build without GUI pass `--without-gui`.
-To build with Qt 5 (recommended) you need the following:
+To build with Qt 5 you need the following:
sudo apt-get install libqt5gui5 libqt5core5a libqt5dbus5 qttools5-dev qttools5-dev-tools libprotobuf-dev protobuf-compiler
-Alternatively, to build with Qt 4 you need the following:
-
- sudo apt-get install libqt4-dev libprotobuf-dev protobuf-compiler
-
libqrencode (optional) can be installed with:
sudo apt-get install libqrencode-dev
@@ -144,7 +127,7 @@ Optional:
sudo dnf install miniupnpc-devel
-To build with Qt 5 (recommended) you need the following:
+To build with Qt 5 you need the following:
sudo dnf install qt5-qttools-devel qt5-qtbase-devel protobuf-devel
diff --git a/doc/dependencies.md b/doc/dependencies.md
index 7aa96c4c9b..793c659419 100644
--- a/doc/dependencies.md
+++ b/doc/dependencies.md
@@ -23,7 +23,7 @@ These are the dependencies currently used by Bitcoin Core. You can find instruct
| protobuf | [2.6.3](https://github.com/google/protobuf/releases) | | No | | |
| Python (tests) | | [3.4](https://www.python.org/downloads) | | | |
| qrencode | [3.4.4](https://fukuchi.org/works/qrencode) | | No | | |
-| Qt | [5.7.1](https://download.qt.io/official_releases/qt/) | 4.7+ | No | | |
+| Qt | [5.7.1](https://download.qt.io/official_releases/qt/) | 5.x | No | | |
| XCB | | | | | [Yes](https://github.com/bitcoin/bitcoin/blob/master/depends/packages/qt.mk#L94) (Linux only) |
| xkbcommon | | | | | [Yes](https://github.com/bitcoin/bitcoin/blob/master/depends/packages/qt.mk#L93) (Linux only) |
| ZeroMQ | [4.2.3](https://github.com/zeromq/libzmq/releases) | | No | | |
diff --git a/doc/developer-notes.md b/doc/developer-notes.md
index 8f6c662f19..2fa91ecb02 100644
--- a/doc/developer-notes.md
+++ b/doc/developer-notes.md
@@ -595,6 +595,12 @@ Source code organization
- *Rationale*: Shorter and simpler header files are easier to read, and reduce compile time
+- Use only the lowercase alphanumerics (`a-z0-9`), underscore (`_`) and hyphen (`-`) in source code filenames.
+
+ - *Rationale*: `grep`:ing and auto-completing filenames is easier when using a consistent
+ naming pattern. Potential problems when building on case-insensitive filesystems are
+ avoided when using only lowercase characters in source code filenames.
+
- Every `.cpp` and `.h` file should `#include` every header file it directly uses classes, functions or other
definitions from, even if those headers are already included indirectly through other headers.
@@ -622,8 +628,8 @@ namespace {
- *Rationale*: Avoids confusion about the namespace context
-- Prefer `#include <primitives/transaction.h>` bracket syntax instead of
- `#include "primitives/transactions.h"` quote syntax when possible.
+- Use `#include <primitives/transaction.h>` bracket syntax instead of
+ `#include "primitives/transactions.h"` quote syntax.
- *Rationale*: Bracket syntax is less ambiguous because the preprocessor
searches a fixed list of include directories without taking location of the
diff --git a/doc/release-notes-pr10740.md b/doc/release-notes-pr10740.md
index c81ea6a4db..a2eb8cd837 100644
--- a/doc/release-notes-pr10740.md
+++ b/doc/release-notes-pr10740.md
@@ -1,9 +1,10 @@
Dynamic loading and creation of wallets
---------------------------------------
-Previously, wallets could only be loaded or created at startup, by specifying `-wallet` parameters on the command line or in the bitcoin.conf file. It is now possible to load and create wallets dynamically at runtime:
+Previously, wallets could only be loaded or created at startup, by specifying `-wallet` parameters on the command line or in the bitcoin.conf file. It is now possible to load, create and unload wallets dynamically at runtime:
- Existing wallets can be loaded by calling the `loadwallet` RPC. The wallet can be specified as file/directory basename (which must be located in the `walletdir` directory), or as an absolute path to a file/directory.
- New wallets can be created (and loaded) by calling the `createwallet` RPC. The provided name must not match a wallet file in the `walletdir` directory or the name of a wallet that is currently loaded.
+- Loaded wallets can be unloaded by calling the `unloadwallet` RPC.
This feature is currently only available through the RPC interface.
diff --git a/doc/release-notes-pr12892.md b/doc/release-notes-pr12892.md
index 8105eca5c0..f4a95bd40f 100644
--- a/doc/release-notes-pr12892.md
+++ b/doc/release-notes-pr12892.md
@@ -18,7 +18,7 @@ Here are the changes to RPC methods:
| Deprecated Method | New Method | Notes |
| :---------------------- | :-------------------- | :-----------|
| `getaccount` | `getaddressinfo` | `getaddressinfo` returns a json object with address information instead of just the name of the account as a string. |
-| `getaccountaddress` | `getlabeladdress` | `getlabeladdress` throws an error by default if the label does not already exist, but provides a `force` option for compatibility with existing applications. |
+| `getaccountaddress` | n/a | There is no replacement for `getaccountaddress` since labels do not have an associated receive address. |
| `getaddressesbyaccount` | `getaddressesbylabel` | `getaddressesbylabel` returns a json object with the addresses as keys, instead of a list of strings. |
| `getreceivedbyaccount` | `getreceivedbylabel` | _no change in behavior_ |
| `listaccounts` | `listlabels` | `listlabels` does not return a balance or accept `minconf` and `watchonly` arguments. |
diff --git a/doc/release-notes.md b/doc/release-notes.md
index 7a9a98bfec..e1bb84cca9 100644
--- a/doc/release-notes.md
+++ b/doc/release-notes.md
@@ -56,6 +56,11 @@ frequently tested on them.
Notable changes
===============
+GUI changes
+-----------
+
+- Block storage can be limited under Preferences, in the Main tab. Undoing this setting requires downloading the full blockchain again. This mode is incompatible with -txindex and -rescan.
+
RPC changes
------------
diff --git a/doc/release-notes/release-notes-0.16.1.md b/doc/release-notes/release-notes-0.16.1.md
new file mode 100644
index 0000000000..d99361ae1d
--- /dev/null
+++ b/doc/release-notes/release-notes-0.16.1.md
@@ -0,0 +1,145 @@
+Bitcoin Core version 0.16.1 is now available from:
+
+ <https://bitcoincore.org/bin/bitcoin-core-0.16.1/>
+
+This is a new minor version release, with various bugfixes
+as well as updated translations.
+
+Please report bugs using the issue tracker at GitHub:
+
+ <https://github.com/bitcoin/bitcoin/issues>
+
+To receive security and update notifications, please subscribe to:
+
+ <https://bitcoincore.org/en/list/announcements/join/>
+
+How to Upgrade
+==============
+
+If you are running an older version, shut it down. Wait until it has completely
+shut down (which might take a few minutes for older versions), then run the
+installer (on Windows) or just copy over `/Applications/Bitcoin-Qt` (on Mac)
+or `bitcoind`/`bitcoin-qt` (on Linux).
+
+The first time you run version 0.15.0 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 or higher. Upgrading
+directly from 0.7.x and earlier without re-downloading the blockchain is not supported.
+However, as usual, old wallet versions are still supported.
+
+Downgrading warning
+-------------------
+
+Wallets created in 0.16 and later are not compatible with versions prior to 0.16
+and will not work if you try to use newly created wallets in older versions. Existing
+wallets that were created with older versions are not affected by this.
+
+Compatibility
+==============
+
+Bitcoin Core is extensively tested on multiple operating systems using
+the Linux kernel, macOS 10.8+, and Windows Vista and later. Windows XP is not supported.
+
+Bitcoin Core should also work on most other Unix-like systems but is not
+frequently tested on them.
+
+Notable changes
+===============
+
+Miner block size removed
+------------------------
+
+The `-blockmaxsize` option for miners to limit their blocks' sizes was
+deprecated in version 0.15.1, and has now been removed. Miners should use the
+`-blockmaxweight` option if they want to limit the weight of their blocks'
+weights.
+
+0.16.1 change log
+------------------
+
+### Policy
+- #11423 `d353dd1` [Policy] Several transaction standardness rules (jl2012)
+
+### Mining
+- #12756 `e802c22` [config] Remove blockmaxsize option (jnewbery)
+
+### Block and transaction handling
+- #13199 `c71e535` Bugfix: ensure consistency of m_failed_blocks after reconsiderblock (sdaftuar)
+- #13023 `bb79aaf` Fix some concurrency issues in ActivateBestChain() (skeees)
+
+### P2P protocol and network code
+- #12626 `f60e84d` Limit the number of IPs addrman learns from each DNS seeder (EthanHeilman)
+
+### Wallet
+- #13265 `5d8de76` Exit SyncMetaData if there are no transactions to sync (laanwj)
+- #13030 `5ff571e` Fix zapwallettxes/multiwallet interaction. (jnewbery)
+
+### GUI
+- #12999 `1720eb3` Show the Window when double clicking the taskbar icon (ken2812221)
+- #12650 `f118a7a` Fix issue: "default port not shown correctly in settings dialog" (251Labs)
+- #13251 `ea487f9` Rephrase Bech32 checkbox texts, and enable it with legacy address default (fanquake)
+
+### Build system
+- #12474 `b0f692f` Allow depends system to support armv7l (hkjn)
+- #12585 `72a3290` depends: Switch to downloading expat from GitHub (fanquake)
+- #12648 `46ca8f3` test: Update trusted git root (MarcoFalke)
+- #11995 `686cb86` depends: Fix Qt build with Xcode 9 (fanquake)
+- #12636 `845838c` backport: #11995 Fix Qt build with Xcode 9 (fanquake)
+- #12946 `e055bc0` depends: Fix Qt build with XCode 9.3 (fanquake)
+- #12998 `7847b92` Default to defining endian-conversion DECLs in compat w/o config (TheBlueMatt)
+
+### Tests and QA
+- #12447 `01f931b` Add missing signal.h header (laanwj)
+- #12545 `1286f3e` Use wait_until to ensure ping goes out (Empact)
+- #12804 `4bdb0ce` Fix intermittent rpc_net.py failure. (jnewbery)
+- #12553 `0e98f96` Prefer wait_until over polling with time.sleep (Empact)
+- #12486 `cfebd40` Round target fee to 8 decimals in assert_fee_amount (kallewoof)
+- #12843 `df38b13` Test starting bitcoind with -h and -version (jnewbery)
+- #12475 `41c29f6` Fix python TypeError in script.py (MarcoFalke)
+- #12638 `0a76ed2` Cache only chain and wallet for regtest datadir (MarcoFalke)
+- #12902 `7460945` Handle potential cookie race when starting node (sdaftuar)
+- #12904 `6c26df0` Ensure bitcoind processes are cleaned up when tests end (sdaftuar)
+- #13049 `9ea62a3` Backports (MarcoFalke)
+- #13201 `b8aacd6` Handle disconnect_node race (sdaftuar)
+
+### Miscellaneous
+- #12518 `a17fecf` Bump leveldb subtree (MarcoFalke)
+- #12442 `f3b8d85` devtools: Exclude patches from lint-whitespace (MarcoFalke)
+- #12988 `acdf433` Hold cs_main while calling UpdatedBlockTip() signal (skeees)
+- #12985 `0684cf9` Windows: Avoid launching as admin when NSIS installer ends. (JeremyRand)
+
+### Documentation
+- #12637 `60086dd` backport: #12556 fix version typo in getpeerinfo RPC call help (fanquake)
+- #13184 `4087dd0` RPC Docs: `gettxout*`: clarify bestblock and unspent counts (harding)
+- #13246 `6de7543` Bump to Ubuntu Bionic 18.04 in build-windows.md (ken2812221)
+- #12556 `e730b82` Fix version typo in getpeerinfo RPC call help (tamasblummer)
+
+Credits
+=======
+
+Thanks to everyone who directly contributed to this release:
+
+- 251
+- Ben Woosley
+- Chun Kuan Lee
+- David A. Harding
+- e0
+- fanquake
+- Henrik Jonsson
+- JeremyRand
+- Jesse Cohen
+- John Newbery
+- Johnson Lau
+- Karl-Johan Alm
+- Luke Dashjr
+- MarcoFalke
+- Matt Corallo
+- Pieter Wuille
+- Suhas Daftuar
+- Tamas Blummer
+- Wladimir J. van der Laan
+
+As well as everyone that helped translating on [Transifex](https://www.transifex.com/projects/p/bitcoin/).
diff --git a/share/genbuild.sh b/share/genbuild.sh
index 419e0da0fd..38c9ba176c 100755
--- a/share/genbuild.sh
+++ b/share/genbuild.sh
@@ -3,6 +3,7 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+export LC_ALL=C
if [ $# -gt 1 ]; then
cd "$2" || exit 1
fi
diff --git a/share/qt/extract_strings_qt.py b/share/qt/extract_strings_qt.py
index e8f0820ca8..e908071321 100755
--- a/share/qt/extract_strings_qt.py
+++ b/share/qt/extract_strings_qt.py
@@ -63,7 +63,7 @@ child = Popen([XGETTEXT,'--output=-','-n','--keyword=_'] + files, stdout=PIPE)
messages = parse_po(out.decode('utf-8'))
-f = open(OUT_CPP, 'w')
+f = open(OUT_CPP, 'w', encoding="utf8")
f.write("""
#include <QtGlobal>
diff --git a/src/Makefile.am b/src/Makefile.am
index 9462c407a1..a2599d33e1 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -29,9 +29,7 @@ LIBBITCOIN_COMMON=libbitcoin_common.a
LIBBITCOIN_CONSENSUS=libbitcoin_consensus.a
LIBBITCOIN_CLI=libbitcoin_cli.a
LIBBITCOIN_UTIL=libbitcoin_util.a
-LIBBITCOIN_CRYPTO=crypto/libbitcoin_crypto.a
-LIBBITCOIN_CRYPTO_SSE41=crypto/libbitcoin_crypto_sse41.a
-LIBBITCOIN_CRYPTO_AVX2=crypto/libbitcoin_crypto_avx2.a
+LIBBITCOIN_CRYPTO_BASE=crypto/libbitcoin_crypto_base.a
LIBBITCOINQT=qt/libbitcoinqt.a
LIBSECP256K1=secp256k1/libsecp256k1.la
@@ -45,6 +43,16 @@ if ENABLE_WALLET
LIBBITCOIN_WALLET=libbitcoin_wallet.a
endif
+LIBBITCOIN_CRYPTO= $(LIBBITCOIN_CRYPTO_BASE)
+if ENABLE_SSE41
+LIBBITCOIN_CRYPTO_SSE41 = crypto/libbitcoin_crypto_sse41.a
+LIBBITCOIN_CRYPTO += $(LIBBITCOIN_CRYPTO_SSE41)
+endif
+if ENABLE_AVX2
+LIBBITCOIN_CRYPTO_AVX2 = crypto/libbitcoin_crypto_avx2.a
+LIBBITCOIN_CRYPTO += $(LIBBITCOIN_CRYPTO_AVX2)
+endif
+
$(LIBSECP256K1): $(wildcard secp256k1/src/*) $(wildcard secp256k1/include/*)
$(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F)
@@ -52,8 +60,6 @@ $(LIBSECP256K1): $(wildcard secp256k1/src/*) $(wildcard secp256k1/include/*)
# But to build the less dependent modules first, we manually select their order here:
EXTRA_LIBRARIES += \
$(LIBBITCOIN_CRYPTO) \
- $(LIBBITCOIN_CRYPTO_SSE41) \
- $(LIBBITCOIN_CRYPTO_AVX2) \
$(LIBBITCOIN_UTIL) \
$(LIBBITCOIN_COMMON) \
$(LIBBITCOIN_CONSENSUS) \
@@ -229,6 +235,7 @@ libbitcoin_server_a_SOURCES = \
rpc/net.cpp \
rpc/rawtransaction.cpp \
rpc/server.cpp \
+ rpc/util.cpp \
script/sigcache.cpp \
timedata.cpp \
torcontrol.cpp \
@@ -270,9 +277,9 @@ libbitcoin_wallet_a_SOURCES = \
$(BITCOIN_CORE_H)
# crypto primitives library
-crypto_libbitcoin_crypto_a_CPPFLAGS = $(AM_CPPFLAGS)
-crypto_libbitcoin_crypto_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
-crypto_libbitcoin_crypto_a_SOURCES = \
+crypto_libbitcoin_crypto_base_a_CPPFLAGS = $(AM_CPPFLAGS)
+crypto_libbitcoin_crypto_base_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
+crypto_libbitcoin_crypto_base_a_SOURCES = \
crypto/aes.cpp \
crypto/aes.h \
crypto/chacha20.h \
@@ -292,23 +299,19 @@ crypto_libbitcoin_crypto_a_SOURCES = \
crypto/sha512.h
if USE_ASM
-crypto_libbitcoin_crypto_a_SOURCES += crypto/sha256_sse4.cpp
+crypto_libbitcoin_crypto_base_a_SOURCES += crypto/sha256_sse4.cpp
endif
crypto_libbitcoin_crypto_sse41_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
crypto_libbitcoin_crypto_sse41_a_CPPFLAGS = $(AM_CPPFLAGS)
-if ENABLE_SSE41
crypto_libbitcoin_crypto_sse41_a_CXXFLAGS += $(SSE41_CXXFLAGS)
crypto_libbitcoin_crypto_sse41_a_CPPFLAGS += -DENABLE_SSE41
-endif
crypto_libbitcoin_crypto_sse41_a_SOURCES = crypto/sha256_sse41.cpp
crypto_libbitcoin_crypto_avx2_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
crypto_libbitcoin_crypto_avx2_a_CPPFLAGS = $(AM_CPPFLAGS)
-if ENABLE_AVX2
crypto_libbitcoin_crypto_avx2_a_CXXFLAGS += $(AVX2_CXXFLAGS)
crypto_libbitcoin_crypto_avx2_a_CPPFLAGS += -DENABLE_AVX2
-endif
crypto_libbitcoin_crypto_avx2_a_SOURCES = crypto/sha256_avx2.cpp
# consensus: shared between all executables that validate any consensus rules.
@@ -390,7 +393,6 @@ libbitcoin_util_a_SOURCES = \
logging.cpp \
random.cpp \
rpc/protocol.cpp \
- rpc/util.cpp \
support/cleanse.cpp \
sync.cpp \
threadinterrupt.cpp \
@@ -433,8 +435,6 @@ bitcoind_LDADD = \
$(LIBBITCOIN_ZMQ) \
$(LIBBITCOIN_CONSENSUS) \
$(LIBBITCOIN_CRYPTO) \
- $(LIBBITCOIN_CRYPTO_SSE41) \
- $(LIBBITCOIN_CRYPTO_AVX2) \
$(LIBLEVELDB) \
$(LIBLEVELDB_SSE42) \
$(LIBMEMENV) \
@@ -456,9 +456,7 @@ bitcoin_cli_LDADD = \
$(LIBBITCOIN_CLI) \
$(LIBUNIVALUE) \
$(LIBBITCOIN_UTIL) \
- $(LIBBITCOIN_CRYPTO) \
- $(LIBBITCOIN_CRYPTO_SSE41) \
- $(LIBBITCOIN_CRYPTO_AVX2)
+ $(LIBBITCOIN_CRYPTO)
bitcoin_cli_LDADD += $(BOOST_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(EVENT_LIBS)
#
@@ -479,8 +477,6 @@ bitcoin_tx_LDADD = \
$(LIBBITCOIN_UTIL) \
$(LIBBITCOIN_CONSENSUS) \
$(LIBBITCOIN_CRYPTO) \
- $(LIBBITCOIN_CRYPTO_SSE41) \
- $(LIBBITCOIN_CRYPTO_AVX2) \
$(LIBSECP256K1)
bitcoin_tx_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
@@ -489,7 +485,7 @@ bitcoin_tx_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
# bitcoinconsensus library #
if BUILD_BITCOIN_LIBS
include_HEADERS = script/bitcoinconsensus.h
-libbitcoinconsensus_la_SOURCES = $(crypto_libbitcoin_crypto_a_SOURCES) $(libbitcoin_consensus_a_SOURCES)
+libbitcoinconsensus_la_SOURCES = $(crypto_libbitcoin_crypto_base_a_SOURCES) $(libbitcoin_consensus_a_SOURCES)
if GLIBC_BACK_COMPAT
libbitcoinconsensus_la_SOURCES += compat/glibc_compat.cpp
diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include
index 804df3bf21..d70df3c9e8 100644
--- a/src/Makefile.bench.include
+++ b/src/Makefile.bench.include
@@ -15,9 +15,10 @@ bench_bench_bitcoin_SOURCES = \
bench/bench_bitcoin.cpp \
bench/bench.cpp \
bench/bench.h \
+ bench/block_assemble.cpp \
bench/checkblock.cpp \
bench/checkqueue.cpp \
- bench/Examples.cpp \
+ bench/examples.cpp \
bench/rollingbloom.cpp \
bench/crypto_hash.cpp \
bench/ccoins_caching.cpp \
@@ -39,8 +40,6 @@ bench_bench_bitcoin_LDADD = \
$(LIBBITCOIN_UTIL) \
$(LIBBITCOIN_CONSENSUS) \
$(LIBBITCOIN_CRYPTO) \
- $(LIBBITCOIN_CRYPTO_SSE41) \
- $(LIBBITCOIN_CRYPTO_AVX2) \
$(LIBLEVELDB) \
$(LIBLEVELDB_SSE42) \
$(LIBMEMENV) \
diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include
index f8c31be3d4..a84a11ac45 100644
--- a/src/Makefile.qt.include
+++ b/src/Makefile.qt.include
@@ -408,7 +408,7 @@ endif
if ENABLE_ZMQ
qt_bitcoin_qt_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS)
endif
-qt_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBBITCOIN_CRYPTO_SSE41) $(LIBBITCOIN_CRYPTO_AVX2) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) \
+qt_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) \
$(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \
$(EVENT_PTHREADS_LIBS) $(EVENT_LIBS)
qt_bitcoin_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include
index a4356f1cbd..4b14212b2e 100644
--- a/src/Makefile.qttest.include
+++ b/src/Makefile.qttest.include
@@ -62,7 +62,7 @@ endif
if ENABLE_ZMQ
qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS)
endif
-qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBBITCOIN_CRYPTO_SSE41) $(LIBBITCOIN_CRYPTO_AVX2) $(LIBUNIVALUE) $(LIBLEVELDB) \
+qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) \
$(LIBLEVELDB_SSE42) $(LIBMEMENV) $(BOOST_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) $(QT_LIBS) \
$(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \
$(EVENT_PTHREADS_LIBS) $(EVENT_LIBS)
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index cbd63cd53d..a4d31795ec 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -46,7 +46,7 @@ BITCOIN_TESTS =\
test/compress_tests.cpp \
test/crypto_tests.cpp \
test/cuckoocache_tests.cpp \
- test/DoS_tests.cpp \
+ test/denialofservice_tests.cpp \
test/getarg_tests.cpp \
test/hash_tests.cpp \
test/key_io_tests.cpp \
@@ -71,7 +71,7 @@ BITCOIN_TESTS =\
test/rpc_tests.cpp \
test/sanity_tests.cpp \
test/scheduler_tests.cpp \
- test/script_P2SH_tests.cpp \
+ test/script_p2sh_tests.cpp \
test/script_tests.cpp \
test/script_standard_tests.cpp \
test/scriptnum_tests.cpp \
@@ -110,7 +110,7 @@ if ENABLE_WALLET
test_test_bitcoin_LDADD += $(LIBBITCOIN_WALLET)
endif
-test_test_bitcoin_LDADD += $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBBITCOIN_CRYPTO_SSE41) $(LIBBITCOIN_CRYPTO_AVX2) $(LIBUNIVALUE) \
+test_test_bitcoin_LDADD += $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) \
$(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(EVENT_LIBS) $(EVENT_PTHREADS_LIBS)
test_test_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
diff --git a/src/bench/block_assemble.cpp b/src/bench/block_assemble.cpp
new file mode 100644
index 0000000000..36fa175a76
--- /dev/null
+++ b/src/bench/block_assemble.cpp
@@ -0,0 +1,116 @@
+// Copyright (c) 2011-2017 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <bench/bench.h>
+#include <chainparams.h>
+#include <coins.h>
+#include <consensus/merkle.h>
+#include <consensus/validation.h>
+#include <miner.h>
+#include <policy/policy.h>
+#include <pow.h>
+#include <scheduler.h>
+#include <txdb.h>
+#include <txmempool.h>
+#include <utiltime.h>
+#include <validation.h>
+#include <validationinterface.h>
+
+#include <boost/thread.hpp>
+
+#include <list>
+#include <vector>
+
+static std::shared_ptr<CBlock> PrepareBlock(const CScript& coinbase_scriptPubKey)
+{
+ auto block = std::make_shared<CBlock>(
+ BlockAssembler{Params()}
+ .CreateNewBlock(coinbase_scriptPubKey, /* fMineWitnessTx */ true)
+ ->block);
+
+ block->nTime = ::chainActive.Tip()->GetMedianTimePast() + 1;
+ block->hashMerkleRoot = BlockMerkleRoot(*block);
+
+ return block;
+}
+
+
+static CTxIn MineBlock(const CScript& coinbase_scriptPubKey)
+{
+ auto block = PrepareBlock(coinbase_scriptPubKey);
+
+ while (!CheckProofOfWork(block->GetHash(), block->nBits, Params().GetConsensus())) {
+ assert(++block->nNonce);
+ }
+
+ bool processed{ProcessNewBlock(Params(), block, true, nullptr)};
+ assert(processed);
+
+ return CTxIn{block->vtx[0]->GetHash(), 0};
+}
+
+
+static void AssembleBlock(benchmark::State& state)
+{
+ const std::vector<unsigned char> op_true{OP_TRUE};
+ CScriptWitness witness;
+ witness.stack.push_back(op_true);
+
+ uint256 witness_program;
+ CSHA256().Write(&op_true[0], op_true.size()).Finalize(witness_program.begin());
+
+ const CScript SCRIPT_PUB{CScript(OP_0) << std::vector<unsigned char>{witness_program.begin(), witness_program.end()}};
+
+ // Switch to regtest so we can mine faster
+ // Also segwit is active, so we can include witness transactions
+ SelectParams(CBaseChainParams::REGTEST);
+
+ InitScriptExecutionCache();
+
+ boost::thread_group thread_group;
+ CScheduler scheduler;
+ {
+ ::pblocktree.reset(new CBlockTreeDB(1 << 20, true));
+ ::pcoinsdbview.reset(new CCoinsViewDB(1 << 23, true));
+ ::pcoinsTip.reset(new CCoinsViewCache(pcoinsdbview.get()));
+
+ const CChainParams& chainparams = Params();
+ thread_group.create_thread(boost::bind(&CScheduler::serviceQueue, &scheduler));
+ GetMainSignals().RegisterBackgroundSignalScheduler(scheduler);
+ LoadGenesisBlock(chainparams);
+ CValidationState state;
+ ActivateBestChain(state, chainparams);
+ assert(::chainActive.Tip() != nullptr);
+ const bool witness_enabled{IsWitnessEnabled(::chainActive.Tip(), chainparams.GetConsensus())};
+ assert(witness_enabled);
+ }
+
+ // Collect some loose transactions that spend the coinbases of our mined blocks
+ constexpr size_t NUM_BLOCKS{200};
+ std::array<CTransactionRef, NUM_BLOCKS - COINBASE_MATURITY + 1> txs;
+ for (size_t b{0}; b < NUM_BLOCKS; ++b) {
+ CMutableTransaction tx;
+ tx.vin.push_back(MineBlock(SCRIPT_PUB));
+ tx.vin.back().scriptWitness = witness;
+ tx.vout.emplace_back(1337, SCRIPT_PUB);
+ if (NUM_BLOCKS - b >= COINBASE_MATURITY)
+ txs.at(b) = MakeTransactionRef(tx);
+ }
+ for (const auto& txr : txs) {
+ CValidationState state;
+ bool ret{::AcceptToMemoryPool(::mempool, state, txr, nullptr /* pfMissingInputs */, nullptr /* plTxnReplaced */, false /* bypass_limits */, /* nAbsurdFee */ 0)};
+ assert(ret);
+ }
+
+ while (state.KeepRunning()) {
+ PrepareBlock(SCRIPT_PUB);
+ }
+
+ thread_group.interrupt_all();
+ thread_group.join_all();
+ GetMainSignals().FlushBackgroundCallbacks();
+ GetMainSignals().UnregisterBackgroundSignalScheduler();
+}
+
+BENCHMARK(AssembleBlock, 700);
diff --git a/src/bench/Examples.cpp b/src/bench/examples.cpp
index b68c9cd156..b68c9cd156 100644
--- a/src/bench/Examples.cpp
+++ b/src/bench/examples.cpp
diff --git a/src/bench/merkle_root.cpp b/src/bench/merkle_root.cpp
index ae2a0a28dc..fab12da311 100644
--- a/src/bench/merkle_root.cpp
+++ b/src/bench/merkle_root.cpp
@@ -2,11 +2,11 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "bench.h"
+#include <bench/bench.h>
-#include "uint256.h"
-#include "random.h"
-#include "consensus/merkle.h"
+#include <uint256.h>
+#include <random.h>
+#include <consensus/merkle.h>
static void MerkleRoot(benchmark::State& state)
{
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index 2a594c3051..e6eb723cf4 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -591,7 +591,7 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr)
if (!prevOut.checkObject(types))
throw std::runtime_error("prevtxs internal object typecheck fail");
- uint256 txid = ParseHashUV(prevOut["txid"], "txid");
+ uint256 txid = ParseHashStr(prevOut["txid"].get_str(), "txid");
int nOut = atoi(prevOut["vout"].getValStr());
if (nOut < 0)
diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp
index a9b952e5a4..4b9abb2a1b 100644
--- a/src/bitcoind.cpp
+++ b/src/bitcoind.cpp
@@ -62,9 +62,6 @@ static bool AppInit(int argc, char* argv[])
//
// If Qt is used, parameters/bitcoin.conf are parsed in qt/bitcoin.cpp's main()
SetupServerArgs();
-#if HAVE_DECL_DAEMON
- gArgs.AddArg("-daemon", "Run in the background as a daemon and accept commands", false, OptionsCategory::OPTIONS);
-#endif
std::string error;
if (!gArgs.ParseParameters(argc, argv, error)) {
fprintf(stderr, "Error parsing command line arguments: %s\n", error.c_str());
diff --git a/src/core_io.h b/src/core_io.h
index 377633ac77..1d87d21d40 100644
--- a/src/core_io.h
+++ b/src/core_io.h
@@ -22,7 +22,6 @@ CScript ParseScript(const std::string& s);
std::string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDecode = false);
bool DecodeHexTx(CMutableTransaction& tx, const std::string& hex_tx, bool try_no_witness = false, bool try_witness = true);
bool DecodeHexBlk(CBlock&, const std::string& strHexBlk);
-uint256 ParseHashUV(const UniValue& v, const std::string& strName);
uint256 ParseHashStr(const std::string&, const std::string& strName);
std::vector<unsigned char> ParseHexUV(const UniValue& v, const std::string& strName);
diff --git a/src/core_read.cpp b/src/core_read.cpp
index aade7e21ca..4d851610ef 100644
--- a/src/core_read.cpp
+++ b/src/core_read.cpp
@@ -160,14 +160,6 @@ bool DecodeHexBlk(CBlock& block, const std::string& strHexBlk)
return true;
}
-uint256 ParseHashUV(const UniValue& v, const std::string& strName)
-{
- std::string strHex;
- if (v.isStr())
- strHex = v.getValStr();
- return ParseHashStr(strHex, strName); // Note: ParseHashStr("") throws a runtime_error
-}
-
uint256 ParseHashStr(const std::string& strHex, const std::string& strName)
{
if (!IsHex(strHex)) // Note: IsHex("") is false
diff --git a/src/crypto/sha256.cpp b/src/crypto/sha256.cpp
index 6ac51d11cd..e62ddc125e 100644
--- a/src/crypto/sha256.cpp
+++ b/src/crypto/sha256.cpp
@@ -446,44 +446,104 @@ void TransformD64Wrapper(unsigned char* out, const unsigned char* in)
WriteBE32(out + 28, s[7]);
}
-bool SelfTest(TransformType tr) {
- static const unsigned char in1[65] = {0, 0x80};
- static const unsigned char in2[129] = {
- 0,
- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
- 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0
- };
- static const uint32_t init[8] = {0x6a09e667ul, 0xbb67ae85ul, 0x3c6ef372ul, 0xa54ff53aul, 0x510e527ful, 0x9b05688cul, 0x1f83d9abul, 0x5be0cd19ul};
- static const uint32_t out1[8] = {0xe3b0c442ul, 0x98fc1c14ul, 0x9afbf4c8ul, 0x996fb924ul, 0x27ae41e4ul, 0x649b934cul, 0xa495991bul, 0x7852b855ul};
- static const uint32_t out2[8] = {0xce4153b0ul, 0x147c2a86ul, 0x3ed4298eul, 0xe0676bc8ul, 0x79fc77a1ul, 0x2abe1f49ul, 0xb2b055dful, 0x1069523eul};
- uint32_t buf[8];
- memcpy(buf, init, sizeof(buf));
- // Process nothing, and check we remain in the initial state.
- tr(buf, nullptr, 0);
- if (memcmp(buf, init, sizeof(buf))) return false;
- // Process the padded empty string (unaligned)
- tr(buf, in1 + 1, 1);
- if (memcmp(buf, out1, sizeof(buf))) return false;
- // Process 64 spaces (unaligned)
- memcpy(buf, init, sizeof(buf));
- tr(buf, in2 + 1, 2);
- if (memcmp(buf, out2, sizeof(buf))) return false;
- return true;
-}
-
TransformType Transform = sha256::Transform;
TransformD64Type TransformD64 = sha256::TransformD64;
TransformD64Type TransformD64_4way = nullptr;
TransformD64Type TransformD64_8way = nullptr;
-#if defined(USE_ASM) && (defined(__x86_64__) || defined(__amd64__))
+bool SelfTest() {
+ // Input state (equal to the initial SHA256 state)
+ static const uint32_t init[8] = {
+ 0x6a09e667ul, 0xbb67ae85ul, 0x3c6ef372ul, 0xa54ff53aul, 0x510e527ful, 0x9b05688cul, 0x1f83d9abul, 0x5be0cd19ul
+ };
+ // Some random input data to test with
+ static const unsigned char data[641] = "-" // Intentionally not aligned
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do "
+ "eiusmod tempor incididunt ut labore et dolore magna aliqua. Et m"
+ "olestie ac feugiat sed lectus vestibulum mattis ullamcorper. Mor"
+ "bi blandit cursus risus at ultrices mi tempus imperdiet nulla. N"
+ "unc congue nisi vita suscipit tellus mauris. Imperdiet proin fer"
+ "mentum leo vel orci. Massa tempor nec feugiat nisl pretium fusce"
+ " id velit. Telus in metus vulputate eu scelerisque felis. Mi tem"
+ "pus imperdiet nulla malesuada pellentesque. Tristique magna sit.";
+ // Expected output state for hashing the i*64 first input bytes above (excluding SHA256 padding).
+ static const uint32_t result[9][8] = {
+ {0x6a09e667ul, 0xbb67ae85ul, 0x3c6ef372ul, 0xa54ff53aul, 0x510e527ful, 0x9b05688cul, 0x1f83d9abul, 0x5be0cd19ul},
+ {0x91f8ec6bul, 0x4da10fe3ul, 0x1c9c292cul, 0x45e18185ul, 0x435cc111ul, 0x3ca26f09ul, 0xeb954caeul, 0x402a7069ul},
+ {0xcabea5acul, 0x374fb97cul, 0x182ad996ul, 0x7bd69cbful, 0x450ff900ul, 0xc1d2be8aul, 0x6a41d505ul, 0xe6212dc3ul},
+ {0xbcff09d6ul, 0x3e76f36eul, 0x3ecb2501ul, 0x78866e97ul, 0xe1c1e2fdul, 0x32f4eafful, 0x8aa6c4e5ul, 0xdfc024bcul},
+ {0xa08c5d94ul, 0x0a862f93ul, 0x6b7f2f40ul, 0x8f9fae76ul, 0x6d40439ful, 0x79dcee0cul, 0x3e39ff3aul, 0xdc3bdbb1ul},
+ {0x216a0895ul, 0x9f1a3662ul, 0xe99946f9ul, 0x87ba4364ul, 0x0fb5db2cul, 0x12bed3d3ul, 0x6689c0c7ul, 0x292f1b04ul},
+ {0xca3067f8ul, 0xbc8c2656ul, 0x37cb7e0dul, 0x9b6b8b0ful, 0x46dc380bul, 0xf1287f57ul, 0xc42e4b23ul, 0x3fefe94dul},
+ {0x3e4c4039ul, 0xbb6fca8cul, 0x6f27d2f7ul, 0x301e44a4ul, 0x8352ba14ul, 0x5769ce37ul, 0x48a1155ful, 0xc0e1c4c6ul},
+ {0xfe2fa9ddul, 0x69d0862bul, 0x1ae0db23ul, 0x471f9244ul, 0xf55c0145ul, 0xc30f9c3bul, 0x40a84ea0ul, 0x5b8a266cul},
+ };
+ // Expected output for each of the individual 8 64-byte messages under full double SHA256 (including padding).
+ static const unsigned char result_d64[256] = {
+ 0x09, 0x3a, 0xc4, 0xd0, 0x0f, 0xf7, 0x57, 0xe1, 0x72, 0x85, 0x79, 0x42, 0xfe, 0xe7, 0xe0, 0xa0,
+ 0xfc, 0x52, 0xd7, 0xdb, 0x07, 0x63, 0x45, 0xfb, 0x53, 0x14, 0x7d, 0x17, 0x22, 0x86, 0xf0, 0x52,
+ 0x48, 0xb6, 0x11, 0x9e, 0x6e, 0x48, 0x81, 0x6d, 0xcc, 0x57, 0x1f, 0xb2, 0x97, 0xa8, 0xd5, 0x25,
+ 0x9b, 0x82, 0xaa, 0x89, 0xe2, 0xfd, 0x2d, 0x56, 0xe8, 0x28, 0x83, 0x0b, 0xe2, 0xfa, 0x53, 0xb7,
+ 0xd6, 0x6b, 0x07, 0x85, 0x83, 0xb0, 0x10, 0xa2, 0xf5, 0x51, 0x3c, 0xf9, 0x60, 0x03, 0xab, 0x45,
+ 0x6c, 0x15, 0x6e, 0xef, 0xb5, 0xac, 0x3e, 0x6c, 0xdf, 0xb4, 0x92, 0x22, 0x2d, 0xce, 0xbf, 0x3e,
+ 0xe9, 0xe5, 0xf6, 0x29, 0x0e, 0x01, 0x4f, 0xd2, 0xd4, 0x45, 0x65, 0xb3, 0xbb, 0xf2, 0x4c, 0x16,
+ 0x37, 0x50, 0x3c, 0x6e, 0x49, 0x8c, 0x5a, 0x89, 0x2b, 0x1b, 0xab, 0xc4, 0x37, 0xd1, 0x46, 0xe9,
+ 0x3d, 0x0e, 0x85, 0xa2, 0x50, 0x73, 0xa1, 0x5e, 0x54, 0x37, 0xd7, 0x94, 0x17, 0x56, 0xc2, 0xd8,
+ 0xe5, 0x9f, 0xed, 0x4e, 0xae, 0x15, 0x42, 0x06, 0x0d, 0x74, 0x74, 0x5e, 0x24, 0x30, 0xce, 0xd1,
+ 0x9e, 0x50, 0xa3, 0x9a, 0xb8, 0xf0, 0x4a, 0x57, 0x69, 0x78, 0x67, 0x12, 0x84, 0x58, 0xbe, 0xc7,
+ 0x36, 0xaa, 0xee, 0x7c, 0x64, 0xa3, 0x76, 0xec, 0xff, 0x55, 0x41, 0x00, 0x2a, 0x44, 0x68, 0x4d,
+ 0xb6, 0x53, 0x9e, 0x1c, 0x95, 0xb7, 0xca, 0xdc, 0x7f, 0x7d, 0x74, 0x27, 0x5c, 0x8e, 0xa6, 0x84,
+ 0xb5, 0xac, 0x87, 0xa9, 0xf3, 0xff, 0x75, 0xf2, 0x34, 0xcd, 0x1a, 0x3b, 0x82, 0x2c, 0x2b, 0x4e,
+ 0x6a, 0x46, 0x30, 0xa6, 0x89, 0x86, 0x23, 0xac, 0xf8, 0xa5, 0x15, 0xe9, 0x0a, 0xaa, 0x1e, 0x9a,
+ 0xd7, 0x93, 0x6b, 0x28, 0xe4, 0x3b, 0xfd, 0x59, 0xc6, 0xed, 0x7c, 0x5f, 0xa5, 0x41, 0xcb, 0x51
+ };
+
+
+ // Test Transform() for 0 through 8 transformations.
+ for (size_t i = 0; i <= 8; ++i) {
+ uint32_t state[8];
+ std::copy(init, init + 8, state);
+ Transform(state, data + 1, i);
+ if (!std::equal(state, state + 8, result[i])) return false;
+ }
+
+ // Test TransformD64
+ unsigned char out[32];
+ TransformD64(out, data + 1);
+ if (!std::equal(out, out + 32, result_d64)) return false;
+
+ // Test TransformD64_4way, if available.
+ if (TransformD64_4way) {
+ unsigned char out[128];
+ TransformD64_4way(out, data + 1);
+ if (!std::equal(out, out + 128, result_d64)) return false;
+ }
+
+ // Test TransformD64_8way, if available.
+ if (TransformD64_8way) {
+ unsigned char out[256];
+ TransformD64_8way(out, data + 1);
+ if (!std::equal(out, out + 256, result_d64)) return false;
+ }
+
+ return true;
+}
+
+
+#if defined(USE_ASM) && (defined(__x86_64__) || defined(__amd64__) || defined(__i386__))
// We can't use cpuid.h's __get_cpuid as it does not support subleafs.
void inline cpuid(uint32_t leaf, uint32_t subleaf, uint32_t& a, uint32_t& b, uint32_t& c, uint32_t& d)
{
__asm__ ("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "0"(leaf), "2"(subleaf));
}
+
+/** Check whether the OS has enabled AVX registers. */
+bool AVXEnabled()
+{
+ uint32_t a, d;
+ __asm__("xgetbv" : "=a"(a), "=d"(d) : "c"(0));
+ return (a & 6) == 6;
+}
#endif
} // namespace
@@ -491,20 +551,27 @@ void inline cpuid(uint32_t leaf, uint32_t subleaf, uint32_t& a, uint32_t& b, uin
std::string SHA256AutoDetect()
{
std::string ret = "standard";
-#if defined(USE_ASM) && (defined(__x86_64__) || defined(__amd64__))
+#if defined(USE_ASM) && (defined(__x86_64__) || defined(__amd64__) || defined(__i386__))
+ (void)AVXEnabled; // Silence unused warning (in case ENABLE_AVX2 is not defined)
uint32_t eax, ebx, ecx, edx;
cpuid(1, 0, eax, ebx, ecx, edx);
if ((ecx >> 19) & 1) {
+#if defined(__x86_64__) || defined(__amd64__)
Transform = sha256_sse4::Transform;
TransformD64 = TransformD64Wrapper<sha256_sse4::Transform>;
+#endif
#if defined(ENABLE_SSE41) && !defined(BUILD_BITCOIN_INTERNAL)
TransformD64_4way = sha256d64_sse41::Transform_4way;
ret = "sse4(1way+4way)";
#if defined(ENABLE_AVX2) && !defined(BUILD_BITCOIN_INTERNAL)
- cpuid(7, 0, eax, ebx, ecx, edx);
- if ((ebx >> 5) & 1) {
- TransformD64_8way = sha256d64_avx2::Transform_8way;
- ret += ",avx2(8way)";
+ if (((ecx >> 27) & 1) && ((ecx >> 28) & 1)) { // XSAVE and AVX
+ cpuid(7, 0, eax, ebx, ecx, edx);
+ if ((ebx >> 5) & 1) { // AVX2 flag
+ if (AVXEnabled()) { // OS has enabled AVX registers
+ TransformD64_8way = sha256d64_avx2::Transform_8way;
+ ret += ",avx2(8way)";
+ }
+ }
}
#endif
#else
@@ -513,7 +580,7 @@ std::string SHA256AutoDetect()
}
#endif
- assert(SelfTest(Transform));
+ assert(SelfTest());
return ret;
}
diff --git a/src/crypto/sha256_avx2.cpp b/src/crypto/sha256_avx2.cpp
index f45c1d4ab6..b338b06927 100644
--- a/src/crypto/sha256_avx2.cpp
+++ b/src/crypto/sha256_avx2.cpp
@@ -7,8 +7,8 @@
#include <x86intrin.h>
#endif
-#include "crypto/sha256.h"
-#include "crypto/common.h"
+#include <crypto/sha256.h>
+#include <crypto/common.h>
namespace sha256d64_avx2 {
namespace {
diff --git a/src/crypto/sha256_sse41.cpp b/src/crypto/sha256_sse41.cpp
index a11d658c70..be71dd8fb8 100644
--- a/src/crypto/sha256_sse41.cpp
+++ b/src/crypto/sha256_sse41.cpp
@@ -7,8 +7,8 @@
#include <x86intrin.h>
#endif
-#include "crypto/sha256.h"
-#include "crypto/common.h"
+#include <crypto/sha256.h>
+#include <crypto/common.h>
namespace sha256d64_sse41 {
namespace {
diff --git a/src/init.cpp b/src/init.cpp
index 40f7996d12..fe27dad4d6 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -76,7 +76,7 @@ std::unique_ptr<PeerLogicValidation> peerLogic;
class DummyWalletInit : public WalletInitInterface {
public:
- void AddWalletOptions() const override {}
+ void AddWalletOptions() const override;
bool ParameterInteraction() const override {return true;}
void RegisterRPC(CRPCTable &) const override {}
bool Verify() const override {return true;}
@@ -87,6 +87,15 @@ public:
void Close() const override {}
};
+void DummyWalletInit::AddWalletOptions() const
+{
+ std::vector<std::string> opts = {"-addresstype", "-changetype", "-disablewallet", "-discardfee=<amt>", "-fallbackfee=<amt>",
+ "-keypool=<n>", "-mintxfee=<amt>", "-paytxfee=<amt>", "-rescan", "-salvagewallet", "-spendzeroconfchange", "-txconfirmtarget=<n>",
+ "-upgradewallet", "-wallet=<path>", "-walletbroadcast", "-walletdir=<dir>", "-walletnotify=<cmd>", "-walletrbf", "-zapwallettxes=<mode>",
+ "-dblogsize=<n>", "-flushwallet", "-privdb", "-walletrejectlongchains"};
+ gArgs.AddHiddenArgs(opts);
+}
+
const WalletInitInterface& g_wallet_init_interface = DummyWalletInit();
#endif
@@ -348,6 +357,12 @@ void SetupServerArgs()
const auto defaultChainParams = CreateChainParams(CBaseChainParams::MAIN);
const auto testnetChainParams = CreateChainParams(CBaseChainParams::TESTNET);
+ // Hidden Options
+ std::vector<std::string> hidden_args = {"-rpcssl", "-benchmark", "-h", "-help", "-socks", "-tor", "-debugnet", "-whitelistalwaysrelay",
+ "-prematurewitness", "-walletprematurewitness", "-promiscuousmempoolflags", "-blockminsize", "-dbcrashratio", "-forcecompactdb", "-usehd",
+ // GUI args. These will be overwritten by SetupUIArgs for the GUI
+ "-allowselfsignedrootcertificates", "-choosedatadir", "-lang=<lang>", "-min", "-resetguisettings", "-rootcertificates=<file>", "-splash", "-uiplatform"};
+
// Set all of the args and their help
// When adding new options to the categories, please keep and ensure alphabetical ordering.
gArgs.AddArg("-?", "Print this help message and exit", false, OptionsCategory::OPTIONS);
@@ -375,6 +390,8 @@ void SetupServerArgs()
gArgs.AddArg("-persistmempool", strprintf("Whether to save the mempool on shutdown and load on restart (default: %u)", DEFAULT_PERSIST_MEMPOOL), false, OptionsCategory::OPTIONS);
#ifndef WIN32
gArgs.AddArg("-pid=<file>", strprintf("Specify pid file. Relative paths will be prefixed by a net-specific datadir location. (default: %s)", BITCOIN_PID_FILENAME), false, OptionsCategory::OPTIONS);
+#else
+ hidden_args.emplace_back("-pid");
#endif
gArgs.AddArg("-prune=<n>", strprintf("Reduce storage requirements by enabling pruning (deleting) of old blocks. This allows the pruneblockchain RPC to be called to delete specific blocks, and enables automatic pruning of old blocks if a target size in MiB is provided. This mode is incompatible with -txindex and -rescan. "
"Warning: Reverting this setting requires re-downloading the entire blockchain. "
@@ -383,6 +400,8 @@ void SetupServerArgs()
gArgs.AddArg("-reindex-chainstate", "Rebuild chain state from the currently indexed blocks", false, OptionsCategory::OPTIONS);
#ifndef WIN32
gArgs.AddArg("-sysperms", "Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality)", false, OptionsCategory::OPTIONS);
+#else
+ hidden_args.emplace_back("-sysperms");
#endif
gArgs.AddArg("-txindex", strprintf("Maintain a full transaction index, used by the getrawtransaction rpc call (default: %u)", DEFAULT_TXINDEX), false, OptionsCategory::OPTIONS);
@@ -421,6 +440,8 @@ void SetupServerArgs()
#else
gArgs.AddArg("-upnp", strprintf("Use UPnP to map the listening port (default: %u)", 0), false, OptionsCategory::CONNECTION);
#endif
+#else
+ hidden_args.emplace_back("-upnp");
#endif
gArgs.AddArg("-whitebind=<addr>", "Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6", false, OptionsCategory::CONNECTION);
gArgs.AddArg("-whitelist=<IP address or network>", "Whitelist peers connecting from the given IP address (e.g. 1.2.3.4) or CIDR notated network (e.g. 1.2.3.0/24). Can be specified multiple times."
@@ -433,6 +454,11 @@ void SetupServerArgs()
gArgs.AddArg("-zmqpubhashtx=<address>", "Enable publish hash transaction in <address>", false, OptionsCategory::ZMQ);
gArgs.AddArg("-zmqpubrawblock=<address>", "Enable publish raw block in <address>", false, OptionsCategory::ZMQ);
gArgs.AddArg("-zmqpubrawtx=<address>", "Enable publish raw transaction in <address>", false, OptionsCategory::ZMQ);
+#else
+ hidden_args.emplace_back("-zmqpubhashblock=<address>");
+ hidden_args.emplace_back("-zmqpubhashtx=<address>");
+ hidden_args.emplace_back("-zmqpubrawblock=<address>");
+ hidden_args.emplace_back("-zmqpubrawtx=<address>");
#endif
gArgs.AddArg("-checkblocks=<n>", strprintf("How many blocks to check at startup (default: %u, 0 = all)", DEFAULT_CHECKBLOCKS), true, OptionsCategory::DEBUG_TEST);
@@ -500,22 +526,14 @@ void SetupServerArgs()
gArgs.AddArg("-rpcworkqueue=<n>", strprintf("Set the depth of the work queue to service RPC calls (default: %d)", DEFAULT_HTTP_WORKQUEUE), true, OptionsCategory::RPC);
gArgs.AddArg("-server", "Accept command line and JSON-RPC commands", false, OptionsCategory::RPC);
- // Hidden options
- gArgs.AddArg("-rpcssl", "", false, OptionsCategory::HIDDEN);
- gArgs.AddArg("-benchmark", "", false, OptionsCategory::HIDDEN);
- gArgs.AddArg("-h", "", false, OptionsCategory::HIDDEN);
- gArgs.AddArg("-help", "", false, OptionsCategory::HIDDEN);
- gArgs.AddArg("-socks", "", false, OptionsCategory::HIDDEN);
- gArgs.AddArg("-tor", "", false, OptionsCategory::HIDDEN);
- gArgs.AddArg("-debugnet", "", false, OptionsCategory::HIDDEN);
- gArgs.AddArg("-whitelistalwaysrelay", "", false, OptionsCategory::HIDDEN);
- gArgs.AddArg("-prematurewitness", "", false, OptionsCategory::HIDDEN);
- gArgs.AddArg("-walletprematurewitness", "", false, OptionsCategory::HIDDEN);
- gArgs.AddArg("-promiscuousmempoolflags", "", false, OptionsCategory::HIDDEN);
- gArgs.AddArg("-blockminsize", "", false, OptionsCategory::HIDDEN);
- gArgs.AddArg("-dbcrashratio", "", false, OptionsCategory::HIDDEN);
- gArgs.AddArg("-forcecompactdb", "", false, OptionsCategory::HIDDEN);
- gArgs.AddArg("-usehd", "", false, OptionsCategory::HIDDEN);
+#if HAVE_DECL_DAEMON
+ gArgs.AddArg("-daemon", "Run in the background as a daemon and accept commands", false, OptionsCategory::OPTIONS);
+#else
+ hidden_args.emplace_back("-daemon");
+#endif
+
+ // Add the hidden options
+ gArgs.AddHiddenArgs(hidden_args);
}
std::string LicenseInfo()
@@ -614,7 +632,7 @@ static void CleanupBlockRevFiles()
// keeping a separate counter. Once we hit a gap (or if 0 doesn't exist)
// start removing block files.
int nContigCounter = 0;
- for (const std::pair<std::string, fs::path>& item : mapBlockFiles) {
+ for (const std::pair<const std::string, fs::path>& item : mapBlockFiles) {
if (atoi(item.first) == nContigCounter) {
nContigCounter++;
continue;
diff --git a/src/interfaces/wallet.cpp b/src/interfaces/wallet.cpp
index 3029dbe8e3..e98acba0df 100644
--- a/src/interfaces/wallet.cpp
+++ b/src/interfaces/wallet.cpp
@@ -429,6 +429,10 @@ public:
bool hdEnabled() override { return m_wallet.IsHDEnabled(); }
OutputType getDefaultAddressType() override { return m_wallet.m_default_address_type; }
OutputType getDefaultChangeType() override { return m_wallet.m_default_change_type; }
+ std::unique_ptr<Handler> handleUnload(UnloadFn fn) override
+ {
+ return MakeHandler(m_wallet.NotifyUnload.connect(fn));
+ }
std::unique_ptr<Handler> handleShowProgress(ShowProgressFn fn) override
{
return MakeHandler(m_wallet.ShowProgress.connect(fn));
diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h
index 82ae0b14b5..ce42e14eea 100644
--- a/src/interfaces/wallet.h
+++ b/src/interfaces/wallet.h
@@ -242,6 +242,10 @@ public:
// Get default change type.
virtual OutputType getDefaultChangeType() = 0;
+ //! Register handler for unload message.
+ using UnloadFn = std::function<void()>;
+ virtual std::unique_ptr<Handler> handleUnload(UnloadFn fn) = 0;
+
//! Register handler for show progress messages.
using ShowProgressFn = std::function<void(const std::string& title, int progress)>;
virtual std::unique_ptr<Handler> handleShowProgress(ShowProgressFn fn) = 0;
diff --git a/src/miner.cpp b/src/miner.cpp
index d4527a1d67..738ccad1b9 100644
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -209,7 +209,7 @@ bool BlockAssembler::TestPackage(uint64_t packageSize, int64_t packageSigOpsCost
// segwit activation)
bool BlockAssembler::TestPackageTransactions(const CTxMemPool::setEntries& package)
{
- for (const CTxMemPool::txiter it : package) {
+ for (CTxMemPool::txiter it : package) {
if (!IsFinalTx(it->GetTx(), nHeight, nLockTimeCutoff))
return false;
if (!fIncludeWitness && it->GetTx().HasWitness())
@@ -241,7 +241,7 @@ int BlockAssembler::UpdatePackagesForAdded(const CTxMemPool::setEntries& already
indexed_modified_transaction_set &mapModifiedTx)
{
int nDescendantsUpdated = 0;
- for (const CTxMemPool::txiter it : alreadyAdded) {
+ for (CTxMemPool::txiter it : alreadyAdded) {
CTxMemPool::setEntries descendants;
mempool.CalculateDescendants(it, descendants);
// Insert all descendants (not yet in block) into the modified set
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index fc05dd2ad2..de456e87f4 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -561,7 +561,7 @@ static void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vec
} // namespace
// This function is used for testing the stale tip eviction logic, see
-// DoS_tests.cpp
+// denialofservice_tests.cpp
void UpdateLastBlockAnnounceTime(NodeId node, int64_t time_in_seconds)
{
LOCK(cs_main);
diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp
index 5963bf371a..aac3fe5c14 100644
--- a/src/policy/policy.cpp
+++ b/src/policy/policy.cpp
@@ -54,7 +54,7 @@ bool IsDust(const CTxOut& txout, const CFeeRate& dustRelayFeeIn)
return (txout.nValue < GetDustThreshold(txout, dustRelayFeeIn));
}
-bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType, const bool witnessEnabled)
+bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType)
{
std::vector<std::vector<unsigned char> > vSolutions;
if (!Solver(scriptPubKey, whichType, vSolutions))
@@ -73,13 +73,10 @@ bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType, const bool w
(!fAcceptDatacarrier || scriptPubKey.size() > nMaxDatacarrierBytes))
return false;
- else if (!witnessEnabled && (whichType == TX_WITNESS_V0_KEYHASH || whichType == TX_WITNESS_V0_SCRIPTHASH))
- return false;
-
return whichType != TX_NONSTANDARD && whichType != TX_WITNESS_UNKNOWN;
}
-bool IsStandardTx(const CTransaction& tx, std::string& reason, const bool witnessEnabled)
+bool IsStandardTx(const CTransaction& tx, std::string& reason)
{
if (tx.nVersion > CTransaction::MAX_STANDARD_VERSION || tx.nVersion < 1) {
reason = "version";
@@ -118,7 +115,7 @@ bool IsStandardTx(const CTransaction& tx, std::string& reason, const bool witnes
unsigned int nDataOut = 0;
txnouttype whichType;
for (const CTxOut& txout : tx.vout) {
- if (!::IsStandard(txout.scriptPubKey, whichType, witnessEnabled)) {
+ if (!::IsStandard(txout.scriptPubKey, whichType)) {
reason = "scriptpubkey";
return false;
}
diff --git a/src/policy/policy.h b/src/policy/policy.h
index 5ce019df4c..035627bd60 100644
--- a/src/policy/policy.h
+++ b/src/policy/policy.h
@@ -79,12 +79,12 @@ CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFee);
bool IsDust(const CTxOut& txout, const CFeeRate& dustRelayFee);
-bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType, const bool witnessEnabled = false);
+bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType);
/**
* Check for standard transaction types
* @return True if all outputs (scriptPubKeys) use only standard transaction forms
*/
-bool IsStandardTx(const CTransaction& tx, std::string& reason, const bool witnessEnabled = false);
+bool IsStandardTx(const CTransaction& tx, std::string& reason);
/**
* Check for standard transaction types
* @param[in] mapInputs Map of previous transactions that have outputs we're spending
diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h
index 1c846d38ec..360615ec56 100644
--- a/src/primitives/transaction.h
+++ b/src/primitives/transaction.h
@@ -388,11 +388,6 @@ struct CMutableTransaction
*/
uint256 GetHash() const;
- friend bool operator==(const CMutableTransaction& a, const CMutableTransaction& b)
- {
- return a.GetHash() == b.GetHash();
- }
-
bool HasWitness() const
{
for (size_t i = 0; i < vin.size(); i++) {
diff --git a/src/qt/README.md b/src/qt/README.md
index bf8139666c..3ec538b4f4 100644
--- a/src/qt/README.md
+++ b/src/qt/README.md
@@ -1,6 +1,6 @@
This directory contains the BitcoinQT graphical user interface (GUI). It uses the cross-platform framework [Qt](https://www1.qt.io/developers/).
-The current precise version for Qt 5 is specified in [qt.mk](/depends/packages/qt.mk). Qt 4 is also supported (see [#8263](https://github.com/bitcoin/bitcoin/issues/8263)).
+The current precise version for Qt 5 is specified in [qt.mk](/depends/packages/qt.mk).
## Compile and run
@@ -16,7 +16,7 @@ To run:
### forms
-Contains [Designer UI](http://doc.qt.io/qt-5.9/designer-using-a-ui-file.html) files. They are created with [Qt Creator](#using-qt-creator-as-ide), but can be edited using any text editor.
+Contains [Designer UI](https://doc.qt.io/qt-5.9/designer-using-a-ui-file.html) files. They are created with [Qt Creator](#using-qt-creator-as-ide), but can be edited using any text editor.
### locale
@@ -36,7 +36,7 @@ Represents the main window of the Bitcoin UI.
### \*model.(h/cpp)
-The model. When it has a corresponding controller, it generally inherits from [QAbstractTableModel](http://doc.qt.io/qt-5/qabstracttablemodel.html). Models that are used by controllers as helpers inherit from other Qt classes like [QValidator](http://doc.qt.io/qt-5/qvalidator.html).
+The model. When it has a corresponding controller, it generally inherits from [QAbstractTableModel](https://doc.qt.io/qt-5/qabstracttablemodel.html). Models that are used by controllers as helpers inherit from other Qt classes like [QValidator](https://doc.qt.io/qt-5/qvalidator.html).
ClientModel is used by the main application `bitcoingui` and several models like `peertablemodel`.
@@ -46,7 +46,7 @@ A controller. `:NAMEpage.cpp` generally includes `:NAMEmodel.h` and `forms/:NAME
### \*dialog.(h/cpp)
-Various dialogs, e.g. to open a URL. Inherit from [QDialog](http://doc.qt.io/qt-4.8/qdialog.html).
+Various dialogs, e.g. to open a URL. Inherit from [QDialog](https://doc.qt.io/qt-5/qdialog.html).
### paymentserver.(h/cpp)
diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp
index f2ddbf259b..d51069d922 100644
--- a/src/qt/addressbookpage.cpp
+++ b/src/qt/addressbookpage.cpp
@@ -160,13 +160,8 @@ void AddressBookPage::setModel(AddressTableModel *_model)
ui->tableView->sortByColumn(0, Qt::AscendingOrder);
// Set column widths
-#if QT_VERSION < 0x050000
- ui->tableView->horizontalHeader()->setResizeMode(AddressTableModel::Label, QHeaderView::Stretch);
- ui->tableView->horizontalHeader()->setResizeMode(AddressTableModel::Address, QHeaderView::ResizeToContents);
-#else
ui->tableView->horizontalHeader()->setSectionResizeMode(AddressTableModel::Label, QHeaderView::Stretch);
ui->tableView->horizontalHeader()->setSectionResizeMode(AddressTableModel::Address, QHeaderView::ResizeToContents);
-#endif
connect(ui->tableView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
this, SLOT(selectionChanged()));
diff --git a/src/qt/bantablemodel.cpp b/src/qt/bantablemodel.cpp
index 26cb03c2c7..aa0d4a31d3 100644
--- a/src/qt/bantablemodel.cpp
+++ b/src/qt/bantablemodel.cpp
@@ -52,9 +52,7 @@ public:
node.getBanned(banMap);
cachedBanlist.clear();
-#if QT_VERSION >= 0x040700
cachedBanlist.reserve(banMap.size());
-#endif
for (const auto& entry : banMap)
{
CCombinedBan banEntry;
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 31d9f936e7..e3d1c746b1 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -55,13 +55,6 @@
#if defined(QT_STATICPLUGIN)
#include <QtPlugin>
-#if QT_VERSION < 0x050000
-Q_IMPORT_PLUGIN(qcncodecs)
-Q_IMPORT_PLUGIN(qjpcodecs)
-Q_IMPORT_PLUGIN(qtwcodecs)
-Q_IMPORT_PLUGIN(qkrcodecs)
-Q_IMPORT_PLUGIN(qtaccessiblewidgets)
-#else
#if QT_VERSION < 0x050400
Q_IMPORT_PLUGIN(AccessibleFactory)
#endif
@@ -73,11 +66,6 @@ Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin);
Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin);
#endif
#endif
-#endif
-
-#if QT_VERSION < 0x050000
-#include <QTextCodec>
-#endif
// Declare meta types used for QMetaObject::invokeMethod
Q_DECLARE_METATYPE(bool*)
@@ -151,16 +139,6 @@ static void initTranslations(QTranslator &qtTranslatorBase, QTranslator &qtTrans
}
/* qDebug() message handler --> debug.log */
-#if QT_VERSION < 0x050000
-void DebugMessageHandler(QtMsgType type, const char *msg)
-{
- if (type == QtDebugMsg) {
- LogPrint(BCLog::QT, "GUI: %s\n", msg);
- } else {
- LogPrintf("GUI: %s\n", msg);
- }
-}
-#else
void DebugMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString &msg)
{
Q_UNUSED(context);
@@ -170,7 +148,6 @@ void DebugMessageHandler(QtMsgType type, const QMessageLogContext& context, cons
LogPrintf("GUI: %s\n", msg.toStdString());
}
}
-#endif
/** Class encapsulating Bitcoin Core startup and shutdown.
* Allows running startup and shutdown in a different thread from the UI thread.
@@ -238,6 +215,7 @@ public Q_SLOTS:
/// Handle runaway exceptions. Shows a message box with the problem and quits the program.
void handleRunawayException(const QString &message);
void addWallet(WalletModel* walletModel);
+ void removeWallet();
Q_SIGNALS:
void requestedInitialize();
@@ -467,11 +445,22 @@ void BitcoinApplication::addWallet(WalletModel* walletModel)
connect(walletModel, SIGNAL(coinsSent(WalletModel*, SendCoinsRecipient, QByteArray)),
paymentServer, SLOT(fetchPaymentACK(WalletModel*, const SendCoinsRecipient&, QByteArray)));
+ connect(walletModel, SIGNAL(unload()), this, SLOT(removeWallet()));
m_wallet_models.push_back(walletModel);
#endif
}
+void BitcoinApplication::removeWallet()
+{
+#ifdef ENABLE_WALLET
+ WalletModel* walletModel = static_cast<WalletModel*>(sender());
+ m_wallet_models.erase(std::find(m_wallet_models.begin(), m_wallet_models.end(), walletModel));
+ window->removeWallet(walletModel);
+ walletModel->deleteLater();
+#endif
+}
+
void BitcoinApplication::initializeResult(bool success)
{
qDebug() << __func__ << ": Initialization result: " << success;
@@ -491,8 +480,10 @@ void BitcoinApplication::initializeResult(bool success)
#ifdef ENABLE_WALLET
m_handler_load_wallet = m_node.handleLoadWallet([this](std::unique_ptr<interfaces::Wallet> wallet) {
- QMetaObject::invokeMethod(this, "addWallet", Qt::QueuedConnection,
- Q_ARG(WalletModel*, new WalletModel(std::move(wallet), m_node, platformStyle, optionsModel)));
+ WalletModel* wallet_model = new WalletModel(std::move(wallet), m_node, platformStyle, optionsModel, nullptr);
+ // Fix wallet model thread affinity.
+ wallet_model->moveToThread(thread());
+ QMetaObject::invokeMethod(this, "addWallet", Qt::QueuedConnection, Q_ARG(WalletModel*, wallet_model));
});
for (auto& wallet : m_node.getWallets()) {
@@ -572,12 +563,6 @@ int main(int argc, char *argv[])
// Do not refer to data directory yet, this can be overridden by Intro::pickDataDirectory
/// 1. Basic Qt initialization (not dependent on parameters or configuration)
-#if QT_VERSION < 0x050000
- // Internal string conversion is all UTF-8
- QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
- QTextCodec::setCodecForCStrings(QTextCodec::codecForTr());
-#endif
-
Q_INIT_RESOURCE(bitcoin);
Q_INIT_RESOURCE(bitcoin_locale);
@@ -708,17 +693,12 @@ int main(int argc, char *argv[])
/// 9. Main GUI initialization
// Install global event filter that makes sure that long tooltips can be word-wrapped
app.installEventFilter(new GUIUtil::ToolTipToRichTextFilter(TOOLTIP_WRAP_THRESHOLD, &app));
-#if QT_VERSION < 0x050000
- // Install qDebug() message handler to route to debug.log
- qInstallMsgHandler(DebugMessageHandler);
-#else
#if defined(Q_OS_WIN)
// Install global event filter for processing Windows session related Windows messages (WM_QUERYENDSESSION and WM_ENDSESSION)
qApp->installNativeEventFilter(new WinShutdownMonitor());
#endif
// Install qDebug() message handler to route to debug.log
qInstallMessageHandler(DebugMessageHandler);
-#endif
// Allow parameter interaction before we create the options model
app.parameterSetup();
// Load GUI settings from QSettings
@@ -739,7 +719,7 @@ int main(int argc, char *argv[])
// so the GUI thread won't be held up.
if (node->baseInitialize()) {
app.requestInitialize();
-#if defined(Q_OS_WIN) && QT_VERSION >= 0x050000
+#if defined(Q_OS_WIN)
WinShutdownMonitor::registerShutdownBlockReason(QObject::tr("%1 didn't yet exit safely...").arg(QObject::tr(PACKAGE_NAME)), (HWND)app.getMainWinId());
#endif
app.exec();
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index 9f5ea02e14..df78652376 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -55,14 +55,8 @@
#include <QStyle>
#include <QTimer>
#include <QToolBar>
-#include <QVBoxLayout>
-
-#if QT_VERSION < 0x050000
-#include <QTextDocument>
-#include <QUrl>
-#else
#include <QUrlQuery>
-#endif
+#include <QVBoxLayout>
const std::string BitcoinGUI::DEFAULT_UIPLATFORM =
#if defined(Q_OS_MAC)
@@ -76,50 +70,7 @@ const std::string BitcoinGUI::DEFAULT_UIPLATFORM =
BitcoinGUI::BitcoinGUI(interfaces::Node& node, const PlatformStyle *_platformStyle, const NetworkStyle *networkStyle, QWidget *parent) :
QMainWindow(parent),
- enableWallet(false),
m_node(node),
- clientModel(0),
- walletFrame(0),
- unitDisplayControl(0),
- labelWalletEncryptionIcon(0),
- labelWalletHDStatusIcon(0),
- labelProxyIcon(0),
- connectionsControl(0),
- labelBlocksIcon(0),
- progressBarLabel(0),
- progressBar(0),
- progressDialog(0),
- appMenuBar(0),
- appToolBar(0),
- overviewAction(0),
- historyAction(0),
- quitAction(0),
- sendCoinsAction(0),
- sendCoinsMenuAction(0),
- usedSendingAddressesAction(0),
- usedReceivingAddressesAction(0),
- signMessageAction(0),
- verifyMessageAction(0),
- aboutAction(0),
- receiveCoinsAction(0),
- receiveCoinsMenuAction(0),
- optionsAction(0),
- toggleHideAction(0),
- encryptWalletAction(0),
- backupWalletAction(0),
- changePassphraseAction(0),
- aboutQtAction(0),
- openRPCConsoleAction(0),
- openAction(0),
- showHelpMessageAction(0),
- trayIcon(0),
- trayIconMenu(0),
- notificator(0),
- rpcConsole(0),
- helpMessageDialog(0),
- modalOverlay(0),
- prevBlocks(0),
- spinnerFrame(0),
platformStyle(_platformStyle)
{
QSettings settings;
@@ -147,12 +98,6 @@ BitcoinGUI::BitcoinGUI(interfaces::Node& node, const PlatformStyle *_platformSty
#endif
setWindowTitle(windowTitle);
-#if defined(Q_OS_MAC) && QT_VERSION < 0x050000
- // This property is not implemented in Qt 5. Setting it has no effect.
- // A replacement API (QtMacUnifiedToolBar) is available in QtMacExtras.
- setUnifiedTitleAndToolBarOnMac(true);
-#endif
-
rpcConsole = new RPCConsole(node, _platformStyle, 0);
helpMessageDialog = new HelpMessageDialog(node, this, false);
#ifdef ENABLE_WALLET
@@ -229,7 +174,7 @@ BitcoinGUI::BitcoinGUI(interfaces::Node& node, const PlatformStyle *_platformSty
// Override style sheet for progress bar for styles that have a segmented progress bar,
// as they make the text unreadable (workaround for issue #1071)
- // See https://qt-project.org/doc/qt-4.8/gallery.html
+ // See https://doc.qt.io/qt-5/gallery.html
QString curStyle = QApplication::style()->metaObject()->className();
if(curStyle == "QWindowsStyle" || curStyle == "QWindowsXPStyle")
{
@@ -477,6 +422,16 @@ void BitcoinGUI::createToolBars()
m_wallet_selector = new QComboBox();
connect(m_wallet_selector, SIGNAL(currentIndexChanged(int)), this, SLOT(setCurrentWalletBySelectorIndex(int)));
+
+ m_wallet_selector_label = new QLabel();
+ m_wallet_selector_label->setText(tr("Wallet:") + " ");
+ m_wallet_selector_label->setBuddy(m_wallet_selector);
+
+ m_wallet_selector_label_action = appToolBar->addWidget(m_wallet_selector_label);
+ m_wallet_selector_action = appToolBar->addWidget(m_wallet_selector);
+
+ m_wallet_selector_label_action->setVisible(false);
+ m_wallet_selector_action->setVisible(false);
#endif
}
}
@@ -556,16 +511,29 @@ bool BitcoinGUI::addWallet(WalletModel *walletModel)
setWalletActionsEnabled(true);
m_wallet_selector->addItem(display_name, name);
if (m_wallet_selector->count() == 2) {
- m_wallet_selector_label = new QLabel();
- m_wallet_selector_label->setText(tr("Wallet:") + " ");
- m_wallet_selector_label->setBuddy(m_wallet_selector);
- appToolBar->addWidget(m_wallet_selector_label);
- appToolBar->addWidget(m_wallet_selector);
+ m_wallet_selector_label_action->setVisible(true);
+ m_wallet_selector_action->setVisible(true);
}
rpcConsole->addWallet(walletModel);
return walletFrame->addWallet(walletModel);
}
+bool BitcoinGUI::removeWallet(WalletModel* walletModel)
+{
+ if (!walletFrame) return false;
+ QString name = walletModel->getWalletName();
+ int index = m_wallet_selector->findData(name);
+ m_wallet_selector->removeItem(index);
+ if (m_wallet_selector->count() == 0) {
+ setWalletActionsEnabled(false);
+ } else if (m_wallet_selector->count() == 1) {
+ m_wallet_selector_label_action->setVisible(false);
+ m_wallet_selector_action->setVisible(false);
+ }
+ rpcConsole->removeWallet(walletModel);
+ return walletFrame->removeWallet(name);
+}
+
bool BitcoinGUI::setCurrentWallet(const QString& name)
{
if(!walletFrame)
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index 89c1c73a79..964e04f848 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -70,9 +70,10 @@ public:
functionality.
*/
bool addWallet(WalletModel *walletModel);
+ bool removeWallet(WalletModel* walletModel);
void removeAllWallets();
#endif // ENABLE_WALLET
- bool enableWallet;
+ bool enableWallet = false;
protected:
void changeEvent(QEvent *e);
@@ -86,56 +87,58 @@ private:
interfaces::Node& m_node;
std::unique_ptr<interfaces::Handler> m_handler_message_box;
std::unique_ptr<interfaces::Handler> m_handler_question;
- ClientModel *clientModel;
- WalletFrame *walletFrame;
-
- UnitDisplayStatusBarControl *unitDisplayControl;
- QLabel *labelWalletEncryptionIcon;
- QLabel *labelWalletHDStatusIcon;
- QLabel *labelProxyIcon;
- QLabel *connectionsControl;
- QLabel *labelBlocksIcon;
- QLabel *progressBarLabel;
- QProgressBar *progressBar;
- QProgressDialog *progressDialog;
-
- QMenuBar *appMenuBar;
- QToolBar *appToolBar;
- QAction *overviewAction;
- QAction *historyAction;
- QAction *quitAction;
- QAction *sendCoinsAction;
- QAction *sendCoinsMenuAction;
- QAction *usedSendingAddressesAction;
- QAction *usedReceivingAddressesAction;
- QAction *signMessageAction;
- QAction *verifyMessageAction;
- QAction *aboutAction;
- QAction *receiveCoinsAction;
- QAction *receiveCoinsMenuAction;
- QAction *optionsAction;
- QAction *toggleHideAction;
- QAction *encryptWalletAction;
- QAction *backupWalletAction;
- QAction *changePassphraseAction;
- QAction *aboutQtAction;
- QAction *openRPCConsoleAction;
- QAction *openAction;
- QAction *showHelpMessageAction;
-
- QLabel *m_wallet_selector_label;
- QComboBox *m_wallet_selector;
-
- QSystemTrayIcon *trayIcon;
- QMenu *trayIconMenu;
- Notificator *notificator;
- RPCConsole *rpcConsole;
- HelpMessageDialog *helpMessageDialog;
- ModalOverlay *modalOverlay;
+ ClientModel* clientModel = nullptr;
+ WalletFrame* walletFrame = nullptr;
+
+ UnitDisplayStatusBarControl* unitDisplayControl = nullptr;
+ QLabel* labelWalletEncryptionIcon = nullptr;
+ QLabel* labelWalletHDStatusIcon = nullptr;
+ QLabel* labelProxyIcon = nullptr;
+ QLabel* connectionsControl = nullptr;
+ QLabel* labelBlocksIcon = nullptr;
+ QLabel* progressBarLabel = nullptr;
+ QProgressBar* progressBar = nullptr;
+ QProgressDialog* progressDialog = nullptr;
+
+ QMenuBar* appMenuBar = nullptr;
+ QToolBar* appToolBar = nullptr;
+ QAction* overviewAction = nullptr;
+ QAction* historyAction = nullptr;
+ QAction* quitAction = nullptr;
+ QAction* sendCoinsAction = nullptr;
+ QAction* sendCoinsMenuAction = nullptr;
+ QAction* usedSendingAddressesAction = nullptr;
+ QAction* usedReceivingAddressesAction = nullptr;
+ QAction* signMessageAction = nullptr;
+ QAction* verifyMessageAction = nullptr;
+ QAction* aboutAction = nullptr;
+ QAction* receiveCoinsAction = nullptr;
+ QAction* receiveCoinsMenuAction = nullptr;
+ QAction* optionsAction = nullptr;
+ QAction* toggleHideAction = nullptr;
+ QAction* encryptWalletAction = nullptr;
+ QAction* backupWalletAction = nullptr;
+ QAction* changePassphraseAction = nullptr;
+ QAction* aboutQtAction = nullptr;
+ QAction* openRPCConsoleAction = nullptr;
+ QAction* openAction = nullptr;
+ QAction* showHelpMessageAction = nullptr;
+ QAction* m_wallet_selector_label_action = nullptr;
+ QAction* m_wallet_selector_action = nullptr;
+
+ QLabel *m_wallet_selector_label = nullptr;
+ QComboBox* m_wallet_selector = nullptr;
+
+ QSystemTrayIcon* trayIcon = nullptr;
+ QMenu* trayIconMenu = nullptr;
+ Notificator* notificator = nullptr;
+ RPCConsole* rpcConsole = nullptr;
+ HelpMessageDialog* helpMessageDialog = nullptr;
+ ModalOverlay* modalOverlay = nullptr;
/** Keep track of previous number of blocks, to detect progress */
- int prevBlocks;
- int spinnerFrame;
+ int prevBlocks = 0;
+ int spinnerFrame = 0;
const PlatformStyle *platformStyle;
diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp
index b08de27041..9b6480a915 100644
--- a/src/qt/coincontroldialog.cpp
+++ b/src/qt/coincontroldialog.cpp
@@ -109,11 +109,7 @@ CoinControlDialog::CoinControlDialog(const PlatformStyle *_platformStyle, QWidge
connect(ui->treeWidget, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(viewItemChanged(QTreeWidgetItem*, int)));
// click on header
-#if QT_VERSION < 0x050000
- ui->treeWidget->header()->setClickable(true);
-#else
ui->treeWidget->header()->setSectionsClickable(true);
-#endif
connect(ui->treeWidget->header(), SIGNAL(sectionClicked(int)), this, SLOT(headerSectionClicked(int)));
// ok button
@@ -122,10 +118,6 @@ CoinControlDialog::CoinControlDialog(const PlatformStyle *_platformStyle, QWidge
// (un)select all
connect(ui->pushButtonSelectAll, SIGNAL(clicked()), this, SLOT(buttonSelectAllClicked()));
- // change coin control first column label due Qt4 bug.
- // see https://github.com/bitcoin/bitcoin/issues/5716
- ui->treeWidget->headerItem()->setText(COLUMN_CHECKBOX, QString());
-
ui->treeWidget->setColumnWidth(COLUMN_CHECKBOX, 84);
ui->treeWidget->setColumnWidth(COLUMN_AMOUNT, 110);
ui->treeWidget->setColumnWidth(COLUMN_LABEL, 190);
@@ -392,13 +384,11 @@ void CoinControlDialog::viewItemChanged(QTreeWidgetItem* item, int column)
// TODO: Remove this temporary qt5 fix after Qt5.3 and Qt5.4 are no longer used.
// Fixed in Qt5.5 and above: https://bugreports.qt.io/browse/QTBUG-43473
-#if QT_VERSION >= 0x050000
else if (column == COLUMN_CHECKBOX && item->childCount() > 0)
{
if (item->checkState(COLUMN_CHECKBOX) == Qt::PartiallyChecked && item->child(0)->checkState(COLUMN_CHECKBOX) == Qt::PartiallyChecked)
item->setCheckState(COLUMN_CHECKBOX, Qt::Checked);
}
-#endif
}
// shows count of locked unspent outputs
diff --git a/src/qt/forms/optionsdialog.ui b/src/qt/forms/optionsdialog.ui
index a3721991ee..8f34e6bc82 100644
--- a/src/qt/forms/optionsdialog.ui
+++ b/src/qt/forms/optionsdialog.ui
@@ -38,6 +38,69 @@
</widget>
</item>
<item>
+ <spacer name="horizontalSpacer_0_Main">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>5</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_Main_Prune">
+ <item>
+ <widget class="QCheckBox" name="prune">
+ <property name="toolTip">
+ <string>Disables some advanced features but all blocks will still be fully validated. Reverting this setting requires re-downloading the entire blockchain. Actual disk usage may be somewhat higher.</string>
+ </property>
+ <property name="text">
+ <string>Prune &amp;block storage to</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="pruneSize"/>
+ </item>
+ <item>
+ <widget class="QLabel" name="pruneSizeUnitLabel">
+ <property name="text">
+ <string>GB</string>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::PlainText</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_Main_Prune">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QLabel" name="pruneWarning">
+ <property name="text">
+ <string>Reverting this setting requires re-downloading the entire blockchain.</string>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::PlainText</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
<layout class="QHBoxLayout" name="horizontalLayout_2_Main">
<item>
<widget class="QLabel" name="databaseCacheLabel">
@@ -81,7 +144,7 @@
</layout>
</item>
<item>
- <layout class="QHBoxLayout" name="horizontalLayout_3_Main">
+ <layout class="QHBoxLayout" name="horizontalLayout_Main_VerifyLabel">
<item>
<widget class="QLabel" name="threadsScriptVerifLabel">
<property name="text">
@@ -103,7 +166,7 @@
</widget>
</item>
<item>
- <spacer name="horizontalSpacer_3_Main">
+ <spacer name="horizontalSpacer_Main_Threads">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index 563f930dec..acd9f7b35c 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -53,13 +53,9 @@
#include <QSettings>
#include <QTextDocument> // for Qt::mightBeRichText
#include <QThread>
+#include <QUrlQuery>
#include <QMouseEvent>
-#if QT_VERSION < 0x050000
-#include <QUrl>
-#else
-#include <QUrlQuery>
-#endif
#if QT_VERSION >= 0x50200
#include <QFontDatabase>
@@ -95,11 +91,7 @@ QFont fixedPitchFont()
return QFontDatabase::systemFont(QFontDatabase::FixedFont);
#else
QFont font("Monospace");
-#if QT_VERSION >= 0x040800
font.setStyleHint(QFont::Monospace);
-#else
- font.setStyleHint(QFont::TypeWriter);
-#endif
return font;
#endif
}
@@ -127,12 +119,10 @@ void setupAddressWidget(QValidatedLineEdit *widget, QWidget *parent)
parent->setFocusProxy(widget);
widget->setFont(fixedPitchFont());
-#if QT_VERSION >= 0x040700
// We don't want translators to use own addresses in translations
// and this is the only place, where this address is supplied.
widget->setPlaceholderText(QObject::tr("Enter a Bitcoin address (e.g. %1)").arg(
QString::fromStdString(DummyAddress(Params()))));
-#endif
widget->setValidator(new BitcoinAddressEntryValidator(parent));
widget->setCheckValidator(new BitcoinAddressCheckValidator(parent));
}
@@ -151,12 +141,8 @@ bool parseBitcoinURI(const QUrl &uri, SendCoinsRecipient *out)
}
rv.amount = 0;
-#if QT_VERSION < 0x050000
- QList<QPair<QString, QString> > items = uri.queryItems();
-#else
QUrlQuery uriQuery(uri);
QList<QPair<QString, QString> > items = uriQuery.queryItems();
-#endif
for (QList<QPair<QString, QString> >::iterator i = items.begin(); i != items.end(); i++)
{
bool fShouldReturnFalse = false;
@@ -242,11 +228,7 @@ bool isDust(interfaces::Node& node, const QString& address, const CAmount& amoun
QString HtmlEscape(const QString& str, bool fMultiLine)
{
-#if QT_VERSION < 0x050000
- QString escaped = Qt::escape(str);
-#else
QString escaped = str.toHtmlEscaped();
-#endif
if(fMultiLine)
{
escaped = escaped.replace("\n", "<br>\n");
@@ -287,11 +269,7 @@ QString getSaveFileName(QWidget *parent, const QString &caption, const QString &
QString myDir;
if(dir.isEmpty()) // Default to user documents location
{
-#if QT_VERSION < 0x050000
- myDir = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation);
-#else
myDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
-#endif
}
else
{
@@ -337,11 +315,7 @@ QString getOpenFileName(QWidget *parent, const QString &caption, const QString &
QString myDir;
if(dir.isEmpty()) // Default to user documents location
{
-#if QT_VERSION < 0x050000
- myDir = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation);
-#else
myDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
-#endif
}
else
{
@@ -495,11 +469,7 @@ void TableViewLastColumnResizingFixer::disconnectViewHeadersSignals()
// Refactored here for readability.
void TableViewLastColumnResizingFixer::setViewHeaderResizeMode(int logicalIndex, QHeaderView::ResizeMode resizeMode)
{
-#if QT_VERSION < 0x050000
- tableView->horizontalHeader()->setResizeMode(logicalIndex, resizeMode);
-#else
tableView->horizontalHeader()->setSectionResizeMode(logicalIndex, resizeMode);
-#endif
}
void TableViewLastColumnResizingFixer::resizeColumn(int nColumnIndex, int width)
diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h
index 4a26964098..e965a91d18 100644
--- a/src/qt/guiutil.h
+++ b/src/qt/guiutil.h
@@ -233,7 +233,7 @@ namespace GUIUtil
void mouseReleaseEvent(QMouseEvent *event);
};
-#if defined(Q_OS_MAC) && QT_VERSION >= 0x050000
+#if defined(Q_OS_MAC)
// workaround for Qt OSX Bug:
// https://bugreports.qt-project.org/browse/QTBUG-15631
// QProgressBar uses around 10% CPU even when app is in background
diff --git a/src/qt/macdockiconhandler.mm b/src/qt/macdockiconhandler.mm
index 9e7de0f98f..a0b62ae000 100644
--- a/src/qt/macdockiconhandler.mm
+++ b/src/qt/macdockiconhandler.mm
@@ -14,10 +14,6 @@
#include <objc/objc.h>
#include <objc/message.h>
-#if QT_VERSION < 0x050000
-extern void qt_mac_set_dock_menu(QMenu *);
-#endif
-
static MacDockIconHandler *s_instance = nullptr;
bool dockClickHandler(id self,SEL _cmd,...) {
@@ -54,9 +50,7 @@ MacDockIconHandler::MacDockIconHandler() : QObject()
this->m_dummyWidget = new QWidget();
this->m_dockMenu = new QMenu(this->m_dummyWidget);
this->setMainWindow(nullptr);
-#if QT_VERSION < 0x050000
- qt_mac_set_dock_menu(this->m_dockMenu);
-#elif QT_VERSION >= 0x050200
+#if QT_VERSION >= 0x050200
this->m_dockMenu->setAsDockMenu();
#endif
[pool release];
diff --git a/src/qt/networkstyle.cpp b/src/qt/networkstyle.cpp
index 2816633b0f..c4b732e3e0 100644
--- a/src/qt/networkstyle.cpp
+++ b/src/qt/networkstyle.cpp
@@ -68,11 +68,7 @@ NetworkStyle::NetworkStyle(const QString &_appName, const int iconColorHueShift,
}
//convert back to QPixmap
-#if QT_VERSION >= 0x040700
pixmap.convertFromImage(img);
-#else
- pixmap = QPixmap::fromImage(img);
-#endif
}
appIcon = QIcon(pixmap);
diff --git a/src/qt/openuridialog.cpp b/src/qt/openuridialog.cpp
index 751cfa8b43..d211f908c8 100644
--- a/src/qt/openuridialog.cpp
+++ b/src/qt/openuridialog.cpp
@@ -15,9 +15,7 @@ OpenURIDialog::OpenURIDialog(QWidget *parent) :
ui(new Ui::OpenURIDialog)
{
ui->setupUi(this);
-#if QT_VERSION >= 0x040700
ui->uriEdit->setPlaceholderText("bitcoin:");
-#endif
}
OpenURIDialog::~OpenURIDialog()
diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp
index c0ddb89b40..3ff6f59c25 100644
--- a/src/qt/optionsdialog.cpp
+++ b/src/qt/optionsdialog.cpp
@@ -36,8 +36,17 @@ OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) :
/* Main elements init */
ui->databaseCache->setMinimum(nMinDbCache);
ui->databaseCache->setMaximum(nMaxDbCache);
+ static const uint64_t GiB = 1024 * 1024 * 1024;
+ static const uint64_t nMinDiskSpace = MIN_DISK_SPACE_FOR_BLOCK_FILES / GiB +
+ (MIN_DISK_SPACE_FOR_BLOCK_FILES % GiB) ? 1 : 0;
+ ui->pruneSize->setMinimum(nMinDiskSpace);
ui->threadsScriptVerif->setMinimum(-GetNumCores());
ui->threadsScriptVerif->setMaximum(MAX_SCRIPTCHECK_THREADS);
+ ui->pruneWarning->setVisible(false);
+ ui->pruneWarning->setStyleSheet("QLabel { color: red; }");
+
+ ui->pruneSize->setEnabled(false);
+ connect(ui->prune, SIGNAL(toggled(bool)), ui->pruneSize, SLOT(setEnabled(bool)));
/* Network elements init */
#ifndef USE_UPNP
@@ -88,28 +97,16 @@ OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) :
/** check if the locale name consists of 2 parts (language_country) */
if(langStr.contains("_"))
{
-#if QT_VERSION >= 0x040800
/** display language strings as "native language - native country (locale name)", e.g. "Deutsch - Deutschland (de)" */
ui->lang->addItem(locale.nativeLanguageName() + QString(" - ") + locale.nativeCountryName() + QString(" (") + langStr + QString(")"), QVariant(langStr));
-#else
- /** display language strings as "language - country (locale name)", e.g. "German - Germany (de)" */
- ui->lang->addItem(QLocale::languageToString(locale.language()) + QString(" - ") + QLocale::countryToString(locale.country()) + QString(" (") + langStr + QString(")"), QVariant(langStr));
-#endif
}
else
{
-#if QT_VERSION >= 0x040800
/** display language strings as "native language (locale name)", e.g. "Deutsch (de)" */
ui->lang->addItem(locale.nativeLanguageName() + QString(" (") + langStr + QString(")"), QVariant(langStr));
-#else
- /** display language strings as "language (locale name)", e.g. "German (de)" */
- ui->lang->addItem(QLocale::languageToString(locale.language()) + QString(" (") + langStr + QString(")"), QVariant(langStr));
-#endif
}
}
-#if QT_VERSION >= 0x040700
ui->thirdPartyTxUrls->setPlaceholderText("https://example.com/tx/%s");
-#endif
ui->unit->setModel(new BitcoinUnits(this));
@@ -157,6 +154,9 @@ void OptionsDialog::setModel(OptionsModel *_model)
/* warn when one of the following settings changes by user action (placed here so init via mapper doesn't trigger them) */
/* Main */
+ connect(ui->prune, SIGNAL(clicked(bool)), this, SLOT(showRestartWarning()));
+ connect(ui->prune, SIGNAL(clicked(bool)), this, SLOT(togglePruneWarning(bool)));
+ connect(ui->pruneSize, SIGNAL(valueChanged(int)), this, SLOT(showRestartWarning()));
connect(ui->databaseCache, SIGNAL(valueChanged(int)), this, SLOT(showRestartWarning()));
connect(ui->threadsScriptVerif, SIGNAL(valueChanged(int)), this, SLOT(showRestartWarning()));
/* Wallet */
@@ -176,6 +176,8 @@ void OptionsDialog::setMapper()
mapper->addMapping(ui->bitcoinAtStartup, OptionsModel::StartAtStartup);
mapper->addMapping(ui->threadsScriptVerif, OptionsModel::ThreadsScriptVerif);
mapper->addMapping(ui->databaseCache, OptionsModel::DatabaseCache);
+ mapper->addMapping(ui->prune, OptionsModel::Prune);
+ mapper->addMapping(ui->pruneSize, OptionsModel::PruneSize);
/* Wallet */
mapper->addMapping(ui->spendZeroConfChange, OptionsModel::SpendZeroConfChange);
@@ -266,6 +268,11 @@ void OptionsDialog::on_hideTrayIcon_stateChanged(int fState)
}
}
+void OptionsDialog::togglePruneWarning(bool enabled)
+{
+ ui->pruneWarning->setVisible(!ui->pruneWarning->isVisible());
+}
+
void OptionsDialog::showRestartWarning(bool fPersistent)
{
ui->statusLabel->setStyleSheet("QLabel { color: red; }");
diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h
index faf9ff8959..5aad484ce7 100644
--- a/src/qt/optionsdialog.h
+++ b/src/qt/optionsdialog.h
@@ -53,6 +53,7 @@ private Q_SLOTS:
void on_hideTrayIcon_stateChanged(int fState);
+ void togglePruneWarning(bool enabled);
void showRestartWarning(bool fPersistent = false);
void clearStatusLabel();
void updateProxyValidationState();
diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp
index cae9dace4c..31a85f4e23 100644
--- a/src/qt/optionsmodel.cpp
+++ b/src/qt/optionsmodel.cpp
@@ -88,6 +88,16 @@ void OptionsModel::Init(bool resetSettings)
// by command-line and show this in the UI.
// Main
+ if (!settings.contains("bPrune"))
+ settings.setValue("bPrune", false);
+ if (!settings.contains("nPruneSize"))
+ settings.setValue("nPruneSize", 2);
+ // Convert prune size to MB:
+ const uint64_t nPruneSizeMB = settings.value("nPruneSize").toInt() * 1000;
+ if (!m_node.softSetArg("-prune", settings.value("bPrune").toBool() ? std::to_string(nPruneSizeMB) : "0")) {
+ addOverriddenOption("-prune");
+ }
+
if (!settings.contains("nDatabaseCache"))
settings.setValue("nDatabaseCache", (qint64)nDefaultDbCache);
if (!m_node.softSetArg("-dbcache", settings.value("nDatabaseCache").toString().toStdString()))
@@ -281,6 +291,10 @@ QVariant OptionsModel::data(const QModelIndex & index, int role) const
return settings.value("language");
case CoinControlFeatures:
return fCoinControlFeatures;
+ case Prune:
+ return settings.value("bPrune");
+ case PruneSize:
+ return settings.value("nPruneSize");
case DatabaseCache:
return settings.value("nDatabaseCache");
case ThreadsScriptVerif:
@@ -405,6 +419,18 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in
settings.setValue("fCoinControlFeatures", fCoinControlFeatures);
Q_EMIT coinControlFeaturesChanged(fCoinControlFeatures);
break;
+ case Prune:
+ if (settings.value("bPrune") != value) {
+ settings.setValue("bPrune", value);
+ setRestartRequired(true);
+ }
+ break;
+ case PruneSize:
+ if (settings.value("nPruneSize") != value) {
+ settings.setValue("nPruneSize", value);
+ setRestartRequired(true);
+ }
+ break;
case DatabaseCache:
if (settings.value("nDatabaseCache") != value) {
settings.setValue("nDatabaseCache", value);
diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h
index fc1d119a71..2777cbeaf2 100644
--- a/src/qt/optionsmodel.h
+++ b/src/qt/optionsmodel.h
@@ -50,6 +50,8 @@ public:
Language, // QString
CoinControlFeatures, // bool
ThreadsScriptVerif, // int
+ Prune, // bool
+ PruneSize, // int
DatabaseCache, // int
SpendZeroConfChange, // bool
Listen, // bool
diff --git a/src/qt/paymentrequestplus.cpp b/src/qt/paymentrequestplus.cpp
index b0ef475b35..dfeb70d669 100644
--- a/src/qt/paymentrequestplus.cpp
+++ b/src/qt/paymentrequestplus.cpp
@@ -97,12 +97,10 @@ bool PaymentRequestPlus::getMerchant(X509_STORE* certStore, QString& merchant) c
qWarning() << "PaymentRequestPlus::getMerchant: Payment request: certificate expired or not yet active: " << qCert;
return false;
}
-#if QT_VERSION >= 0x050000
if (qCert.isBlacklisted()) {
qWarning() << "PaymentRequestPlus::getMerchant: Payment request: certificate blacklisted: " << qCert;
return false;
}
-#endif
const unsigned char *data = (const unsigned char *)certChain.certificate(i).data();
X509 *cert = d2i_X509(nullptr, &data, certChain.certificate(i).size());
if (cert)
diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp
index 59bb5d5bb6..e5e6430959 100644
--- a/src/qt/paymentserver.cpp
+++ b/src/qt/paymentserver.cpp
@@ -41,12 +41,7 @@
#include <QSslSocket>
#include <QStringList>
#include <QTextDocument>
-
-#if QT_VERSION < 0x050000
-#include <QUrl>
-#else
#include <QUrlQuery>
-#endif
const int BITCOIN_IPC_CONNECT_TIMEOUT = 1000; // milliseconds
const QString BITCOIN_IPC_PREFIX("bitcoin:");
@@ -100,11 +95,7 @@ static QList<QString> savedPaymentRequests;
static void ReportInvalidCertificate(const QSslCertificate& cert)
{
-#if QT_VERSION < 0x050000
- qDebug() << QString("%1: Payment server found an invalid certificate: ").arg(__func__) << cert.serialNumber() << cert.subjectInfo(QSslCertificate::CommonName) << cert.subjectInfo(QSslCertificate::OrganizationalUnitName);
-#else
qDebug() << QString("%1: Payment server found an invalid certificate: ").arg(__func__) << cert.serialNumber() << cert.subjectInfo(QSslCertificate::CommonName) << cert.subjectInfo(QSslCertificate::DistinguishedNameQualifier) << cert.subjectInfo(QSslCertificate::OrganizationalUnitName);
-#endif
}
//
@@ -157,13 +148,11 @@ void PaymentServer::LoadRootCAs(X509_STORE* _store)
continue;
}
-#if QT_VERSION >= 0x050000
// Blacklisted certificate
if (cert.isBlacklisted()) {
ReportInvalidCertificate(cert);
continue;
}
-#endif
QByteArray certData = cert.toDer();
const unsigned char *data = (const unsigned char *)certData.data();
@@ -413,11 +402,7 @@ void PaymentServer::handleURIOrFile(const QString& s)
}
else if (s.startsWith(BITCOIN_IPC_PREFIX, Qt::CaseInsensitive)) // bitcoin: URI
{
-#if QT_VERSION < 0x050000
- QUrl uri(s);
-#else
QUrlQuery uri((QUrl(s)));
-#endif
if (uri.hasQueryItem("r")) // payment request URI
{
QByteArray temp;
diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp
index 7e318e3035..0ca9d48bf6 100644
--- a/src/qt/peertablemodel.cpp
+++ b/src/qt/peertablemodel.cpp
@@ -64,9 +64,7 @@ public:
interfaces::Node::NodesStats nodes_stats;
node.getNodesStats(nodes_stats);
-#if QT_VERSION >= 0x040700
cachedNodeStats.reserve(nodes_stats.size());
-#endif
for (auto& node_stats : nodes_stats)
{
CNodeCombinedStats stats;
diff --git a/src/qt/platformstyle.cpp b/src/qt/platformstyle.cpp
index fce71f661a..a3a10aac18 100644
--- a/src/qt/platformstyle.cpp
+++ b/src/qt/platformstyle.cpp
@@ -46,7 +46,7 @@ void MakeSingleColorImage(QImage& img, const QColor& colorbase)
QIcon ColorizeIcon(const QIcon& ico, const QColor& colorbase)
{
QIcon new_ico;
- for (const QSize sz : ico.availableSizes())
+ for (const QSize& sz : ico.availableSizes())
{
QImage img(ico.pixmap(sz).toImage());
MakeSingleColorImage(img, colorbase);
diff --git a/src/qt/receiverequestdialog.cpp b/src/qt/receiverequestdialog.cpp
index 75146e2214..f9610f2d3b 100644
--- a/src/qt/receiverequestdialog.cpp
+++ b/src/qt/receiverequestdialog.cpp
@@ -16,9 +16,6 @@
#include <QMimeData>
#include <QMouseEvent>
#include <QPixmap>
-#if QT_VERSION < 0x050000
-#include <QUrl>
-#endif
#if defined(HAVE_CONFIG_H)
#include <config/bitcoin-config.h> /* for USE_QRCODE */
diff --git a/src/qt/res/movies/makespinner.sh b/src/qt/res/movies/makespinner.sh
index d0deb1238c..76e36e4f31 100755
--- a/src/qt/res/movies/makespinner.sh
+++ b/src/qt/res/movies/makespinner.sh
@@ -2,6 +2,7 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+export LC_ALL=C
FRAMEDIR=$(dirname $0)
for i in {0..35}
do
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 4550ae9396..f222357f27 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -40,10 +40,6 @@
#include <QTimer>
#include <QStringList>
-#if QT_VERSION < 0x050000
-#include <QUrl>
-#endif
-
// TODO: add a scrollback limit, as there is currently none
// TODO: make it possible to filter out categories (esp debug messages when implemented)
// TODO: receive errors and debug messages through ClientModel
@@ -713,6 +709,16 @@ void RPCConsole::addWallet(WalletModel * const walletModel)
ui->WalletSelectorLabel->setVisible(true);
}
}
+
+void RPCConsole::removeWallet(WalletModel * const walletModel)
+{
+ const QString name = walletModel->getWalletName();
+ ui->WalletSelector->removeItem(ui->WalletSelector->findData(name));
+ if (ui->WalletSelector->count() == 2) {
+ ui->WalletSelector->setVisible(false);
+ ui->WalletSelectorLabel->setVisible(false);
+ }
+}
#endif
static QString categoryClass(int category)
diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h
index a53c4c24f9..0a1a469934 100644
--- a/src/qt/rpcconsole.h
+++ b/src/qt/rpcconsole.h
@@ -48,6 +48,7 @@ public:
void setClientModel(ClientModel *model);
void addWallet(WalletModel * const walletModel);
+ void removeWallet(WalletModel* const walletModel);
enum MessageClass {
MC_ERROR,
diff --git a/src/qt/sendcoinsentry.cpp b/src/qt/sendcoinsentry.cpp
index 977425f7e3..e8c85bc2a1 100644
--- a/src/qt/sendcoinsentry.cpp
+++ b/src/qt/sendcoinsentry.cpp
@@ -32,9 +32,7 @@ SendCoinsEntry::SendCoinsEntry(const PlatformStyle *_platformStyle, QWidget *par
if (platformStyle->getUseExtraSpacing())
ui->payToLayout->setSpacing(4);
-#if QT_VERSION >= 0x040700
ui->addAsLabel->setPlaceholderText(tr("Enter a label for this address to add it to your address book"));
-#endif
// normal bitcoin address field
GUIUtil::setupAddressWidget(ui->payTo, this);
diff --git a/src/qt/signverifymessagedialog.cpp b/src/qt/signverifymessagedialog.cpp
index 94a3ad7987..c8e694e658 100644
--- a/src/qt/signverifymessagedialog.cpp
+++ b/src/qt/signverifymessagedialog.cpp
@@ -37,9 +37,7 @@ SignVerifyMessageDialog::SignVerifyMessageDialog(const PlatformStyle *_platformS
ui->verifyMessageButton_VM->setIcon(platformStyle->SingleColorIcon(":/icons/transaction_0"));
ui->clearButton_VM->setIcon(platformStyle->SingleColorIcon(":/icons/remove"));
-#if QT_VERSION >= 0x040700
ui->signatureOut_SM->setPlaceholderText(tr("Click \"Sign Message\" to generate signature"));
-#endif
GUIUtil::setupAddressWidget(ui->addressIn_SM, this);
GUIUtil::setupAddressWidget(ui->addressIn_VM, this);
diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp
index 56d4d3e457..f0ac43a58c 100644
--- a/src/qt/test/test_main.cpp
+++ b/src/qt/test/test_main.cpp
@@ -26,12 +26,6 @@
#if defined(QT_STATICPLUGIN)
#include <QtPlugin>
-#if QT_VERSION < 0x050000
-Q_IMPORT_PLUGIN(qcncodecs)
-Q_IMPORT_PLUGIN(qjpcodecs)
-Q_IMPORT_PLUGIN(qtwcodecs)
-Q_IMPORT_PLUGIN(qkrcodecs)
-#else
#if defined(QT_QPA_PLATFORM_MINIMAL)
Q_IMPORT_PLUGIN(QMinimalIntegrationPlugin);
#endif
@@ -43,7 +37,6 @@ Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin);
Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin);
#endif
#endif
-#endif
extern void noui_connect();
diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp
index 33c49dc7cb..c314dadde4 100644
--- a/src/qt/test/wallettests.cpp
+++ b/src/qt/test/wallettests.cpp
@@ -87,17 +87,6 @@ QModelIndex FindTx(const QAbstractItemModel& model, const uint256& txid)
return {};
}
-//! Request context menu (call method that is public in qt5, but protected in qt4).
-void RequestContextMenu(QWidget* widget)
-{
- class Qt4Hack : public QWidget
- {
- public:
- using QWidget::customContextMenuRequested;
- };
- static_cast<Qt4Hack*>(widget)->customContextMenuRequested({});
-}
-
//! Invoke bumpfee on txid and check results.
void BumpFee(TransactionView& view, const uint256& txid, bool expectDisabled, std::string expectError, bool cancel)
{
@@ -110,7 +99,7 @@ void BumpFee(TransactionView& view, const uint256& txid, bool expectDisabled, st
QAction* action = view.findChild<QAction*>("bumpFeeAction");
table->selectionModel()->select(index, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
action->setEnabled(expectDisabled);
- RequestContextMenu(table);
+ table->customContextMenuRequested({});
QCOMPARE(action->isEnabled(), !expectDisabled);
action->setEnabled(true);
diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp
index aa6444245a..e60a387934 100644
--- a/src/qt/transactionview.cpp
+++ b/src/qt/transactionview.cpp
@@ -95,15 +95,11 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa
hlayout->addWidget(typeWidget);
search_widget = new QLineEdit(this);
-#if QT_VERSION >= 0x040700
search_widget->setPlaceholderText(tr("Enter address, transaction id, or label to search"));
-#endif
hlayout->addWidget(search_widget);
amountWidget = new QLineEdit(this);
-#if QT_VERSION >= 0x040700
amountWidget->setPlaceholderText(tr("Min amount"));
-#endif
if (platformStyle->getUseExtraSpacing()) {
amountWidget->setFixedWidth(97);
} else {
diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp
index eb0eba21ef..c5a13f61f4 100644
--- a/src/qt/walletframe.cpp
+++ b/src/qt/walletframe.cpp
@@ -94,6 +94,7 @@ bool WalletFrame::removeWallet(const QString &name)
WalletView *walletView = mapWalletViews.take(name);
walletStack->removeWidget(walletView);
+ delete walletView;
return true;
}
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index 3418b1f1a9..389acf0a95 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -364,6 +364,12 @@ bool WalletModel::changePassphrase(const SecureString &oldPass, const SecureStri
}
// Handlers for core signals
+static void NotifyUnload(WalletModel* walletModel)
+{
+ qDebug() << "NotifyUnload";
+ QMetaObject::invokeMethod(walletModel, "unload", Qt::QueuedConnection);
+}
+
static void NotifyKeyStoreStatusChanged(WalletModel *walletmodel)
{
qDebug() << "NotifyKeyStoreStatusChanged";
@@ -411,6 +417,7 @@ 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));
@@ -421,6 +428,7 @@ void WalletModel::subscribeToCoreSignals()
void WalletModel::unsubscribeFromCoreSignals()
{
// Disconnect signals from wallet
+ m_handler_unload->disconnect();
m_handler_status_changed->disconnect();
m_handler_address_book_changed->disconnect();
m_handler_transaction_changed->disconnect();
diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h
index 9173fcae52..35ededb121 100644
--- a/src/qt/walletmodel.h
+++ b/src/qt/walletmodel.h
@@ -208,6 +208,7 @@ public:
AddressTableModel* getAddressTableModel() const { return addressTableModel; }
private:
std::unique_ptr<interfaces::Wallet> m_wallet;
+ std::unique_ptr<interfaces::Handler> m_handler_unload;
std::unique_ptr<interfaces::Handler> m_handler_status_changed;
std::unique_ptr<interfaces::Handler> m_handler_address_book_changed;
std::unique_ptr<interfaces::Handler> m_handler_transaction_changed;
@@ -261,6 +262,9 @@ Q_SIGNALS:
// Watch-only address added
void notifyWatchonlyChanged(bool fHaveWatchonly);
+ // Signal that wallet is about to be removed
+ void unload();
+
public Q_SLOTS:
/* Wallet status might have changed */
void updateStatus();
diff --git a/src/qt/winshutdownmonitor.cpp b/src/qt/winshutdownmonitor.cpp
index 1e7a76efc0..6190a74598 100644
--- a/src/qt/winshutdownmonitor.cpp
+++ b/src/qt/winshutdownmonitor.cpp
@@ -4,7 +4,7 @@
#include <qt/winshutdownmonitor.h>
-#if defined(Q_OS_WIN) && QT_VERSION >= 0x050000
+#if defined(Q_OS_WIN)
#include <init.h>
#include <util.h>
diff --git a/src/qt/winshutdownmonitor.h b/src/qt/winshutdownmonitor.h
index 0bed55a2c6..c8a523a538 100644
--- a/src/qt/winshutdownmonitor.h
+++ b/src/qt/winshutdownmonitor.h
@@ -9,7 +9,6 @@
#include <QByteArray>
#include <QString>
-#if QT_VERSION >= 0x050000
#include <windef.h> // for HWND
#include <QAbstractNativeEventFilter>
@@ -24,6 +23,5 @@ public:
static void registerShutdownBlockReason(const QString& strReason, const HWND& mainWinId);
};
#endif
-#endif
#endif // BITCOIN_QT_WINSHUTDOWNMONITOR_H
diff --git a/src/rest.cpp b/src/rest.cpp
index ffa75c241f..a5f164497d 100644
--- a/src/rest.cpp
+++ b/src/rest.cpp
@@ -217,7 +217,7 @@ static bool rest_block(HTTPRequest* req,
return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found");
}
- if (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0)
+ if (IsBlockPruned(pblockindex))
return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not available (pruned data)");
if (!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus()))
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 48e0e02d1a..d9d803ac7d 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -95,6 +95,7 @@ UniValue blockheaderToJSON(const CBlockIndex* blockindex)
result.pushKV("bits", strprintf("%08x", blockindex->nBits));
result.pushKV("difficulty", GetDifficulty(blockindex));
result.pushKV("chainwork", blockindex->nChainWork.GetHex());
+ result.pushKV("nTx", (uint64_t)blockindex->nTx);
if (blockindex->pprev)
result.pushKV("previousblockhash", blockindex->pprev->GetBlockHash().GetHex());
@@ -140,6 +141,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx
result.pushKV("bits", strprintf("%08x", block.nBits));
result.pushKV("difficulty", GetDifficulty(blockindex));
result.pushKV("chainwork", blockindex->nChainWork.GetHex());
+ result.pushKV("nTx", (uint64_t)blockindex->nTx);
if (blockindex->pprev)
result.pushKV("previousblockhash", blockindex->pprev->GetBlockHash().GetHex());
@@ -694,6 +696,7 @@ static UniValue getblockheader(const JSONRPCRequest& request)
" \"bits\" : \"1d00ffff\", (string) The bits\n"
" \"difficulty\" : x.xxx, (numeric) The difficulty\n"
" \"chainwork\" : \"0000...1f3\" (string) Expected number of hashes required to produce the current chain (in hex)\n"
+ " \"nTx\" : n, (numeric) The number of transactions in the block.\n"
" \"previousblockhash\" : \"hash\", (string) The hash of the previous block\n"
" \"nextblockhash\" : \"hash\", (string) The hash of the next block\n"
"}\n"
@@ -732,7 +735,7 @@ static UniValue getblockheader(const JSONRPCRequest& request)
static CBlock GetBlockChecked(const CBlockIndex* pblockindex)
{
CBlock block;
- if (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0) {
+ if (IsBlockPruned(pblockindex)) {
throw JSONRPCError(RPC_MISC_ERROR, "Block not available (pruned data)");
}
@@ -782,6 +785,7 @@ static UniValue getblock(const JSONRPCRequest& request)
" \"bits\" : \"1d00ffff\", (string) The bits\n"
" \"difficulty\" : x.xxx, (numeric) The difficulty\n"
" \"chainwork\" : \"xxxx\", (string) Expected number of hashes required to produce the chain up to this block (in hex)\n"
+ " \"nTx\" : n, (numeric) The number of transactions in the block.\n"
" \"previousblockhash\" : \"hash\", (string) The hash of the previous block\n"
" \"nextblockhash\" : \"hash\" (string) The hash of the next block\n"
"}\n"
@@ -849,7 +853,7 @@ static void ApplyStats(CCoinsStats &stats, CHashWriter& ss, const uint256& hash,
ss << hash;
ss << VARINT(outputs.begin()->second.nHeight * 2 + outputs.begin()->second.fCoinBase ? 1u : 0u);
stats.nTransactions++;
- for (const auto output : outputs) {
+ for (const auto& output : outputs) {
ss << VARINT(output.first + 1);
ss << output.second.out.scriptPubKey;
ss << VARINT(output.second.out.nValue, VarIntMode::NONNEGATIVE_SIGNED);
diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp
index bb68f72ccc..0f35fd3770 100644
--- a/src/rpc/client.cpp
+++ b/src/rpc/client.cpp
@@ -52,7 +52,6 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "listreceivedbylabel", 0, "minconf" },
{ "listreceivedbylabel", 1, "include_empty" },
{ "listreceivedbylabel", 2, "include_watchonly" },
- { "getlabeladdress", 1, "force" },
{ "getbalance", 1, "minconf" },
{ "getbalance", 2, "include_watchonly" },
{ "getblockhash", 0, "height" },
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index 85b864e6b9..81c4fb040f 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -725,7 +725,6 @@ static UniValue submitblock(const JSONRPCRequest& request)
}
uint256 hash = block.GetHash();
- bool fBlockPresent = false;
{
LOCK(cs_main);
const CBlockIndex* pindex = LookupBlockIndex(hash);
@@ -736,8 +735,6 @@ static UniValue submitblock(const JSONRPCRequest& request)
if (pindex->nStatus & BLOCK_FAILED_MASK) {
return "duplicate-invalid";
}
- // Otherwise, we might only have the header - process the block before returning
- fBlockPresent = true;
}
}
@@ -749,13 +746,15 @@ static UniValue submitblock(const JSONRPCRequest& request)
}
}
+ bool new_block;
submitblock_StateCatcher sc(block.GetHash());
RegisterValidationInterface(&sc);
- bool fAccepted = ProcessNewBlock(Params(), blockptr, true, nullptr);
+ bool accepted = ProcessNewBlock(Params(), blockptr, /* fForceProcessing */ true, /* fNewBlock */ &new_block);
UnregisterValidationInterface(&sc);
- if (fBlockPresent) {
- if (fAccepted && !sc.found) {
- return "duplicate-inconclusive";
+ if (!new_block) {
+ if (!accepted) {
+ // TODO Maybe pass down fNewBlock to AcceptBlockHeader, so it is properly set to true in this case?
+ return "invalid";
}
return "duplicate";
}
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index 1530d8578b..8fa56e9335 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -475,7 +475,7 @@ static UniValue getnetworkinfo(const JSONRPCRequest& request)
UniValue localAddresses(UniValue::VARR);
{
LOCK(cs_mapLocalHost);
- for (const std::pair<CNetAddr, LocalServiceInfo> &item : mapLocalHost)
+ for (const std::pair<const CNetAddr, LocalServiceInfo> &item : mapLocalHost)
{
UniValue rec(UniValue::VOBJ);
rec.pushKV("address", item.first.ToString());
diff --git a/src/test/blockchain_tests.cpp b/src/test/blockchain_tests.cpp
index d2d0008122..7d8ae46fb8 100644
--- a/src/test/blockchain_tests.cpp
+++ b/src/test/blockchain_tests.cpp
@@ -1,9 +1,9 @@
#include <boost/test/unit_test.hpp>
-#include "stdlib.h"
+#include <stdlib.h>
-#include "rpc/blockchain.h"
-#include "test/test_bitcoin.h"
+#include <rpc/blockchain.h>
+#include <test/test_bitcoin.h>
/* Equality between doubles is imprecise. Comparison should be done
* with a small threshold of tolerance, rather than exact equality.
diff --git a/src/test/DoS_tests.cpp b/src/test/denialofservice_tests.cpp
index 1868aed7dd..e5f914ba8a 100644
--- a/src/test/DoS_tests.cpp
+++ b/src/test/denialofservice_tests.cpp
@@ -42,7 +42,7 @@ static NodeId id = 0;
void UpdateLastBlockAnnounceTime(NodeId node, int64_t time_in_seconds);
-BOOST_FIXTURE_TEST_SUITE(DoS_tests, TestingSetup)
+BOOST_FIXTURE_TEST_SUITE(denialofservice_tests, TestingSetup)
// Test eviction of an outbound peer whose chain never advances
// Mock a node connection, and use mocktime to simulate a peer
diff --git a/src/test/mempool_tests.cpp b/src/test/mempool_tests.cpp
index 5ca243f42e..0264d29455 100644
--- a/src/test/mempool_tests.cpp
+++ b/src/test/mempool_tests.cpp
@@ -571,4 +571,179 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
SetMockTime(0);
}
+inline CTransactionRef make_tx(std::vector<CAmount>&& output_values, std::vector<CTransactionRef>&& inputs=std::vector<CTransactionRef>(), std::vector<uint32_t>&& input_indices=std::vector<uint32_t>())
+{
+ CMutableTransaction tx = CMutableTransaction();
+ tx.vin.resize(inputs.size());
+ tx.vout.resize(output_values.size());
+ for (size_t i = 0; i < inputs.size(); ++i) {
+ tx.vin[i].prevout.hash = inputs[i]->GetHash();
+ tx.vin[i].prevout.n = input_indices.size() > i ? input_indices[i] : 0;
+ }
+ for (size_t i = 0; i < output_values.size(); ++i) {
+ tx.vout[i].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
+ tx.vout[i].nValue = output_values[i];
+ }
+ return MakeTransactionRef(tx);
+}
+
+
+BOOST_AUTO_TEST_CASE(MempoolAncestryTests)
+{
+ size_t ancestors, descendants;
+
+ CTxMemPool pool;
+ TestMemPoolEntryHelper entry;
+
+ /* Base transaction */
+ //
+ // [tx1]
+ //
+ CTransactionRef tx1 = make_tx(/* output_values */ {10 * COIN});
+ pool.addUnchecked(tx1->GetHash(), entry.Fee(10000LL).FromTx(tx1));
+
+ // Ancestors / descendants should be 1 / 1 (itself / itself)
+ pool.GetTransactionAncestry(tx1->GetHash(), ancestors, descendants);
+ BOOST_CHECK_EQUAL(ancestors, 1ULL);
+ BOOST_CHECK_EQUAL(descendants, 1ULL);
+
+ /* Child transaction */
+ //
+ // [tx1].0 <- [tx2]
+ //
+ CTransactionRef tx2 = make_tx(/* output_values */ {495 * CENT, 5 * COIN}, /* inputs */ {tx1});
+ pool.addUnchecked(tx2->GetHash(), entry.Fee(10000LL).FromTx(tx2));
+
+ // Ancestors / descendants should be:
+ // transaction ancestors descendants
+ // ============ =========== ===========
+ // tx1 1 (tx1) 2 (tx1,2)
+ // tx2 2 (tx1,2) 2 (tx1,2)
+ pool.GetTransactionAncestry(tx1->GetHash(), ancestors, descendants);
+ BOOST_CHECK_EQUAL(ancestors, 1ULL);
+ BOOST_CHECK_EQUAL(descendants, 2ULL);
+ pool.GetTransactionAncestry(tx2->GetHash(), ancestors, descendants);
+ BOOST_CHECK_EQUAL(ancestors, 2ULL);
+ BOOST_CHECK_EQUAL(descendants, 2ULL);
+
+ /* Grand-child 1 */
+ //
+ // [tx1].0 <- [tx2].0 <- [tx3]
+ //
+ CTransactionRef tx3 = make_tx(/* output_values */ {290 * CENT, 200 * CENT}, /* inputs */ {tx2});
+ pool.addUnchecked(tx3->GetHash(), entry.Fee(10000LL).FromTx(tx3));
+
+ // Ancestors / descendants should be:
+ // transaction ancestors descendants
+ // ============ =========== ===========
+ // tx1 1 (tx1) 3 (tx1,2,3)
+ // tx2 2 (tx1,2) 3 (tx1,2,3)
+ // tx3 3 (tx1,2,3) 3 (tx1,2,3)
+ pool.GetTransactionAncestry(tx1->GetHash(), ancestors, descendants);
+ BOOST_CHECK_EQUAL(ancestors, 1ULL);
+ BOOST_CHECK_EQUAL(descendants, 3ULL);
+ pool.GetTransactionAncestry(tx2->GetHash(), ancestors, descendants);
+ BOOST_CHECK_EQUAL(ancestors, 2ULL);
+ BOOST_CHECK_EQUAL(descendants, 3ULL);
+ pool.GetTransactionAncestry(tx3->GetHash(), ancestors, descendants);
+ BOOST_CHECK_EQUAL(ancestors, 3ULL);
+ BOOST_CHECK_EQUAL(descendants, 3ULL);
+
+ /* Grand-child 2 */
+ //
+ // [tx1].0 <- [tx2].0 <- [tx3]
+ // |
+ // \---1 <- [tx4]
+ //
+ CTransactionRef tx4 = make_tx(/* output_values */ {290 * CENT, 250 * CENT}, /* inputs */ {tx2}, /* input_indices */ {1});
+ pool.addUnchecked(tx4->GetHash(), entry.Fee(10000LL).FromTx(tx4));
+
+ // Ancestors / descendants should be:
+ // transaction ancestors descendants
+ // ============ =========== ===========
+ // tx1 1 (tx1) 4 (tx1,2,3,4)
+ // tx2 2 (tx1,2) 4 (tx1,2,3,4)
+ // tx3 3 (tx1,2,3) 4 (tx1,2,3,4)
+ // tx4 3 (tx1,2,4) 4 (tx1,2,3,4)
+ pool.GetTransactionAncestry(tx1->GetHash(), ancestors, descendants);
+ BOOST_CHECK_EQUAL(ancestors, 1ULL);
+ BOOST_CHECK_EQUAL(descendants, 4ULL);
+ pool.GetTransactionAncestry(tx2->GetHash(), ancestors, descendants);
+ BOOST_CHECK_EQUAL(ancestors, 2ULL);
+ BOOST_CHECK_EQUAL(descendants, 4ULL);
+ pool.GetTransactionAncestry(tx3->GetHash(), ancestors, descendants);
+ BOOST_CHECK_EQUAL(ancestors, 3ULL);
+ BOOST_CHECK_EQUAL(descendants, 4ULL);
+ pool.GetTransactionAncestry(tx4->GetHash(), ancestors, descendants);
+ BOOST_CHECK_EQUAL(ancestors, 3ULL);
+ BOOST_CHECK_EQUAL(descendants, 4ULL);
+
+ /* Make an alternate branch that is longer and connect it to tx3 */
+ //
+ // [ty1].0 <- [ty2].0 <- [ty3].0 <- [ty4].0 <- [ty5].0
+ // |
+ // [tx1].0 <- [tx2].0 <- [tx3].0 <- [ty6] --->--/
+ // |
+ // \---1 <- [tx4]
+ //
+ CTransactionRef ty1, ty2, ty3, ty4, ty5;
+ CTransactionRef* ty[5] = {&ty1, &ty2, &ty3, &ty4, &ty5};
+ CAmount v = 5 * COIN;
+ for (uint64_t i = 0; i < 5; i++) {
+ CTransactionRef& tyi = *ty[i];
+ tyi = make_tx(/* output_values */ {v}, /* inputs */ i > 0 ? std::vector<CTransactionRef>{*ty[i - 1]} : std::vector<CTransactionRef>{});
+ v -= 50 * CENT;
+ pool.addUnchecked(tyi->GetHash(), entry.Fee(10000LL).FromTx(tyi));
+ pool.GetTransactionAncestry(tyi->GetHash(), ancestors, descendants);
+ BOOST_CHECK_EQUAL(ancestors, i+1);
+ BOOST_CHECK_EQUAL(descendants, i+1);
+ }
+ CTransactionRef ty6 = make_tx(/* output_values */ {5 * COIN}, /* inputs */ {tx3, ty5});
+ pool.addUnchecked(ty6->GetHash(), entry.Fee(10000LL).FromTx(ty6));
+
+ // Ancestors / descendants should be:
+ // transaction ancestors descendants
+ // ============ =================== ===========
+ // tx1 1 (tx1) 5 (tx1,2,3,4, ty6)
+ // tx2 2 (tx1,2) 5 (tx1,2,3,4, ty6)
+ // tx3 3 (tx1,2,3) 5 (tx1,2,3,4, ty6)
+ // tx4 3 (tx1,2,4) 5 (tx1,2,3,4, ty6)
+ // ty1 1 (ty1) 6 (ty1,2,3,4,5,6)
+ // ty2 2 (ty1,2) 6 (ty1,2,3,4,5,6)
+ // ty3 3 (ty1,2,3) 6 (ty1,2,3,4,5,6)
+ // ty4 4 (y1234) 6 (ty1,2,3,4,5,6)
+ // ty5 5 (y12345) 6 (ty1,2,3,4,5,6)
+ // ty6 9 (tx123, ty123456) 6 (ty1,2,3,4,5,6)
+ pool.GetTransactionAncestry(tx1->GetHash(), ancestors, descendants);
+ BOOST_CHECK_EQUAL(ancestors, 1ULL);
+ BOOST_CHECK_EQUAL(descendants, 5ULL);
+ pool.GetTransactionAncestry(tx2->GetHash(), ancestors, descendants);
+ BOOST_CHECK_EQUAL(ancestors, 2ULL);
+ BOOST_CHECK_EQUAL(descendants, 5ULL);
+ pool.GetTransactionAncestry(tx3->GetHash(), ancestors, descendants);
+ BOOST_CHECK_EQUAL(ancestors, 3ULL);
+ BOOST_CHECK_EQUAL(descendants, 5ULL);
+ pool.GetTransactionAncestry(tx4->GetHash(), ancestors, descendants);
+ BOOST_CHECK_EQUAL(ancestors, 3ULL);
+ BOOST_CHECK_EQUAL(descendants, 5ULL);
+ pool.GetTransactionAncestry(ty1->GetHash(), ancestors, descendants);
+ BOOST_CHECK_EQUAL(ancestors, 1ULL);
+ BOOST_CHECK_EQUAL(descendants, 6ULL);
+ pool.GetTransactionAncestry(ty2->GetHash(), ancestors, descendants);
+ BOOST_CHECK_EQUAL(ancestors, 2ULL);
+ BOOST_CHECK_EQUAL(descendants, 6ULL);
+ pool.GetTransactionAncestry(ty3->GetHash(), ancestors, descendants);
+ BOOST_CHECK_EQUAL(ancestors, 3ULL);
+ BOOST_CHECK_EQUAL(descendants, 6ULL);
+ pool.GetTransactionAncestry(ty4->GetHash(), ancestors, descendants);
+ BOOST_CHECK_EQUAL(ancestors, 4ULL);
+ BOOST_CHECK_EQUAL(descendants, 6ULL);
+ pool.GetTransactionAncestry(ty5->GetHash(), ancestors, descendants);
+ BOOST_CHECK_EQUAL(ancestors, 5ULL);
+ BOOST_CHECK_EQUAL(descendants, 6ULL);
+ pool.GetTransactionAncestry(ty6->GetHash(), ancestors, descendants);
+ BOOST_CHECK_EQUAL(ancestors, 9ULL);
+ BOOST_CHECK_EQUAL(descendants, 6ULL);
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_p2sh_tests.cpp
index 63d211dd97..803a673fab 100644
--- a/src/test/script_P2SH_tests.cpp
+++ b/src/test/script_p2sh_tests.cpp
@@ -46,7 +46,7 @@ Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict, Scri
}
-BOOST_FIXTURE_TEST_SUITE(script_P2SH_tests, BasicTestingSetup)
+BOOST_FIXTURE_TEST_SUITE(script_p2sh_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(sign)
{
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index bb585fc075..8090172e3f 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -69,12 +69,12 @@ void CTxMemPool::UpdateForDescendants(txiter updateIt, cacheMap &cachedDescendan
setAllDescendants.insert(cit);
stageEntries.erase(cit);
const setEntries &setChildren = GetMemPoolChildren(cit);
- for (const txiter childEntry : setChildren) {
+ for (txiter childEntry : setChildren) {
cacheMap::iterator cacheIt = cachedDescendants.find(childEntry);
if (cacheIt != cachedDescendants.end()) {
// We've already calculated this one, just add the entries for this set
// but don't traverse again.
- for (const txiter cacheEntry : cacheIt->second) {
+ for (txiter cacheEntry : cacheIt->second) {
setAllDescendants.insert(cacheEntry);
}
} else if (!setAllDescendants.count(childEntry)) {
@@ -693,18 +693,18 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
// Check children against mapNextTx
CTxMemPool::setEntries setChildrenCheck;
auto iter = mapNextTx.lower_bound(COutPoint(it->GetTx().GetHash(), 0));
- int64_t childSizes = 0;
+ uint64_t child_sizes = 0;
for (; iter != mapNextTx.end() && iter->first->hash == it->GetTx().GetHash(); ++iter) {
txiter childit = mapTx.find(iter->second->GetHash());
assert(childit != mapTx.end()); // mapNextTx points to in-mempool transactions
if (setChildrenCheck.insert(childit).second) {
- childSizes += childit->GetTxSize();
+ child_sizes += childit->GetTxSize();
}
}
assert(setChildrenCheck == GetMemPoolChildren(it));
// Also check to make sure size is greater than sum with immediate children.
// just a sanity check, not definitive that this calc is correct...
- assert(it->GetSizeWithDescendants() >= childSizes + it->GetTxSize());
+ assert(it->GetSizeWithDescendants() >= child_sizes + it->GetTxSize());
if (fDependsWait)
waitingOnDependants.push_back(&(*it));
@@ -1055,11 +1055,36 @@ void CTxMemPool::TrimToSize(size_t sizelimit, std::vector<COutPoint>* pvNoSpends
}
}
-bool CTxMemPool::TransactionWithinChainLimit(const uint256& txid, size_t chainLimit) const {
+uint64_t CTxMemPool::CalculateDescendantMaximum(txiter entry) const {
+ // find parent with highest descendant count
+ std::vector<txiter> candidates;
+ setEntries counted;
+ candidates.push_back(entry);
+ uint64_t maximum = 0;
+ while (candidates.size()) {
+ txiter candidate = candidates.back();
+ candidates.pop_back();
+ if (!counted.insert(candidate).second) continue;
+ const setEntries& parents = GetMemPoolParents(candidate);
+ if (parents.size() == 0) {
+ maximum = std::max(maximum, candidate->GetCountWithDescendants());
+ } else {
+ for (txiter i : parents) {
+ candidates.push_back(i);
+ }
+ }
+ }
+ return maximum;
+}
+
+void CTxMemPool::GetTransactionAncestry(const uint256& txid, size_t& ancestors, size_t& descendants) const {
LOCK(cs);
auto it = mapTx.find(txid);
- return it == mapTx.end() || (it->GetCountWithAncestors() < chainLimit &&
- it->GetCountWithDescendants() < chainLimit);
+ ancestors = descendants = 0;
+ if (it != mapTx.end()) {
+ ancestors = it->GetCountWithAncestors();
+ descendants = CalculateDescendantMaximum(it);
+ }
}
SaltedTxidHasher::SaltedTxidHasher() : k0(GetRand(std::numeric_limits<uint64_t>::max())), k1(GetRand(std::numeric_limits<uint64_t>::max())) {}
diff --git a/src/txmempool.h b/src/txmempool.h
index ca7b1cd4be..ebfcf36e11 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -486,7 +486,7 @@ public:
mutable CCriticalSection cs;
indexed_transaction_set mapTx GUARDED_BY(cs);
- typedef indexed_transaction_set::nth_index<0>::type::iterator txiter;
+ using txiter = indexed_transaction_set::nth_index<0>::type::const_iterator;
std::vector<std::pair<uint256, txiter> > vTxHashes; //!< All tx witness hashes/entries in mapTx, in random order
struct CompareIteratorByHash {
@@ -498,6 +498,7 @@ public:
const setEntries & GetMemPoolParents(txiter entry) const EXCLUSIVE_LOCKS_REQUIRED(cs);
const setEntries & GetMemPoolChildren(txiter entry) const EXCLUSIVE_LOCKS_REQUIRED(cs);
+ uint64_t CalculateDescendantMaximum(txiter entry) const EXCLUSIVE_LOCKS_REQUIRED(cs);
private:
typedef std::map<txiter, setEntries, CompareIteratorByHash> cacheMap;
@@ -619,8 +620,11 @@ public:
/** Expire all transaction (and their dependencies) in the mempool older than time. Return the number of removed transactions. */
int Expire(int64_t time);
- /** Returns false if the transaction is in the mempool and not within the chain limit specified. */
- bool TransactionWithinChainLimit(const uint256& txid, size_t chainLimit) const;
+ /**
+ * Calculate the ancestor and descendant count for the given transaction.
+ * The counts include the transaction itself.
+ */
+ void GetTransactionAncestry(const uint256& txid, size_t& ancestors, size_t& descendants) const;
unsigned long size()
{
diff --git a/src/util.cpp b/src/util.cpp
index 48d64e3eec..ab262b4063 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -585,6 +585,13 @@ void ArgsManager::AddArg(const std::string& name, const std::string& help, const
assert(ret.second); // Make sure an insertion actually happened
}
+void ArgsManager::AddHiddenArgs(const std::vector<std::string>& names)
+{
+ for (const std::string& name : names) {
+ AddArg(name, "", false, OptionsCategory::HIDDEN);
+ }
+}
+
std::string ArgsManager::GetHelpMessage()
{
const bool show_debug = gArgs.GetBoolArg("-help-debug", false);
diff --git a/src/util.h b/src/util.h
index efd8a4bd9d..8094d72d6b 100644
--- a/src/util.h
+++ b/src/util.h
@@ -264,6 +264,11 @@ public:
void AddArg(const std::string& name, const std::string& help, const bool debug_only, const OptionsCategory& cat);
/**
+ * Add many hidden arguments
+ */
+ void AddHiddenArgs(const std::vector<std::string>& args);
+
+ /**
* Clear available arguments
*/
void ClearArgs() { m_available_args.clear(); }
diff --git a/src/validation.cpp b/src/validation.cpp
index 9791d6e2d8..3b8118b036 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -205,7 +205,7 @@ private:
void InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state);
CBlockIndex* FindMostWorkChain();
- bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBlockIndex *pindexNew, const CDiskBlockPos& pos, const Consensus::Params& consensusParams);
+ void ReceivedBlockTransactions(const CBlock& block, CBlockIndex* pindexNew, const CDiskBlockPos& pos, const Consensus::Params& consensusParams);
bool RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& inputs, const CChainParams& params);
@@ -577,15 +577,9 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
if (tx.IsCoinBase())
return state.DoS(100, false, REJECT_INVALID, "coinbase");
- // Reject transactions with witness before segregated witness activates (override with -prematurewitness)
- bool witnessEnabled = IsWitnessEnabled(chainActive.Tip(), chainparams.GetConsensus());
- if (!gArgs.GetBoolArg("-prematurewitness", false) && tx.HasWitness() && !witnessEnabled) {
- return state.DoS(0, false, REJECT_NONSTANDARD, "no-witness-yet", true);
- }
-
// Rather not work on nonstandard transactions (unless -testnet/-regtest)
std::string reason;
- if (fRequireStandard && !IsStandardTx(tx, reason, witnessEnabled))
+ if (fRequireStandard && !IsStandardTx(tx, reason))
return state.DoS(0, false, REJECT_NONSTANDARD, reason);
// Do not work on transactions that are too small.
@@ -657,7 +651,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
view.SetBackend(viewMemPool);
// do all inputs exist?
- for (const CTxIn txin : tx.vin) {
+ for (const CTxIn& txin : tx.vin) {
if (!pcoinsTip->HaveCoinInCache(txin.prevout)) {
coins_to_uncache.push_back(txin.prevout);
}
@@ -963,7 +957,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
}
// Remove conflicting transactions from the mempool
- for (const CTxMemPool::txiter it : allConflicting)
+ for (CTxMemPool::txiter it : allConflicting)
{
LogPrint(BCLog::MEMPOOL, "replacing tx %s with %s for %s BTC additional fees, %d delta bytes\n",
it->GetTx().GetHash().ToString(),
@@ -2704,6 +2698,9 @@ bool CChainState::ActivateBestChain(CValidationState &state, const CChainParams&
// Block until the validation queue drains. This should largely
// never happen in normal operation, however may happen during
// reindex, causing memory blowup if we run too far ahead.
+ // Note that if a validationinterface callback ends up calling
+ // ActivateBestChain this may lead to a deadlock! We should
+ // probably have a DEBUG_LOCKORDER test for this in the future.
SyncWithValidationInterfaceQueue();
}
@@ -2956,7 +2953,7 @@ CBlockIndex* CChainState::AddToBlockIndex(const CBlockHeader& block)
}
/** Mark a block as having its data received and checked (up to BLOCK_VALID_TRANSACTIONS). */
-bool CChainState::ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBlockIndex *pindexNew, const CDiskBlockPos& pos, const Consensus::Params& consensusParams)
+void CChainState::ReceivedBlockTransactions(const CBlock& block, CBlockIndex* pindexNew, const CDiskBlockPos& pos, const Consensus::Params& consensusParams)
{
pindexNew->nTx = block.vtx.size();
pindexNew->nChainTx = 0;
@@ -3000,8 +2997,6 @@ bool CChainState::ReceivedBlockTransactions(const CBlock &block, CValidationStat
mapBlocksUnlinked.insert(std::make_pair(pindexNew->pprev, pindexNew));
}
}
-
- return true;
}
static bool FindBlockPos(CDiskBlockPos &pos, unsigned int nAddSize, unsigned int nHeight, uint64_t nTime, bool fKnown = false)
@@ -3513,7 +3508,6 @@ bool CChainState::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CVali
// request; don't process these.
if (pindex->nChainWork < nMinimumChainWork) return true;
}
- if (fNewBlock) *fNewBlock = true;
if (!CheckBlock(block, state, chainparams.GetConsensus()) ||
!ContextualCheckBlock(block, state, chainparams.GetConsensus(), pindex->pprev)) {
@@ -3530,14 +3524,14 @@ bool CChainState::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CVali
GetMainSignals().NewPoWValidBlock(pindex, pblock);
// Write block to history file
+ if (fNewBlock) *fNewBlock = true;
try {
CDiskBlockPos blockPos = SaveBlockToDisk(block, pindex->nHeight, chainparams, dbp);
if (blockPos.IsNull()) {
state.Error(strprintf("%s: Failed to find position to write new block to disk", __func__));
return false;
}
- if (!ReceivedBlockTransactions(block, state, pindex, blockPos, chainparams.GetConsensus()))
- return error("AcceptBlock(): ReceivedBlockTransactions failed");
+ ReceivedBlockTransactions(block, pindex, blockPos, chainparams.GetConsensus());
} catch (const std::runtime_error& e) {
return AbortNode(state, std::string("System error: ") + e.what());
}
@@ -3840,7 +3834,7 @@ bool CChainState::LoadBlockIndex(const Consensus::Params& consensus_params, CBlo
// Calculate nChainWork
std::vector<std::pair<int, CBlockIndex*> > vSortedByHeight;
vSortedByHeight.reserve(mapBlockIndex.size());
- for (const std::pair<uint256, CBlockIndex*>& item : mapBlockIndex)
+ for (const std::pair<const uint256, CBlockIndex*>& item : mapBlockIndex)
{
CBlockIndex* pindex = item.second;
vSortedByHeight.push_back(std::make_pair(pindex->nHeight, pindex));
@@ -3907,7 +3901,7 @@ bool static LoadBlockIndexDB(const CChainParams& chainparams)
// Check presence of blk files
LogPrintf("Checking all blk files are present...\n");
std::set<int> setBlkDataFiles;
- for (const std::pair<uint256, CBlockIndex*>& item : mapBlockIndex)
+ for (const std::pair<const uint256, CBlockIndex*>& item : mapBlockIndex)
{
CBlockIndex* pindex = item.second;
if (pindex->nStatus & BLOCK_HAVE_DATA) {
@@ -4006,7 +4000,7 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
reportDone = percentageDone/10;
}
uiInterface.ShowProgress(_("Verifying blocks..."), percentageDone, false);
- if (pindex->nHeight < chainActive.Height()-nCheckDepth)
+ if (pindex->nHeight <= chainActive.Height()-nCheckDepth)
break;
if (fPruneMode && !(pindex->nStatus & BLOCK_HAVE_DATA)) {
// If pruning, only go back as far as we have data.
@@ -4346,9 +4340,7 @@ bool CChainState::LoadGenesisBlock(const CChainParams& chainparams)
if (blockPos.IsNull())
return error("%s: writing genesis block to disk failed", __func__);
CBlockIndex *pindex = AddToBlockIndex(block);
- CValidationState state;
- if (!ReceivedBlockTransactions(block, state, pindex, blockPos, chainparams.GetConsensus()))
- return error("%s: genesis block not accepted (%s)", __func__, FormatStateMessage(state));
+ ReceivedBlockTransactions(block, pindex, blockPos, chainparams.GetConsensus());
} catch (const std::runtime_error& e) {
return error("%s: failed to write genesis block: %s", __func__, e.what());
}
diff --git a/src/validation.h b/src/validation.h
index b5ab10786a..b9c2f6c023 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -233,7 +233,8 @@ static const uint64_t MIN_DISK_SPACE_FOR_BLOCK_FILES = 550 * 1024 * 1024;
* Note that we guarantee that either the proof-of-work is valid on pblock, or
* (and possibly also) BlockChecked will have been called.
*
- * Call without cs_main held.
+ * May not be called with cs_main held. May not be called in a
+ * validationinterface callback.
*
* @param[in] pblock The block we want to process.
* @param[in] fForceProcessing Process this block even if unrequested; used for non-network block sources and whitelisted peers.
@@ -245,7 +246,8 @@ bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<cons
/**
* Process incoming block headers.
*
- * Call without cs_main held.
+ * May not be called with cs_main held. May not be called in a
+ * validationinterface callback.
*
* @param[in] block The block headers themselves
* @param[out] state This may be set to an Error state if any error occurred processing them
@@ -278,7 +280,12 @@ void ThreadScriptCheck();
bool IsInitialBlockDownload();
/** Retrieve a transaction (from memory pool, or from disk, if possible) */
bool GetTransaction(const uint256& hash, CTransactionRef& tx, const Consensus::Params& params, uint256& hashBlock, bool fAllowSlow = false, CBlockIndex* blockIndex = nullptr);
-/** Find the best known block, and make it the tip of the block chain */
+/**
+ * Find the best known block, and make it the tip of the block chain
+ *
+ * May not be called with cs_main held. May not be called in a
+ * validationinterface callback.
+ */
bool ActivateBestChain(CValidationState& state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock = std::shared_ptr<const CBlock>());
CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams);
@@ -445,7 +452,11 @@ inline CBlockIndex* LookupBlockIndex(const uint256& hash)
/** Find the last common block between the parameter chain and a locator. */
CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator);
-/** Mark a block as precious and reorganize. */
+/** Mark a block as precious and reorganize.
+ *
+ * May not be called with cs_main held. May not be called in a
+ * validationinterface callback.
+ */
bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex *pindex);
/** Mark a block as invalid. */
@@ -497,4 +508,10 @@ bool DumpMempool();
/** Load the mempool from disk. */
bool LoadMempool();
+//! Check whether the block associated with this index entry is pruned or not.
+inline bool IsBlockPruned(const CBlockIndex* pblockindex)
+{
+ return (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0);
+}
+
#endif // BITCOIN_VALIDATION_H
diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp
index 410dd5009f..01b8eacccb 100644
--- a/src/wallet/db.cpp
+++ b/src/wallet/db.cpp
@@ -694,8 +694,10 @@ void BerkeleyEnvironment::Flush(bool fShutdown)
if (mapFileUseCount.empty()) {
dbenv->log_archive(&listp, DB_ARCH_REMOVE);
Close();
- if (!fMockDb)
+ if (!fMockDb) {
fs::remove_all(fs::path(strPath) / "database");
+ }
+ g_dbenvs.erase(strPath);
}
}
}
@@ -794,5 +796,6 @@ void BerkeleyDatabase::Flush(bool shutdown)
{
if (!IsDummy()) {
env->Flush(shutdown);
+ if (shutdown) env = nullptr;
}
}
diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp
index daeff1d0e8..74312b7124 100644
--- a/src/wallet/init.cpp
+++ b/src/wallet/init.cpp
@@ -200,7 +200,7 @@ bool WalletInit::Verify() const
// Keep track of each wallet absolute path to detect duplicates.
std::set<fs::path> wallet_paths;
- for (const auto wallet_file : wallet_files) {
+ for (const auto& wallet_file : wallet_files) {
fs::path wallet_path = fs::absolute(wallet_file, GetWalletDir());
if (!wallet_paths.insert(wallet_path).second) {
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index d09af1dbd1..882ddbbe4e 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -441,7 +441,7 @@ UniValue importpubkey(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() < 1 || request.params.size() > 4)
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 3)
throw std::runtime_error(
"importpubkey \"pubkey\" ( \"label\" rescan )\n"
"\nAdds a public key (in hex) that can be watched as if it were in your wallet but cannot be used to spend. Requires a new wallet backup.\n"
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 456f08bc14..bc381d3cda 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -40,12 +40,21 @@
static const std::string WALLET_ENDPOINT_BASE = "/wallet/";
-std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& request)
+bool GetWalletNameFromJSONRPCRequest(const JSONRPCRequest& request, std::string& wallet_name)
{
if (request.URI.substr(0, WALLET_ENDPOINT_BASE.size()) == WALLET_ENDPOINT_BASE) {
// wallet endpoint was used
- std::string requestedWallet = urlDecode(request.URI.substr(WALLET_ENDPOINT_BASE.size()));
- std::shared_ptr<CWallet> pwallet = GetWallet(requestedWallet);
+ wallet_name = urlDecode(request.URI.substr(WALLET_ENDPOINT_BASE.size()));
+ return true;
+ }
+ return false;
+}
+
+std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& request)
+{
+ std::string wallet_name;
+ if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) {
+ std::shared_ptr<CWallet> pwallet = GetWallet(wallet_name);
if (!pwallet) throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded");
return pwallet;
}
@@ -66,11 +75,6 @@ bool EnsureWalletIsAvailable(CWallet * const pwallet, bool avoidException)
if (pwallet) return true;
if (avoidException) return false;
if (!HasWallets()) {
- // Note: It isn't currently possible to trigger this error because
- // wallet RPC methods aren't registered unless a wallet is loaded. But
- // this error is being kept as a precaution, because it's possible in
- // the future that wallet RPC methods might get or remain registered
- // when no wallets are loaded.
throw JSONRPCError(
RPC_METHOD_NOT_FOUND, "Method not found (wallet method is disabled because no wallet is loaded)");
}
@@ -120,7 +124,7 @@ static void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry)
}
entry.pushKV("bip125-replaceable", rbfStatus);
- for (const std::pair<std::string, std::string>& item : wtx.mapValue)
+ for (const std::pair<const std::string, std::string>& item : wtx.mapValue)
entry.pushKV(item.first, item.second);
}
@@ -198,7 +202,7 @@ CTxDestination GetLabelDestination(CWallet* const pwallet, const std::string& la
return dest;
}
-static UniValue getlabeladdress(const JSONRPCRequest& request)
+static UniValue getaccountaddress(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
CWallet* const pwallet = wallet.get();
@@ -207,53 +211,36 @@ static UniValue getlabeladdress(const JSONRPCRequest& request)
return NullUniValue;
}
- if (!IsDeprecatedRPCEnabled("accounts") && request.strMethod == "getaccountaddress") {
+ if (!IsDeprecatedRPCEnabled("accounts")) {
if (request.fHelp) {
throw std::runtime_error("getaccountaddress (Deprecated, will be removed in V0.18. To use this command, start bitcoind with -deprecatedrpc=accounts)");
}
throw JSONRPCError(RPC_METHOD_DEPRECATED, "getaccountaddress is deprecated and will be removed in V0.18. To use this command, start bitcoind with -deprecatedrpc=accounts.");
}
- if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
+ if (request.fHelp || request.params.size() != 1)
throw std::runtime_error(
- "getlabeladdress \"label\" ( force ) \n"
- "\nReturns the default receiving address for this label. This will reset to a fresh address once there's a transaction that spends to it.\n"
+ "getaccountaddress \"account\"\n"
+ "\n\nDEPRECATED. Returns the current Bitcoin address for receiving payments to this account.\n"
"\nArguments:\n"
- "1. \"label\" (string, required) The label for the address. It can also be set to the empty string \"\" to represent the default label.\n"
- "2. \"force\" (bool, optional) Whether the label should be created if it does not yet exist. If False, the RPC will return an error if called with a label that doesn't exist.\n"
- " Defaults to false (unless the getaccountaddress method alias is being called, in which case defaults to true for backwards compatibility).\n"
+ "1. \"account\" (string, required) The account for the address. It can also be set to the empty string \"\" to represent the default account. The account does not need to exist, it will be created and a new address created if there is no account by the given name.\n"
"\nResult:\n"
- "\"address\" (string) The current receiving address for the label.\n"
+ "\"address\" (string) The account bitcoin address\n"
"\nExamples:\n"
- + HelpExampleCli("getlabeladdress", "")
- + HelpExampleCli("getlabeladdress", "\"\"")
- + HelpExampleCli("getlabeladdress", "\"mylabel\"")
- + HelpExampleRpc("getlabeladdress", "\"mylabel\"")
+ + HelpExampleCli("getaccountaddress", "")
+ + HelpExampleCli("getaccountaddress", "\"\"")
+ + HelpExampleCli("getaccountaddress", "\"myaccount\"")
+ + HelpExampleRpc("getaccountaddress", "\"myaccount\"")
);
LOCK2(cs_main, pwallet->cs_wallet);
- // Parse the label first so we don't generate a key if there's an error
- std::string label = LabelFromValue(request.params[0]);
- bool force = request.strMethod == "getaccountaddress";
- if (!request.params[1].isNull()) {
- force = request.params[1].get_bool();
- }
-
- bool label_found = false;
- for (const std::pair<CTxDestination, CAddressBookData>& item : pwallet->mapAddressBook) {
- if (item.second.name == label) {
- label_found = true;
- break;
- }
- }
- if (!force && !label_found) {
- throw JSONRPCError(RPC_WALLET_INVALID_LABEL_NAME, std::string("No addresses with label " + label));
- }
+ // Parse the account first so we don't generate a key if there's an error
+ std::string account = LabelFromValue(request.params[0]);
UniValue ret(UniValue::VSTR);
- ret = EncodeDestination(GetLabelDestination(pwallet, label));
+ ret = EncodeDestination(GetLabelDestination(pwallet, account));
return ret;
}
@@ -343,23 +330,33 @@ static UniValue setlabel(const JSONRPCRequest& request)
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
}
+ std::string old_label = pwallet->mapAddressBook[dest].name;
std::string label = LabelFromValue(request.params[1]);
if (IsMine(*pwallet, dest)) {
- // Detect when changing the label of an address that is the receiving address of another label:
- // If so, delete the account record for it. Labels, unlike addresses, can be deleted,
- // and if we wouldn't do this, the record would stick around forever.
- if (pwallet->mapAddressBook.count(dest)) {
- std::string old_label = pwallet->mapAddressBook[dest].name;
- if (old_label != label && dest == GetLabelDestination(pwallet, old_label)) {
- pwallet->DeleteLabel(old_label);
- }
- }
pwallet->SetAddressBook(dest, label, "receive");
+ if (request.strMethod == "setaccount" && old_label != label && dest == GetLabelDestination(pwallet, old_label)) {
+ // for setaccount, call GetLabelDestination so a new receive address is created for the old account
+ GetLabelDestination(pwallet, old_label, true);
+ }
} else {
pwallet->SetAddressBook(dest, label, "send");
}
+ // Detect when there are no addresses using this label.
+ // If so, delete the account record for it. Labels, unlike addresses, can be deleted,
+ // and if we wouldn't do this, the record would stick around forever.
+ bool found_address = false;
+ for (const std::pair<const CTxDestination, CAddressBookData>& item : pwallet->mapAddressBook) {
+ if (item.second.name == label) {
+ found_address = true;
+ break;
+ }
+ }
+ if (!found_address) {
+ pwallet->DeleteLabel(old_label);
+ }
+
return NullUniValue;
}
@@ -447,7 +444,7 @@ static UniValue getaddressesbyaccount(const JSONRPCRequest& request)
// Find all addresses that have the given account
UniValue ret(UniValue::VARR);
- for (const std::pair<CTxDestination, CAddressBookData>& item : pwallet->mapAddressBook) {
+ for (const std::pair<const CTxDestination, CAddressBookData>& item : pwallet->mapAddressBook) {
const CTxDestination& dest = item.first;
const std::string& strName = item.second.name;
if (strName == strAccount) {
@@ -760,7 +757,7 @@ static UniValue getreceivedbyaddress(const JSONRPCRequest& request)
// Tally
CAmount nAmount = 0;
- for (const std::pair<uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
+ for (const std::pair<const uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
const CWalletTx& wtx = pairWtx.second;
if (wtx.IsCoinBase() || !CheckFinalTx(*wtx.tx))
continue;
@@ -828,7 +825,7 @@ static UniValue getreceivedbylabel(const JSONRPCRequest& request)
// Tally
CAmount nAmount = 0;
- for (const std::pair<uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
+ for (const std::pair<const uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
const CWalletTx& wtx = pairWtx.second;
if (wtx.IsCoinBase() || !CheckFinalTx(*wtx.tx))
continue;
@@ -1024,6 +1021,14 @@ static UniValue sendfrom(const JSONRPCRequest& request)
return NullUniValue;
}
+ if (!IsDeprecatedRPCEnabled("accounts")) {
+ if (request.fHelp) {
+ throw std::runtime_error("sendfrom (Deprecated, will be removed in V0.18. To use this command, start bitcoind with -deprecatedrpc=accounts)");
+ }
+ throw JSONRPCError(RPC_METHOD_DEPRECATED, "sendfrom is deprecated and will be removed in V0.18. To use this command, start bitcoind with -deprecatedrpc=accounts.");
+ }
+
+
if (request.fHelp || request.params.size() < 3 || request.params.size() > 6)
throw std::runtime_error(
"sendfrom \"fromaccount\" \"toaddress\" amount ( minconf \"comment\" \"comment_to\" )\n"
@@ -1262,9 +1267,11 @@ static UniValue sendmany(const JSONRPCRequest& request)
EnsureWalletIsUnlocked(pwallet);
// Check funds
- CAmount nBalance = pwallet->GetLegacyBalance(ISMINE_SPENDABLE, nMinDepth, &strAccount);
- if (totalAmount > nBalance)
+ if (IsDeprecatedRPCEnabled("accounts") && totalAmount > pwallet->GetLegacyBalance(ISMINE_SPENDABLE, nMinDepth, &strAccount)) {
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
+ } else if (!IsDeprecatedRPCEnabled("accounts") && totalAmount > pwallet->GetLegacyBalance(ISMINE_SPENDABLE, nMinDepth, nullptr)) {
+ throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Wallet has insufficient funds");
+ }
// Shuffle recipient list
std::shuffle(vecSend.begin(), vecSend.end(), FastRandomContext());
@@ -1457,13 +1464,6 @@ static UniValue addwitnessaddress(const JSONRPCRequest& request)
"Projects should transition to using the address_type argument of getnewaddress, or option -addresstype=[bech32|p2sh-segwit] instead.\n");
}
- {
- LOCK(cs_main);
- if (!IsWitnessEnabled(chainActive.Tip(), Params().GetConsensus()) && !gArgs.GetBoolArg("-walletprematurewitness", false)) {
- throw JSONRPCError(RPC_WALLET_ERROR, "Segregated witness not enabled on network");
- }
- }
-
CTxDestination dest = DecodeDestination(request.params[0].get_str());
if (!IsValidDestination(dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
@@ -1541,7 +1541,7 @@ static UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bo
// Tally
std::map<CTxDestination, tallyitem> mapTally;
- for (const std::pair<uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
+ for (const std::pair<const uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
const CWalletTx& wtx = pairWtx.second;
if (wtx.IsCoinBase() || !CheckFinalTx(*wtx.tx))
@@ -2120,13 +2120,13 @@ static UniValue listaccounts(const JSONRPCRequest& request)
includeWatchonly = includeWatchonly | ISMINE_WATCH_ONLY;
std::map<std::string, CAmount> mapAccountBalances;
- for (const std::pair<CTxDestination, CAddressBookData>& entry : pwallet->mapAddressBook) {
+ for (const std::pair<const CTxDestination, CAddressBookData>& entry : pwallet->mapAddressBook) {
if (IsMine(*pwallet, entry.first) & includeWatchonly) { // This address belongs to me
mapAccountBalances[entry.second.name] = 0;
}
}
- for (const std::pair<uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
+ for (const std::pair<const uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
const CWalletTx& wtx = pairWtx.second;
CAmount nFee;
std::string strSentAccount;
@@ -2155,7 +2155,7 @@ static UniValue listaccounts(const JSONRPCRequest& request)
mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
UniValue ret(UniValue::VOBJ);
- for (const std::pair<std::string, CAmount>& accountBalance : mapAccountBalances) {
+ for (const std::pair<const std::string, CAmount>& accountBalance : mapAccountBalances) {
ret.pushKV(accountBalance.first, ValueFromAmount(accountBalance.second));
}
return ret;
@@ -2264,7 +2264,7 @@ static UniValue listsinceblock(const JSONRPCRequest& request)
UniValue transactions(UniValue::VARR);
- for (const std::pair<uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
+ for (const std::pair<const uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
CWalletTx tx = pairWtx.second;
if (depth == -1 || tx.GetDepthInMainChain() < depth) {
@@ -3067,7 +3067,7 @@ static UniValue listwallets(const JSONRPCRequest& request)
return obj;
}
-UniValue loadwallet(const JSONRPCRequest& request)
+static UniValue loadwallet(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1)
throw std::runtime_error(
@@ -3114,7 +3114,7 @@ UniValue loadwallet(const JSONRPCRequest& request)
return obj;
}
-UniValue createwallet(const JSONRPCRequest& request)
+static UniValue createwallet(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1) {
throw std::runtime_error(
@@ -3161,6 +3161,55 @@ UniValue createwallet(const JSONRPCRequest& request)
return obj;
}
+static UniValue unloadwallet(const JSONRPCRequest& request)
+{
+ if (request.fHelp || request.params.size() > 1) {
+ throw std::runtime_error(
+ "unloadwallet ( \"wallet_name\" )\n"
+ "Unloads the wallet referenced by the request endpoint otherwise unloads the wallet specified in the argument.\n"
+ "Specifying the wallet name on a wallet endpoint is invalid."
+ "\nArguments:\n"
+ "1. \"wallet_name\" (string, optional) The name of the wallet to unload.\n"
+ "\nExamples:\n"
+ + HelpExampleCli("unloadwallet", "wallet_name")
+ + HelpExampleRpc("unloadwallet", "wallet_name")
+ );
+ }
+
+ std::string wallet_name;
+ if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) {
+ if (!request.params[0].isNull()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot unload the requested wallet");
+ }
+ } else {
+ wallet_name = request.params[0].get_str();
+ }
+
+ std::shared_ptr<CWallet> wallet = GetWallet(wallet_name);
+ if (!wallet) {
+ throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded");
+ }
+
+ // Release the "main" shared pointer and prevent further notifications.
+ // Note that any attempt to load the same wallet would fail until the wallet
+ // is destroyed (see CheckUniqueFileid).
+ if (!RemoveWallet(wallet)) {
+ throw JSONRPCError(RPC_MISC_ERROR, "Requested wallet already unloaded");
+ }
+ UnregisterValidationInterface(wallet.get());
+
+ // The wallet can be in use so it's not possible to explicitly unload here.
+ // Just notify the unload intent so that all shared pointers are released.
+ // The wallet will be destroyed once the last shared pointer is released.
+ wallet->NotifyUnload();
+
+ // There's no point in waiting for the wallet to unload.
+ // At this point this method should never fail. The unloading could only
+ // fail due to an unexpected error which would cause a process termination.
+
+ return NullUniValue;
+}
+
static UniValue resendwallettransactions(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
@@ -4201,7 +4250,7 @@ static UniValue getaddressesbylabel(const JSONRPCRequest& request)
// Find all addresses that have the given label
UniValue ret(UniValue::VOBJ);
- for (const std::pair<CTxDestination, CAddressBookData>& item : pwallet->mapAddressBook) {
+ for (const std::pair<const CTxDestination, CAddressBookData>& item : pwallet->mapAddressBook) {
if (item.second.name == label) {
ret.pushKV(EncodeDestination(item.first), AddressBookDataToJSON(item.second, false));
}
@@ -4254,7 +4303,7 @@ static UniValue listlabels(const JSONRPCRequest& request)
// Add to a set to sort by label name, then insert into Univalue array
std::set<std::string> label_set;
- for (const std::pair<CTxDestination, CAddressBookData>& entry : pwallet->mapAddressBook) {
+ for (const std::pair<const CTxDestination, CAddressBookData>& entry : pwallet->mapAddressBook) {
if (purpose.empty() || entry.second.purpose == purpose) {
label_set.insert(entry.second.name);
}
@@ -4390,12 +4439,12 @@ static const CRPCCommand commands[] =
{ "wallet", "listwallets", &listwallets, {} },
{ "wallet", "loadwallet", &loadwallet, {"filename"} },
{ "wallet", "lockunspent", &lockunspent, {"unlock","transactions"} },
- { "wallet", "sendfrom", &sendfrom, {"fromaccount","toaddress","amount","minconf","comment","comment_to"} },
{ "wallet", "sendmany", &sendmany, {"fromaccount|dummy","amounts","minconf","comment","subtractfeefrom","replaceable","conf_target","estimate_mode"} },
{ "wallet", "sendtoaddress", &sendtoaddress, {"address","amount","comment","comment_to","subtractfeefromamount","replaceable","conf_target","estimate_mode"} },
{ "wallet", "settxfee", &settxfee, {"amount"} },
{ "wallet", "signmessage", &signmessage, {"address","message"} },
{ "wallet", "signrawtransactionwithwallet", &signrawtransactionwithwallet, {"hexstring","prevtxs","sighashtype"} },
+ { "wallet", "unloadwallet", &unloadwallet, {"wallet_name"} },
{ "wallet", "walletlock", &walletlock, {} },
{ "wallet", "walletpassphrasechange", &walletpassphrasechange, {"oldpassphrase","newpassphrase"} },
{ "wallet", "walletpassphrase", &walletpassphrase, {"passphrase","timeout"} },
@@ -4404,17 +4453,17 @@ static const CRPCCommand commands[] =
{ "wallet", "sethdseed", &sethdseed, {"newkeypool","seed"} },
/** Account functions (deprecated) */
- { "wallet", "getaccountaddress", &getlabeladdress, {"account"} },
+ { "wallet", "getaccountaddress", &getaccountaddress, {"account"} },
{ "wallet", "getaccount", &getaccount, {"address"} },
{ "wallet", "getaddressesbyaccount", &getaddressesbyaccount, {"account"} },
{ "wallet", "getreceivedbyaccount", &getreceivedbylabel, {"account","minconf"} },
{ "wallet", "listaccounts", &listaccounts, {"minconf","include_watchonly"} },
{ "wallet", "listreceivedbyaccount", &listreceivedbylabel, {"minconf","include_empty","include_watchonly"} },
{ "wallet", "setaccount", &setlabel, {"address","account"} },
+ { "wallet", "sendfrom", &sendfrom, {"fromaccount","toaddress","amount","minconf","comment","comment_to"} },
{ "wallet", "move", &movecmd, {"fromaccount","toaccount","amount","minconf","comment"} },
/** Label functions (to replace non-balance account functions) */
- { "wallet", "getlabeladdress", &getlabeladdress, {"label","force"} },
{ "wallet", "getaddressesbylabel", &getaddressesbylabel, {"label"} },
{ "wallet", "getreceivedbylabel", &getreceivedbylabel, {"label","minconf"} },
{ "wallet", "listlabels", &listlabels, {"purpose"} },
diff --git a/src/wallet/test/coinselector_tests.cpp b/src/wallet/test/coinselector_tests.cpp
index e90370cf06..d90be33000 100644
--- a/src/wallet/test/coinselector_tests.cpp
+++ b/src/wallet/test/coinselector_tests.cpp
@@ -2,14 +2,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "wallet/wallet.h"
-#include "wallet/coinselection.h"
-#include "wallet/coincontrol.h"
-#include "amount.h"
-#include "primitives/transaction.h"
-#include "random.h"
-#include "test/test_bitcoin.h"
-#include "wallet/test/wallet_test_fixture.h"
+#include <wallet/wallet.h>
+#include <wallet/coinselection.h>
+#include <wallet/coincontrol.h>
+#include <amount.h>
+#include <primitives/transaction.h>
+#include <random.h>
+#include <test/test_bitcoin.h>
+#include <wallet/test/wallet_test_fixture.h>
#include <boost/test/unit_test.hpp>
#include <random>
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index c3597aace8..842516bb0e 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -79,6 +79,15 @@ std::shared_ptr<CWallet> GetWallet(const std::string& name)
return nullptr;
}
+// Custom deleter for shared_ptr<CWallet>.
+static void ReleaseWallet(CWallet* wallet)
+{
+ LogPrintf("Releasing wallet %s\n", wallet->GetName());
+ wallet->BlockUntilSyncedToCurrentChain();
+ wallet->Flush();
+ delete wallet;
+}
+
const uint32_t BIP32_HARDENED_KEY_LIMIT = 0x80000000;
const uint256 CMerkleTx::ABANDON_HASH(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));
@@ -600,6 +609,8 @@ void CWallet::AddToSpends(const COutPoint& outpoint, const uint256& wtxid)
{
mapTxSpends.insert(std::make_pair(outpoint, wtxid));
+ setLockedCoins.erase(outpoint);
+
std::pair<TxSpends::iterator, TxSpends::iterator> range;
range = mapTxSpends.equal_range(outpoint);
SyncMetaData(range);
@@ -923,11 +934,10 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
CWalletTx& wtx = (*ret.first).second;
wtx.BindWallet(this);
bool fInsertedNew = ret.second;
- if (fInsertedNew)
- {
+ if (fInsertedNew) {
wtx.nTimeReceived = GetAdjustedTime();
wtx.nOrderPos = IncOrderPosNext(&batch);
- wtxOrdered.insert(std::make_pair(wtx.nOrderPos, TxPair(&wtx, nullptr)));
+ wtx.m_it_wtxOrdered = wtxOrdered.insert(std::make_pair(wtx.nOrderPos, TxPair(&wtx, nullptr)));
wtx.nTimeSmart = ComputeTimeSmart(wtx);
AddToSpends(hash);
}
@@ -998,9 +1008,12 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
bool CWallet::LoadToWallet(const CWalletTx& wtxIn)
{
uint256 hash = wtxIn.GetHash();
- CWalletTx& wtx = mapWallet.emplace(hash, wtxIn).first->second;
+ const auto& ins = mapWallet.emplace(hash, wtxIn);
+ CWalletTx& wtx = ins.first->second;
wtx.BindWallet(this);
- wtxOrdered.insert(std::make_pair(wtx.nOrderPos, TxPair(&wtx, nullptr)));
+ if (/* insertion took place */ ins.second) {
+ wtx.m_it_wtxOrdered = wtxOrdered.insert(std::make_pair(wtx.nOrderPos, TxPair(&wtx, nullptr)));
+ }
AddToSpends(hash);
for (const CTxIn& txin : wtx.tx->vin) {
auto it = mapWallet.find(txin.prevout.hash);
@@ -1294,7 +1307,7 @@ void CWallet::BlockUntilSyncedToCurrentChain() {
LOCK(cs_main);
const CBlockIndex* initialChainTip = chainActive.Tip();
- if (m_last_block_processed->GetAncestor(initialChainTip->nHeight) == initialChainTip) {
+ if (m_last_block_processed && m_last_block_processed->GetAncestor(initialChainTip->nHeight) == initialChainTip) {
return;
}
}
@@ -2469,8 +2482,11 @@ bool CWallet::OutputEligibleForSpending(const COutput& output, const CoinEligibi
if (output.nDepth < (output.tx->IsFromMe(ISMINE_ALL) ? eligibility_filter.conf_mine : eligibility_filter.conf_theirs))
return false;
- if (!mempool.TransactionWithinChainLimit(output.tx->GetHash(), eligibility_filter.max_ancestors))
+ size_t ancestors, descendants;
+ mempool.GetTransactionAncestry(output.tx->GetHash(), ancestors, descendants);
+ if (ancestors > eligibility_filter.max_ancestors || descendants > eligibility_filter.max_descendants) {
return false;
+ }
return true;
}
@@ -2582,16 +2598,17 @@ bool CWallet::SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAm
++it;
}
- size_t nMaxChainLength = std::min(gArgs.GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT), gArgs.GetArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT));
+ size_t max_ancestors = (size_t)std::max<int64_t>(1, gArgs.GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT));
+ size_t max_descendants = (size_t)std::max<int64_t>(1, gArgs.GetArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT));
bool fRejectLongChains = gArgs.GetBoolArg("-walletrejectlongchains", DEFAULT_WALLET_REJECT_LONG_CHAINS);
bool res = nTargetValue <= nValueFromPresetInputs ||
SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, CoinEligibilityFilter(1, 6, 0), vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used) ||
SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, CoinEligibilityFilter(1, 1, 0), vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used) ||
(m_spend_zero_conf_change && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, CoinEligibilityFilter(0, 1, 2), vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)) ||
- (m_spend_zero_conf_change && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, CoinEligibilityFilter(0, 1, std::min((size_t)4, nMaxChainLength/3)), vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)) ||
- (m_spend_zero_conf_change && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, CoinEligibilityFilter(0, 1, nMaxChainLength/2), vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)) ||
- (m_spend_zero_conf_change && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, CoinEligibilityFilter(0, 1, nMaxChainLength), vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)) ||
+ (m_spend_zero_conf_change && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, CoinEligibilityFilter(0, 1, std::min((size_t)4, max_ancestors/3), std::min((size_t)4, max_descendants/3)), vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)) ||
+ (m_spend_zero_conf_change && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, CoinEligibilityFilter(0, 1, max_ancestors/2, max_descendants/2), vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)) ||
+ (m_spend_zero_conf_change && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, CoinEligibilityFilter(0, 1, max_ancestors-1, max_descendants-1), vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)) ||
(m_spend_zero_conf_change && !fRejectLongChains && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, CoinEligibilityFilter(0, 1, std::numeric_limits<uint64_t>::max()), vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
// because SelectCoinsMinConf clears the setCoinsRet, we now add the possible inputs to the coinset
@@ -3206,8 +3223,11 @@ DBErrors CWallet::ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256
{
AssertLockHeld(cs_wallet); // mapWallet
DBErrors nZapSelectTxRet = WalletBatch(*database,"cr+").ZapSelectTx(vHashIn, vHashOut);
- for (uint256 hash : vHashOut)
- mapWallet.erase(hash);
+ for (uint256 hash : vHashOut) {
+ const auto& it = mapWallet.find(hash);
+ wtxOrdered.erase(it->second.m_it_wtxOrdered);
+ mapWallet.erase(it);
+ }
if (nZapSelectTxRet == DBErrors::NEED_REWRITE)
{
@@ -3280,7 +3300,7 @@ bool CWallet::DelAddressBook(const CTxDestination& address)
// Delete destdata tuples associated with address
std::string strAddress = EncodeDestination(address);
- for (const std::pair<std::string, std::string> &item : mapAddressBook[address].destdata)
+ for (const std::pair<const std::string, std::string> &item : mapAddressBook[address].destdata)
{
WalletBatch(*database).EraseDestData(strAddress, item.first);
}
@@ -3681,7 +3701,7 @@ std::set<CTxDestination> CWallet::GetLabelAddresses(const std::string& label) co
{
LOCK(cs_wallet);
std::set<CTxDestination> result;
- for (const std::pair<CTxDestination, CAddressBookData>& item : mapAddressBook)
+ for (const std::pair<const CTxDestination, CAddressBookData>& item : mapAddressBook)
{
const CTxDestination& address = item.first;
const std::string& strName = item.second.name;
@@ -4057,7 +4077,9 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(const std::string& name,
int64_t nStart = GetTimeMillis();
bool fFirstRun = true;
- std::shared_ptr<CWallet> walletInstance = std::make_shared<CWallet>(name, WalletDatabase::Create(path));
+ // TODO: Can't use std::make_shared because we need a custom deleter but
+ // should be possible to use std::allocate_shared.
+ std::shared_ptr<CWallet> walletInstance(new CWallet(name, WalletDatabase::Create(path)), ReleaseWallet);
DBErrors nLoadWalletRet = walletInstance->LoadWallet(fFirstRun);
if (nLoadWalletRet != DBErrors::LOAD_OK)
{
@@ -4086,8 +4108,6 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(const std::string& name,
}
}
- uiInterface.LoadWallet(walletInstance);
-
int prev_version = walletInstance->nWalletVersion;
if (gArgs.GetBoolArg("-upgradewallet", fFirstRun))
{
@@ -4337,6 +4357,8 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(const std::string& name,
}
}
+ uiInterface.LoadWallet(walletInstance);
+
// Register with the validation interface. It's ok to do this after rescan since we're still holding cs_main.
RegisterValidationInterface(walletInstance.get());
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index f1761b0fcf..b829394847 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -339,6 +339,7 @@ public:
char fFromMe;
std::string strFromAccount;
int64_t nOrderPos; //!< position in ordered transaction list
+ std::multimap<int64_t, std::pair<CWalletTx*, CAccountingEntry*>>::const_iterator m_it_wtxOrdered;
// memory only
mutable bool fDebitCached;
@@ -662,8 +663,10 @@ struct CoinEligibilityFilter
const int conf_mine;
const int conf_theirs;
const uint64_t max_ancestors;
+ const uint64_t max_descendants;
- CoinEligibilityFilter(int conf_mine, int conf_theirs, uint64_t max_ancestors) : conf_mine(conf_mine), conf_theirs(conf_theirs), max_ancestors(max_ancestors) {}
+ CoinEligibilityFilter(int conf_mine, int conf_theirs, uint64_t max_ancestors) : conf_mine(conf_mine), conf_theirs(conf_theirs), max_ancestors(max_ancestors), max_descendants(max_ancestors) {}
+ CoinEligibilityFilter(int conf_mine, int conf_theirs, uint64_t max_ancestors, uint64_t max_descendants) : conf_mine(conf_mine), conf_theirs(conf_theirs), max_ancestors(max_ancestors), max_descendants(max_descendants) {}
};
class WalletRescanReserver; //forward declarations for ScanForWalletTransactions/RescanFromTime
@@ -1097,6 +1100,9 @@ public:
//! Flush wallet (bitdb flush)
void Flush(bool shutdown=false);
+ /** Wallet is about to be unloaded */
+ boost::signals2::signal<void ()> NotifyUnload;
+
/**
* Address book entry changed.
* @note called with lock cs_wallet held.
diff --git a/test/functional/combine_logs.py b/test/functional/combine_logs.py
index d1bf9206b2..91b6415a7c 100755
--- a/test/functional/combine_logs.py
+++ b/test/functional/combine_logs.py
@@ -63,7 +63,7 @@ def get_log_events(source, logfile):
Log events may be split over multiple lines. We use the timestamp
regex match as the marker for a new log event."""
try:
- with open(logfile, 'r') as infile:
+ with open(logfile, 'r', encoding='utf-8') as infile:
event = ''
timestamp = ''
for line in infile:
diff --git a/test/functional/feature_assumevalid.py b/test/functional/feature_assumevalid.py
index 5a09142412..a925c70783 100755
--- a/test/functional/feature_assumevalid.py
+++ b/test/functional/feature_assumevalid.py
@@ -68,12 +68,12 @@ class AssumeValidTest(BitcoinTestFramework):
def send_blocks_until_disconnected(self, p2p_conn):
"""Keep sending blocks to the node until we're disconnected."""
for i in range(len(self.blocks)):
- if p2p_conn.state != "connected":
+ if not p2p_conn.is_connected:
break
try:
p2p_conn.send_message(msg_block(self.blocks[i]))
except IOError as e:
- assert str(e) == 'Not connected, no pushbuf'
+ assert not p2p_conn.is_connected
break
def assert_blockchain_height(self, node, height):
diff --git a/test/functional/feature_notifications.py b/test/functional/feature_notifications.py
index 8964c8d64b..6d51f31e35 100755
--- a/test/functional/feature_notifications.py
+++ b/test/functional/feature_notifications.py
@@ -36,7 +36,7 @@ class NotificationsTest(BitcoinTestFramework):
wait_until(lambda: os.path.isfile(self.block_filename) and os.stat(self.block_filename).st_size >= (block_count * 65), timeout=10)
# file content should equal the generated blocks hashes
- with open(self.block_filename, 'r') as f:
+ with open(self.block_filename, 'r', encoding="utf-8") as f:
assert_equal(sorted(blocks), sorted(l.strip() for l in f.read().splitlines()))
self.log.info("test -walletnotify")
@@ -45,7 +45,7 @@ class NotificationsTest(BitcoinTestFramework):
# file content should equal the generated transaction hashes
txids_rpc = list(map(lambda t: t['txid'], self.nodes[1].listtransactions("*", block_count)))
- with open(self.tx_filename, 'r') as f:
+ with open(self.tx_filename, 'r', encoding="ascii") as f:
assert_equal(sorted(txids_rpc), sorted(l.strip() for l in f.read().splitlines()))
os.remove(self.tx_filename)
@@ -58,7 +58,7 @@ class NotificationsTest(BitcoinTestFramework):
# file content should equal the generated transaction hashes
txids_rpc = list(map(lambda t: t['txid'], self.nodes[1].listtransactions("*", block_count)))
- with open(self.tx_filename, 'r') as f:
+ with open(self.tx_filename, 'r', encoding="ascii") as f:
assert_equal(sorted(txids_rpc), sorted(l.strip() for l in f.read().splitlines()))
# Mine another 41 up-version blocks. -alertnotify should trigger on the 51st.
diff --git a/test/functional/feature_nulldummy.py b/test/functional/feature_nulldummy.py
index 7db6a03b45..6577d83f5c 100755
--- a/test/functional/feature_nulldummy.py
+++ b/test/functional/feature_nulldummy.py
@@ -42,7 +42,7 @@ class NULLDUMMYTest(BitcoinTestFramework):
self.setup_clean_chain = True
# This script tests NULLDUMMY activation, which is part of the 'segwit' deployment, so we go through
# normal segwit activation here (and don't use the default always-on behaviour).
- self.extra_args = [['-whitelist=127.0.0.1', '-walletprematurewitness', '-vbparams=segwit:0:999999999999', '-addresstype=legacy', "-deprecatedrpc=addwitnessaddress"]]
+ self.extra_args = [['-whitelist=127.0.0.1', '-vbparams=segwit:0:999999999999', '-addresstype=legacy', "-deprecatedrpc=addwitnessaddress"]]
def run_test(self):
self.address = self.nodes[0].getnewaddress()
diff --git a/test/functional/feature_pruning.py b/test/functional/feature_pruning.py
index 11a52b9ee2..d400507a66 100755
--- a/test/functional/feature_pruning.py
+++ b/test/functional/feature_pruning.py
@@ -260,10 +260,17 @@ class PruneTest(BitcoinTestFramework):
# should not prune because chain tip of node 3 (995) < PruneAfterHeight (1000)
assert_raises_rpc_error(-1, "Blockchain is too short for pruning", node.pruneblockchain, height(500))
+ # Save block transaction count before pruning, assert value
+ block1_details = node.getblock(node.getblockhash(1))
+ assert_equal(block1_details["nTx"], len(block1_details["tx"]))
+
# mine 6 blocks so we are at height 1001 (i.e., above PruneAfterHeight)
node.generate(6)
assert_equal(node.getblockchaininfo()["blocks"], 1001)
+ # Pruned block should still know the number of transactions
+ assert_equal(node.getblockheader(node.getblockhash(1))["nTx"], block1_details["nTx"])
+
# negative heights should raise an exception
assert_raises_rpc_error(-8, "Negative", node.pruneblockchain, -10)
diff --git a/test/functional/feature_segwit.py b/test/functional/feature_segwit.py
index 3622e1834a..b10306b283 100755
--- a/test/functional/feature_segwit.py
+++ b/test/functional/feature_segwit.py
@@ -42,9 +42,9 @@ class SegWitTest(BitcoinTestFramework):
self.setup_clean_chain = True
self.num_nodes = 3
# This test tests SegWit both pre and post-activation, so use the normal BIP9 activation.
- self.extra_args = [["-walletprematurewitness", "-rpcserialversion=0", "-vbparams=segwit:0:999999999999", "-addresstype=legacy", "-deprecatedrpc=addwitnessaddress"],
- ["-blockversion=4", "-promiscuousmempoolflags=517", "-prematurewitness", "-walletprematurewitness", "-rpcserialversion=1", "-vbparams=segwit:0:999999999999", "-addresstype=legacy", "-deprecatedrpc=addwitnessaddress"],
- ["-blockversion=536870915", "-promiscuousmempoolflags=517", "-prematurewitness", "-walletprematurewitness", "-vbparams=segwit:0:999999999999", "-addresstype=legacy", "-deprecatedrpc=addwitnessaddress"]]
+ self.extra_args = [["-rpcserialversion=0", "-vbparams=segwit:0:999999999999", "-addresstype=legacy", "-deprecatedrpc=addwitnessaddress"],
+ ["-blockversion=4", "-promiscuousmempoolflags=517", "-rpcserialversion=1", "-vbparams=segwit:0:999999999999", "-addresstype=legacy", "-deprecatedrpc=addwitnessaddress"],
+ ["-blockversion=536870915", "-promiscuousmempoolflags=517", "-vbparams=segwit:0:999999999999", "-addresstype=legacy", "-deprecatedrpc=addwitnessaddress"]]
def setup_network(self):
super().setup_network()
@@ -129,21 +129,6 @@ class SegWitTest(BitcoinTestFramework):
self.nodes[0].generate(260) #block 423
sync_blocks(self.nodes)
- self.log.info("Verify default node can't accept any witness format txs before fork")
- # unsigned, no scriptsig
- self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", wit_ids[NODE_0][WIT_V0][0], False)
- self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", wit_ids[NODE_0][WIT_V1][0], False)
- self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", p2sh_ids[NODE_0][WIT_V0][0], False)
- self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", p2sh_ids[NODE_0][WIT_V1][0], False)
- # unsigned with redeem script
- self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", p2sh_ids[NODE_0][WIT_V0][0], False, witness_script(False, self.pubkey[0]))
- self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", p2sh_ids[NODE_0][WIT_V1][0], False, witness_script(True, self.pubkey[0]))
- # signed
- self.fail_accept(self.nodes[0], "no-witness-yet", wit_ids[NODE_0][WIT_V0][0], True)
- self.fail_accept(self.nodes[0], "no-witness-yet", wit_ids[NODE_0][WIT_V1][0], True)
- self.fail_accept(self.nodes[0], "no-witness-yet", p2sh_ids[NODE_0][WIT_V0][0], True)
- self.fail_accept(self.nodes[0], "no-witness-yet", p2sh_ids[NODE_0][WIT_V1][0], True)
-
self.log.info("Verify witness txs are skipped for mining before the fork")
self.skip_mine(self.nodes[2], wit_ids[NODE_2][WIT_V0][0], True) #block 424
self.skip_mine(self.nodes[2], wit_ids[NODE_2][WIT_V1][0], True) #block 425
@@ -164,6 +149,16 @@ class SegWitTest(BitcoinTestFramework):
segwit_tx_list = self.nodes[2].getblock(block[0])["tx"]
assert_equal(len(segwit_tx_list), 5)
+ self.log.info("Verify default node can't accept txs with missing witness")
+ # unsigned, no scriptsig
+ self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", wit_ids[NODE_0][WIT_V0][0], False)
+ self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", wit_ids[NODE_0][WIT_V1][0], False)
+ self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", p2sh_ids[NODE_0][WIT_V0][0], False)
+ self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", p2sh_ids[NODE_0][WIT_V1][0], False)
+ # unsigned with redeem script
+ self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", p2sh_ids[NODE_0][WIT_V0][0], False, witness_script(False, self.pubkey[0]))
+ self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", p2sh_ids[NODE_0][WIT_V1][0], False, witness_script(True, self.pubkey[0]))
+
self.log.info("Verify block and transaction serialization rpcs return differing serializations depending on rpc serialization flag")
assert(self.nodes[2].getblock(block[0], False) != self.nodes[0].getblock(block[0], False))
assert(self.nodes[1].getblock(block[0], False) == self.nodes[2].getblock(block[0], False))
diff --git a/test/functional/p2p_compactblocks.py b/test/functional/p2p_compactblocks.py
index cb4c9867a3..37849e9213 100755
--- a/test/functional/p2p_compactblocks.py
+++ b/test/functional/p2p_compactblocks.py
@@ -87,7 +87,7 @@ class TestP2PConn(P2PInterface):
This is used when we want to send a message into the node that we expect
will get us disconnected, eg an invalid block."""
self.send_message(message)
- wait_until(lambda: self.state != "connected", timeout=timeout, lock=mininode_lock)
+ wait_until(lambda: not self.is_connected, timeout=timeout, lock=mininode_lock)
class CompactBlocksTest(BitcoinTestFramework):
def set_test_params(self):
diff --git a/test/functional/p2p_leak.py b/test/functional/p2p_leak.py
index 198dcc1490..dca5ea39de 100755
--- a/test/functional/p2p_leak.py
+++ b/test/functional/p2p_leak.py
@@ -118,11 +118,11 @@ class P2PLeakTest(BitcoinTestFramework):
time.sleep(5)
#This node should have been banned
- assert no_version_bannode.state != "connected"
+ assert not no_version_bannode.is_connected
# These nodes should have been disconnected
- assert unsupported_service_bit5_node.state != "connected"
- assert unsupported_service_bit7_node.state != "connected"
+ assert not unsupported_service_bit5_node.is_connected
+ assert not unsupported_service_bit7_node.is_connected
self.nodes[0].disconnect_p2ps()
diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py
index e80a764477..940d085e89 100755
--- a/test/functional/p2p_segwit.py
+++ b/test/functional/p2p_segwit.py
@@ -230,55 +230,9 @@ class SegWitTest(BitcoinTestFramework):
sync_blocks(self.nodes)
- # Create a p2sh output -- this is so we can pass the standardness
- # rules (an anyone-can-spend OP_TRUE would be rejected, if not wrapped
- # in P2SH).
- p2sh_program = CScript([OP_TRUE])
- p2sh_pubkey = hash160(p2sh_program)
- scriptPubKey = CScript([OP_HASH160, p2sh_pubkey, OP_EQUAL])
-
- # Now check that unnecessary witnesses can't be used to blind a node
- # to a transaction, eg by violating standardness checks.
- tx2 = CTransaction()
- tx2.vin.append(CTxIn(COutPoint(tx.sha256, 0), b""))
- tx2.vout.append(CTxOut(tx.vout[0].nValue-1000, scriptPubKey))
- tx2.rehash()
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx2, False, True)
- self.nodes[0].generate(1)
- sync_blocks(self.nodes)
-
- # We'll add an unnecessary witness to this transaction that would cause
- # it to be non-standard, to test that violating policy with a witness before
- # segwit activation doesn't blind a node to a transaction. Transactions
- # rejected for having a witness before segwit activation shouldn't be added
- # to the rejection cache.
- tx3 = CTransaction()
- tx3.vin.append(CTxIn(COutPoint(tx2.sha256, 0), CScript([p2sh_program])))
- tx3.vout.append(CTxOut(tx2.vout[0].nValue-1000, scriptPubKey))
- tx3.wit.vtxinwit.append(CTxInWitness())
- tx3.wit.vtxinwit[0].scriptWitness.stack = [b'a'*400000]
- tx3.rehash()
- # Note that this should be rejected for the premature witness reason,
- # rather than a policy check, since segwit hasn't activated yet.
- test_transaction_acceptance(self.nodes[1].rpc, self.std_node, tx3, True, False, b'no-witness-yet')
-
- # If we send without witness, it should be accepted.
- test_transaction_acceptance(self.nodes[1].rpc, self.std_node, tx3, False, True)
-
- # Now create a new anyone-can-spend utxo for the next test.
- tx4 = CTransaction()
- tx4.vin.append(CTxIn(COutPoint(tx3.sha256, 0), CScript([p2sh_program])))
- tx4.vout.append(CTxOut(tx3.vout[0].nValue - 1000, CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE])))
- tx4.rehash()
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx3, False, True)
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx4, False, True)
-
- self.nodes[0].generate(1)
- sync_blocks(self.nodes)
-
# Update our utxo list; we spent the first entry.
self.utxo.pop(0)
- self.utxo.append(UTXO(tx4.sha256, 0, tx4.vout[0].nValue))
+ self.utxo.append(UTXO(tx.sha256, 0, tx.vout[0].nValue))
# ~6 months after segwit activation, the SCRIPT_VERIFY_WITNESS flag was
# backdated so that it applies to all blocks, going back to the genesis
@@ -1119,7 +1073,7 @@ class SegWitTest(BitcoinTestFramework):
self.old_node.announce_tx_and_wait_for_getdata(block4.vtx[0])
assert(block4.sha256 not in self.old_node.getdataset)
- # V0 segwit outputs should be standard after activation, but not before.
+ # V0 segwit outputs and inputs are always standard. V0 segwit inputs may only be mined after activation, but not before.
def test_standardness_v0(self, segwit_activated):
self.log.info("Testing standardness of v0 outputs (%s activation)" % ("after" if segwit_activated else "before"))
assert(len(self.utxo))
@@ -1148,45 +1102,46 @@ class SegWitTest(BitcoinTestFramework):
tx.vin = [CTxIn(COutPoint(p2sh_tx.sha256, 0), CScript([witness_program]))]
tx.vout = [CTxOut(p2sh_tx.vout[0].nValue-10000, scriptPubKey)]
tx.vout.append(CTxOut(8000, scriptPubKey)) # Might burn this later
+ tx.vin[0].nSequence = BIP125_SEQUENCE_NUMBER # Just to have the option to bump this tx from the mempool
tx.rehash()
- test_transaction_acceptance(self.nodes[1].rpc, self.std_node, tx, with_witness=True, accepted=segwit_activated)
+ # This is always accepted, since the mempool policy is to consider segwit as always active
+ # and thus allow segwit outputs
+ test_transaction_acceptance(self.nodes[1].rpc, self.std_node, tx, with_witness=True, accepted=True)
# Now create something that looks like a P2PKH output. This won't be spendable.
scriptPubKey = CScript([OP_0, hash160(witness_hash)])
tx2 = CTransaction()
- if segwit_activated:
- # if tx was accepted, then we spend the second output.
- tx2.vin = [CTxIn(COutPoint(tx.sha256, 1), b"")]
- tx2.vout = [CTxOut(7000, scriptPubKey)]
- tx2.wit.vtxinwit.append(CTxInWitness())
- tx2.wit.vtxinwit[0].scriptWitness.stack = [witness_program]
- else:
- # if tx wasn't accepted, we just re-spend the p2sh output we started with.
- tx2.vin = [CTxIn(COutPoint(p2sh_tx.sha256, 0), CScript([witness_program]))]
- tx2.vout = [CTxOut(p2sh_tx.vout[0].nValue-1000, scriptPubKey)]
+ # tx was accepted, so we spend the second output.
+ tx2.vin = [CTxIn(COutPoint(tx.sha256, 1), b"")]
+ tx2.vout = [CTxOut(7000, scriptPubKey)]
+ tx2.wit.vtxinwit.append(CTxInWitness())
+ tx2.wit.vtxinwit[0].scriptWitness.stack = [witness_program]
tx2.rehash()
- test_transaction_acceptance(self.nodes[1].rpc, self.std_node, tx2, with_witness=True, accepted=segwit_activated)
+ test_transaction_acceptance(self.nodes[1].rpc, self.std_node, tx2, with_witness=True, accepted=True)
# Now update self.utxo for later tests.
tx3 = CTransaction()
- if segwit_activated:
- # tx and tx2 were both accepted. Don't bother trying to reclaim the
- # P2PKH output; just send tx's first output back to an anyone-can-spend.
- sync_mempools([self.nodes[0], self.nodes[1]])
- tx3.vin = [CTxIn(COutPoint(tx.sha256, 0), b"")]
- tx3.vout = [CTxOut(tx.vout[0].nValue - 1000, CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE]))]
- tx3.wit.vtxinwit.append(CTxInWitness())
- tx3.wit.vtxinwit[0].scriptWitness.stack = [witness_program]
- tx3.rehash()
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx3, with_witness=True, accepted=True)
- else:
- # tx and tx2 didn't go anywhere; just clean up the p2sh_tx output.
- tx3.vin = [CTxIn(COutPoint(p2sh_tx.sha256, 0), CScript([witness_program]))]
- tx3.vout = [CTxOut(p2sh_tx.vout[0].nValue - 1000, CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE]))]
+ # tx and tx2 were both accepted. Don't bother trying to reclaim the
+ # P2PKH output; just send tx's first output back to an anyone-can-spend.
+ sync_mempools([self.nodes[0], self.nodes[1]])
+ tx3.vin = [CTxIn(COutPoint(tx.sha256, 0), b"")]
+ tx3.vout = [CTxOut(tx.vout[0].nValue - 1000, CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE]))]
+ tx3.wit.vtxinwit.append(CTxInWitness())
+ tx3.wit.vtxinwit[0].scriptWitness.stack = [witness_program]
+ tx3.rehash()
+ if not segwit_activated:
+ # Just check mempool acceptance, but don't add the transaction to the mempool, since witness is disallowed
+ # in blocks and the tx is impossible to mine right now.
+ assert_equal(self.nodes[0].testmempoolaccept([bytes_to_hex_str(tx3.serialize_with_witness())]), [{'txid': tx3.hash, 'allowed': True}])
+ # Create the same output as tx3, but by replacing tx
+ tx3_out = tx3.vout[0]
+ tx3 = tx
+ tx3.vout = [tx3_out]
tx3.rehash()
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx3, with_witness=True, accepted=True)
+ assert_equal(self.nodes[0].testmempoolaccept([bytes_to_hex_str(tx3.serialize_with_witness())]), [{'txid': tx3.hash, 'allowed': True}])
+ test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx3, with_witness=True, accepted=True)
self.nodes[0].generate(1)
sync_blocks(self.nodes)
@@ -1855,6 +1810,60 @@ class SegWitTest(BitcoinTestFramework):
test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
self.utxo.append(UTXO(tx5.sha256, 0, tx5.vout[0].nValue))
+ def test_non_standard_witness_blinding(self):
+ self.log.info("Testing behavior of unnecessary witnesses in transactions does not blind the node for the transaction")
+ assert (len(self.utxo) > 0)
+
+ # Create a p2sh output -- this is so we can pass the standardness
+ # rules (an anyone-can-spend OP_TRUE would be rejected, if not wrapped
+ # in P2SH).
+ p2sh_program = CScript([OP_TRUE])
+ p2sh_pubkey = hash160(p2sh_program)
+ scriptPubKey = CScript([OP_HASH160, p2sh_pubkey, OP_EQUAL])
+
+ # Now check that unnecessary witnesses can't be used to blind a node
+ # to a transaction, eg by violating standardness checks.
+ tx = CTransaction()
+ tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b""))
+ tx.vout.append(CTxOut(self.utxo[0].nValue - 1000, scriptPubKey))
+ tx.rehash()
+ test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx, False, True)
+ self.nodes[0].generate(1)
+ sync_blocks(self.nodes)
+
+ # We'll add an unnecessary witness to this transaction that would cause
+ # it to be non-standard, to test that violating policy with a witness
+ # doesn't blind a node to a transaction. Transactions
+ # rejected for having a witness shouldn't be added
+ # to the rejection cache.
+ tx2 = CTransaction()
+ tx2.vin.append(CTxIn(COutPoint(tx.sha256, 0), CScript([p2sh_program])))
+ tx2.vout.append(CTxOut(tx.vout[0].nValue - 1000, scriptPubKey))
+ tx2.wit.vtxinwit.append(CTxInWitness())
+ tx2.wit.vtxinwit[0].scriptWitness.stack = [b'a' * 400]
+ tx2.rehash()
+ # This will be rejected due to a policy check:
+ # No witness is allowed, since it is not a witness program but a p2sh program
+ test_transaction_acceptance(self.nodes[1].rpc, self.std_node, tx2, True, False, b'bad-witness-nonstandard')
+
+ # If we send without witness, it should be accepted.
+ test_transaction_acceptance(self.nodes[1].rpc, self.std_node, tx2, False, True)
+
+ # Now create a new anyone-can-spend utxo for the next test.
+ tx3 = CTransaction()
+ tx3.vin.append(CTxIn(COutPoint(tx2.sha256, 0), CScript([p2sh_program])))
+ tx3.vout.append(CTxOut(tx2.vout[0].nValue - 1000, CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE])))
+ tx3.rehash()
+ test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx2, False, True)
+ test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx3, False, True)
+
+ self.nodes[0].generate(1)
+ sync_blocks(self.nodes)
+
+ # Update our utxo list; we spent the first entry.
+ self.utxo.pop(0)
+ self.utxo.append(UTXO(tx3.sha256, 0, tx3.vout[0].nValue))
+
def test_non_standard_witness(self):
self.log.info("Testing detection of non-standard P2WSH witness")
pad = chr(1).encode('latin-1')
@@ -2023,6 +2032,7 @@ class SegWitTest(BitcoinTestFramework):
self.test_premature_coinbase_witness_spend()
self.test_uncompressed_pubkey()
self.test_signature_version_1()
+ self.test_non_standard_witness_blinding()
self.test_non_standard_witness()
sync_blocks(self.nodes)
self.test_upgrade_after_activation(node_id=2)
diff --git a/test/functional/p2p_sendheaders.py b/test/functional/p2p_sendheaders.py
index 095cc4b734..7ee8168e2f 100755
--- a/test/functional/p2p_sendheaders.py
+++ b/test/functional/p2p_sendheaders.py
@@ -288,6 +288,7 @@ class SendHeadersTest(BitcoinTestFramework):
# 1. Mine a block; expect inv announcements each time
self.log.info("Part 1: headers don't start before sendheaders message...")
for i in range(4):
+ self.log.debug("Part 1.{}: starting...".format(i))
old_tip = tip
tip = self.mine_blocks(1)
inv_node.check_last_inv_announcement(inv=[tip])
@@ -335,11 +336,13 @@ class SendHeadersTest(BitcoinTestFramework):
height = self.nodes[0].getblockcount() + 1
block_time += 10 # Advance far enough ahead
for i in range(10):
+ self.log.debug("Part 2.{}: starting...".format(i))
# Mine i blocks, and alternate announcing either via
# inv (of tip) or via headers. After each, new blocks
# mined by the node should successfully be announced
# with block header, even though the blocks are never requested
for j in range(2):
+ self.log.debug("Part 2.{}.{}: starting...".format(i, j))
blocks = []
for b in range(i + 1):
blocks.append(create_block(tip, create_coinbase(height), block_time))
@@ -386,6 +389,7 @@ class SendHeadersTest(BitcoinTestFramework):
# PART 3. Headers announcements can stop after large reorg, and resume after
# getheaders or inv from peer.
for j in range(2):
+ self.log.debug("Part 3.{}: starting...".format(j))
# First try mining a reorg that can propagate with header announcement
new_block_hashes = self.mine_reorg(length=7)
tip = new_block_hashes[-1]
@@ -412,23 +416,28 @@ class SendHeadersTest(BitcoinTestFramework):
test_node.wait_for_block(new_block_hashes[-1])
for i in range(3):
+ self.log.debug("Part 3.{}.{}: starting...".format(j, i))
+
# Mine another block, still should get only an inv
tip = self.mine_blocks(1)
inv_node.check_last_inv_announcement(inv=[tip])
test_node.check_last_inv_announcement(inv=[tip])
if i == 0:
- self.log.debug("Just get the data -- shouldn't cause headers announcements to resume")
+ # Just get the data -- shouldn't cause headers announcements to resume
test_node.send_get_data([tip])
test_node.wait_for_block(tip)
elif i == 1:
- self.log.debug("Send a getheaders message that shouldn't trigger headers announcements to resume (best header sent will be too old)")
+ # Send a getheaders message that shouldn't trigger headers announcements
+ # to resume (best header sent will be too old)
test_node.send_get_headers(locator=[fork_point], hashstop=new_block_hashes[1])
test_node.send_get_data([tip])
test_node.wait_for_block(tip)
elif i == 2:
+ # This time, try sending either a getheaders to trigger resumption
+ # of headers announcements, or mine a new block and inv it, also
+ # triggering resumption of headers announcements.
test_node.send_get_data([tip])
test_node.wait_for_block(tip)
- self.log.debug("This time, try sending either a getheaders to trigger resumption of headers announcements, or mine a new block and inv it, also triggering resumption of headers announcements.")
if j == 0:
test_node.send_get_headers(locator=[tip], hashstop=0)
test_node.sync_with_ping()
@@ -532,6 +541,7 @@ class SendHeadersTest(BitcoinTestFramework):
# First we test that receipt of an unconnecting header doesn't prevent
# chain sync.
for i in range(10):
+ self.log.debug("Part 5.{}: starting...".format(i))
test_node.last_message.pop("getdata", None)
blocks = []
# Create two more blocks.
diff --git a/test/functional/p2p_timeouts.py b/test/functional/p2p_timeouts.py
index 6a21b693b4..e958536cf9 100755
--- a/test/functional/p2p_timeouts.py
+++ b/test/functional/p2p_timeouts.py
@@ -47,9 +47,9 @@ class TimeoutsTest(BitcoinTestFramework):
sleep(1)
- assert no_verack_node.connected
- assert no_version_node.connected
- assert no_send_node.connected
+ assert no_verack_node.is_connected
+ assert no_version_node.is_connected
+ assert no_send_node.is_connected
no_verack_node.send_message(msg_ping())
no_version_node.send_message(msg_ping())
@@ -58,18 +58,18 @@ class TimeoutsTest(BitcoinTestFramework):
assert "version" in no_verack_node.last_message
- assert no_verack_node.connected
- assert no_version_node.connected
- assert no_send_node.connected
+ assert no_verack_node.is_connected
+ assert no_version_node.is_connected
+ assert no_send_node.is_connected
no_verack_node.send_message(msg_ping())
no_version_node.send_message(msg_ping())
sleep(31)
- assert not no_verack_node.connected
- assert not no_version_node.connected
- assert not no_send_node.connected
+ assert not no_verack_node.is_connected
+ assert not no_version_node.is_connected
+ assert not no_send_node.is_connected
if __name__ == '__main__':
TimeoutsTest().main()
diff --git a/test/functional/rpc_blockchain.py b/test/functional/rpc_blockchain.py
index 17e24453e5..7acc59c2c6 100755
--- a/test/functional/rpc_blockchain.py
+++ b/test/functional/rpc_blockchain.py
@@ -217,6 +217,7 @@ class BlockchainTest(BitcoinTestFramework):
assert_equal(header['confirmations'], 1)
assert_equal(header['previousblockhash'], secondbesthash)
assert_is_hex_string(header['chainwork'])
+ assert_equal(header['nTx'], 1)
assert_is_hash_string(header['hash'])
assert_is_hash_string(header['previousblockhash'])
assert_is_hash_string(header['merkleroot'])
diff --git a/test/functional/rpc_deprecated.py b/test/functional/rpc_deprecated.py
index 2e0500e7c4..bc27c183b1 100755
--- a/test/functional/rpc_deprecated.py
+++ b/test/functional/rpc_deprecated.py
@@ -40,7 +40,6 @@ class DeprecatedRpcTest(BitcoinTestFramework):
#
# The following 'label' RPC methods are usable both with and without the
# -deprecatedrpc=accounts switch enabled.
- # - getlabeladdress
# - getaddressesbylabel
# - getreceivedbylabel
# - listlabels
@@ -69,10 +68,6 @@ class DeprecatedRpcTest(BitcoinTestFramework):
assert_raises_rpc_error(-32, "getaccountaddress is deprecated", self.nodes[0].getaccountaddress, "label0")
self.nodes[1].getaccountaddress("label1")
- self.log.info("- getlabeladdress")
- self.nodes[0].getlabeladdress("label0")
- self.nodes[1].getlabeladdress("label1")
-
self.log.info("- getaddressesbyaccount")
assert_raises_rpc_error(-32, "getaddressesbyaccount is deprecated", self.nodes[0].getaddressesbyaccount, "label0")
self.nodes[1].getaddressesbyaccount("label1")
diff --git a/test/functional/rpc_getblockstats.py b/test/functional/rpc_getblockstats.py
index 060a2373b1..f573faaf17 100755
--- a/test/functional/rpc_getblockstats.py
+++ b/test/functional/rpc_getblockstats.py
@@ -81,11 +81,11 @@ class GetblockstatsTest(BitcoinTestFramework):
'mocktime': int(mocktime),
'stats': self.expected_stats,
}
- with open(filename, 'w') as f:
+ with open(filename, 'w', encoding="utf8") as f:
json.dump(to_dump, f, sort_keys=True, indent=2)
def load_test_data(self, filename):
- with open(filename, 'r') as f:
+ with open(filename, 'r', encoding="utf8") as f:
d = json.load(f)
blocks = d['blocks']
mocktime = d['mocktime']
diff --git a/test/functional/test_framework/mininode.py b/test/functional/test_framework/mininode.py
index 7c2125a177..5859f108a4 100755
--- a/test/functional/test_framework/mininode.py
+++ b/test/functional/test_framework/mininode.py
@@ -77,6 +77,12 @@ class P2PConnection(asyncore.dispatcher):
super().__init__(map=mininode_socket_map)
+ self._conn_open = False
+
+ @property
+ def is_connected(self):
+ return self._conn_open
+
def peer_connect(self, dstaddr, dstport, net="regtest"):
self.dstaddr = dstaddr
self.dstport = dstport
@@ -84,7 +90,7 @@ class P2PConnection(asyncore.dispatcher):
self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
self.sendbuf = b""
self.recvbuf = b""
- self.state = "connecting"
+ self._asyncore_pre_connection = True
self.network = net
self.disconnect = False
@@ -97,22 +103,23 @@ class P2PConnection(asyncore.dispatcher):
def peer_disconnect(self):
# Connection could have already been closed by other end.
- if self.state == "connected":
- self.disconnect_node()
+ if self.is_connected:
+ self.disconnect = True # Signal asyncore to disconnect
# Connection and disconnection methods
def handle_connect(self):
"""asyncore callback when a connection is opened."""
- if self.state != "connected":
+ if not self.is_connected:
logger.debug("Connected & Listening: %s:%d" % (self.dstaddr, self.dstport))
- self.state = "connected"
+ self._conn_open = True
+ self._asyncore_pre_connection = False
self.on_open()
def handle_close(self):
"""asyncore callback when a connection is closed."""
logger.debug("Closing connection to: %s:%d" % (self.dstaddr, self.dstport))
- self.state = "closed"
+ self._conn_open = False
self.recvbuf = b""
self.sendbuf = b""
try:
@@ -121,13 +128,6 @@ class P2PConnection(asyncore.dispatcher):
pass
self.on_close()
- def disconnect_node(self):
- """Disconnect the p2p connection.
-
- Called by the test logic thread. Causes the p2p connection
- to be disconnected on the next iteration of the asyncore loop."""
- self.disconnect = True
-
# Socket read methods
def handle_read(self):
@@ -182,9 +182,8 @@ class P2PConnection(asyncore.dispatcher):
def writable(self):
"""asyncore method to determine whether the handle_write() callback should be called on the next loop."""
with mininode_lock:
- pre_connection = self.state == "connecting"
length = len(self.sendbuf)
- return (length > 0 or pre_connection)
+ return length > 0 or self._asyncore_pre_connection
def handle_write(self):
"""asyncore callback when data should be written to the socket."""
@@ -192,7 +191,7 @@ class P2PConnection(asyncore.dispatcher):
# asyncore does not expose socket connection, only the first read/write
# event, thus we must check connection manually here to know when we
# actually connect
- if self.state == "connecting":
+ if self._asyncore_pre_connection:
self.handle_connect()
if not self.writable():
return
@@ -204,26 +203,17 @@ class P2PConnection(asyncore.dispatcher):
return
self.sendbuf = self.sendbuf[sent:]
- def send_message(self, message, pushbuf=False):
+ def send_message(self, message):
"""Send a P2P message over the socket.
This method takes a P2P payload, builds the P2P header and adds
the message to the send buffer to be sent over the socket."""
- if self.state != "connected" and not pushbuf:
- raise IOError('Not connected, no pushbuf')
+ if not self.is_connected:
+ raise IOError('Not connected')
self._log_message("send", message)
- command = message.command
- data = message.serialize()
- tmsg = MAGIC_BYTES[self.network]
- tmsg += command
- tmsg += b"\x00" * (12 - len(command))
- tmsg += struct.pack("<I", len(data))
- th = sha256(data)
- h = sha256(th)
- tmsg += h[:4]
- tmsg += data
+ tmsg = self._build_message(message)
with mininode_lock:
- if (len(self.sendbuf) == 0 and not pushbuf):
+ if len(self.sendbuf) == 0:
try:
sent = self.send(tmsg)
self.sendbuf = tmsg[sent:]
@@ -234,6 +224,20 @@ class P2PConnection(asyncore.dispatcher):
# Class utility methods
+ def _build_message(self, message):
+ """Build a serialized P2P message"""
+ command = message.command
+ data = message.serialize()
+ tmsg = MAGIC_BYTES[self.network]
+ tmsg += command
+ tmsg += b"\x00" * (12 - len(command))
+ tmsg += struct.pack("<I", len(data))
+ th = sha256(data)
+ h = sha256(th)
+ tmsg += h[:4]
+ tmsg += data
+ return tmsg
+
def _log_message(self, direction, msg):
"""Logs a message being sent or received over the connection."""
if direction == "send":
@@ -280,7 +284,7 @@ class P2PInterface(P2PConnection):
vt.addrTo.port = self.dstport
vt.addrFrom.ip = "0.0.0.0"
vt.addrFrom.port = 0
- self.send_message(vt, True)
+ self.sendbuf = self._build_message(vt) # Will be sent right after handle_connect
# Message receiving methods
@@ -348,7 +352,7 @@ class P2PInterface(P2PConnection):
# Connection helper methods
def wait_for_disconnect(self, timeout=60):
- test_function = lambda: self.state != "connected"
+ test_function = lambda: not self.is_connected
wait_until(test_function, timeout=timeout, lock=mininode_lock)
# Message receiving helper methods
diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py
index 75a8986793..5c2555c1ff 100755
--- a/test/functional/test_framework/test_framework.py
+++ b/test/functional/test_framework/test_framework.py
@@ -359,7 +359,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
self.log = logging.getLogger('TestFramework')
self.log.setLevel(logging.DEBUG)
# Create file handler to log all messages
- fh = logging.FileHandler(self.options.tmpdir + '/test_framework.log')
+ fh = logging.FileHandler(self.options.tmpdir + '/test_framework.log', encoding='utf-8')
fh.setLevel(logging.DEBUG)
# Create console handler to log messages to stderr. By default this logs only error messages, but can be configured with --loglevel.
ch = logging.StreamHandler(sys.stdout)
diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py
index e016148f70..5e0b61b5e7 100644
--- a/test/functional/test_framework/util.py
+++ b/test/functional/test_framework/util.py
@@ -327,7 +327,7 @@ def get_auth_cookie(datadir):
assert password is None # Ensure that there is only one rpcpassword line
password = line.split("=")[1].strip("\n")
if os.path.isfile(os.path.join(datadir, "regtest", ".cookie")):
- with open(os.path.join(datadir, "regtest", ".cookie"), 'r') as f:
+ with open(os.path.join(datadir, "regtest", ".cookie"), 'r', encoding="ascii") as f:
userpass = f.read()
split_userpass = userpass.split(':')
user = split_userpass[0]
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index 65e4c0817e..36101d9f57 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -213,7 +213,7 @@ def main():
# Read config generated by configure.
config = configparser.ConfigParser()
configfile = os.path.abspath(os.path.dirname(__file__)) + "/../config.ini"
- config.read_file(open(configfile))
+ config.read_file(open(configfile, encoding="utf8"))
passon_args.append("--configfile=%s" % configfile)
@@ -419,10 +419,6 @@ class TestHandler:
self.test_list = test_list
self.flags = flags
self.num_running = 0
- # In case there is a graveyard of zombie bitcoinds, we can apply a
- # pseudorandom offset to hopefully jump over them.
- # (625 is PORT_RANGE/MAX_NODES)
- self.portseed_offset = int(time.time() * 1000) % 625
self.jobs = []
def get_next(self):
@@ -430,7 +426,7 @@ class TestHandler:
# Add tests
self.num_running += 1
test = self.test_list.pop(0)
- portseed = len(self.test_list) + self.portseed_offset
+ portseed = len(self.test_list)
portseed_arg = ["--portseed={}".format(portseed)]
log_stdout = tempfile.SpooledTemporaryFile(max_size=2**16)
log_stderr = tempfile.SpooledTemporaryFile(max_size=2**16)
@@ -594,7 +590,7 @@ class RPCCoverage():
if not os.path.isfile(coverage_ref_filename):
raise RuntimeError("No coverage reference found")
- with open(coverage_ref_filename, 'r') as coverage_ref_file:
+ with open(coverage_ref_filename, 'r', encoding="utf8") as coverage_ref_file:
all_cmds.update([line.strip() for line in coverage_ref_file.readlines()])
for root, dirs, files in os.walk(self.dir):
@@ -603,7 +599,7 @@ class RPCCoverage():
coverage_filenames.add(os.path.join(root, filename))
for filename in coverage_filenames:
- with open(filename, 'r') as coverage_file:
+ with open(filename, 'r', encoding="utf8") as coverage_file:
covered_cmds.update([line.strip() for line in coverage_file.readlines()])
return all_cmds - covered_cmds
diff --git a/test/functional/wallet_basic.py b/test/functional/wallet_basic.py
index 9c58b84819..d6a64eaefb 100755
--- a/test/functional/wallet_basic.py
+++ b/test/functional/wallet_basic.py
@@ -129,6 +129,15 @@ class WalletTest(BitcoinTestFramework):
self.nodes[2].lockunspent, False,
[{"txid": unspent_0["txid"], "vout": 999}])
+ # An output should be unlocked when spent
+ unspent_0 = self.nodes[1].listunspent()[0]
+ self.nodes[1].lockunspent(False, [unspent_0])
+ tx = self.nodes[1].createrawtransaction([unspent_0], { self.nodes[1].getnewaddress() : 1 })
+ tx = self.nodes[1].fundrawtransaction(tx)['hex']
+ tx = self.nodes[1].signrawtransactionwithwallet(tx)["hex"]
+ self.nodes[1].sendrawtransaction(tx)
+ assert_equal(len(self.nodes[1].listlockunspent()), 0)
+
# Have node1 generate 100 blocks (so node0 can recover the fee)
self.nodes[1].generate(100)
self.sync_all([self.nodes[0:3]])
diff --git a/test/functional/wallet_bumpfee.py b/test/functional/wallet_bumpfee.py
index fcc11abce0..f07041706a 100755
--- a/test/functional/wallet_bumpfee.py
+++ b/test/functional/wallet_bumpfee.py
@@ -31,7 +31,7 @@ class BumpFeeTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
self.setup_clean_chain = True
- self.extra_args = [["-prematurewitness", "-walletprematurewitness", "-deprecatedrpc=addwitnessaddress", "-walletrbf={}".format(i)]
+ self.extra_args = [["-deprecatedrpc=addwitnessaddress", "-walletrbf={}".format(i)]
for i in range(self.num_nodes)]
def run_test(self):
diff --git a/test/functional/wallet_fallbackfee.py b/test/functional/wallet_fallbackfee.py
index e9cd052344..cc0a5175d5 100755
--- a/test/functional/wallet_fallbackfee.py
+++ b/test/functional/wallet_fallbackfee.py
@@ -21,7 +21,6 @@ class WalletRBFTest(BitcoinTestFramework):
self.restart_node(0, extra_args=["-fallbackfee=0"])
assert_raises_rpc_error(-4, "Fee estimation failed", lambda: self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1))
assert_raises_rpc_error(-4, "Fee estimation failed", lambda: self.nodes[0].fundrawtransaction(self.nodes[0].createrawtransaction([], {self.nodes[0].getnewaddress(): 1})))
- assert_raises_rpc_error(-4, "Fee estimation failed", lambda: self.nodes[0].sendfrom("", self.nodes[0].getnewaddress(), 1))
assert_raises_rpc_error(-6, "Fee estimation failed", lambda: self.nodes[0].sendmany("", {self.nodes[0].getnewaddress(): 1}))
if __name__ == '__main__':
diff --git a/test/functional/wallet_labels.py b/test/functional/wallet_labels.py
index 705dd8985e..8d961fb34a 100755
--- a/test/functional/wallet_labels.py
+++ b/test/functional/wallet_labels.py
@@ -5,7 +5,7 @@
"""Test label RPCs.
RPCs tested are:
- - getlabeladdress
+ - getaccountaddress
- getaddressesbyaccount/getaddressesbylabel
- listaddressgroupings
- setlabel
@@ -85,24 +85,32 @@ class WalletLabelsTest(BitcoinTestFramework):
# we want to reset so that the "" label has what's expected.
# otherwise we're off by exactly the fee amount as that's mined
# and matures in the next 100 blocks
- node.sendfrom("", common_address, fee)
+ if accounts_api:
+ node.sendfrom("", common_address, fee)
amount_to_send = 1.0
# Create labels and make sure subsequent label API calls
# recognize the label/address associations.
labels = [Label(name, accounts_api) for name in ("a", "b", "c", "d", "e")]
for label in labels:
- label.add_receive_address(node.getlabeladdress(label=label.name, force=True))
+ if accounts_api:
+ address = node.getaccountaddress(label.name)
+ else:
+ address = node.getnewaddress(label.name)
+ label.add_receive_address(address)
label.verify(node)
# Check all labels are returned by listlabels.
assert_equal(node.listlabels(), [label.name for label in labels])
# Send a transaction to each label, and make sure this forces
- # getlabeladdress to generate a new receiving address.
+ # getaccountaddress to generate a new receiving address.
for label in labels:
- node.sendtoaddress(label.receive_address, amount_to_send)
- label.add_receive_address(node.getlabeladdress(label.name))
+ if accounts_api:
+ node.sendtoaddress(label.receive_address, amount_to_send)
+ label.add_receive_address(node.getaccountaddress(label.name))
+ else:
+ node.sendtoaddress(label.addresses[0], amount_to_send)
label.verify(node)
# Check the amounts received.
@@ -115,10 +123,17 @@ class WalletLabelsTest(BitcoinTestFramework):
# Check that sendfrom label reduces listaccounts balances.
for i, label in enumerate(labels):
to_label = labels[(i + 1) % len(labels)]
- node.sendfrom(label.name, to_label.receive_address, amount_to_send)
+ if accounts_api:
+ node.sendfrom(label.name, to_label.receive_address, amount_to_send)
+ else:
+ node.sendtoaddress(to_label.addresses[0], amount_to_send)
node.generate(1)
for label in labels:
- label.add_receive_address(node.getlabeladdress(label.name))
+ if accounts_api:
+ address = node.getaccountaddress(label.name)
+ else:
+ address = node.getnewaddress(label.name)
+ label.add_receive_address(address)
label.verify(node)
assert_equal(node.getreceivedbylabel(label.name), 2)
if accounts_api:
@@ -134,12 +149,12 @@ class WalletLabelsTest(BitcoinTestFramework):
# Check that setlabel can assign a label to a new unused address.
for label in labels:
- address = node.getlabeladdress(label="", force=True)
+ address = node.getnewaddress()
node.setlabel(address, label.name)
label.add_address(address)
label.verify(node)
if accounts_api:
- assert(address not in node.getaddressesbyaccount(""))
+ assert address not in node.getaddressesbyaccount("")
else:
assert_raises_rpc_error(-11, "No addresses with label", node.getaddressesbylabel, "")
@@ -152,7 +167,8 @@ class WalletLabelsTest(BitcoinTestFramework):
label.add_address(multisig_address)
label.purpose[multisig_address] = "send"
label.verify(node)
- node.sendfrom("", multisig_address, 50)
+ if accounts_api:
+ node.sendfrom("", multisig_address, 50)
node.generate(101)
if accounts_api:
for label in labels:
@@ -160,19 +176,20 @@ class WalletLabelsTest(BitcoinTestFramework):
# Check that setlabel can change the label of an address from a
# different label.
- change_label(node, labels[0].addresses[0], labels[0], labels[1])
-
- # Check that setlabel can change the label of an address which
- # is the receiving address of a different label.
- change_label(node, labels[0].receive_address, labels[0], labels[1])
+ change_label(node, labels[0].addresses[0], labels[0], labels[1], accounts_api)
# Check that setlabel can set the label of an address already
# in the label. This is a no-op.
- change_label(node, labels[2].addresses[0], labels[2], labels[2])
+ change_label(node, labels[2].addresses[0], labels[2], labels[2], accounts_api)
- # Check that setlabel can set the label of an address which is
- # already the receiving address of the label. This is a no-op.
- change_label(node, labels[2].receive_address, labels[2], labels[2])
+ if accounts_api:
+ # Check that setaccount can change the label of an address which
+ # is the receiving address of a different label.
+ change_label(node, labels[0].receive_address, labels[0], labels[1], accounts_api)
+
+ # Check that setaccount can set the label of an address which is
+ # already the receiving address of the label. This is a no-op.
+ change_label(node, labels[2].receive_address, labels[2], labels[2], accounts_api)
class Label:
def __init__(self, name, accounts_api):
@@ -192,12 +209,14 @@ class Label:
def add_receive_address(self, address):
self.add_address(address)
- self.receive_address = address
+ if self.accounts_api:
+ self.receive_address = address
def verify(self, node):
if self.receive_address is not None:
assert self.receive_address in self.addresses
- assert_equal(node.getlabeladdress(self.name), self.receive_address)
+ if self.accounts_api:
+ assert_equal(node.getaccountaddress(self.name), self.receive_address)
for address in self.addresses:
assert_equal(
@@ -216,22 +235,26 @@ class Label:
assert_equal(set(node.getaddressesbyaccount(self.name)), set(self.addresses))
-def change_label(node, address, old_label, new_label):
+def change_label(node, address, old_label, new_label, accounts_api):
assert_equal(address in old_label.addresses, True)
- node.setlabel(address, new_label.name)
+ if accounts_api:
+ node.setaccount(address, new_label.name)
+ else:
+ node.setlabel(address, new_label.name)
old_label.addresses.remove(address)
new_label.add_address(address)
- # Calling setlabel on an address which was previously the receiving
- # address of a different label should reset the receiving address of
- # the old label, causing getlabeladdress to return a brand new
+ # Calling setaccount on an address which was previously the receiving
+ # address of a different account should reset the receiving address of
+ # the old account, causing getaccountaddress to return a brand new
# address.
- if old_label.name != new_label.name and address == old_label.receive_address:
- new_address = node.getlabeladdress(old_label.name)
- assert_equal(new_address not in old_label.addresses, True)
- assert_equal(new_address not in new_label.addresses, True)
- old_label.add_receive_address(new_address)
+ if accounts_api:
+ if old_label.name != new_label.name and address == old_label.receive_address:
+ new_address = node.getaccountaddress(old_label.name)
+ assert_equal(new_address not in old_label.addresses, True)
+ assert_equal(new_address not in new_label.addresses, True)
+ old_label.add_receive_address(new_address)
old_label.verify(node)
new_label.verify(node)
diff --git a/test/functional/wallet_multiwallet.py b/test/functional/wallet_multiwallet.py
index 53638615f6..3cefd83459 100755
--- a/test/functional/wallet_multiwallet.py
+++ b/test/functional/wallet_multiwallet.py
@@ -88,7 +88,7 @@ class MultiWalletTest(BitcoinTestFramework):
self.nodes[0].assert_start_raises_init_error(['-walletdir=bad'], 'Error: Specified -walletdir "bad" does not exist')
# should not initialize if the specified walletdir is not a directory
not_a_dir = wallet_dir('notadir')
- open(not_a_dir, 'a').close()
+ open(not_a_dir, 'a', encoding="utf8").close()
self.nodes[0].assert_start_raises_init_error(['-walletdir=' + not_a_dir], 'Error: Specified -walletdir "' + not_a_dir + '" is not a directory')
self.log.info("Do not allow -zapwallettxes with multiwallet")
@@ -234,5 +234,32 @@ class MultiWalletTest(BitcoinTestFramework):
assert new_wallet_name in self.nodes[0].listwallets()
+ self.log.info("Test dynamic wallet unloading")
+
+ # Test `unloadwallet` errors
+ assert_raises_rpc_error(-1, "JSON value is not a string as expected", self.nodes[0].unloadwallet)
+ assert_raises_rpc_error(-18, "Requested wallet does not exist or is not loaded", self.nodes[0].unloadwallet, "dummy")
+ assert_raises_rpc_error(-18, "Requested wallet does not exist or is not loaded", node.get_wallet_rpc("dummy").unloadwallet)
+ assert_raises_rpc_error(-8, "Cannot unload the requested wallet", w1.unloadwallet, "w2"),
+
+ # Successfully unload the specified wallet name
+ self.nodes[0].unloadwallet("w1")
+ assert 'w1' not in self.nodes[0].listwallets()
+
+ # Successfully unload the wallet referenced by the request endpoint
+ w2.unloadwallet()
+ assert 'w2' not in self.nodes[0].listwallets()
+
+ # Successfully unload all wallets
+ for wallet_name in self.nodes[0].listwallets():
+ self.nodes[0].unloadwallet(wallet_name)
+ assert_equal(self.nodes[0].listwallets(), [])
+ assert_raises_rpc_error(-32601, "Method not found (wallet method is disabled because no wallet is loaded)", self.nodes[0].getwalletinfo)
+
+ # Successfully load a previously unloaded wallet
+ self.nodes[0].loadwallet('w1')
+ assert_equal(self.nodes[0].listwallets(), ['w1'])
+ assert_equal(w1.getwalletinfo()['walletname'], 'w1')
+
if __name__ == '__main__':
MultiWalletTest().main()
diff --git a/test/lint/check-doc.py b/test/lint/check-doc.py
index de5719eb29..89776b2a6b 100755
--- a/test/lint/check-doc.py
+++ b/test/lint/check-doc.py
@@ -22,7 +22,7 @@ CMD_ROOT_DIR = '`git rev-parse --show-toplevel`/{}'.format(FOLDER_GREP)
CMD_GREP_ARGS = r"git grep --perl-regexp '{}' -- {} ':(exclude){}'".format(REGEX_ARG, CMD_ROOT_DIR, FOLDER_TEST)
CMD_GREP_DOCS = r"git grep --perl-regexp '{}' {}".format(REGEX_DOC, CMD_ROOT_DIR)
# list unsupported, deprecated and duplicate args as they need no documentation
-SET_DOC_OPTIONAL = set(['-rpcssl', '-benchmark', '-h', '-help', '-socks', '-tor', '-debugnet', '-whitelistalwaysrelay', '-prematurewitness', '-walletprematurewitness', '-promiscuousmempoolflags', '-blockminsize', '-dbcrashratio', '-forcecompactdb', '-usehd'])
+SET_DOC_OPTIONAL = set(['-rpcssl', '-benchmark', '-h', '-help', '-socks', '-tor', '-debugnet', '-whitelistalwaysrelay', '-promiscuousmempoolflags', '-blockminsize', '-dbcrashratio', '-forcecompactdb', '-usehd'])
def main():
diff --git a/test/lint/check-rpc-mappings.py b/test/lint/check-rpc-mappings.py
index 7e96852c5c..c3cdeef580 100755
--- a/test/lint/check-rpc-mappings.py
+++ b/test/lint/check-rpc-mappings.py
@@ -44,7 +44,7 @@ def process_commands(fname):
"""Find and parse dispatch table in implementation file `fname`."""
cmds = []
in_rpcs = False
- with open(fname, "r") as f:
+ with open(fname, "r", encoding="utf8") as f:
for line in f:
line = line.rstrip()
if not in_rpcs:
@@ -70,7 +70,7 @@ def process_mapping(fname):
"""Find and parse conversion table in implementation file `fname`."""
cmds = []
in_rpcs = False
- with open(fname, "r") as f:
+ with open(fname, "r", encoding="utf8") as f:
for line in f:
line = line.rstrip()
if not in_rpcs:
diff --git a/test/lint/commit-script-check.sh b/test/lint/commit-script-check.sh
index 1c9dbc7f68..f1327469f3 100755
--- a/test/lint/commit-script-check.sh
+++ b/test/lint/commit-script-check.sh
@@ -11,6 +11,7 @@
# The resulting script should exactly transform the previous commit into the current
# one. Any remaining diff signals an error.
+export LC_ALL=C
if test "x$1" = "x"; then
echo "Usage: $0 <commit>..."
exit 1
diff --git a/test/lint/git-subtree-check.sh b/test/lint/git-subtree-check.sh
index 184951715e..85e8b841b6 100755
--- a/test/lint/git-subtree-check.sh
+++ b/test/lint/git-subtree-check.sh
@@ -3,6 +3,7 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+export LC_ALL=C
DIR="$1"
COMMIT="$2"
if [ -z "$COMMIT" ]; then
diff --git a/test/lint/lint-all.sh b/test/lint/lint-all.sh
index b6d86959c6..7c4f96cb3b 100755
--- a/test/lint/lint-all.sh
+++ b/test/lint/lint-all.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
#
# Copyright (c) 2017 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
@@ -7,6 +7,10 @@
# This script runs all contrib/devtools/lint-*.sh files, and fails if any exit
# with a non-zero status code.
+# This script is intentionally locale dependent by not setting "export LC_ALL=C"
+# in order to allow for the executed lint scripts to opt in or opt out of locale
+# dependence themselves.
+
set -u
SCRIPTDIR=$(dirname "${BASH_SOURCE[0]}")
diff --git a/test/lint/lint-filenames.sh b/test/lint/lint-filenames.sh
new file mode 100755
index 0000000000..5391e43d91
--- /dev/null
+++ b/test/lint/lint-filenames.sh
@@ -0,0 +1,24 @@
+#!/usr/bin/env bash
+#
+# Copyright (c) 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.
+#
+# Make sure only lowercase alphanumerics (a-z0-9), underscores (_),
+# hyphens (-) and dots (.) are used in source code filenames.
+
+export LC_ALL=C
+
+EXIT_CODE=0
+OUTPUT=$(git ls-files --full-name -- "*.[cC][pP][pP]" "*.[hH]" "*.[pP][yY]" "*.[sS][hH]" | \
+ grep -vE '^[a-z0-9_./-]+$' | \
+ grep -vE '^src/(secp256k1|univalue)/')
+
+if [[ ${OUTPUT} != "" ]]; then
+ echo "Use only lowercase alphanumerics (a-z0-9), underscores (_), hyphens (-) and dots (.)"
+ echo "in source code filenames:"
+ echo
+ echo "${OUTPUT}"
+ EXIT_CODE=1
+fi
+exit ${EXIT_CODE}
diff --git a/test/lint/lint-include-guards.sh b/test/lint/lint-include-guards.sh
index 6a0dd556bb..464969794b 100755
--- a/test/lint/lint-include-guards.sh
+++ b/test/lint/lint-include-guards.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
#
# Copyright (c) 2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
@@ -6,6 +6,7 @@
#
# Check include guards.
+export LC_ALL=C
HEADER_ID_PREFIX="BITCOIN_"
HEADER_ID_SUFFIX="_H"
diff --git a/test/lint/lint-includes.sh b/test/lint/lint-includes.sh
index 2c3456b644..fdc3f5bd35 100755
--- a/test/lint/lint-includes.sh
+++ b/test/lint/lint-includes.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
#
# Copyright (c) 2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
@@ -6,9 +6,13 @@
#
# Check for duplicate includes.
# Guard against accidental introduction of new Boost dependencies.
+# Check includes: Check for duplicate includes. Enforce bracket syntax includes.
+
+export LC_ALL=C
+IGNORE_REGEXP="/(leveldb|secp256k1|univalue)/"
filter_suffix() {
- git ls-files | grep -E "^src/.*\.${1}"'$' | grep -Ev "/(leveldb|secp256k1|univalue)/"
+ git ls-files | grep -E "^src/.*\.${1}"'$' | grep -Ev "${IGNORE_REGEXP}"
}
EXIT_CODE=0
@@ -105,4 +109,12 @@ for EXPECTED_BOOST_INCLUDE in "${EXPECTED_BOOST_INCLUDES[@]}"; do
fi
done
+QUOTE_SYNTAX_INCLUDES=$(git grep '^#include "' -- "*.cpp" "*.h" | grep -Ev "${IGNORE_REGEXP}")
+if [[ ${QUOTE_SYNTAX_INCLUDES} != "" ]]; then
+ echo "Please use bracket syntax includes (\"#include <foo.h>\") instead of quote syntax includes:"
+ echo "${QUOTE_SYNTAX_INCLUDES}"
+ echo
+ EXIT_CODE=1
+fi
+
exit ${EXIT_CODE}
diff --git a/test/lint/lint-locale-dependence.sh b/test/lint/lint-locale-dependence.sh
index 3144f2c841..cbe1143bd0 100755
--- a/test/lint/lint-locale-dependence.sh
+++ b/test/lint/lint-locale-dependence.sh
@@ -1,5 +1,6 @@
-#!/bin/bash
+#!/usr/bin/env bash
+export LC_ALL=C
KNOWN_VIOLATIONS=(
"src/base58.cpp:.*isspace"
"src/bitcoin-tx.cpp.*stoul"
diff --git a/test/lint/lint-logs.sh b/test/lint/lint-logs.sh
index 35be13ec19..1afd4cfc1a 100755
--- a/test/lint/lint-logs.sh
+++ b/test/lint/lint-logs.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
#
# Copyright (c) 2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
@@ -12,7 +12,7 @@
# There are some instances of LogPrintf() in comments. Those can be
# ignored
-
+export LC_ALL=C
UNTERMINATED_LOGS=$(git grep --extended-regexp "LogPrintf?\(" -- "*.cpp" | \
grep -v '\\n"' | \
grep -v "/\* Continued \*/" | \
diff --git a/test/lint/lint-python-shebang.sh b/test/lint/lint-python-shebang.sh
index f5c5971c03..4ff87f0bf7 100755
--- a/test/lint/lint-python-shebang.sh
+++ b/test/lint/lint-python-shebang.sh
@@ -1,5 +1,7 @@
-#!/bin/bash
+#!/usr/bin/env bash
# Shebang must use python3 (not python or python2)
+
+export LC_ALL=C
EXIT_CODE=0
for PYTHON_FILE in $(git ls-files -- "*.py"); do
if [[ $(head -c 2 "${PYTHON_FILE}") == "#!" &&
diff --git a/test/lint/lint-python-utf8-encoding.sh b/test/lint/lint-python-utf8-encoding.sh
new file mode 100755
index 0000000000..14183a5ccf
--- /dev/null
+++ b/test/lint/lint-python-utf8-encoding.sh
@@ -0,0 +1,20 @@
+#!/usr/bin/env bash
+#
+# Copyright (c) 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.
+#
+# Make sure we explicitly open all text files using UTF-8 (or ASCII) encoding to
+# avoid potential issues on the BSDs where the locale is not always set.
+
+export LC_ALL=C
+EXIT_CODE=0
+OUTPUT=$(git grep " open(" -- "*.py" | grep -vE "encoding=.(ascii|utf8|utf-8)." | grep -vE "open\([^,]*, ['\"][^'\"]*b[^'\"]*['\"]")
+if [[ ${OUTPUT} != "" ]]; then
+ echo "Python's open(...) seems to be used to open text files without explicitly"
+ echo "specifying encoding=\"utf8\":"
+ echo
+ echo "${OUTPUT}"
+ EXIT_CODE=1
+fi
+exit ${EXIT_CODE}
diff --git a/test/lint/lint-python.sh b/test/lint/lint-python.sh
index 7d3555b6d4..d9d46d86d5 100755
--- a/test/lint/lint-python.sh
+++ b/test/lint/lint-python.sh
@@ -6,6 +6,8 @@
#
# Check for specified flake8 warnings in python files.
+export LC_ALL=C
+
# E101 indentation contains mixed spaces and tabs
# E112 expected an indented block
# E113 unexpected indentation
diff --git a/test/lint/lint-shell-locale.sh b/test/lint/lint-shell-locale.sh
new file mode 100755
index 0000000000..242b27c763
--- /dev/null
+++ b/test/lint/lint-shell-locale.sh
@@ -0,0 +1,24 @@
+#!/usr/bin/env bash
+#
+# Copyright (c) 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.
+#
+# Make sure all shell scripts:
+# a.) explicitly opt out of locale dependence using "export LC_ALL=C", or
+# b.) explicitly opt in to locale dependence using the annotation below.
+
+export LC_ALL=C
+
+EXIT_CODE=0
+for SHELL_SCRIPT in $(git ls-files -- "*.sh" | grep -vE "src/(secp256k1|univalue)/"); do
+ if grep -q "# This script is intentionally locale dependent by not setting \"export LC_ALL=C\"" "${SHELL_SCRIPT}"; then
+ continue
+ fi
+ FIRST_NON_COMMENT_LINE=$(grep -vE '^(#.*|)$' "${SHELL_SCRIPT}" | head -1)
+ if [[ ${FIRST_NON_COMMENT_LINE} != "export LC_ALL=C" ]]; then
+ echo "Missing \"export LC_ALL=C\" (to avoid locale dependence) as first non-comment non-empty line in ${SHELL_SCRIPT}"
+ EXIT_CODE=1
+ fi
+done
+exit ${EXIT_CODE}
diff --git a/test/lint/lint-shell.sh b/test/lint/lint-shell.sh
index 5f5fa9a925..e2ccdb5165 100755
--- a/test/lint/lint-shell.sh
+++ b/test/lint/lint-shell.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
#
# Copyright (c) 2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
@@ -6,6 +6,10 @@
#
# Check for shellcheck warnings in shell scripts.
+# This script is intentionally locale dependent by not setting "export LC_ALL=C"
+# to allow running certain versions of shellcheck that core dump when LC_ALL=C
+# is set.
+
# Disabled warnings:
# SC2001: See if you can use ${variable//search/replace} instead.
# SC2004: $/${} is unnecessary on arithmetic variables.
diff --git a/test/lint/lint-tests.sh b/test/lint/lint-tests.sh
index ffc0660551..35d11023eb 100755
--- a/test/lint/lint-tests.sh
+++ b/test/lint/lint-tests.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
#
# Copyright (c) 2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
@@ -6,6 +6,7 @@
#
# Check the test suite naming conventions
+export LC_ALL=C
EXIT_CODE=0
NAMING_INCONSISTENCIES=$(git grep -E '^BOOST_FIXTURE_TEST_SUITE\(' -- \
diff --git a/test/lint/lint-whitespace.sh b/test/lint/lint-whitespace.sh
index c5d43043d5..beb7ec42f4 100755
--- a/test/lint/lint-whitespace.sh
+++ b/test/lint/lint-whitespace.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
#
# Copyright (c) 2017 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
@@ -8,6 +8,7 @@
# We can't run this check unless we know the commit range for the PR.
+export LC_ALL=C
while getopts "?" opt; do
case $opt in
?)
diff --git a/test/util/bitcoin-util-test.py b/test/util/bitcoin-util-test.py
index 30bd13d0dc..16371a6234 100755
--- a/test/util/bitcoin-util-test.py
+++ b/test/util/bitcoin-util-test.py
@@ -28,7 +28,7 @@ import sys
def main():
config = configparser.ConfigParser()
config.optionxform = str
- config.readfp(open(os.path.join(os.path.dirname(__file__), "../config.ini")))
+ config.readfp(open(os.path.join(os.path.dirname(__file__), "../config.ini"), encoding="utf8"))
env_conf = dict(config.items('environment'))
parser = argparse.ArgumentParser(description=__doc__)
@@ -49,7 +49,7 @@ def main():
def bctester(testDir, input_basename, buildenv):
""" Loads and parses the input file, runs all tests and reports results"""
input_filename = os.path.join(testDir, input_basename)
- raw_data = open(input_filename).read()
+ raw_data = open(input_filename, encoding="utf8").read()
input_data = json.loads(raw_data)
failed_testcases = []
@@ -86,7 +86,7 @@ def bctest(testDir, testObj, buildenv):
inputData = None
if "input" in testObj:
filename = os.path.join(testDir, testObj["input"])
- inputData = open(filename).read()
+ inputData = open(filename, encoding="utf8").read()
stdinCfg = subprocess.PIPE
# Read the expected output data (if there is any)
@@ -97,7 +97,7 @@ def bctest(testDir, testObj, buildenv):
outputFn = testObj['output_cmp']
outputType = os.path.splitext(outputFn)[1][1:] # output type from file extension (determines how to compare)
try:
- outputData = open(os.path.join(testDir, outputFn)).read()
+ outputData = open(os.path.join(testDir, outputFn), encoding="utf8").read()
except:
logging.error("Output file " + outputFn + " can not be opened")
raise
diff --git a/test/util/rpcauth-test.py b/test/util/rpcauth-test.py
index 2456feb102..46e9fbc739 100755
--- a/test/util/rpcauth-test.py
+++ b/test/util/rpcauth-test.py
@@ -18,7 +18,7 @@ class TestRPCAuth(unittest.TestCase):
config_path = os.path.abspath(
os.path.join(os.sep, os.path.abspath(os.path.dirname(__file__)),
"../config.ini"))
- with open(config_path) as config_file:
+ with open(config_path, encoding="utf8") as config_file:
config.read_file(config_file)
sys.path.insert(0, os.path.dirname(config['environment']['RPCAUTH']))
self.rpcauth = importlib.import_module('rpcauth')