aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml18
-rwxr-xr-xci/lint/04_install.sh3
-rwxr-xr-xci/test/00_setup_env_android.sh2
-rwxr-xr-xci/test/00_setup_env_native_valgrind.sh2
-rwxr-xr-xci/test/06_script_a.sh2
-rwxr-xr-xci/test/06_script_b.sh2
-rw-r--r--configure.ac56
-rwxr-xr-xcontrib/devtools/security-check.py2
-rwxr-xr-xcontrib/devtools/symbol-check.py2
-rwxr-xr-xcontrib/guix/libexec/build.sh2
-rw-r--r--contrib/tracing/README.md7
-rwxr-xr-xcontrib/tracing/connectblock_benchmark.bt22
-rw-r--r--depends/packages/expat.mk2
-rw-r--r--depends/packages/fontconfig.mk2
-rw-r--r--depends/packages/freetype.mk2
-rw-r--r--depends/packages/libXau.mk2
-rw-r--r--depends/packages/qt.mk1
-rw-r--r--doc/descriptors.md41
-rw-r--r--doc/psbt.md3
-rw-r--r--doc/release-notes-22539.md8
-rw-r--r--doc/release-notes-23093.md11
-rw-r--r--doc/release-notes.md14
-rw-r--r--doc/release-process.md6
-rw-r--r--doc/tracing.md9
-rw-r--r--src/Makefile.am26
-rw-r--r--src/Makefile.leveldb.include5
-rw-r--r--src/Makefile.qt.include14
-rw-r--r--src/Makefile.test.include22
-rw-r--r--src/Makefile.univalue.include6
-rw-r--r--src/addrdb.cpp20
-rw-r--r--src/addrman.cpp64
-rw-r--r--src/banman.h2
-rw-r--r--src/bench/coin_selection.cpp11
-rw-r--r--src/bench/rollingbloom.cpp2
-rw-r--r--src/bench/rpc_blockchain.cpp4
-rw-r--r--src/bench/wallet_balance.cpp16
-rw-r--r--src/bitcoin-cli.cpp25
-rw-r--r--src/bitcoin-wallet.cpp1
-rw-r--r--src/chain.h2
-rw-r--r--src/chainparams.cpp28
-rw-r--r--src/common/bloom.cpp (renamed from src/bloom.cpp)4
-rw-r--r--src/common/bloom.h (renamed from src/bloom.h)6
-rw-r--r--src/consensus/amount.h1
-rw-r--r--src/core_io.h11
-rw-r--r--src/core_write.cpp31
-rw-r--r--src/crypto/chacha_poly_aead.h4
-rw-r--r--src/dbwrapper.cpp18
-rw-r--r--src/external_signer.cpp12
-rw-r--r--src/flatfile.cpp4
-rw-r--r--src/fs.cpp9
-rw-r--r--src/fs.h132
-rw-r--r--src/i2p.cpp2
-rw-r--r--src/index/base.cpp2
-rw-r--r--src/init.cpp26
-rw-r--r--src/init/common.cpp14
-rw-r--r--src/ipc/process.cpp4
-rw-r--r--src/logging.cpp1
-rw-r--r--src/logging.h1
-rw-r--r--src/merkleblock.h4
-rw-r--r--src/net.cpp3
-rw-r--r--src/net.h4
-rw-r--r--src/net_processing.cpp22
-rw-r--r--src/node/blockstorage.cpp19
-rw-r--r--src/node/interfaces.cpp2
-rw-r--r--src/policy/fees.cpp6
-rw-r--r--src/policy/policy.cpp7
-rw-r--r--src/policy/rbf.cpp4
-rw-r--r--src/primitives/transaction.h5
-rw-r--r--src/protocol.cpp2
-rw-r--r--src/qt/bitcoingui.cpp2
-rw-r--r--src/qt/forms/createwalletdialog.ui3
-rw-r--r--src/qt/guiutil.cpp4
-rw-r--r--src/qt/intro.cpp2
-rw-r--r--src/qt/test/addressbooktests.cpp6
-rw-r--r--src/qt/test/wallettests.cpp17
-rw-r--r--src/rest.cpp8
-rw-r--r--src/rpc/blockchain.cpp63
-rw-r--r--src/rpc/blockchain.h3
-rw-r--r--src/rpc/request.cpp8
-rw-r--r--src/rpc/server.cpp2
-rw-r--r--src/support/allocators/secure.h17
-rw-r--r--src/support/allocators/zeroafterfree.h16
-rw-r--r--src/test/bloom_tests.cpp2
-rw-r--r--src/test/crypto_tests.cpp4
-rw-r--r--src/test/denialofservice_tests.cpp2
-rw-r--r--src/test/fs_tests.cpp27
-rw-r--r--src/test/fuzz/banman.cpp4
-rw-r--r--src/test/fuzz/bloom_filter.cpp2
-rw-r--r--src/test/fuzz/rolling_bloom_filter.cpp2
-rw-r--r--src/test/fuzz/txrequest.cpp4
-rw-r--r--src/test/mempool_tests.cpp36
-rw-r--r--src/test/settings_tests.cpp6
-rw-r--r--src/test/txrequest_tests.cpp6
-rw-r--r--src/test/util/chainstate.h2
-rw-r--r--src/test/util/net.h6
-rw-r--r--src/test/util/setup_common.cpp4
-rw-r--r--src/test/util/wallet.cpp12
-rw-r--r--src/test/util_tests.cpp14
-rw-r--r--src/torcontrol.cpp8
-rw-r--r--src/txmempool.cpp6
-rw-r--r--src/txmempool.h6
-rw-r--r--src/txrequest.cpp2
-rw-r--r--src/univalue/.cirrus.yml44
-rw-r--r--src/univalue/.travis.yml51
-rw-r--r--src/univalue/Makefile.am90
-rw-r--r--src/univalue/build-aux/m4/ax_cxx_compile_stdcxx.m4962
-rw-r--r--src/univalue/configure.ac9
-rw-r--r--src/univalue/gen/gen.cpp4
-rw-r--r--src/univalue/include/univalue.h4
-rw-r--r--src/univalue/lib/univalue.cpp16
-rw-r--r--src/univalue/lib/univalue_escapes.h442
-rw-r--r--src/univalue/lib/univalue_get.cpp7
-rw-r--r--src/univalue/lib/univalue_read.cpp6
-rw-r--r--src/univalue/lib/univalue_utffilter.h2
-rw-r--r--src/univalue/lib/univalue_write.cpp7
-rw-r--r--src/univalue/sources.mk95
-rw-r--r--src/univalue/test/object.cpp2
-rw-r--r--src/univalue/test/unitester.cpp4
-rw-r--r--src/util/asmap.cpp4
-rw-r--r--src/util/settings.cpp12
-rw-r--r--src/util/syscall_sandbox.cpp37
-rw-r--r--src/util/system.cpp28
-rw-r--r--src/validation.cpp37
-rw-r--r--src/validation.h2
-rw-r--r--src/wallet/bdb.cpp38
-rw-r--r--src/wallet/bdb.h4
-rw-r--r--src/wallet/db.cpp15
-rw-r--r--src/wallet/dump.cpp10
-rw-r--r--src/wallet/interfaces.cpp4
-rw-r--r--src/wallet/load.cpp16
-rw-r--r--src/wallet/rpcdump.cpp8
-rw-r--r--src/wallet/rpcwallet.cpp50
-rw-r--r--src/wallet/scriptpubkeyman.cpp2
-rw-r--r--src/wallet/sqlite.cpp4
-rw-r--r--src/wallet/test/coinselector_tests.cpp404
-rw-r--r--src/wallet/test/db_tests.cpp8
-rw-r--r--src/wallet/test/init_test_fixture.cpp8
-rw-r--r--src/wallet/test/init_tests.cpp8
-rw-r--r--src/wallet/test/psbt_wallet_tests.cpp43
-rw-r--r--src/wallet/test/spend_tests.cpp2
-rw-r--r--src/wallet/test/util.cpp14
-rw-r--r--src/wallet/test/wallet_tests.cpp54
-rw-r--r--src/wallet/wallet.cpp11
-rw-r--r--src/wallet/walletdb.cpp16
-rw-r--r--src/wallet/wallettool.cpp20
-rw-r--r--src/wallet/walletutil.cpp2
-rw-r--r--test/README.md15
-rwxr-xr-xtest/functional/combine_logs.py2
-rw-r--r--test/functional/data/__init__.py0
-rwxr-xr-xtest/functional/feature_rbf.py2
-rwxr-xr-xtest/functional/interface_rest.py9
-rwxr-xr-xtest/functional/mempool_package_limits.py2
-rwxr-xr-xtest/functional/mempool_packages.py3
-rwxr-xr-xtest/functional/mining_prioritisetransaction.py2
-rwxr-xr-xtest/functional/p2p_invalid_messages.py2
-rwxr-xr-xtest/functional/p2p_ping.py14
-rwxr-xr-xtest/functional/rpc_blockchain.py66
-rwxr-xr-xtest/functional/rpc_invalid_address_message.py2
-rwxr-xr-xtest/functional/rpc_misc.py2
-rwxr-xr-xtest/functional/test_framework/test_framework.py16
-rwxr-xr-xtest/functional/test_framework/test_node.py16
-rw-r--r--test/functional/test_framework/wallet.py4
-rwxr-xr-xtest/functional/test_runner.py3
-rwxr-xr-xtest/functional/tool_wallet.py4
-rwxr-xr-xtest/functional/wallet_abandonconflict.py10
-rwxr-xr-xtest/functional/wallet_address_types.py3
-rwxr-xr-xtest/functional/wallet_backup.py6
-rwxr-xr-xtest/functional/wallet_basic.py2
-rwxr-xr-xtest/functional/wallet_bumpfee.py10
-rwxr-xr-xtest/functional/wallet_create_tx.py4
-rwxr-xr-xtest/functional/wallet_descriptor.py2
-rwxr-xr-xtest/functional/wallet_hd.py2
-rwxr-xr-xtest/functional/wallet_import_rescan.py2
-rwxr-xr-xtest/functional/wallet_importdescriptors.py16
-rwxr-xr-xtest/functional/wallet_keypool.py14
-rwxr-xr-xtest/functional/wallet_listdescriptors.py2
-rwxr-xr-xtest/functional/wallet_listsinceblock.py11
-rwxr-xr-xtest/functional/wallet_listtransactions.py13
-rwxr-xr-xtest/functional/wallet_multisig_descriptor_psbt.py163
-rwxr-xr-xtest/functional/wallet_taproot.py2
-rwxr-xr-xtest/functional/wallet_transactiontime_rescan.py8
-rwxr-xr-xtest/functional/wallet_upgradewallet.py20
-rwxr-xr-xtest/lint/lint-python.sh2
-rw-r--r--test/sanitizer_suppressions/ubsan4
184 files changed, 2903 insertions, 1298 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index 5491f2c04b..1f32dd5231 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -79,14 +79,14 @@ task:
<< : *FILTER_TEMPLATE
windows_container:
cpu: 4
- memory: 16G
+ memory: 8G
image: cirrusci/windowsservercore:visualstudio2019
timeout_in: 120m
env:
PATH: 'C:\jom;C:\Python39;C:\Python39\Scripts;C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\MSBuild\Current\Bin;%PATH%'
PYTHONUTF8: 1
- VCPKG_TAG: '75522bb1f2e7d863078bcd06322348f053a9e33f'
- VCPKG_FEATURE_FLAGS: 'manifests'
+ CI_VCPKG_TAG: '2021.05.12'
+ VCPKG_DEFAULT_BINARY_CACHE: 'C:\Users\ContainerAdministrator\AppData\Local\vcpkg\archives'
QT_DOWNLOAD_URL: 'https://download.qt.io/official_releases/qt/5.12/5.12.11/single/qt-everywhere-src-5.12.11.zip'
QT_LOCAL_PATH: 'C:\qt-everywhere-src-5.12.11.zip'
QT_SOURCE_DIR: 'C:\qt-everywhere-src-5.12.11'
@@ -121,8 +121,14 @@ task:
- ..\configure -release -silent -opensource -confirm-license -opengl desktop -no-shared -static -static-runtime -mp -qt-zlib -qt-pcre -qt-libpng -no-libjpeg -nomake examples -nomake tests -nomake tools -no-dbus -no-libudev -no-icu -no-gtk -no-opengles3 -no-angle -no-sql-sqlite -no-sql-odbc -no-sqlite -no-libudev -no-vulkan -skip qt3d -skip qtactiveqt -skip qtandroidextras -skip qtcanvas3d -skip qtcharts -skip qtconnectivity -skip qtdatavis3d -skip qtdeclarative -skip qtdoc -skip qtgamepad -skip qtgraphicaleffects -skip qtimageformats -skip qtlocation -skip qtmacextras -skip qtmultimedia -skip qtnetworkauth -skip qtpurchasing -skip qtquickcontrols -skip qtquickcontrols2 -skip qtscript -skip qtscxml -skip qtsensors -skip qtserialbus -skip qtserialport -skip qtspeech -skip qtvirtualkeyboard -skip qtwayland -skip qtwebchannel -skip qtwebengine -skip qtwebsockets -skip qtwebview -skip qtx11extras -skip qtxmlpatterns -no-openssl -no-feature-sql -no-feature-sqlmodel -prefix %QTBASEDIR%
- jom
- jom install
- vcpkg_cache:
- folder: 'C:\Users\ContainerAdministrator\AppData\Local\vcpkg\archives'
+ vcpkg_binary_cache:
+ folder: '%VCPKG_DEFAULT_BINARY_CACHE%'
+ reupload_on_changes: true
+ fingerprint_script:
+ - echo %CI_VCPKG_TAG%
+ - msbuild -version
+ populate_script:
+ - mkdir %VCPKG_DEFAULT_BINARY_CACHE%
install_python_script:
- choco install --yes --no-progress python3 --version=3.9.6
- pip install zmq
@@ -131,7 +137,7 @@ task:
- cd ..
- git clone --quiet https://github.com/microsoft/vcpkg.git
- cd vcpkg
- - git -c advice.detachedHead=false checkout %VCPKG_TAG%
+ - git -c advice.detachedHead=false checkout %CI_VCPKG_TAG%
- .\bootstrap-vcpkg -disableMetrics
- echo set(VCPKG_BUILD_TYPE release) >> triplets\x64-windows-static.cmake
- .\vcpkg integrate install
diff --git a/ci/lint/04_install.sh b/ci/lint/04_install.sh
index 5587618f2d..991234a436 100755
--- a/ci/lint/04_install.sh
+++ b/ci/lint/04_install.sh
@@ -13,7 +13,8 @@ update-alternatives --install /usr/bin/clang-format-diff clang-format-diff $(whi
${CI_RETRY_EXE} pip3 install codespell==2.0.0
${CI_RETRY_EXE} pip3 install flake8==3.8.3
-${CI_RETRY_EXE} pip3 install mypy==0.781
+${CI_RETRY_EXE} pip3 install mypy==0.910
+${CI_RETRY_EXE} pip3 install pyzmq==22.3.0
${CI_RETRY_EXE} pip3 install vulture==2.3
SHELLCHECK_VERSION=v0.7.2
diff --git a/ci/test/00_setup_env_android.sh b/ci/test/00_setup_env_android.sh
index 4ef3ae1ceb..2f9d1f2a9f 100755
--- a/ci/test/00_setup_env_android.sh
+++ b/ci/test/00_setup_env_android.sh
@@ -22,4 +22,4 @@ export ANDROID_HOME="${DEPENDS_DIR}/SDKs/android"
export ANDROID_NDK_HOME="${ANDROID_HOME}/ndk/${ANDROID_NDK_VERSION}"
export DEP_OPTS="ANDROID_SDK=${ANDROID_HOME} ANDROID_NDK=${ANDROID_NDK_HOME} ANDROID_API_LEVEL=${ANDROID_API_LEVEL} ANDROID_TOOLCHAIN_BIN=${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/"
-export BITCOIN_CONFIG="--disable-ccache"
+export BITCOIN_CONFIG="--disable-ccache --disable-tests --enable-gui-tests --disable-bench --disable-fuzz-binary --without-utils --without-libs --without-daemon"
diff --git a/ci/test/00_setup_env_native_valgrind.sh b/ci/test/00_setup_env_native_valgrind.sh
index 78af869e70..0058a042f5 100755
--- a/ci/test/00_setup_env_native_valgrind.sh
+++ b/ci/test/00_setup_env_native_valgrind.sh
@@ -11,6 +11,6 @@ export CONTAINER_NAME=ci_native_valgrind
export PACKAGES="valgrind clang llvm python3-zmq libevent-dev bsdmainutils libboost-dev libboost-system-dev libboost-filesystem-dev libboost-test-dev libdb5.3++-dev libminiupnpc-dev libnatpmp-dev libzmq3-dev libsqlite3-dev"
export USE_VALGRIND=1
export NO_DEPENDS=1
-export TEST_RUNNER_EXTRA="--exclude rpc_bind,feature_bind_extra" # Excluded for now, see https://github.com/bitcoin/bitcoin/issues/17765#issuecomment-602068547
+export TEST_RUNNER_EXTRA="--nosandbox --exclude rpc_bind,feature_bind_extra" # Excluded for now, see https://github.com/bitcoin/bitcoin/issues/17765#issuecomment-602068547
export GOAL="install"
export BITCOIN_CONFIG="--enable-zmq --with-incompatible-bdb --with-gui=no CC=clang CXX=clang++" # TODO enable GUI
diff --git a/ci/test/06_script_a.sh b/ci/test/06_script_a.sh
index a42cd6cee1..b1d83883d1 100755
--- a/ci/test/06_script_a.sh
+++ b/ci/test/06_script_a.sh
@@ -10,7 +10,7 @@ if [ -n "$ANDROID_TOOLS_URL" ]; then
DOCKER_EXEC make distclean || true
DOCKER_EXEC ./autogen.sh
DOCKER_EXEC ./configure $BITCOIN_CONFIG --prefix=$DEPENDS_DIR/aarch64-linux-android || ( (DOCKER_EXEC cat config.log) && false)
- DOCKER_EXEC "cd src/qt && make $MAKEJOBS && ANDROID_HOME=${ANDROID_HOME} ANDROID_NDK_HOME=${ANDROID_NDK_HOME} make apk"
+ DOCKER_EXEC "make $MAKEJOBS && cd src/qt && ANDROID_HOME=${ANDROID_HOME} ANDROID_NDK_HOME=${ANDROID_NDK_HOME} make apk"
exit 0
fi
diff --git a/ci/test/06_script_b.sh b/ci/test/06_script_b.sh
index 194b14beab..311a43755a 100755
--- a/ci/test/06_script_b.sh
+++ b/ci/test/06_script_b.sh
@@ -9,14 +9,12 @@ export LC_ALL=C.UTF-8
if [[ $HOST = *-mingw32 ]]; then
# Generate all binaries, so that they can be wrapped
DOCKER_EXEC make $MAKEJOBS -C src/secp256k1 VERBOSE=1
- DOCKER_EXEC make $MAKEJOBS -C src/univalue VERBOSE=1
DOCKER_EXEC "${BASE_ROOT_DIR}/ci/test/wrap-wine.sh"
fi
if [ -n "$QEMU_USER_CMD" ]; then
# Generate all binaries, so that they can be wrapped
DOCKER_EXEC make $MAKEJOBS -C src/secp256k1 VERBOSE=1
- DOCKER_EXEC make $MAKEJOBS -C src/univalue VERBOSE=1
DOCKER_EXEC "${BASE_ROOT_DIR}/ci/test/wrap-qemu.sh"
fi
diff --git a/configure.ac b/configure.ac
index 2548182340..dc3b07e4bb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -107,7 +107,7 @@ AC_PATH_TOOL(GCOV, gcov)
AC_PATH_TOOL(LLVM_COV, llvm-cov)
AC_PATH_PROG(LCOV, lcov)
dnl Python 3.6 is specified in .python-version and should be used if available, see doc/dependencies.md
-AC_PATH_PROGS([PYTHON], [python3.6 python3.7 python3.8 python3.9, python3.10, python3 python])
+AC_PATH_PROGS([PYTHON], [python3.6 python3.7 python3.8 python3.9 python3.10 python3.11 python3 python])
AC_PATH_PROG(GENHTML, genhtml)
AC_PATH_PROG([GIT], [git])
AC_PATH_PROG(CCACHE,ccache)
@@ -261,12 +261,6 @@ if test "x$use_asm" = xyes; then
AC_DEFINE(USE_ASM, 1, [Define this symbol to build in assembly routines])
fi
-AC_ARG_WITH([system-univalue],
- [AS_HELP_STRING([--with-system-univalue],
- [Build with system UniValue (default is no)])],
- [system_univalue=$withval],
- [system_univalue=no]
-)
AC_ARG_ENABLE([zmq],
[AS_HELP_STRING([--disable-zmq],
[disable ZMQ notifications])],
@@ -425,15 +419,12 @@ if test "x$CXXFLAGS_overridden" = "xno"; then
AX_CHECK_COMPILE_FLAG([-Wformat -Wformat-security],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wformat -Wformat-security"],,[[$CXXFLAG_WERROR]])
AX_CHECK_COMPILE_FLAG([-Wvla],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wvla"],,[[$CXXFLAG_WERROR]])
AX_CHECK_COMPILE_FLAG([-Wshadow-field],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wshadow-field"],,[[$CXXFLAG_WERROR]])
- AX_CHECK_COMPILE_FLAG([-Wswitch],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wswitch"],,[[$CXXFLAG_WERROR]])
AX_CHECK_COMPILE_FLAG([-Wthread-safety],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wthread-safety"],,[[$CXXFLAG_WERROR]])
- AX_CHECK_COMPILE_FLAG([-Wrange-loop-analysis],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wrange-loop-analysis"],,[[$CXXFLAG_WERROR]])
+ AX_CHECK_COMPILE_FLAG([-Wloop-analysis],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wloop-analysis"],,[[$CXXFLAG_WERROR]])
AX_CHECK_COMPILE_FLAG([-Wredundant-decls],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wredundant-decls"],,[[$CXXFLAG_WERROR]])
- AX_CHECK_COMPILE_FLAG([-Wunused-variable],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wunused-variable"],,[[$CXXFLAG_WERROR]])
AX_CHECK_COMPILE_FLAG([-Wunused-member-function],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wunused-member-function"],,[[$CXXFLAG_WERROR]])
AX_CHECK_COMPILE_FLAG([-Wdate-time],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wdate-time"],,[[$CXXFLAG_WERROR]])
AX_CHECK_COMPILE_FLAG([-Wconditional-uninitialized],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wconditional-uninitialized"],,[[$CXXFLAG_WERROR]])
- AX_CHECK_COMPILE_FLAG([-Wsign-compare],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wsign-compare"],,[[$CXXFLAG_WERROR]])
AX_CHECK_COMPILE_FLAG([-Wduplicated-branches],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wduplicated-branches"],,[[$CXXFLAG_WERROR]])
AX_CHECK_COMPILE_FLAG([-Wduplicated-cond],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wduplicated-cond"],,[[$CXXFLAG_WERROR]])
AX_CHECK_COMPILE_FLAG([-Wlogical-op],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wlogical-op"],,[[$CXXFLAG_WERROR]])
@@ -454,7 +445,6 @@ if test "x$CXXFLAGS_overridden" = "xno"; then
dnl set the -Wno-foo case if it works.
AX_CHECK_COMPILE_FLAG([-Wunused-parameter],[NOWARN_CXXFLAGS="$NOWARN_CXXFLAGS -Wno-unused-parameter"],,[[$CXXFLAG_WERROR]])
AX_CHECK_COMPILE_FLAG([-Wself-assign],[NOWARN_CXXFLAGS="$NOWARN_CXXFLAGS -Wno-self-assign"],,[[$CXXFLAG_WERROR]])
- AX_CHECK_COMPILE_FLAG([-Wunused-local-typedef],[NOWARN_CXXFLAGS="$NOWARN_CXXFLAGS -Wno-unused-local-typedef"],,[[$CXXFLAG_WERROR]])
if test x$suppress_external_warnings != xyes ; then
AX_CHECK_COMPILE_FLAG([-Wdeprecated-copy],[NOWARN_CXXFLAGS="$NOWARN_CXXFLAGS -Wno-deprecated-copy"],,[[$CXXFLAG_WERROR]])
fi
@@ -1229,14 +1219,6 @@ if test "x$have_any_system" != "xno"; then
AC_DEFINE(HAVE_SYSTEM, 1, Define to 1 if std::system or ::wsystem is available.)
fi
-LEVELDB_CPPFLAGS=
-LIBLEVELDB=
-LIBMEMENV=
-AM_CONDITIONAL([EMBEDDED_LEVELDB],[true])
-AC_SUBST(LEVELDB_CPPFLAGS)
-AC_SUBST(LIBLEVELDB)
-AC_SUBST(LIBMEMENV)
-
dnl SUPPRESSED_CPPFLAGS=SUPPRESS_WARNINGS([$SOME_CPPFLAGS])
dnl Replace -I with -isystem in $SOME_CPPFLAGS to suppress warnings from
dnl headers from its include directories and return the result.
@@ -1526,34 +1508,6 @@ if test "x$use_zmq" = xyes; then
esac
fi
-dnl univalue check
-
-need_bundled_univalue=yes
-if test x$build_bitcoin_wallet$build_bitcoin_cli$build_bitcoin_tx$build_bitcoin_util$build_bitcoind$bitcoin_enable_qt$use_tests$use_bench = xnononononononono; then
- need_bundled_univalue=no
-else
- if test x$system_univalue != xno; then
- PKG_CHECK_MODULES([UNIVALUE], [libunivalue >= 1.0.4], [found_univalue=yes], [found_univalue=no])
- if test x$found_univalue = xyes; then
- system_univalue=yes
- need_bundled_univalue=no
- elif test x$system_univalue = xyes; then
- AC_MSG_ERROR([univalue not found])
- else
- system_univalue=no
- fi
- fi
-
- if test x$need_bundled_univalue = xyes; then
- UNIVALUE_CFLAGS='-I$(srcdir)/univalue/include'
- UNIVALUE_LIBS='univalue/libunivalue.la'
- fi
-fi
-
-AM_CONDITIONAL([EMBEDDED_UNIVALUE],[test x$need_bundled_univalue = xyes])
-AC_SUBST(UNIVALUE_CFLAGS)
-AC_SUBST(UNIVALUE_LIBS)
-
dnl libmultiprocess library check
libmultiprocess_found=no
@@ -1916,11 +1870,7 @@ PKGCONFIG_LIBDIR_TEMP="$PKG_CONFIG_LIBDIR"
unset PKG_CONFIG_LIBDIR
PKG_CONFIG_LIBDIR="$PKGCONFIG_LIBDIR_TEMP"
-if test x$need_bundled_univalue = xyes; then
- AC_CONFIG_SUBDIRS([src/univalue])
-fi
-
-ac_configure_args="${ac_configure_args} --disable-shared --with-pic --enable-benchmark=no --enable-module-recovery --enable-module-schnorrsig --enable-experimental"
+ac_configure_args="${ac_configure_args} --disable-shared --with-pic --enable-benchmark=no --enable-module-recovery --enable-module-schnorrsig --enable-experimental --disable-openssl-tests"
AC_CONFIG_SUBDIRS([src/secp256k1])
AC_OUTPUT
diff --git a/contrib/devtools/security-check.py b/contrib/devtools/security-check.py
index c374de4b55..ef421aebb1 100755
--- a/contrib/devtools/security-check.py
+++ b/contrib/devtools/security-check.py
@@ -10,7 +10,7 @@ Otherwise the exit status will be 1 and it will log which executables failed whi
import sys
from typing import List
-import lief
+import lief #type:ignore
def check_ELF_RELRO(binary) -> bool:
'''
diff --git a/contrib/devtools/symbol-check.py b/contrib/devtools/symbol-check.py
index 158b6fa0ff..136a9b70c1 100755
--- a/contrib/devtools/symbol-check.py
+++ b/contrib/devtools/symbol-check.py
@@ -13,7 +13,7 @@ Example usage:
import sys
from typing import List, Dict
-import lief
+import lief #type:ignore
# temporary constant, to be replaced with lief.ELF.ARCH.RISCV
# https://github.com/lief-project/LIEF/pull/562
diff --git a/contrib/guix/libexec/build.sh b/contrib/guix/libexec/build.sh
index 93476d5f30..e009f97c60 100755
--- a/contrib/guix/libexec/build.sh
+++ b/contrib/guix/libexec/build.sh
@@ -297,7 +297,7 @@ mkdir -p "$DISTSRC"
${HOST_CXXFLAGS:+CXXFLAGS="${HOST_CXXFLAGS}"} \
${HOST_LDFLAGS:+LDFLAGS="${HOST_LDFLAGS}"}
- sed -i.old 's/-lstdc++ //g' config.status libtool src/univalue/config.status src/univalue/libtool
+ sed -i.old 's/-lstdc++ //g' config.status libtool
# Build Bitcoin Core
make --jobs="$JOBS" ${V:+V=1}
diff --git a/contrib/tracing/README.md b/contrib/tracing/README.md
index 047354cda1..1f93474fa0 100644
--- a/contrib/tracing/README.md
+++ b/contrib/tracing/README.md
@@ -176,17 +176,12 @@ third acts as a duration threshold in milliseconds. When the `ConnectBlock()`
function takes longer than the threshold, information about the block, is
printed. For more details, see the header comment in the script.
-By default, `bpftrace` limits strings to 64 bytes due to the limited stack size
-in the kernel VM. Block hashes as zero-terminated hex strings are 65 bytes which
-exceed the string limit. The string size limit can be set to 65 bytes with the
-environment variable `BPFTRACE_STRLEN`.
-
The following command can be used to benchmark, for example, `ConnectBlock()`
between height 20000 and 38000 on SigNet while logging all blocks that take
longer than 25ms to connect.
```
-$ BPFTRACE_STRLEN=65 bpftrace contrib/tracing/connectblock_benchmark.bt 20000 38000 25
+$ bpftrace contrib/tracing/connectblock_benchmark.bt 20000 38000 25
```
In a different terminal, starting Bitcoin Core in SigNet mode and with
diff --git a/contrib/tracing/connectblock_benchmark.bt b/contrib/tracing/connectblock_benchmark.bt
index d268eff7f8..6e7a98ef07 100755
--- a/contrib/tracing/connectblock_benchmark.bt
+++ b/contrib/tracing/connectblock_benchmark.bt
@@ -4,11 +4,8 @@
USAGE:
- BPFTRACE_STRLEN=65 bpftrace contrib/tracing/connectblock_benchmark.bt <start height> <end height> <logging threshold in ms>
+ bpftrace contrib/tracing/connectblock_benchmark.bt <start height> <end height> <logging threshold in ms>
- - The environment variable BPFTRACE_STRLEN needs to be set to 65 chars as
- strings are limited to 64 chars by default. Hex strings with Bitcoin block
- hashes are 64 hex chars + 1 null-termination char.
- <start height> sets the height at which the benchmark should start. Setting
the start height to 0 starts the benchmark immediately, even before the
first block is connected.
@@ -23,7 +20,7 @@
EXAMPLES:
- BPFTRACE_STRLEN=65 bpftrace contrib/tracing/connectblock_benchmark.bt 300000 680000 1000
+ bpftrace contrib/tracing/connectblock_benchmark.bt 300000 680000 1000
When run together 'bitcoind -reindex', this benchmarks the time it takes to
connect the blocks between height 300.000 and 680.000 (inclusive) and prints
@@ -31,7 +28,7 @@
histogram with block connection times when the benchmark is finished.
- BPFTRACE_STRLEN=65 bpftrace contrib/tracing/connectblock_benchmark.bt 0 0 500
+ bpftrace contrib/tracing/connectblock_benchmark.bt 0 0 500
When running together 'bitcoind', all newly connected blocks that
take longer than 500ms to connect are logged. A histogram with block
@@ -107,14 +104,23 @@ usdt:./src/bitcoind:validation:block_connected /arg1 >= $1 && (arg1 <= $2 || $2
*/
usdt:./src/bitcoind:validation:block_connected / (uint64) arg5 / 1000> $3 /
{
- $hash_str = str(arg0);
+ $hash = arg0;
$height = (int32) arg1;
$transactions = (uint64) arg2;
$inputs = (int32) arg3;
$sigops = (int64) arg4;
$duration = (int64) arg5;
- printf("Block %d (%s) %4d tx %5d ins %5d sigops took %4d ms\n", $height, $hash_str, $transactions, $inputs, $sigops, (uint64) $duration / 1000);
+
+ printf("Block %d (", $height);
+ /* Prints each byte of the block hash as hex in big-endian (the block-explorer format) */
+ $p = $hash + 31;
+ unroll(32) {
+ $b = *(uint8*)$p;
+ printf("%02x", $b);
+ $p -= 1;
+ }
+ printf(") %4d tx %5d ins %5d sigops took %4d ms\n", $transactions, $inputs, $sigops, (uint64) $duration / 1000);
}
diff --git a/depends/packages/expat.mk b/depends/packages/expat.mk
index 902fe43be2..41c1114be0 100644
--- a/depends/packages/expat.mk
+++ b/depends/packages/expat.mk
@@ -23,5 +23,5 @@ define $(package)_stage_cmds
endef
define $(package)_postprocess_cmds
- rm lib/*.la
+ rm -rf share lib/*.la
endef
diff --git a/depends/packages/fontconfig.mk b/depends/packages/fontconfig.mk
index 0d5f94f380..22b5022f06 100644
--- a/depends/packages/fontconfig.mk
+++ b/depends/packages/fontconfig.mk
@@ -29,5 +29,5 @@ define $(package)_stage_cmds
endef
define $(package)_postprocess_cmds
- rm lib/*.la
+ rm -rf var lib/*.la
endef
diff --git a/depends/packages/freetype.mk b/depends/packages/freetype.mk
index a1584608e1..aebc8a5f3b 100644
--- a/depends/packages/freetype.mk
+++ b/depends/packages/freetype.mk
@@ -23,5 +23,5 @@ define $(package)_stage_cmds
endef
define $(package)_postprocess_cmds
- rm lib/*.la
+ rm -rf share/man lib/*.la
endef
diff --git a/depends/packages/libXau.mk b/depends/packages/libXau.mk
index 4c55c2df04..24e0e9d325 100644
--- a/depends/packages/libXau.mk
+++ b/depends/packages/libXau.mk
@@ -30,5 +30,5 @@ define $(package)_stage_cmds
endef
define $(package)_postprocess_cmds
- rm lib/*.la
+ rm -rf share lib/*.la
endef
diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk
index 9004b064d6..12e0494ad4 100644
--- a/depends/packages/qt.mk
+++ b/depends/packages/qt.mk
@@ -248,7 +248,6 @@ endef
define $(package)_config_cmds
export PKG_CONFIG_SYSROOT_DIR=/ && \
export PKG_CONFIG_LIBDIR=$(host_prefix)/lib/pkgconfig && \
- export PKG_CONFIG_PATH=$(host_prefix)/share/pkgconfig && \
cd qtbase && \
./configure -top-level $($(package)_config_opts)
endef
diff --git a/doc/descriptors.md b/doc/descriptors.md
index 3bbb626a42..57a0f99d70 100644
--- a/doc/descriptors.md
+++ b/doc/descriptors.md
@@ -139,6 +139,47 @@ Key order does not matter for `sortedmulti()`. `sortedmulti()` behaves in the sa
as `multi()` does but the keys are reordered in the resulting script such that they
are lexicographically ordered as described in BIP67.
+#### Basic multisig example
+
+For a good example of a basic M-of-N multisig between multiple participants using descriptor
+wallets and PSBTs, as well as a signing flow, see [this functional test](/test/functional/wallet_multisig_descriptor_psbt.py).
+
+Disclaimers: It is important to note that this example serves as a quick-start and is kept basic for readability. A downside of the approach
+outlined here is that each participant must maintain (and backup) two separate wallets: a signer and the corresponding multisig.
+It should also be noted that privacy best-practices are not "by default" here - participants should take care to only use the signer to sign
+transactions related to the multisig. Lastly, it is not recommended to use anything other than a Bitcoin Core descriptor wallet to serve as your
+signer(s). Other wallets, whether hardware or software, likely impose additional checks and safeguards to prevent users from signing transactions that
+could lead to loss of funds, or are deemed security hazards. Conforming to various 3rd-party checks and verifications is not in the scope of this example.
+
+The basic steps are:
+
+ 1. Every participant generates an xpub. The most straightforward way is to create a new descriptor wallet which we will refer to as
+ the participant's signer wallet. Avoid reusing this wallet for any purpose other than signing transactions from the
+ corresponding multisig we are about to create. Hint: extract the wallet's xpubs using `listdescriptors` and pick the one from the
+ `pkh` descriptor since it's least likely to be accidentally reused (legacy addresses)
+ 2. Create a watch-only descriptor wallet (blank, private keys disabled). Now the multisig is created by importing the two descriptors:
+ `wsh(sortedmulti(<M>,XPUB1/0/*,XPUB2/0/*,…,XPUBN/0/*))` and `wsh(sortedmulti(<M>,XPUB1/1/*,XPUB2/1/*,…,XPUBN/1/*))`
+ (one descriptor w/ `0` for receiving addresses and another w/ `1` for change). Every participant does this
+ 3. A receiving address is generated for the multisig. As a check to ensure step 2 was done correctly, every participant
+ should verify they get the same addresses
+ 4. Funds are sent to the resulting address
+ 5. A sending transaction from the multisig is created using `walletcreatefundedpsbt` (anyone can initiate this). It is simple to do
+ this in the GUI by going to the `Send` tab in the multisig wallet and creating an unsigned transaction (PSBT)
+ 6. At least `M` participants check the PSBT with their multisig using `decodepsbt` to verify the transaction is OK before signing it.
+ 7. (If OK) the participant signs the PSBT with their signer wallet using `walletprocesspsbt`. It is simple to do this in the GUI by
+ loading the PSBT from file and signing it
+ 8. The signed PSBTs are collected with `combinepsbt`, finalized w/ `finalizepsbt`, and then the resulting transaction is broadcasted
+ to the network. Note that any wallet (eg one of the signers or multisig) is capable of doing this.
+ 9. Checks that balances are correct after the transaction has been included in a block
+
+You may prefer a daisy chained signing flow where each participant signs the PSBT one after another until
+the PSBT has been signed `M` times and is "complete." For the most part, the steps above remain the same, except (6, 7)
+change slightly from signing the original PSBT in parallel to signing it in series. `combinepsbt` is not necessary with
+this signing flow and the last (`m`th) signer can just broadcast the PSBT after signing. Note that a parallel signing flow may be
+preferable in cases where there are more signers. This signing flow is also included in the test / Python example.
+[The test](/test/functional/wallet_multisig_descriptor_psbt.py) is meant to be documentation as much as it is a functional test, so
+it is kept as simple and readable as possible.
+
### BIP32 derived keys and chains
Most modern wallet software and hardware uses keys that are derived using
diff --git a/doc/psbt.md b/doc/psbt.md
index c411b31d5d..0f31cb8eba 100644
--- a/doc/psbt.md
+++ b/doc/psbt.md
@@ -92,6 +92,9 @@ hardware implementations will typically implement multiple roles simultaneously.
#### Multisig with multiple Bitcoin Core instances
+For a quick start see [Basic M-of-N multisig example using descriptor wallets and PSBTs](./descriptors.md#basic-multisig-example).
+If you are using legacy wallets feel free to continue with the example provided here.
+
Alice, Bob, and Carol want to create a 2-of-3 multisig address. They're all using
Bitcoin Core. We assume their wallets only contain the multisig funds. In case
they also have a personal wallet, this can be accomplished through the
diff --git a/doc/release-notes-22539.md b/doc/release-notes-22539.md
deleted file mode 100644
index 9f56071451..0000000000
--- a/doc/release-notes-22539.md
+++ /dev/null
@@ -1,8 +0,0 @@
-Notable changes
-===============
-
-P2P and network changes
------------------------
-
-- Fee estimation now takes the feerate of replacement (RBF) transactions into
- account.
diff --git a/doc/release-notes-23093.md b/doc/release-notes-23093.md
new file mode 100644
index 0000000000..68fbaec53c
--- /dev/null
+++ b/doc/release-notes-23093.md
@@ -0,0 +1,11 @@
+Notable changes
+===============
+
+Updated RPCs
+------------
+
+- `upgradewallet` will now automatically flush the keypool if upgrading
+from a non-HD wallet to an HD wallet, to immediately start using the
+newly-generated HD keys.
+- a new RPC `newkeypool` has been added, which will flush (entirely
+clear and refill) the keypool.
diff --git a/doc/release-notes.md b/doc/release-notes.md
index 81e79dd3a9..b460cd3eb2 100644
--- a/doc/release-notes.md
+++ b/doc/release-notes.md
@@ -61,6 +61,12 @@ P2P and network changes
They will become eligible for address gossip after sending an ADDR, ADDRV2,
or GETADDR message. (#21528)
+Fee estimation changes
+----------------------
+
+- Fee estimation now takes the feerate of replacement (RBF) transactions into
+ account. (#22539)
+
Rescan startup parameter removed
--------------------------------
@@ -76,6 +82,14 @@ Updated RPCs
`gettransaction verbose=true` and REST endpoints `/rest/tx`, `/rest/getutxos`,
`/rest/block` no longer return the `addresses` and `reqSigs` fields, which
were previously deprecated in 22.0. (#22650)
+- The `getblock` RPC command now supports verbose level 3 containing transaction inputs
+ `prevout` information. The existing `/rest/block/` REST endpoint is modified to contain
+ this information too. Every `vin` field will contain an additional `prevout` subfield
+ describing the spent output. `prevout` contains the following keys:
+ - `generated` - true if the spent coins was a coinbase.
+ - `height`
+ - `value`
+ - `scriptPubKey`
- `listunspent` now includes `ancestorcount`, `ancestorsize`, and
`ancestorfees` for each transaction output that is still in the mempool.
diff --git a/doc/release-process.md b/doc/release-process.md
index 6a5202d0f9..14567d4f15 100644
--- a/doc/release-process.md
+++ b/doc/release-process.md
@@ -60,7 +60,7 @@ Release Process
To tag the version (or release candidate) in git, use the `make-tag.py` script from [bitcoin-maintainer-tools](https://github.com/bitcoin-core/bitcoin-maintainer-tools). From the root of the repository run:
- ../bitcoin-maintainer-tools/make-tag.py v(new version, e.g. 0.20.0)
+ ../bitcoin-maintainer-tools/make-tag.py v(new version, e.g. 23.0)
This will perform a few last-minute consistency checks in the build system files, and if they pass, create a signed tag.
@@ -253,6 +253,10 @@ cat "$VERSION"/*/all.SHA256SUMS.asc > SHA256SUMS.asc
- bitcoincore.org maintained versions update:
[table](https://github.com/bitcoin-core/bitcoincore.org/commits/master/_includes/posts/maintenance-table.md)
+ - Delete post-EOL [release branches](https://github.com/bitcoin/bitcoin/branches/all) and create a tag `v${branch_name}-final`.
+
+ - Delete ["Needs backport" labels](https://github.com/bitcoin/bitcoin/labels?q=backport) for non-existing branches.
+
- bitcoincore.org RPC documentation update
- Install [golang](https://golang.org/doc/install)
diff --git a/doc/tracing.md b/doc/tracing.md
index 87fc9603fe..57104c43a0 100644
--- a/doc/tracing.md
+++ b/doc/tracing.md
@@ -101,19 +101,12 @@ Is called *after* a block is connected to the chain. Can, for example, be used
to benchmark block connections together with `-reindex`.
Arguments passed:
-1. Block Header Hash as `pointer to C-style String` (64 characters)
+1. Block Header Hash as `pointer to unsigned chars` (i.e. 32 bytes in little-endian)
2. Block Height as `int32`
3. Transactions in the Block as `uint64`
4. Inputs spend in the Block as `int32`
5. SigOps in the Block (excluding coinbase SigOps) `uint64`
6. Time it took to connect the Block in microseconds (µs) as `uint64`
-7. Block Header Hash as `pointer to unsigned chars` (i.e. 32 bytes in little-endian)
-
-Note: The 7th argument can't be accessed by bpftrace and is purposefully chosen
-to be the block header hash as bytes. See [bpftrace argument limit] for more
-details.
-
-[bpftrace argument limit]: #bpftrace-argument-limit
## Adding tracepoints to Bitcoin Core
diff --git a/src/Makefile.am b/src/Makefile.am
index 9d15120b72..856e6f1985 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -6,7 +6,7 @@
print-%: FORCE
@echo '$*'='$($*)'
-DIST_SUBDIRS = secp256k1 univalue
+DIST_SUBDIRS = secp256k1
AM_LDFLAGS = $(LIBTOOL_LDFLAGS) $(HARDENED_LDFLAGS) $(GPROF_LDFLAGS) $(SANITIZER_LDFLAGS)
AM_CXXFLAGS = $(DEBUG_CXXFLAGS) $(HARDENED_CXXFLAGS) $(WARN_CXXFLAGS) $(NOWARN_CXXFLAGS) $(ERROR_CXXFLAGS) $(GPROF_CXXFLAGS) $(SANITIZER_CXXFLAGS)
@@ -15,18 +15,7 @@ AM_LIBTOOLFLAGS = --preserve-dup-deps
PTHREAD_FLAGS = $(PTHREAD_CFLAGS) $(PTHREAD_LIBS)
EXTRA_LIBRARIES =
-if EMBEDDED_UNIVALUE
-LIBUNIVALUE = univalue/libunivalue.la
-
-$(LIBUNIVALUE): $(wildcard univalue/lib/*) $(wildcard univalue/include/*)
- $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F)
-else
-LIBUNIVALUE = $(UNIVALUE_LIBS)
-endif
-
-BITCOIN_INCLUDES=-I$(builddir) -I$(srcdir)/secp256k1/include $(BDB_CPPFLAGS) $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS)
-
-BITCOIN_INCLUDES += $(UNIVALUE_CFLAGS)
+BITCOIN_INCLUDES=-I$(builddir) -I$(srcdir)/secp256k1/include -I$(srcdir)/$(UNIVALUE_INCLUDE_DIR_INT) $(BDB_CPPFLAGS) $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS)
LIBBITCOIN_SERVER=libbitcoin_server.a
LIBBITCOIN_COMMON=libbitcoin_common.a
@@ -80,6 +69,7 @@ EXTRA_LIBRARIES += \
$(LIBBITCOIN_ZMQ)
lib_LTLIBRARIES = $(LIBBITCOINCONSENSUS)
+noinst_LTLIBRARIES =
bin_PROGRAMS =
noinst_PROGRAMS =
@@ -124,7 +114,6 @@ BITCOIN_CORE_H = \
bech32.h \
blockencodings.h \
blockfilter.h \
- bloom.h \
chain.h \
chainparams.h \
chainparamsbase.h \
@@ -132,6 +121,7 @@ BITCOIN_CORE_H = \
checkqueue.h \
clientversion.h \
coins.h \
+ common/bloom.h \
compat.h \
compat/assumptions.h \
compat/byteswap.h \
@@ -539,9 +529,9 @@ libbitcoin_common_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_common_a_SOURCES = \
base58.cpp \
bech32.cpp \
- bloom.cpp \
chainparams.cpp \
coins.cpp \
+ common/bloom.cpp \
compressor.cpp \
core_read.cpp \
core_write.cpp \
@@ -797,7 +787,6 @@ $(top_srcdir)/$(subdir)/config/bitcoin-config.h.in: $(am__configure_deps)
clean-local:
-$(MAKE) -C secp256k1 clean
- -$(MAKE) -C univalue clean
-rm -f leveldb/*/*.gcda leveldb/*/*.gcno leveldb/helpers/memenv/*.gcda leveldb/helpers/memenv/*.gcno
-rm -f config.h
-rm -rf test/__pycache__
@@ -852,11 +841,8 @@ nodist_libbitcoin_ipc_a_SOURCES = $(libbitcoin_ipc_mpgen_output)
CLEANFILES += $(libbitcoin_ipc_mpgen_output)
endif
-if EMBEDDED_LEVELDB
include Makefile.crc32c.include
include Makefile.leveldb.include
-endif
-
include Makefile.test_util.include
include Makefile.test_fuzz.include
@@ -875,3 +861,5 @@ endif
if ENABLE_QT_TESTS
include Makefile.qttest.include
endif
+
+include Makefile.univalue.include
diff --git a/src/Makefile.leveldb.include b/src/Makefile.leveldb.include
index ce1f93f11f..3bec92482a 100644
--- a/src/Makefile.leveldb.include
+++ b/src/Makefile.leveldb.include
@@ -8,9 +8,10 @@ LIBMEMENV_INT = leveldb/libmemenv.a
EXTRA_LIBRARIES += $(LIBLEVELDB_INT)
EXTRA_LIBRARIES += $(LIBMEMENV_INT)
-LIBLEVELDB += $(LIBLEVELDB_INT) $(LIBCRC32C)
-LIBMEMENV += $(LIBMEMENV_INT)
+LIBLEVELDB = $(LIBLEVELDB_INT) $(LIBCRC32C)
+LIBMEMENV = $(LIBMEMENV_INT)
+LEVELDB_CPPFLAGS =
LEVELDB_CPPFLAGS += -I$(srcdir)/leveldb/include
LEVELDB_CPPFLAGS += -I$(srcdir)/leveldb/helpers/memenv
diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include
index f4b0b3adbe..1e3d75a8d8 100644
--- a/src/Makefile.qt.include
+++ b/src/Makefile.qt.include
@@ -168,10 +168,10 @@ BITCOIN_QT_H = \
qt/walletview.h \
qt/winshutdownmonitor.h
-RES_FONTS = \
+QT_RES_FONTS = \
qt/res/fonts/RobotoMono-Bold.ttf
-RES_ICONS = \
+QT_RES_ICONS = \
qt/res/icons/add.png \
qt/res/icons/address-book.png \
qt/res/icons/bitcoin.ico \
@@ -287,9 +287,9 @@ if ENABLE_WALLET
BITCOIN_QT_CPP += $(BITCOIN_QT_WALLET_CPP)
endif # ENABLE_WALLET
-RES_ANIMATION = $(wildcard $(srcdir)/qt/res/animation/spinner-*.png)
+QT_RES_ANIMATION = $(wildcard $(srcdir)/qt/res/animation/spinner-*.png)
-BITCOIN_RC = qt/res/bitcoin-qt-res.rc
+BITCOIN_QT_RC = qt/res/bitcoin-qt-res.rc
BITCOIN_QT_INCLUDES = -DQT_NO_KEYWORDS -DQT_USE_QSTRINGBUILDER
@@ -299,7 +299,7 @@ qt_libbitcoinqt_a_CXXFLAGS = $(AM_CXXFLAGS) $(QT_PIE_FLAGS)
qt_libbitcoinqt_a_OBJCXXFLAGS = $(AM_OBJCXXFLAGS) $(QT_PIE_FLAGS)
qt_libbitcoinqt_a_SOURCES = $(BITCOIN_QT_CPP) $(BITCOIN_QT_H) $(QT_FORMS_UI) \
- $(QT_QRC) $(QT_QRC_LOCALE) $(QT_TS) $(RES_FONTS) $(RES_ICONS) $(RES_ANIMATION)
+ $(QT_QRC) $(QT_QRC_LOCALE) $(QT_TS) $(QT_RES_FONTS) $(QT_RES_ICONS) $(QT_RES_ANIMATION)
if TARGET_DARWIN
qt_libbitcoinqt_a_SOURCES += $(BITCOIN_MM)
endif
@@ -321,7 +321,7 @@ bitcoin_qt_cxxflags = $(AM_CXXFLAGS) $(QT_PIE_FLAGS)
bitcoin_qt_sources = qt/main.cpp
if TARGET_WINDOWS
- bitcoin_qt_sources += $(BITCOIN_RC)
+ bitcoin_qt_sources += $(BITCOIN_QT_RC)
endif
bitcoin_qt_ldadd = qt/libbitcoinqt.a $(LIBBITCOIN_SERVER)
if ENABLE_WALLET
@@ -371,7 +371,7 @@ $(QT_QRC_LOCALE_CPP): $(QT_QRC_LOCALE) $(QT_QM)
$(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(RCC) -name bitcoin_locale --format-version 1 $(@D)/temp_$(<F) > $@
@rm $(@D)/temp_$(<F)
-$(QT_QRC_CPP): $(QT_QRC) $(QT_FORMS_H) $(RES_FONTS) $(RES_ICONS) $(RES_ANIMATION)
+$(QT_QRC_CPP): $(QT_QRC) $(QT_FORMS_H) $(QT_RES_FONTS) $(QT_RES_ICONS) $(QT_RES_ANIMATION)
@test -f $(RCC)
$(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(RCC) -name bitcoin --format-version 1 $< > $@
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index d70793ffa9..27f9382631 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -350,8 +350,26 @@ if ENABLE_BENCH
endif
endif
$(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C secp256k1 check
-if EMBEDDED_UNIVALUE
- $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C univalue check
+
+if !ENABLE_FUZZ
+UNIVALUE_TESTS = univalue/test/object univalue/test/unitester univalue/test/no_nul
+noinst_PROGRAMS += $(UNIVALUE_TESTS)
+TESTS += $(UNIVALUE_TESTS)
+
+univalue_test_unitester_SOURCES = $(UNIVALUE_TEST_UNITESTER_INT)
+univalue_test_unitester_LDADD = $(LIBUNIVALUE)
+univalue_test_unitester_CPPFLAGS = -I$(srcdir)/$(UNIVALUE_INCLUDE_DIR_INT) -DJSON_TEST_SRC=\"$(srcdir)/$(UNIVALUE_TEST_DATA_DIR_INT)\"
+univalue_test_unitester_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS)
+
+univalue_test_no_nul_SOURCES = $(UNIVALUE_TEST_NO_NUL_INT)
+univalue_test_no_nul_LDADD = $(LIBUNIVALUE)
+univalue_test_no_nul_CPPFLAGS = -I$(srcdir)/$(UNIVALUE_INCLUDE_DIR_INT)
+univalue_test_no_nul_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS)
+
+univalue_test_object_SOURCES = $(UNIVALUE_TEST_OBJECT_INT)
+univalue_test_object_LDADD = $(LIBUNIVALUE)
+univalue_test_object_CPPFLAGS = -I$(srcdir)/$(UNIVALUE_INCLUDE_DIR_INT)
+univalue_test_object_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS)
endif
%.cpp.test: %.cpp
diff --git a/src/Makefile.univalue.include b/src/Makefile.univalue.include
new file mode 100644
index 0000000000..3644e36368
--- /dev/null
+++ b/src/Makefile.univalue.include
@@ -0,0 +1,6 @@
+include univalue/sources.mk
+
+LIBUNIVALUE = libunivalue.la
+noinst_LTLIBRARIES += $(LIBUNIVALUE)
+libunivalue_la_SOURCES = $(UNIVALUE_LIB_SOURCES_INT) $(UNIVALUE_DIST_HEADERS_INT) $(UNIVALUE_LIB_HEADERS_INT) $(UNIVALUE_TEST_FILES_INT)
+libunivalue_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(srcdir)/$(UNIVALUE_INCLUDE_DIR_INT)
diff --git a/src/addrdb.cpp b/src/addrdb.cpp
index 50fd09101e..bdb1fc6b2b 100644
--- a/src/addrdb.cpp
+++ b/src/addrdb.cpp
@@ -58,7 +58,7 @@ bool SerializeFileDB(const std::string& prefix, const fs::path& path, const Data
if (fileout.IsNull()) {
fileout.fclose();
remove(pathTmp);
- return error("%s: Failed to open file %s", __func__, pathTmp.string());
+ return error("%s: Failed to open file %s", __func__, fs::PathToString(pathTmp));
}
// Serialize
@@ -70,7 +70,7 @@ bool SerializeFileDB(const std::string& prefix, const fs::path& path, const Data
if (!FileCommit(fileout.Get())) {
fileout.fclose();
remove(pathTmp);
- return error("%s: Failed to flush file %s", __func__, pathTmp.string());
+ return error("%s: Failed to flush file %s", __func__, fs::PathToString(pathTmp));
}
fileout.fclose();
@@ -122,8 +122,8 @@ void DeserializeFileDB(const fs::path& path, Data& data, int version)
} // namespace
CBanDB::CBanDB(fs::path ban_list_path)
- : m_banlist_dat(ban_list_path.string() + ".dat"),
- m_banlist_json(ban_list_path.string() + ".json")
+ : m_banlist_dat(ban_list_path + ".dat"),
+ m_banlist_json(ban_list_path + ".json")
{
}
@@ -143,7 +143,7 @@ bool CBanDB::Write(const banmap_t& banSet)
bool CBanDB::Read(banmap_t& banSet)
{
if (fs::exists(m_banlist_dat)) {
- LogPrintf("banlist.dat ignored because it can only be read by " PACKAGE_NAME " version 22.x. Remove %s to silence this warning.\n", m_banlist_dat);
+ LogPrintf("banlist.dat ignored because it can only be read by " PACKAGE_NAME " version 22.x. Remove %s to silence this warning.\n", fs::quoted(fs::PathToString(m_banlist_dat)));
}
// If the JSON banlist does not exist, then recreate it
if (!fs::exists(m_banlist_json)) {
@@ -155,7 +155,7 @@ bool CBanDB::Read(banmap_t& banSet)
if (!util::ReadSettings(m_banlist_json, settings, errors)) {
for (const auto& err : errors) {
- LogPrintf("Cannot load banlist %s: %s\n", m_banlist_json.string(), err);
+ LogPrintf("Cannot load banlist %s: %s\n", fs::PathToString(m_banlist_json), err);
}
return false;
}
@@ -163,7 +163,7 @@ bool CBanDB::Read(banmap_t& banSet)
try {
BanMapFromJson(settings[JSON_KEY], banSet);
} catch (const std::runtime_error& e) {
- LogPrintf("Cannot parse banlist %s: %s\n", m_banlist_json.string(), e.what());
+ LogPrintf("Cannot parse banlist %s: %s\n", fs::PathToString(m_banlist_json), e.what());
return false;
}
@@ -194,12 +194,12 @@ std::optional<bilingual_str> LoadAddrman(const std::vector<bool>& asmap, const A
} catch (const DbNotFoundError&) {
// Addrman can be in an inconsistent state after failure, reset it
addrman = std::make_unique<AddrMan>(asmap, /* deterministic */ false, /* consistency_check_ratio */ check_addrman);
- LogPrintf("Creating peers.dat because the file was not found (%s)\n", path_addr);
+ LogPrintf("Creating peers.dat because the file was not found (%s)\n", fs::quoted(fs::PathToString(path_addr)));
DumpPeerAddresses(args, *addrman);
} catch (const std::exception& e) {
addrman = nullptr;
return strprintf(_("Invalid or corrupt peers.dat (%s). If you believe this is a bug, please report it to %s. As a workaround, you can move the file (%s) out of the way (rename, move, or delete) to have a new one created on the next start."),
- e.what(), PACKAGE_BUGREPORT, path_addr);
+ e.what(), PACKAGE_BUGREPORT, fs::quoted(fs::PathToString(path_addr)));
}
return std::nullopt;
}
@@ -215,7 +215,7 @@ std::vector<CAddress> ReadAnchors(const fs::path& anchors_db_path)
std::vector<CAddress> anchors;
try {
DeserializeFileDB(anchors_db_path, anchors, CLIENT_VERSION | ADDRV2_FORMAT);
- LogPrintf("Loaded %i addresses from %s\n", anchors.size(), anchors_db_path.filename());
+ LogPrintf("Loaded %i addresses from %s\n", anchors.size(), fs::quoted(fs::PathToString(anchors_db_path.filename())));
} catch (const std::exception&) {
anchors.clear();
}
diff --git a/src/addrman.cpp b/src/addrman.cpp
index c364a7710b..cf6e847b04 100644
--- a/src/addrman.cpp
+++ b/src/addrman.cpp
@@ -45,10 +45,7 @@ int AddrInfo::GetTriedBucket(const uint256& nKey, const std::vector<bool>& asmap
{
uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << GetKey()).GetCheapHash();
uint64_t hash2 = (CHashWriter(SER_GETHASH, 0) << nKey << GetGroup(asmap) << (hash1 % ADDRMAN_TRIED_BUCKETS_PER_GROUP)).GetCheapHash();
- int tried_bucket = hash2 % ADDRMAN_TRIED_BUCKET_COUNT;
- uint32_t mapped_as = GetMappedAS(asmap);
- LogPrint(BCLog::NET, "IP %s mapped to AS%i belongs to tried bucket %i\n", ToStringIP(), mapped_as, tried_bucket);
- return tried_bucket;
+ return hash2 % ADDRMAN_TRIED_BUCKET_COUNT;
}
int AddrInfo::GetNewBucket(const uint256& nKey, const CNetAddr& src, const std::vector<bool>& asmap) const
@@ -56,10 +53,7 @@ int AddrInfo::GetNewBucket(const uint256& nKey, const CNetAddr& src, const std::
std::vector<unsigned char> vchSourceGroupKey = src.GetGroup(asmap);
uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << GetGroup(asmap) << vchSourceGroupKey).GetCheapHash();
uint64_t hash2 = (CHashWriter(SER_GETHASH, 0) << nKey << vchSourceGroupKey << (hash1 % ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP)).GetCheapHash();
- int new_bucket = hash2 % ADDRMAN_NEW_BUCKET_COUNT;
- uint32_t mapped_as = GetMappedAS(asmap);
- LogPrint(BCLog::NET, "IP %s mapped to AS%i belongs to new bucket %i\n", ToStringIP(), mapped_as, new_bucket);
- return new_bucket;
+ return hash2 % ADDRMAN_NEW_BUCKET_COUNT;
}
int AddrInfo::GetBucketPosition(const uint256& nKey, bool fNew, int nBucket) const
@@ -481,6 +475,7 @@ void AddrManImpl::ClearNew(int nUBucket, int nUBucketPos)
assert(infoDelete.nRefCount > 0);
infoDelete.nRefCount--;
vvNew[nUBucket][nUBucketPos] = -1;
+ LogPrint(BCLog::ADDRMAN, "Removed %s from new[%i][%i]\n", infoDelete.ToString(), nUBucket, nUBucketPos);
if (infoDelete.nRefCount == 0) {
Delete(nIdDelete);
}
@@ -532,6 +527,8 @@ void AddrManImpl::MakeTried(AddrInfo& info, int nId)
infoOld.nRefCount = 1;
vvNew[nUBucket][nUBucketPos] = nIdEvict;
nNew++;
+ LogPrint(BCLog::ADDRMAN, "Moved %s from tried[%i][%i] to new[%i][%i] to make space\n",
+ infoOld.ToString(), nKBucket, nKBucketPos, nUBucket, nUBucketPos);
}
assert(vvTried[nKBucket][nKBucketPos] == -1);
@@ -582,17 +579,20 @@ void AddrManImpl::Good_(const CService& addr, bool test_before_evict, int64_t nT
// Will moving this address into tried evict another entry?
if (test_before_evict && (vvTried[tried_bucket][tried_bucket_pos] != -1)) {
- // Output the entry we'd be colliding with, for debugging purposes
- auto colliding_entry = mapInfo.find(vvTried[tried_bucket][tried_bucket_pos]);
- LogPrint(BCLog::ADDRMAN, "Collision inserting element into tried table (%s), moving %s to m_tried_collisions=%d\n", colliding_entry != mapInfo.end() ? colliding_entry->second.ToString() : "", addr.ToString(), m_tried_collisions.size());
if (m_tried_collisions.size() < ADDRMAN_SET_TRIED_COLLISION_SIZE) {
m_tried_collisions.insert(nId);
}
+ // Output the entry we'd be colliding with, for debugging purposes
+ auto colliding_entry = mapInfo.find(vvTried[tried_bucket][tried_bucket_pos]);
+ LogPrint(BCLog::ADDRMAN, "Collision with %s while attempting to move %s to tried table. Collisions=%d\n",
+ colliding_entry != mapInfo.end() ? colliding_entry->second.ToString() : "",
+ addr.ToString(),
+ m_tried_collisions.size());
} else {
- LogPrint(BCLog::ADDRMAN, "Moving %s to tried\n", addr.ToString());
-
// move nId to the tried tables
MakeTried(info, nId);
+ LogPrint(BCLog::ADDRMAN, "Moved %s mapped to AS%i to tried[%i][%i]\n",
+ addr.ToString(), addr.GetMappedAS(m_asmap), tried_bucket, tried_bucket_pos);
}
}
@@ -662,6 +662,8 @@ bool AddrManImpl::Add_(const CAddress& addr, const CNetAddr& source, int64_t nTi
ClearNew(nUBucket, nUBucketPos);
pinfo->nRefCount++;
vvNew[nUBucket][nUBucketPos] = nId;
+ LogPrint(BCLog::ADDRMAN, "Added %s mapped to AS%i to new[%i][%i]\n",
+ addr.ToString(), addr.GetMappedAS(m_asmap), nUBucket, nUBucketPos);
} else {
if (pinfo->nRefCount == 0) {
Delete(nId);
@@ -709,38 +711,56 @@ std::pair<CAddress, int64_t> AddrManImpl::Select_(bool newOnly) const
// use a tried node
double fChanceFactor = 1.0;
while (1) {
+ // Pick a tried bucket, and an initial position in that bucket.
int nKBucket = insecure_rand.randrange(ADDRMAN_TRIED_BUCKET_COUNT);
int nKBucketPos = insecure_rand.randrange(ADDRMAN_BUCKET_SIZE);
- while (vvTried[nKBucket][nKBucketPos] == -1) {
- nKBucket = (nKBucket + insecure_rand.randbits(ADDRMAN_TRIED_BUCKET_COUNT_LOG2)) % ADDRMAN_TRIED_BUCKET_COUNT;
- nKBucketPos = (nKBucketPos + insecure_rand.randbits(ADDRMAN_BUCKET_SIZE_LOG2)) % ADDRMAN_BUCKET_SIZE;
+ // Iterate over the positions of that bucket, starting at the initial one,
+ // and looping around.
+ int i;
+ for (i = 0; i < ADDRMAN_BUCKET_SIZE; ++i) {
+ if (vvTried[nKBucket][(nKBucketPos + i) % ADDRMAN_BUCKET_SIZE] != -1) break;
}
- int nId = vvTried[nKBucket][nKBucketPos];
+ // If the bucket is entirely empty, start over with a (likely) different one.
+ if (i == ADDRMAN_BUCKET_SIZE) continue;
+ // Find the entry to return.
+ int nId = vvTried[nKBucket][(nKBucketPos + i) % ADDRMAN_BUCKET_SIZE];
const auto it_found{mapInfo.find(nId)};
assert(it_found != mapInfo.end());
const AddrInfo& info{it_found->second};
+ // With probability GetChance() * fChanceFactor, return the entry.
if (insecure_rand.randbits(30) < fChanceFactor * info.GetChance() * (1 << 30)) {
+ LogPrint(BCLog::ADDRMAN, "Selected %s from tried\n", info.ToString());
return {info, info.nLastTry};
}
+ // Otherwise start over with a (likely) different bucket, and increased chance factor.
fChanceFactor *= 1.2;
}
} else {
// use a new node
double fChanceFactor = 1.0;
while (1) {
+ // Pick a new bucket, and an initial position in that bucket.
int nUBucket = insecure_rand.randrange(ADDRMAN_NEW_BUCKET_COUNT);
int nUBucketPos = insecure_rand.randrange(ADDRMAN_BUCKET_SIZE);
- while (vvNew[nUBucket][nUBucketPos] == -1) {
- nUBucket = (nUBucket + insecure_rand.randbits(ADDRMAN_NEW_BUCKET_COUNT_LOG2)) % ADDRMAN_NEW_BUCKET_COUNT;
- nUBucketPos = (nUBucketPos + insecure_rand.randbits(ADDRMAN_BUCKET_SIZE_LOG2)) % ADDRMAN_BUCKET_SIZE;
+ // Iterate over the positions of that bucket, starting at the initial one,
+ // and looping around.
+ int i;
+ for (i = 0; i < ADDRMAN_BUCKET_SIZE; ++i) {
+ if (vvNew[nUBucket][(nUBucketPos + i) % ADDRMAN_BUCKET_SIZE] != -1) break;
}
- int nId = vvNew[nUBucket][nUBucketPos];
+ // If the bucket is entirely empty, start over with a (likely) different one.
+ if (i == ADDRMAN_BUCKET_SIZE) continue;
+ // Find the entry to return.
+ int nId = vvNew[nUBucket][(nUBucketPos + i) % ADDRMAN_BUCKET_SIZE];
const auto it_found{mapInfo.find(nId)};
assert(it_found != mapInfo.end());
const AddrInfo& info{it_found->second};
+ // With probability GetChance() * fChanceFactor, return the entry.
if (insecure_rand.randbits(30) < fChanceFactor * info.GetChance() * (1 << 30)) {
+ LogPrint(BCLog::ADDRMAN, "Selected %s from new\n", info.ToString());
return {info, info.nLastTry};
}
+ // Otherwise start over with a (likely) different bucket, and increased chance factor.
fChanceFactor *= 1.2;
}
}
@@ -780,7 +800,7 @@ std::vector<CAddress> AddrManImpl::GetAddr_(size_t max_addresses, size_t max_pct
addresses.push_back(ai);
}
-
+ LogPrint(BCLog::ADDRMAN, "GetAddr returned %d random addresses\n", addresses.size());
return addresses;
}
diff --git a/src/banman.h b/src/banman.h
index 8a03a9e3fc..f495dab49d 100644
--- a/src/banman.h
+++ b/src/banman.h
@@ -6,7 +6,7 @@
#define BITCOIN_BANMAN_H
#include <addrdb.h>
-#include <bloom.h>
+#include <common/bloom.h>
#include <fs.h>
#include <net_types.h> // For banmap_t
#include <sync.h>
diff --git a/src/bench/coin_selection.cpp b/src/bench/coin_selection.cpp
index 934b574f8b..fd5145950b 100644
--- a/src/bench/coin_selection.cpp
+++ b/src/bench/coin_selection.cpp
@@ -33,7 +33,6 @@ static void CoinSelection(benchmark::Bench& bench)
NodeContext node;
auto chain = interfaces::MakeChain(node);
CWallet wallet(chain.get(), "", CreateDummyWalletDatabase());
- wallet.SetupLegacyScriptPubKeyMan();
std::vector<std::unique_ptr<CWalletTx>> wtxs;
LOCK(wallet.cs_wallet);
@@ -65,10 +64,6 @@ static void CoinSelection(benchmark::Bench& bench)
}
typedef std::set<CInputCoin> CoinSet;
-static NodeContext testNode;
-static auto testChain = interfaces::MakeChain(testNode);
-static CWallet testWallet(testChain.get(), "", CreateDummyWalletDatabase());
-std::vector<std::unique_ptr<CWalletTx>> wtxn;
// Copied from src/wallet/test/coinselector_tests.cpp
static void add_coin(const CAmount& nValue, int nInput, std::vector<OutputGroup>& set)
@@ -76,10 +71,9 @@ static void add_coin(const CAmount& nValue, int nInput, std::vector<OutputGroup>
CMutableTransaction tx;
tx.vout.resize(nInput + 1);
tx.vout[nInput].nValue = nValue;
- std::unique_ptr<CWalletTx> wtx = std::make_unique<CWalletTx>(MakeTransactionRef(std::move(tx)));
+ CInputCoin coin(MakeTransactionRef(tx), nInput);
set.emplace_back();
- set.back().Insert(COutput(testWallet, *wtx, nInput, 0, true, true, true).GetInputCoin(), 0, true, 0, 0, false);
- wtxn.emplace_back(std::move(wtx));
+ set.back().Insert(coin, 0, true, 0, 0, false);
}
// Copied from src/wallet/test/coinselector_tests.cpp
static CAmount make_hard_case(int utxos, std::vector<OutputGroup>& utxo_pool)
@@ -97,7 +91,6 @@ static CAmount make_hard_case(int utxos, std::vector<OutputGroup>& utxo_pool)
static void BnBExhaustion(benchmark::Bench& bench)
{
// Setup
- testWallet.SetupLegacyScriptPubKeyMan();
std::vector<OutputGroup> utxo_pool;
CoinSet selection;
CAmount value_ret = 0;
diff --git a/src/bench/rollingbloom.cpp b/src/bench/rollingbloom.cpp
index 28167767db..30bc1d5fdf 100644
--- a/src/bench/rollingbloom.cpp
+++ b/src/bench/rollingbloom.cpp
@@ -4,7 +4,7 @@
#include <bench/bench.h>
-#include <bloom.h>
+#include <common/bloom.h>
static void RollingBloom(benchmark::Bench& bench)
{
diff --git a/src/bench/rpc_blockchain.cpp b/src/bench/rpc_blockchain.cpp
index c8886a4c23..3bef64f720 100644
--- a/src/bench/rpc_blockchain.cpp
+++ b/src/bench/rpc_blockchain.cpp
@@ -40,7 +40,7 @@ static void BlockToJsonVerbose(benchmark::Bench& bench)
{
TestBlockAndIndex data;
bench.run([&] {
- auto univalue = blockToJSON(data.block, &data.blockindex, &data.blockindex, /*verbose*/ true);
+ auto univalue = blockToJSON(data.block, &data.blockindex, &data.blockindex, TxVerbosity::SHOW_DETAILS_AND_PREVOUT);
ankerl::nanobench::doNotOptimizeAway(univalue);
});
}
@@ -50,7 +50,7 @@ BENCHMARK(BlockToJsonVerbose);
static void BlockToJsonVerboseWrite(benchmark::Bench& bench)
{
TestBlockAndIndex data;
- auto univalue = blockToJSON(data.block, &data.blockindex, &data.blockindex, /*verbose*/ true);
+ auto univalue = blockToJSON(data.block, &data.blockindex, &data.blockindex, TxVerbosity::SHOW_DETAILS_AND_PREVOUT);
bench.run([&] {
auto str = univalue.write();
ankerl::nanobench::doNotOptimizeAway(str);
diff --git a/src/bench/wallet_balance.cpp b/src/bench/wallet_balance.cpp
index a205d8b6e7..166ed16042 100644
--- a/src/bench/wallet_balance.cpp
+++ b/src/bench/wallet_balance.cpp
@@ -14,7 +14,7 @@
#include <optional>
-static void WalletBalance(benchmark::Bench& bench, const bool set_dirty, const bool add_watchonly, const bool add_mine)
+static void WalletBalance(benchmark::Bench& bench, const bool set_dirty, const bool add_mine)
{
const auto test_setup = MakeNoLogFileContext<const TestingSetup>();
@@ -22,13 +22,14 @@ static void WalletBalance(benchmark::Bench& bench, const bool set_dirty, const b
CWallet wallet{test_setup->m_node.chain.get(), "", CreateMockWalletDatabase()};
{
- wallet.SetupLegacyScriptPubKeyMan();
+ LOCK(wallet.cs_wallet);
+ wallet.SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
+ wallet.SetupDescriptorScriptPubKeyMans();
if (wallet.LoadWallet() != DBErrors::LOAD_OK) assert(false);
}
auto handler = test_setup->m_node.chain->handleNotifications({&wallet, [](CWallet*) {}});
const std::optional<std::string> address_mine{add_mine ? std::optional<std::string>{getnewaddress(wallet)} : std::nullopt};
- if (add_watchonly) importaddress(wallet, ADDRESS_WATCHONLY);
for (int i = 0; i < 100; ++i) {
generatetoaddress(test_setup->m_node, address_mine.value_or(ADDRESS_WATCHONLY));
@@ -42,14 +43,13 @@ static void WalletBalance(benchmark::Bench& bench, const bool set_dirty, const b
if (set_dirty) wallet.MarkDirty();
bal = GetBalance(wallet);
if (add_mine) assert(bal.m_mine_trusted > 0);
- if (add_watchonly) assert(bal.m_watchonly_trusted > 0);
});
}
-static void WalletBalanceDirty(benchmark::Bench& bench) { WalletBalance(bench, /* set_dirty */ true, /* add_watchonly */ true, /* add_mine */ true); }
-static void WalletBalanceClean(benchmark::Bench& bench) { WalletBalance(bench, /* set_dirty */ false, /* add_watchonly */ true, /* add_mine */ true); }
-static void WalletBalanceMine(benchmark::Bench& bench) { WalletBalance(bench, /* set_dirty */ false, /* add_watchonly */ false, /* add_mine */ true); }
-static void WalletBalanceWatch(benchmark::Bench& bench) { WalletBalance(bench, /* set_dirty */ false, /* add_watchonly */ true, /* add_mine */ false); }
+static void WalletBalanceDirty(benchmark::Bench& bench) { WalletBalance(bench, /* set_dirty */ true, /* add_mine */ true); }
+static void WalletBalanceClean(benchmark::Bench& bench) { WalletBalance(bench, /* set_dirty */ false, /* add_mine */ true); }
+static void WalletBalanceMine(benchmark::Bench& bench) { WalletBalance(bench, /* set_dirty */ false, /* add_mine */ true); }
+static void WalletBalanceWatch(benchmark::Bench& bench) { WalletBalance(bench, /* set_dirty */ false, /* add_mine */ false); }
BENCHMARK(WalletBalanceDirty);
BENCHMARK(WalletBalanceClean);
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index 3c22ee0f67..b6344ec413 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -551,15 +551,26 @@ public:
}
// Report peer connection totals by type.
- result += " ipv4 ipv6 onion";
- const bool any_i2p_peers = m_counts.at(2).at(3); // false if total i2p peers count is 0, otherwise true
- if (any_i2p_peers) result += " i2p";
+ result += " ";
+ std::vector<int8_t> reachable_networks;
+ for (const UniValue& network : networkinfo["networks"].getValues()) {
+ if (network["reachable"].get_bool()) {
+ const std::string& network_name{network["name"].get_str()};
+ const int8_t network_id{NetworkStringToId(network_name)};
+ if (network_id == UNKNOWN_NETWORK) continue;
+ result += strprintf("%8s", network_name); // column header
+ reachable_networks.push_back(network_id);
+ }
+ };
result += " total block";
if (m_manual_peers_count) result += " manual";
+
const std::array rows{"in", "out", "total"};
- for (uint8_t i = 0; i < 3; ++i) {
- result += strprintf("\n%-5s %5i %5i %5i", rows.at(i), m_counts.at(i).at(0), m_counts.at(i).at(1), m_counts.at(i).at(2)); // ipv4/ipv6/onion peers counts
- if (any_i2p_peers) result += strprintf(" %5i", m_counts.at(i).at(3)); // i2p peers count
+ for (size_t i = 0; i < rows.size(); ++i) {
+ result += strprintf("\n%-5s", rows[i]); // row header
+ for (int8_t n : reachable_networks) {
+ result += strprintf("%8i", m_counts.at(i).at(n)); // network peers count
+ }
result += strprintf(" %5i", m_counts.at(i).at(m_networks.size())); // total peers count
if (i == 1) { // the outbound row has two extra columns for block relay and manual peer counts
result += strprintf(" %5i", m_block_relay_peers_count);
@@ -786,7 +797,7 @@ static UniValue CallRPC(BaseRequestHandler* rh, const std::string& strMethod, co
if (failedToGetAuthCookie) {
throw std::runtime_error(strprintf(
"Could not locate RPC credentials. No authentication cookie could be found, and RPC password is not set. See -rpcpassword and -stdinrpcpass. Configuration file: (%s)",
- GetConfigFile(gArgs.GetArg("-conf", BITCOIN_CONF_FILENAME)).string()));
+ fs::PathToString(GetConfigFile(gArgs.GetArg("-conf", BITCOIN_CONF_FILENAME)))));
} else {
throw std::runtime_error("Authorization failed: Incorrect rpcuser or rpcpassword");
}
diff --git a/src/bitcoin-wallet.cpp b/src/bitcoin-wallet.cpp
index 765954c92e..21d4df5b01 100644
--- a/src/bitcoin-wallet.cpp
+++ b/src/bitcoin-wallet.cpp
@@ -30,6 +30,7 @@ static void SetupWalletToolArgs(ArgsManager& argsman)
argsman.AddArg("-dumpfile=<file name>", "When used with 'dump', writes out the records to this file. When used with 'createfromdump', loads the records into a new wallet.", ArgsManager::ALLOW_STRING, OptionsCategory::OPTIONS);
argsman.AddArg("-debug=<category>", "Output debugging information (default: 0).", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-descriptors", "Create descriptors wallet. Only for 'create'", ArgsManager::ALLOW_BOOL, OptionsCategory::OPTIONS);
+ argsman.AddArg("-legacy", "Create legacy wallet. Only for 'create'", ArgsManager::ALLOW_BOOL, OptionsCategory::OPTIONS);
argsman.AddArg("-format=<format>", "The format of the wallet file to create. Either \"bdb\" or \"sqlite\". Only used with 'createfromdump'", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-printtoconsole", "Send trace/debug info to console (default: 1 when no -debug is true, 0 otherwise).", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
diff --git a/src/chain.h b/src/chain.h
index 365a7f79b6..15ca8f8750 100644
--- a/src/chain.h
+++ b/src/chain.h
@@ -178,7 +178,7 @@ public:
//! (memory only) Number of transactions in the chain up to and including this block.
//! This value will be non-zero only if and only if transactions for this block and all its parents are available.
- //! Change to 64-bit type when necessary; won't happen before 2030
+ //! Change to 64-bit type before 2024 (assuming worst case of 60 byte transactions).
//!
//! Note: this value is faked during use of a UTXO snapshot because we don't
//! have the underlying block data available during snapshot load.
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index b155745794..2e823c1211 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -118,15 +118,15 @@ public:
// This is fine at runtime as we'll fall back to using them as an addrfetch if they don't support the
// service bits we want, but we should get them updated to support all service bits wanted by any
// release ASAP to avoid it where possible.
- vSeeds.emplace_back("seed.bitcoin.sipa.be"); // Pieter Wuille, only supports x1, x5, x9, and xd
- vSeeds.emplace_back("dnsseed.bluematt.me"); // Matt Corallo, only supports x9
- vSeeds.emplace_back("dnsseed.bitcoin.dashjr.org"); // Luke Dashjr
- vSeeds.emplace_back("seed.bitcoinstats.com"); // Christian Decker, supports x1 - xf
- vSeeds.emplace_back("seed.bitcoin.jonasschnelli.ch"); // Jonas Schnelli, only supports x1, x5, x9, and xd
- vSeeds.emplace_back("seed.btc.petertodd.org"); // Peter Todd, only supports x1, x5, x9, and xd
- vSeeds.emplace_back("seed.bitcoin.sprovoost.nl"); // Sjors Provoost
- vSeeds.emplace_back("dnsseed.emzy.de"); // Stephan Oeste
- vSeeds.emplace_back("seed.bitcoin.wiz.biz"); // Jason Maurice
+ vSeeds.emplace_back("seed.bitcoin.sipa.be."); // Pieter Wuille, only supports x1, x5, x9, and xd
+ vSeeds.emplace_back("dnsseed.bluematt.me."); // Matt Corallo, only supports x9
+ vSeeds.emplace_back("dnsseed.bitcoin.dashjr.org."); // Luke Dashjr
+ vSeeds.emplace_back("seed.bitcoinstats.com."); // Christian Decker, supports x1 - xf
+ vSeeds.emplace_back("seed.bitcoin.jonasschnelli.ch."); // Jonas Schnelli, only supports x1, x5, x9, and xd
+ vSeeds.emplace_back("seed.btc.petertodd.org."); // Peter Todd, only supports x1, x5, x9, and xd
+ vSeeds.emplace_back("seed.bitcoin.sprovoost.nl."); // Sjors Provoost
+ vSeeds.emplace_back("dnsseed.emzy.de."); // Stephan Oeste
+ vSeeds.emplace_back("seed.bitcoin.wiz.biz."); // Jason Maurice
base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,0);
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,5);
@@ -230,10 +230,10 @@ public:
vFixedSeeds.clear();
vSeeds.clear();
// nodes with support for servicebits filtering should be at the top
- vSeeds.emplace_back("testnet-seed.bitcoin.jonasschnelli.ch");
- vSeeds.emplace_back("seed.tbtc.petertodd.org");
- vSeeds.emplace_back("seed.testnet.bitcoin.sprovoost.nl");
- vSeeds.emplace_back("testnet-seed.bluematt.me"); // Just a static list of stable node(s), only supports x9
+ vSeeds.emplace_back("testnet-seed.bitcoin.jonasschnelli.ch.");
+ vSeeds.emplace_back("seed.tbtc.petertodd.org.");
+ vSeeds.emplace_back("seed.testnet.bitcoin.sprovoost.nl.");
+ vSeeds.emplace_back("testnet-seed.bluematt.me."); // Just a static list of stable node(s), only supports x9
base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,111);
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,196);
@@ -280,7 +280,7 @@ public:
if (!args.IsArgSet("-signetchallenge")) {
bin = ParseHex("512103ad5e0edad18cb1f0fc0d28a3d4f1f3e445640337489abb10404f2d1e086be430210359ef5021964fe22d6f8e05b2463c9540ce96883fe3b278760f048f5189f2e6c452ae");
- vSeeds.emplace_back("seed.signet.bitcoin.sprovoost.nl");
+ vSeeds.emplace_back("seed.signet.bitcoin.sprovoost.nl.");
// Hardcoded nodes can be removed once there are more DNS seeds
vSeeds.emplace_back("178.128.221.177");
diff --git a/src/bloom.cpp b/src/common/bloom.cpp
index 15e06389de..26b70b4d14 100644
--- a/src/bloom.cpp
+++ b/src/common/bloom.cpp
@@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <bloom.h>
+#include <common/bloom.h>
#include <hash.h>
#include <primitives/transaction.h>
@@ -82,7 +82,7 @@ bool CBloomFilter::contains(const COutPoint& outpoint) const
{
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
stream << outpoint;
- return contains(MakeUCharSpan(stream));
+ return contains(stream);
}
bool CBloomFilter::IsWithinSizeConstraints() const
diff --git a/src/bloom.h b/src/common/bloom.h
index 422646d8b9..25c16fbfe2 100644
--- a/src/bloom.h
+++ b/src/common/bloom.h
@@ -2,8 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#ifndef BITCOIN_BLOOM_H
-#define BITCOIN_BLOOM_H
+#ifndef BITCOIN_COMMON_BLOOM_H
+#define BITCOIN_COMMON_BLOOM_H
#include <serialize.h>
#include <span.h>
@@ -124,4 +124,4 @@ private:
int nHashFuncs;
};
-#endif // BITCOIN_BLOOM_H
+#endif // BITCOIN_COMMON_BLOOM_H
diff --git a/src/consensus/amount.h b/src/consensus/amount.h
index 8b41a2277d..96566ea13f 100644
--- a/src/consensus/amount.h
+++ b/src/consensus/amount.h
@@ -11,6 +11,7 @@
/** Amount in satoshis (Can be negative) */
typedef int64_t CAmount;
+/** The amount of satoshis in one BTC. */
static constexpr CAmount COIN = 100000000;
/** No amount larger than this (in satoshi) is valid.
diff --git a/src/core_io.h b/src/core_io.h
index be93a17efe..4d7199ab12 100644
--- a/src/core_io.h
+++ b/src/core_io.h
@@ -20,6 +20,15 @@ class uint256;
class UniValue;
class CTxUndo;
+/**
+ * Verbose level for block's transaction
+ */
+enum class TxVerbosity {
+ SHOW_TXID, //!< Only TXID for each block's transaction
+ SHOW_DETAILS, //!< Include TXID, inputs, outputs, and other common block's transaction information
+ SHOW_DETAILS_AND_PREVOUT //!< The same as previous option with information about prevouts if available
+};
+
// core_read.cpp
CScript ParseScript(const std::string& s);
std::string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDecode = false);
@@ -46,6 +55,6 @@ std::string EncodeHexTx(const CTransaction& tx, const int serializeFlags = 0);
std::string SighashToStr(unsigned char sighash_type);
void ScriptPubKeyToUniv(const CScript& scriptPubKey, UniValue& out, bool include_hex, bool include_address = true);
void ScriptToUniv(const CScript& script, UniValue& out);
-void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex = true, int serialize_flags = 0, const CTxUndo* txundo = nullptr);
+void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex = true, int serialize_flags = 0, const CTxUndo* txundo = nullptr, TxVerbosity verbosity = TxVerbosity::SHOW_DETAILS);
#endif // BITCOIN_CORE_IO_H
diff --git a/src/core_write.cpp b/src/core_write.cpp
index 6b13e4c586..468694b011 100644
--- a/src/core_write.cpp
+++ b/src/core_write.cpp
@@ -163,7 +163,7 @@ void ScriptPubKeyToUniv(const CScript& scriptPubKey, UniValue& out, bool include
out.pushKV("type", GetTxnOutputType(type));
}
-void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex, int serialize_flags, const CTxUndo* txundo)
+void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex, int serialize_flags, const CTxUndo* txundo, TxVerbosity verbosity)
{
entry.pushKV("txid", tx.GetHash().GetHex());
entry.pushKV("hash", tx.GetWitnessHash().GetHex());
@@ -179,7 +179,7 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry,
// If available, use Undo data to calculate the fee. Note that txundo == nullptr
// for coinbase transactions and for transactions where undo data is unavailable.
- const bool calculate_fee = txundo != nullptr;
+ const bool have_undo = txundo != nullptr;
CAmount amt_total_in = 0;
CAmount amt_total_out = 0;
@@ -203,9 +203,28 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry,
}
in.pushKV("txinwitness", txinwitness);
}
- if (calculate_fee) {
- const CTxOut& prev_txout = txundo->vprevout[i].out;
+ if (have_undo) {
+ const Coin& prev_coin = txundo->vprevout[i];
+ const CTxOut& prev_txout = prev_coin.out;
+
amt_total_in += prev_txout.nValue;
+ switch (verbosity) {
+ case TxVerbosity::SHOW_TXID:
+ case TxVerbosity::SHOW_DETAILS:
+ break;
+
+ case TxVerbosity::SHOW_DETAILS_AND_PREVOUT:
+ UniValue o_script_pub_key(UniValue::VOBJ);
+ ScriptPubKeyToUniv(prev_txout.scriptPubKey, o_script_pub_key, /* includeHex */ true);
+
+ UniValue p(UniValue::VOBJ);
+ p.pushKV("generated", bool(prev_coin.fCoinBase));
+ p.pushKV("height", uint64_t(prev_coin.nHeight));
+ p.pushKV("value", ValueFromAmount(prev_txout.nValue));
+ p.pushKV("scriptPubKey", o_script_pub_key);
+ in.pushKV("prevout", p);
+ break;
+ }
}
in.pushKV("sequence", (int64_t)txin.nSequence);
vin.push_back(in);
@@ -226,13 +245,13 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry,
out.pushKV("scriptPubKey", o);
vout.push_back(out);
- if (calculate_fee) {
+ if (have_undo) {
amt_total_out += txout.nValue;
}
}
entry.pushKV("vout", vout);
- if (calculate_fee) {
+ if (have_undo) {
const CAmount fee = amt_total_in - amt_total_out;
CHECK_NONFATAL(MoneyRange(fee));
entry.pushKV("fee", ValueFromAmount(fee));
diff --git a/src/crypto/chacha_poly_aead.h b/src/crypto/chacha_poly_aead.h
index 0afe8fcc14..6a7998335d 100644
--- a/src/crypto/chacha_poly_aead.h
+++ b/src/crypto/chacha_poly_aead.h
@@ -117,8 +117,8 @@ static constexpr int AAD_PACKAGES_PER_ROUND = 21; /* 64 / 3 round down*/
class ChaCha20Poly1305AEAD
{
private:
- ChaCha20 m_chacha_main; // payload and poly1305 key-derivation cipher instance
- ChaCha20 m_chacha_header; // AAD cipher instance (encrypted length)
+ ChaCha20 m_chacha_header; // AAD cipher instance (encrypted length) and poly1305 key-derivation cipher instance
+ ChaCha20 m_chacha_main; // payload
unsigned char m_aad_keystream_buffer[CHACHA20_ROUND_OUTPUT]; // aad keystream cache
uint64_t m_cached_aad_seqnr; // aad keystream cache hint
diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp
index bcaf746167..2fdc54464a 100644
--- a/src/dbwrapper.cpp
+++ b/src/dbwrapper.cpp
@@ -115,7 +115,7 @@ static leveldb::Options GetOptions(size_t nCacheSize)
}
CDBWrapper::CDBWrapper(const fs::path& path, size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate)
- : m_name{path.stem().string()}
+ : m_name{fs::PathToString(path.stem())}
{
penv = nullptr;
readoptions.verify_checksums = true;
@@ -129,21 +129,21 @@ CDBWrapper::CDBWrapper(const fs::path& path, size_t nCacheSize, bool fMemory, bo
options.env = penv;
} else {
if (fWipe) {
- LogPrintf("Wiping LevelDB in %s\n", path.string());
- leveldb::Status result = leveldb::DestroyDB(path.string(), options);
+ LogPrintf("Wiping LevelDB in %s\n", fs::PathToString(path));
+ leveldb::Status result = leveldb::DestroyDB(fs::PathToString(path), options);
dbwrapper_private::HandleError(result);
}
TryCreateDirectories(path);
- LogPrintf("Opening LevelDB in %s\n", path.string());
+ LogPrintf("Opening LevelDB in %s\n", fs::PathToString(path));
}
- leveldb::Status status = leveldb::DB::Open(options, path.string(), &pdb);
+ leveldb::Status status = leveldb::DB::Open(options, fs::PathToString(path), &pdb);
dbwrapper_private::HandleError(status);
LogPrintf("Opened LevelDB successfully\n");
if (gArgs.GetBoolArg("-forcecompactdb", false)) {
- LogPrintf("Starting database compaction of %s\n", path.string());
+ LogPrintf("Starting database compaction of %s\n", fs::PathToString(path));
pdb->CompactRange(nullptr, nullptr);
- LogPrintf("Finished database compaction of %s\n", path.string());
+ LogPrintf("Finished database compaction of %s\n", fs::PathToString(path));
}
// The base-case obfuscation key, which is a noop.
@@ -160,10 +160,10 @@ CDBWrapper::CDBWrapper(const fs::path& path, size_t nCacheSize, bool fMemory, bo
Write(OBFUSCATE_KEY_KEY, new_key);
obfuscate_key = new_key;
- LogPrintf("Wrote new obfuscate key for %s: %s\n", path.string(), HexStr(obfuscate_key));
+ LogPrintf("Wrote new obfuscate key for %s: %s\n", fs::PathToString(path), HexStr(obfuscate_key));
}
- LogPrintf("Using obfuscation key for %s: %s\n", path.string(), HexStr(obfuscate_key));
+ LogPrintf("Using obfuscation key for %s: %s\n", fs::PathToString(path), HexStr(obfuscate_key));
}
CDBWrapper::~CDBWrapper()
diff --git a/src/external_signer.cpp b/src/external_signer.cpp
index d6388b759a..75070899c6 100644
--- a/src/external_signer.cpp
+++ b/src/external_signer.cpp
@@ -9,6 +9,7 @@
#include <util/system.h>
#include <external_signer.h>
+#include <algorithm>
#include <stdexcept>
#include <string>
#include <vector>
@@ -75,15 +76,14 @@ bool ExternalSigner::SignTransaction(PartiallySignedTransaction& psbtx, std::str
ssTx << psbtx;
// Check if signer fingerprint matches any input master key fingerprint
- bool match = false;
- for (unsigned int i = 0; i < psbtx.inputs.size(); ++i) {
- const PSBTInput& input = psbtx.inputs[i];
+ auto matches_signer_fingerprint = [&](const PSBTInput& input) {
for (const auto& entry : input.hd_keypaths) {
- if (m_fingerprint == strprintf("%08x", ReadBE32(entry.second.fingerprint))) match = true;
+ if (m_fingerprint == strprintf("%08x", ReadBE32(entry.second.fingerprint))) return true;
}
- }
+ return false;
+ };
- if (!match) {
+ if (!std::any_of(psbtx.inputs.begin(), psbtx.inputs.end(), matches_signer_fingerprint)) {
error = "Signer fingerprint " + m_fingerprint + " does not match any of the inputs:\n" + EncodeBase64(ssTx.str());
return false;
}
diff --git a/src/flatfile.cpp b/src/flatfile.cpp
index 151f1a38f1..929808c7fa 100644
--- a/src/flatfile.cpp
+++ b/src/flatfile.cpp
@@ -41,11 +41,11 @@ FILE* FlatFileSeq::Open(const FlatFilePos& pos, bool read_only)
if (!file && !read_only)
file = fsbridge::fopen(path, "wb+");
if (!file) {
- LogPrintf("Unable to open file %s\n", path.string());
+ LogPrintf("Unable to open file %s\n", fs::PathToString(path));
return nullptr;
}
if (pos.nPos && fseek(file, pos.nPos, SEEK_SET)) {
- LogPrintf("Unable to seek to position %u of %s\n", pos.nPos, path.string());
+ LogPrintf("Unable to seek to position %u of %s\n", pos.nPos, fs::PathToString(path));
fclose(file);
return nullptr;
}
diff --git a/src/fs.cpp b/src/fs.cpp
index b9b3c46d8d..7a99444eef 100644
--- a/src/fs.cpp
+++ b/src/fs.cpp
@@ -16,6 +16,7 @@
#define NOMINMAX
#endif
#include <codecvt>
+#include <limits>
#include <windows.h>
#endif
@@ -24,7 +25,7 @@ namespace fsbridge {
FILE *fopen(const fs::path& p, const char *mode)
{
#ifndef WIN32
- return ::fopen(p.string().c_str(), mode);
+ return ::fopen(p.c_str(), mode);
#else
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>,wchar_t> utf8_cvt;
return ::_wfopen(p.wstring().c_str(), utf8_cvt.from_bytes(mode).c_str());
@@ -46,7 +47,7 @@ static std::string GetErrorReason()
FileLock::FileLock(const fs::path& file)
{
- fd = open(file.string().c_str(), O_RDWR);
+ fd = open(file.c_str(), O_RDWR);
if (fd == -1) {
reason = GetErrorReason();
}
@@ -249,9 +250,9 @@ void ofstream::close()
#else // __GLIBCXX__
#if BOOST_VERSION >= 107700
-static_assert(sizeof(*BOOST_FILESYSTEM_C_STR(fs::path())) == sizeof(wchar_t),
+static_assert(sizeof(*BOOST_FILESYSTEM_C_STR(boost::filesystem::path())) == sizeof(wchar_t),
#else
-static_assert(sizeof(*fs::path().BOOST_FILESYSTEM_C_STR) == sizeof(wchar_t),
+static_assert(sizeof(*boost::filesystem::path().BOOST_FILESYSTEM_C_STR) == sizeof(wchar_t),
#endif // BOOST_VERSION >= 107700
"Warning: This build is using boost::filesystem ofstream and ifstream "
"implementations which will fail to open paths containing multibyte "
diff --git a/src/fs.h b/src/fs.h
index d77b90be66..4a0bf39e95 100644
--- a/src/fs.h
+++ b/src/fs.h
@@ -13,9 +13,132 @@
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
+#include <tinyformat.h>
/** Filesystem operations and types */
-namespace fs = boost::filesystem;
+namespace fs {
+
+using namespace boost::filesystem;
+
+/**
+ * Path class wrapper to prepare application code for transition from
+ * boost::filesystem library to std::filesystem implementation. The main
+ * purpose of the class is to define fs::path::u8string() and fs::u8path()
+ * functions not present in boost. It also blocks calls to the
+ * fs::path(std::string) implicit constructor and the fs::path::string()
+ * method, which worked well in the boost::filesystem implementation, but have
+ * unsafe and unpredictable behavior on Windows in the std::filesystem
+ * implementation (see implementation note in \ref PathToString for details).
+ */
+class path : public boost::filesystem::path
+{
+public:
+ using boost::filesystem::path::path;
+
+ // Allow path objects arguments for compatibility.
+ path(boost::filesystem::path path) : boost::filesystem::path::path(std::move(path)) {}
+ path& operator=(boost::filesystem::path path) { boost::filesystem::path::operator=(std::move(path)); return *this; }
+ path& operator/=(boost::filesystem::path path) { boost::filesystem::path::operator/=(std::move(path)); return *this; }
+
+ // Allow literal string arguments, which are safe as long as the literals are ASCII.
+ path(const char* c) : boost::filesystem::path(c) {}
+ path& operator=(const char* c) { boost::filesystem::path::operator=(c); return *this; }
+ path& operator/=(const char* c) { boost::filesystem::path::operator/=(c); return *this; }
+ path& append(const char* c) { boost::filesystem::path::append(c); return *this; }
+
+ // Disallow std::string arguments to avoid locale-dependent decoding on windows.
+ path(std::string) = delete;
+ path& operator=(std::string) = delete;
+ path& operator/=(std::string) = delete;
+ path& append(std::string) = delete;
+
+ // Disallow std::string conversion method to avoid locale-dependent encoding on windows.
+ std::string string() const = delete;
+
+ // Define UTF-8 string conversion method not present in boost::filesystem but present in std::filesystem.
+ std::string u8string() const { return boost::filesystem::path::string(); }
+};
+
+// Define UTF-8 string conversion function not present in boost::filesystem but present in std::filesystem.
+static inline path u8path(const std::string& string)
+{
+ return boost::filesystem::path(string);
+}
+
+// Disallow implicit std::string conversion for system_complete to avoid
+// locale-dependent encoding on windows.
+static inline path system_complete(const path& p)
+{
+ return boost::filesystem::system_complete(p);
+}
+
+// Disallow implicit std::string conversion for exists to avoid
+// locale-dependent encoding on windows.
+static inline bool exists(const path& p)
+{
+ return boost::filesystem::exists(p);
+}
+
+// Allow explicit quoted stream I/O.
+static inline auto quoted(const std::string& s)
+{
+ return boost::io::quoted(s, '&');
+}
+
+// Allow safe path append operations.
+static inline path operator+(path p1, path p2)
+{
+ p1 += std::move(p2);
+ return p1;
+}
+
+/**
+ * Convert path object to byte string. On POSIX, paths natively are byte
+ * strings so this is trivial. On Windows, paths natively are Unicode, so an
+ * encoding step is necessary.
+ *
+ * The inverse of \ref PathToString is \ref PathFromString. The strings
+ * returned and parsed by these functions can be used to call POSIX APIs, and
+ * for roundtrip conversion, logging, and debugging. But they are not
+ * guaranteed to be valid UTF-8, and are generally meant to be used internally,
+ * not externally. When communicating with external programs and libraries that
+ * require UTF-8, fs::path::u8string() and fs::u8path() methods can be used.
+ * For other applications, if support for non UTF-8 paths is required, or if
+ * higher-level JSON or XML or URI or C-style escapes are preferred, it may be
+ * also be appropriate to use different path encoding functions.
+ *
+ * Implementation note: On Windows, the std::filesystem::path(string)
+ * constructor and std::filesystem::path::string() method are not safe to use
+ * here, because these methods encode the path using C++'s narrow multibyte
+ * encoding, which on Windows corresponds to the current "code page", which is
+ * unpredictable and typically not able to represent all valid paths. So
+ * std::filesystem::path::u8string() and std::filesystem::u8path() functions
+ * are used instead on Windows. On POSIX, u8string/u8path functions are not
+ * safe to use because paths are not always valid UTF-8, so plain string
+ * methods which do not transform the path there are used.
+ */
+static inline std::string PathToString(const path& path)
+{
+#ifdef WIN32
+ return path.u8string();
+#else
+ static_assert(std::is_same<path::string_type, std::string>::value, "PathToString not implemented on this platform");
+ return path.boost::filesystem::path::string();
+#endif
+}
+
+/**
+ * Convert byte string to path object. Inverse of \ref PathToString.
+ */
+static inline path PathFromString(const std::string& string)
+{
+#ifdef WIN32
+ return u8path(string);
+#else
+ return boost::filesystem::path(string);
+#endif
+}
+} // namespace fs
/** Bridge operations to C stdio */
namespace fsbridge {
@@ -103,4 +226,11 @@ namespace fsbridge {
#endif // WIN32 && __GLIBCXX__
};
+// Disallow path operator<< formatting in tinyformat to avoid locale-dependent
+// encoding on windows.
+namespace tinyformat {
+template<> inline void formatValue(std::ostream&, const char*, const char*, int, const boost::filesystem::path&) = delete;
+template<> inline void formatValue(std::ostream&, const char*, const char*, int, const fs::path&) = delete;
+} // namespace tinyformat
+
#endif // BITCOIN_FS_H
diff --git a/src/i2p.cpp b/src/i2p.cpp
index 5e7e42fb77..35ac8731f2 100644
--- a/src/i2p.cpp
+++ b/src/i2p.cpp
@@ -328,7 +328,7 @@ void Session::GenerateAndSavePrivateKey(const Sock& sock)
if (!WriteBinaryFile(m_private_key_file,
std::string(m_private_key.begin(), m_private_key.end()))) {
throw std::runtime_error(
- strprintf("Cannot save I2P private key to %s", m_private_key_file));
+ strprintf("Cannot save I2P private key to %s", fs::quoted(fs::PathToString(m_private_key_file))));
}
}
diff --git a/src/index/base.cpp b/src/index/base.cpp
index 3ca86a310e..fc6dd77a72 100644
--- a/src/index/base.cpp
+++ b/src/index/base.cpp
@@ -321,7 +321,7 @@ bool BaseIndex::BlockUntilSyncedToCurrentChain() const
{
// Skip the queue-draining stuff if we know we're caught up with
- // ::ChainActive().Tip().
+ // m_chain.Tip().
LOCK(cs_main);
const CBlockIndex* chain_tip = m_chainstate->m_chain.Tip();
const CBlockIndex* best_block_index = m_best_block_index.load();
diff --git a/src/init.cpp b/src/init.cpp
index 4495ded64d..164b7bb55d 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -113,7 +113,7 @@ static const char* BITCOIN_PID_FILENAME = "bitcoind.pid";
static fs::path GetPidFile(const ArgsManager& args)
{
- return AbsPathForConfigVal(fs::path(args.GetArg("-pid", BITCOIN_PID_FILENAME)));
+ return AbsPathForConfigVal(fs::PathFromString(args.GetArg("-pid", BITCOIN_PID_FILENAME)));
}
[[nodiscard]] static bool CreatePidFile(const ArgsManager& args)
@@ -127,7 +127,7 @@ static fs::path GetPidFile(const ArgsManager& args)
#endif
return true;
} else {
- return InitError(strprintf(_("Unable to create the PID file '%s': %s"), GetPidFile(args).string(), std::strerror(errno)));
+ return InitError(strprintf(_("Unable to create the PID file '%s': %s"), fs::PathToString(GetPidFile(args)), std::strerror(errno)));
}
}
@@ -1062,10 +1062,10 @@ static bool LockDataDirectory(bool probeOnly)
// Make sure only a single Bitcoin process is using the data directory.
fs::path datadir = gArgs.GetDataDirNet();
if (!DirIsWritable(datadir)) {
- return InitError(strprintf(_("Cannot write to data directory '%s'; check permissions."), datadir.string()));
+ return InitError(strprintf(_("Cannot write to data directory '%s'; check permissions."), fs::PathToString(datadir)));
}
if (!LockDirectory(datadir, ".lock", probeOnly)) {
- return InitError(strprintf(_("Cannot obtain a lock on data directory %s. %s is probably already running."), datadir.string(), PACKAGE_NAME));
+ return InitError(strprintf(_("Cannot obtain a lock on data directory %s. %s is probably already running."), fs::PathToString(datadir), PACKAGE_NAME));
}
return true;
}
@@ -1126,12 +1126,12 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
LogPrintf("Using at most %i automatic connections (%i file descriptors available)\n", nMaxConnections, nFD);
// Warn about relative -datadir path.
- if (args.IsArgSet("-datadir") && !fs::path(args.GetArg("-datadir", "")).is_absolute()) {
+ if (args.IsArgSet("-datadir") && !fs::PathFromString(args.GetArg("-datadir", "")).is_absolute()) {
LogPrintf("Warning: relative datadir option '%s' specified, which will be interpreted relative to the " /* Continued */
"current working directory '%s'. This is fragile, because if bitcoin is started in the future "
"from a different location, it will be unable to locate the current data files. There could "
"also be data loss if bitcoin is started while in a temporary directory.\n",
- args.GetArg("-datadir", ""), fs::current_path().string());
+ args.GetArg("-datadir", ""), fs::PathToString(fs::current_path()));
}
InitSignatureCache();
@@ -1215,20 +1215,20 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
// Read asmap file if configured
std::vector<bool> asmap;
if (args.IsArgSet("-asmap")) {
- fs::path asmap_path = fs::path(args.GetArg("-asmap", ""));
+ fs::path asmap_path = fs::PathFromString(args.GetArg("-asmap", ""));
if (asmap_path.empty()) {
- asmap_path = DEFAULT_ASMAP_FILENAME;
+ asmap_path = fs::PathFromString(DEFAULT_ASMAP_FILENAME);
}
if (!asmap_path.is_absolute()) {
asmap_path = gArgs.GetDataDirNet() / asmap_path;
}
if (!fs::exists(asmap_path)) {
- InitError(strprintf(_("Could not find asmap file %s"), asmap_path));
+ InitError(strprintf(_("Could not find asmap file %s"), fs::quoted(fs::PathToString(asmap_path))));
return false;
}
asmap = DecodeAsmap(asmap_path);
if (asmap.size() == 0) {
- InitError(strprintf(_("Could not parse asmap file %s"), asmap_path));
+ InitError(strprintf(_("Could not parse asmap file %s"), fs::quoted(fs::PathToString(asmap_path))));
return false;
}
const uint256 asmap_version = SerializeHash(asmap);
@@ -1653,11 +1653,11 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
// ********************************************************* Step 11: import blocks
if (!CheckDiskSpace(gArgs.GetDataDirNet())) {
- InitError(strprintf(_("Error: Disk space is low for %s"), gArgs.GetDataDirNet()));
+ InitError(strprintf(_("Error: Disk space is low for %s"), fs::quoted(fs::PathToString(gArgs.GetDataDirNet()))));
return false;
}
if (!CheckDiskSpace(gArgs.GetBlocksDirPath())) {
- InitError(strprintf(_("Error: Disk space is low for %s"), gArgs.GetBlocksDirPath()));
+ InitError(strprintf(_("Error: Disk space is low for %s"), fs::quoted(fs::PathToString(gArgs.GetBlocksDirPath()))));
return false;
}
@@ -1685,7 +1685,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
std::vector<fs::path> vImportFiles;
for (const std::string& strFile : args.GetArgs("-loadblock")) {
- vImportFiles.push_back(strFile);
+ vImportFiles.push_back(fs::PathFromString(strFile));
}
chainman.m_load_block = std::thread(&util::TraceThread, "loadblk", [=, &chainman, &args] {
diff --git a/src/init/common.cpp b/src/init/common.cpp
index 5c1f469081..8f9e0ebc87 100644
--- a/src/init/common.cpp
+++ b/src/init/common.cpp
@@ -81,7 +81,7 @@ void AddLoggingArgs(ArgsManager& argsman)
void SetLoggingOptions(const ArgsManager& args)
{
LogInstance().m_print_to_file = !args.IsArgNegated("-debuglogfile");
- LogInstance().m_file_path = AbsPathForConfigVal(args.GetArg("-debuglogfile", DEFAULT_DEBUGLOGFILE));
+ LogInstance().m_file_path = AbsPathForConfigVal(fs::PathFromString(args.GetArg("-debuglogfile", DEFAULT_DEBUGLOGFILE)));
LogInstance().m_print_to_console = args.GetBoolArg("-printtoconsole", !args.GetBoolArg("-daemon", false));
LogInstance().m_log_timestamps = args.GetBoolArg("-logtimestamps", DEFAULT_LOGTIMESTAMPS);
LogInstance().m_log_time_micros = args.GetBoolArg("-logtimemicros", DEFAULT_LOGTIMEMICROS);
@@ -128,24 +128,24 @@ bool StartLogging(const ArgsManager& args)
}
if (!LogInstance().StartLogging()) {
return InitError(strprintf(Untranslated("Could not open debug log file %s"),
- LogInstance().m_file_path.string()));
+ fs::PathToString(LogInstance().m_file_path)));
}
if (!LogInstance().m_log_timestamps)
LogPrintf("Startup time: %s\n", FormatISO8601DateTime(GetTime()));
- LogPrintf("Default data directory %s\n", GetDefaultDataDir().string());
- LogPrintf("Using data directory %s\n", gArgs.GetDataDirNet().string());
+ LogPrintf("Default data directory %s\n", fs::PathToString(GetDefaultDataDir()));
+ LogPrintf("Using data directory %s\n", fs::PathToString(gArgs.GetDataDirNet()));
// Only log conf file usage message if conf file actually exists.
fs::path config_file_path = GetConfigFile(args.GetArg("-conf", BITCOIN_CONF_FILENAME));
if (fs::exists(config_file_path)) {
- LogPrintf("Config file: %s\n", config_file_path.string());
+ LogPrintf("Config file: %s\n", fs::PathToString(config_file_path));
} else if (args.IsArgSet("-conf")) {
// Warn if no conf file exists at path provided by user
- InitWarning(strprintf(_("The specified config file %s does not exist"), config_file_path.string()));
+ InitWarning(strprintf(_("The specified config file %s does not exist"), fs::PathToString(config_file_path)));
} else {
// Not categorizing as "Warning" because it's the default behavior
- LogPrintf("Config file: %s (not found, skipping)\n", config_file_path.string());
+ LogPrintf("Config file: %s (not found, skipping)\n", fs::PathToString(config_file_path));
}
// Log the config arguments to debug.log
diff --git a/src/ipc/process.cpp b/src/ipc/process.cpp
index 43ed1f1bae..9036b80c45 100644
--- a/src/ipc/process.cpp
+++ b/src/ipc/process.cpp
@@ -30,8 +30,8 @@ public:
return mp::SpawnProcess(pid, [&](int fd) {
fs::path path = argv0_path;
path.remove_filename();
- path.append(new_exe_name);
- return std::vector<std::string>{path.string(), "-ipcfd", strprintf("%i", fd)};
+ path /= fs::PathFromString(new_exe_name);
+ return std::vector<std::string>{fs::PathToString(path), "-ipcfd", strprintf("%i", fd)};
});
}
int waitSpawned(int pid) override { return mp::WaitProcess(pid); }
diff --git a/src/logging.cpp b/src/logging.cpp
index a352e106e5..1efce21bdb 100644
--- a/src/logging.cpp
+++ b/src/logging.cpp
@@ -161,6 +161,7 @@ const CLogCategoryDesc LogCategories[] =
{BCLog::IPC, "ipc"},
{BCLog::LOCK, "lock"},
{BCLog::UTIL, "util"},
+ {BCLog::BLOCKSTORE, "blockstorage"},
{BCLog::ALL, "1"},
{BCLog::ALL, "all"},
};
diff --git a/src/logging.h b/src/logging.h
index 02e64a7c48..f46104364c 100644
--- a/src/logging.h
+++ b/src/logging.h
@@ -61,6 +61,7 @@ namespace BCLog {
IPC = (1 << 23),
LOCK = (1 << 24),
UTIL = (1 << 25),
+ BLOCKSTORE = (1 << 26),
ALL = ~(uint32_t)0,
};
diff --git a/src/merkleblock.h b/src/merkleblock.h
index 0e4ed72130..70749b6378 100644
--- a/src/merkleblock.h
+++ b/src/merkleblock.h
@@ -6,10 +6,10 @@
#ifndef BITCOIN_MERKLEBLOCK_H
#define BITCOIN_MERKLEBLOCK_H
+#include <common/bloom.h>
+#include <primitives/block.h>
#include <serialize.h>
#include <uint256.h>
-#include <primitives/block.h>
-#include <bloom.h>
#include <vector>
diff --git a/src/net.cpp b/src/net.cpp
index 7271ff22b2..ad558dd598 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -1295,9 +1295,8 @@ void CConnman::NotifyNumConnectionsChanged()
}
}
-bool CConnman::ShouldRunInactivityChecks(const CNode& node, std::optional<int64_t> now_in) const
+bool CConnman::ShouldRunInactivityChecks(const CNode& node, int64_t now) const
{
- const int64_t now = now_in ? now_in.value() : GetTimeSeconds();
return node.nTimeConnected + m_peer_connect_timeout < now;
}
diff --git a/src/net.h b/src/net.h
index e2071414b4..48dfb3043f 100644
--- a/src/net.h
+++ b/src/net.h
@@ -7,8 +7,8 @@
#define BITCOIN_NET_H
#include <addrman.h>
-#include <bloom.h>
#include <chainparams.h>
+#include <common/bloom.h>
#include <compat.h>
#include <consensus/amount.h>
#include <crypto/siphash.h>
@@ -942,7 +942,7 @@ public:
std::chrono::microseconds PoissonNextSendInbound(std::chrono::microseconds now, std::chrono::seconds average_interval);
/** Return true if we should disconnect the peer for failing an inactivity check. */
- bool ShouldRunInactivityChecks(const CNode& node, std::optional<int64_t> now=std::nullopt) const;
+ bool ShouldRunInactivityChecks(const CNode& node, int64_t secs_now) const;
private:
struct ListenSocket {
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 66b99aa2bb..13f13d5285 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -2960,16 +2960,17 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
best_block = &inv.hash;
}
} else if (inv.IsGenTxMsg()) {
+ if (reject_tx_invs) {
+ LogPrint(BCLog::NET, "transaction (%s) inv sent in violation of protocol, disconnecting peer=%d\n", inv.hash.ToString(), pfrom.GetId());
+ pfrom.fDisconnect = true;
+ return;
+ }
const GenTxid gtxid = ToGenTxid(inv);
const bool fAlreadyHave = AlreadyHaveTx(gtxid);
LogPrint(BCLog::NET, "got inv: %s %s peer=%d\n", inv.ToString(), fAlreadyHave ? "have" : "new", pfrom.GetId());
pfrom.AddKnownTx(inv.hash);
- if (reject_tx_invs) {
- LogPrint(BCLog::NET, "transaction (%s) inv sent in violation of protocol, disconnecting peer=%d\n", inv.hash.ToString(), pfrom.GetId());
- pfrom.fDisconnect = true;
- return;
- } else if (!fAlreadyHave && !m_chainman.ActiveChainstate().IsInitialBlockDownload()) {
+ if (!fAlreadyHave && !m_chainman.ActiveChainstate().IsInitialBlockDownload()) {
AddTxAnnouncement(pfrom, gtxid, current_time);
}
} else {
@@ -3242,12 +3243,12 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// already; and an adversary can already relay us old transactions
// (older than our recency filter) if trying to DoS us, without any need
// for witness malleation.
- if (AlreadyHaveTx(GenTxid(/* is_wtxid=*/true, wtxid))) {
+ if (AlreadyHaveTx(GenTxid::Wtxid(wtxid))) {
if (pfrom.HasPermission(NetPermissionFlags::ForceRelay)) {
// Always relay transactions received from peers with forcerelay
// permission, even if they were already in the mempool, allowing
// the node to function as a gateway for nodes hidden behind it.
- if (!m_mempool.exists(tx.GetHash())) {
+ if (!m_mempool.exists(GenTxid::Txid(tx.GetHash()))) {
LogPrintf("Not relaying non-mempool transaction %s from forcerelay peer=%d\n", tx.GetHash().ToString(), pfrom.GetId());
} else {
LogPrintf("Force relaying tx %s from peer=%d\n", tx.GetHash().ToString(), pfrom.GetId());
@@ -3312,7 +3313,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// wtxidrelay peers.
// Eventually we should replace this with an improved
// protocol for getting all unconfirmed parents.
- const GenTxid gtxid{/* is_wtxid=*/false, parent_txid};
+ const auto gtxid{GenTxid::Txid(parent_txid)};
pfrom.AddKnownTx(parent_txid);
if (!AlreadyHaveTx(gtxid)) AddTxAnnouncement(pfrom, gtxid, current_time);
}
@@ -4312,8 +4313,11 @@ void PeerManagerImpl::CheckForStaleTipAndEvictPeers()
void PeerManagerImpl::MaybeSendPing(CNode& node_to, Peer& peer, std::chrono::microseconds now)
{
- if (m_connman.ShouldRunInactivityChecks(node_to) && peer.m_ping_nonce_sent &&
+ if (m_connman.ShouldRunInactivityChecks(node_to, std::chrono::duration_cast<std::chrono::seconds>(now).count()) &&
+ peer.m_ping_nonce_sent &&
now > peer.m_ping_start.load() + std::chrono::seconds{TIMEOUT_INTERVAL}) {
+ // The ping timeout is using mocktime. To disable the check during
+ // testing, increase -peertimeout.
LogPrint(BCLog::NET, "ping timeout: %fs peer=%d\n", 0.000001 * count_microseconds(now - peer.m_ping_start.load()), peer.m_id);
node_to.fDisconnect = true;
return;
diff --git a/src/node/blockstorage.cpp b/src/node/blockstorage.cpp
index 0b7df9bd9a..53bc2b5069 100644
--- a/src/node/blockstorage.cpp
+++ b/src/node/blockstorage.cpp
@@ -68,13 +68,14 @@ void CleanupBlockRevFiles()
LogPrintf("Removing unusable blk?????.dat and rev?????.dat files for -reindex with -prune\n");
fs::path blocksdir = gArgs.GetBlocksDirPath();
for (fs::directory_iterator it(blocksdir); it != fs::directory_iterator(); it++) {
+ const std::string path = fs::PathToString(it->path().filename());
if (fs::is_regular_file(*it) &&
- it->path().filename().string().length() == 12 &&
- it->path().filename().string().substr(8,4) == ".dat")
+ path.length() == 12 &&
+ path.substr(8,4) == ".dat")
{
- if (it->path().filename().string().substr(0, 3) == "blk") {
- mapBlockFiles[it->path().filename().string().substr(3, 5)] = it->path();
- } else if (it->path().filename().string().substr(0, 3) == "rev") {
+ if (path.substr(0, 3) == "blk") {
+ mapBlockFiles[path.substr(3, 5)] = it->path();
+ } else if (path.substr(0, 3) == "rev") {
remove(it->path());
}
}
@@ -204,7 +205,7 @@ void UnlinkPrunedFiles(const std::set<int>& setFilesToPrune)
FlatFilePos pos(*it, 0);
fs::remove(BlockFileSeq().FileName(pos));
fs::remove(UndoFileSeq().FileName(pos));
- LogPrintf("Prune: %s deleted blk/rev (%05u)\n", __func__, *it);
+ LogPrint(BCLog::BLOCKSTORE, "Prune: %s deleted blk/rev (%05u)\n", __func__, *it);
}
}
@@ -261,7 +262,7 @@ bool FindBlockPos(FlatFilePos& pos, unsigned int nAddSize, unsigned int nHeight,
if ((int)nFile != nLastBlockFile) {
if (!fKnown) {
- LogPrint(BCLog::VALIDATION, "Leaving block file %i: %s\n", nLastBlockFile, vinfoBlockFile[nLastBlockFile].ToString());
+ LogPrint(BCLog::BLOCKSTORE, "Leaving block file %i: %s\n", nLastBlockFile, vinfoBlockFile[nLastBlockFile].ToString());
}
FlushBlockFile(!fKnown, finalize_undo);
nLastBlockFile = nFile;
@@ -527,14 +528,14 @@ void ThreadImport(ChainstateManager& chainman, std::vector<fs::path> vImportFile
for (const fs::path& path : vImportFiles) {
FILE* file = fsbridge::fopen(path, "rb");
if (file) {
- LogPrintf("Importing blocks file %s...\n", path.string());
+ LogPrintf("Importing blocks file %s...\n", fs::PathToString(path));
chainman.ActiveChainstate().LoadExternalBlockFile(file);
if (ShutdownRequested()) {
LogPrintf("Shutdown requested. Exit %s\n", __func__);
return;
}
} else {
- LogPrintf("Warning: Could not open blocks file %s\n", path.string());
+ LogPrintf("Warning: Could not open blocks file %s\n", fs::PathToString(path));
}
}
diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp
index 73f4036057..192caf7994 100644
--- a/src/node/interfaces.cpp
+++ b/src/node/interfaces.cpp
@@ -555,7 +555,7 @@ public:
{
if (!m_node.mempool) return false;
LOCK(m_node.mempool->cs);
- return m_node.mempool->exists(txid);
+ return m_node.mempool->exists(GenTxid::Txid(txid));
}
bool hasDescendantsInMempool(const uint256& txid) override
{
diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp
index 2ae5798ebe..d8c21bd833 100644
--- a/src/policy/fees.cpp
+++ b/src/policy/fees.cpp
@@ -527,7 +527,7 @@ CBlockPolicyEstimator::CBlockPolicyEstimator()
fs::path est_filepath = gArgs.GetDataDirNet() / FEE_ESTIMATES_FILENAME;
CAutoFile est_file(fsbridge::fopen(est_filepath, "rb"), SER_DISK, CLIENT_VERSION);
if (est_file.IsNull() || !Read(est_file)) {
- LogPrintf("Failed to read fee estimates from %s. Continue anyway.\n", est_filepath.string());
+ LogPrintf("Failed to read fee estimates from %s. Continue anyway.\n", fs::PathToString(est_filepath));
}
}
@@ -549,7 +549,7 @@ void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, boo
if (txHeight != nBestSeenHeight) {
// Ignore side chains and re-orgs; assuming they are random they don't
// affect the estimate. We'll potentially double count transactions in 1-block reorgs.
- // Ignore txs if BlockPolicyEstimator is not in sync with ::ChainActive().Tip().
+ // Ignore txs if BlockPolicyEstimator is not in sync with ActiveChain().Tip().
// It will be synced next time a block is processed.
return;
}
@@ -887,7 +887,7 @@ void CBlockPolicyEstimator::Flush() {
fs::path est_filepath = gArgs.GetDataDirNet() / FEE_ESTIMATES_FILENAME;
CAutoFile est_file(fsbridge::fopen(est_filepath, "wb"), SER_DISK, CLIENT_VERSION);
if (est_file.IsNull() || !Write(est_file)) {
- LogPrintf("Failed to write fee estimates to %s. Continue anyway.\n", est_filepath.string());
+ LogPrintf("Failed to write fee estimates to %s. Continue anyway.\n", fs::PathToString(est_filepath));
}
}
diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp
index 9e433584e7..fced397e51 100644
--- a/src/policy/policy.cpp
+++ b/src/policy/policy.cpp
@@ -22,7 +22,7 @@ CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFeeIn)
// so dust is a spendable txout less than
// 182*dustRelayFee/1000 (in satoshis).
// 546 satoshis at the default rate of 3000 sat/kvB.
- // A typical spendable segwit txout is 31 bytes big, and will
+ // A typical spendable segwit P2WPKH txout is 31 bytes big, and will
// need a CTxIn of at least 67 bytes to spend:
// so dust is a spendable txout less than
// 98*dustRelayFee/1000 (in satoshis).
@@ -34,6 +34,11 @@ CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFeeIn)
int witnessversion = 0;
std::vector<unsigned char> witnessprogram;
+ // Note this computation is for spending a Segwit v0 P2WPKH output (a 33 bytes
+ // public key + an ECDSA signature). For Segwit v1 Taproot outputs the minimum
+ // satisfaction is lower (a single BIP340 signature) but this computation was
+ // kept to not further reduce the dust level.
+ // See discussion in https://github.com/bitcoin/bitcoin/pull/22779 for details.
if (txout.scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) {
// sum the sizes of the parts of a transaction input
// with 75% segwit discount applied to the script size.
diff --git a/src/policy/rbf.cpp b/src/policy/rbf.cpp
index 7ac2e22006..7e6b0cf245 100644
--- a/src/policy/rbf.cpp
+++ b/src/policy/rbf.cpp
@@ -22,7 +22,7 @@ RBFTransactionState IsRBFOptIn(const CTransaction& tx, const CTxMemPool& pool)
// If this transaction is not in our mempool, then we can't be sure
// we will know about all its inputs.
- if (!pool.exists(tx.GetHash())) {
+ if (!pool.exists(GenTxid::Txid(tx.GetHash()))) {
return RBFTransactionState::UNKNOWN;
}
@@ -98,7 +98,7 @@ std::optional<std::string> HasNoNewUnconfirmed(const CTransaction& tx,
if (!parents_of_conflicts.count(tx.vin[j].prevout.hash)) {
// Rather than check the UTXO set - potentially expensive - it's cheaper to just check
// if the new input refers to a tx that's in the mempool.
- if (pool.exists(tx.vin[j].prevout.hash)) {
+ if (pool.exists(GenTxid::Txid(tx.vin[j].prevout.hash))) {
return strprintf("replacement %s adds unconfirmed input, idx %d",
tx.GetHash().ToString(), j);
}
diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h
index 46db39f8db..947c1c60bb 100644
--- a/src/primitives/transaction.h
+++ b/src/primitives/transaction.h
@@ -391,8 +391,11 @@ class GenTxid
{
bool m_is_wtxid;
uint256 m_hash;
-public:
GenTxid(bool is_wtxid, const uint256& hash) : m_is_wtxid(is_wtxid), m_hash(hash) {}
+
+public:
+ static GenTxid Txid(const uint256& hash) { return GenTxid{false, hash}; }
+ static GenTxid Wtxid(const uint256& hash) { return GenTxid{true, hash}; }
bool IsWtxid() const { return m_is_wtxid; }
const uint256& GetHash() const { return m_hash; }
friend bool operator==(const GenTxid& a, const GenTxid& b) { return a.m_is_wtxid == b.m_is_wtxid && a.m_hash == b.m_hash; }
diff --git a/src/protocol.cpp b/src/protocol.cpp
index 2e70b41e4c..7506c81815 100644
--- a/src/protocol.cpp
+++ b/src/protocol.cpp
@@ -223,5 +223,5 @@ std::vector<std::string> serviceFlagsToStr(uint64_t flags)
GenTxid ToGenTxid(const CInv& inv)
{
assert(inv.IsGenTxMsg());
- return {inv.IsMsgWtx(), inv.hash};
+ return inv.IsMsgWtx() ? GenTxid::Wtxid(inv.hash) : GenTxid::Txid(inv.hash);
}
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index 610637360b..b68ce39b53 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -1304,8 +1304,6 @@ void BitcoinGUI::setHDStatus(bool privkeyDisabled, int hdEnabled)
labelWalletHDStatusIcon->setThemedPixmap(privkeyDisabled ? QStringLiteral(":/icons/eye") : hdEnabled ? QStringLiteral(":/icons/hd_enabled") : QStringLiteral(":/icons/hd_disabled"), STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE);
labelWalletHDStatusIcon->setToolTip(privkeyDisabled ? tr("Private key <b>disabled</b>") : hdEnabled ? tr("HD key generation is <b>enabled</b>") : tr("HD key generation is <b>disabled</b>"));
labelWalletHDStatusIcon->show();
- // eventually disable the QLabel to set its opacity to 50%
- labelWalletHDStatusIcon->setEnabled(hdEnabled);
}
void BitcoinGUI::setEncryptionStatus(int status)
diff --git a/src/qt/forms/createwalletdialog.ui b/src/qt/forms/createwalletdialog.ui
index b11fb026b0..56adbe17a5 100644
--- a/src/qt/forms/createwalletdialog.ui
+++ b/src/qt/forms/createwalletdialog.ui
@@ -107,6 +107,9 @@
<property name="text">
<string>Descriptor Wallet</string>
</property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
</widget>
</item>
<item>
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index 12d3a48d01..4262866f32 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -653,12 +653,12 @@ void setClipboard(const QString& str)
fs::path qstringToBoostPath(const QString &path)
{
- return fs::path(path.toStdString());
+ return fs::u8path(path.toStdString());
}
QString boostPathToQString(const fs::path &path)
{
- return QString::fromStdString(path.string());
+ return QString::fromStdString(path.u8string());
}
QString NetworkToQString(Network net)
diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp
index 4c78fba752..2ca4b6a21e 100644
--- a/src/qt/intro.cpp
+++ b/src/qt/intro.cpp
@@ -263,7 +263,7 @@ bool Intro::showIfNeeded(bool& did_show_intro, int64_t& prune_MiB)
* (to be consistent with bitcoind behavior)
*/
if(dataDir != GUIUtil::getDefaultDataDirectory()) {
- gArgs.SoftSetArg("-datadir", GUIUtil::qstringToBoostPath(dataDir).string()); // use OS locale for path setting
+ gArgs.SoftSetArg("-datadir", fs::PathToString(GUIUtil::qstringToBoostPath(dataDir))); // use OS locale for path setting
}
return true;
}
diff --git a/src/qt/test/addressbooktests.cpp b/src/qt/test/addressbooktests.cpp
index 0de781661a..729957699a 100644
--- a/src/qt/test/addressbooktests.cpp
+++ b/src/qt/test/addressbooktests.cpp
@@ -64,8 +64,12 @@ void TestAddAddressesToSendBook(interfaces::Node& node)
test.m_node.wallet_client = wallet_client.get();
node.setContext(&test.m_node);
std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(node.context()->chain.get(), "", CreateMockWalletDatabase());
- wallet->SetupLegacyScriptPubKeyMan();
wallet->LoadWallet();
+ wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
+ {
+ LOCK(wallet->cs_wallet);
+ wallet->SetupDescriptorScriptPubKeyMans();
+ }
auto build_address = [&wallet]() {
CKey key;
diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp
index 62b135d3f1..c74c8f25b3 100644
--- a/src/qt/test/wallettests.cpp
+++ b/src/qt/test/wallettests.cpp
@@ -143,11 +143,20 @@ void TestGUI(interfaces::Node& node)
node.setContext(&test.m_node);
std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(node.context()->chain.get(), "", CreateMockWalletDatabase());
wallet->LoadWallet();
+ wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
{
- auto spk_man = wallet->GetOrCreateLegacyScriptPubKeyMan();
- LOCK2(wallet->cs_wallet, spk_man->cs_KeyStore);
- wallet->SetAddressBook(GetDestinationForKey(test.coinbaseKey.GetPubKey(), wallet->m_default_address_type), "", "receive");
- spk_man->AddKeyPubKey(test.coinbaseKey, test.coinbaseKey.GetPubKey());
+ LOCK(wallet->cs_wallet);
+ wallet->SetupDescriptorScriptPubKeyMans();
+
+ // Add the coinbase key
+ FlatSigningProvider provider;
+ std::string error;
+ std::unique_ptr<Descriptor> desc = Parse("combo(" + EncodeSecret(test.coinbaseKey) + ")", provider, error, /* require_checksum=*/ false);
+ assert(desc);
+ WalletDescriptor w_desc(std::move(desc), 0, 0, 1, 1);
+ if (!wallet->AddWalletDescriptor(w_desc, provider, "", false)) assert(false);
+ CTxDestination dest = GetDestinationForKey(test.coinbaseKey.GetPubKey(), wallet->m_default_address_type);
+ wallet->SetAddressBook(dest, "", "receive");
wallet->SetLastBlockProcessed(105, node.context()->chainman->ActiveChain().Tip()->GetBlockHash());
}
{
diff --git a/src/rest.cpp b/src/rest.cpp
index f6e34c2d81..3746fd752a 100644
--- a/src/rest.cpp
+++ b/src/rest.cpp
@@ -262,7 +262,7 @@ static bool rest_headers(const std::any& context,
static bool rest_block(const std::any& context,
HTTPRequest* req,
const std::string& strURIPart,
- bool showTxDetails)
+ TxVerbosity tx_verbosity)
{
if (!CheckWarmup(req))
return false;
@@ -314,7 +314,7 @@ static bool rest_block(const std::any& context,
}
case RetFormat::JSON: {
- UniValue objBlock = blockToJSON(block, tip, pblockindex, showTxDetails);
+ UniValue objBlock = blockToJSON(block, tip, pblockindex, tx_verbosity);
std::string strJSON = objBlock.write() + "\n";
req->WriteHeader("Content-Type", "application/json");
req->WriteReply(HTTP_OK, strJSON);
@@ -329,12 +329,12 @@ static bool rest_block(const std::any& context,
static bool rest_block_extended(const std::any& context, HTTPRequest* req, const std::string& strURIPart)
{
- return rest_block(context, req, strURIPart, true);
+ return rest_block(context, req, strURIPart, TxVerbosity::SHOW_DETAILS_AND_PREVOUT);
}
static bool rest_block_notxdetails(const std::any& context, HTTPRequest* req, const std::string& strURIPart)
{
- return rest_block(context, req, strURIPart, false);
+ return rest_block(context, req, strURIPart, TxVerbosity::SHOW_TXID);
}
// A bit of a hack - dependency on a function defined in rpc/blockchain.cpp
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index ac746de32f..aa7a55e7a9 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -200,7 +200,7 @@ UniValue blockheaderToJSON(const CBlockIndex* tip, const CBlockIndex* blockindex
return result;
}
-UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, bool txDetails)
+UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, TxVerbosity verbosity)
{
UniValue result = blockheaderToJSON(tip, blockindex);
@@ -208,22 +208,29 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn
result.pushKV("size", (int)::GetSerializeSize(block, PROTOCOL_VERSION));
result.pushKV("weight", (int)::GetBlockWeight(block));
UniValue txs(UniValue::VARR);
- if (txDetails) {
- CBlockUndo blockUndo;
- const bool have_undo = !IsBlockPruned(blockindex) && UndoReadFromDisk(blockUndo, blockindex);
- for (size_t i = 0; i < block.vtx.size(); ++i) {
- const CTransactionRef& tx = block.vtx.at(i);
- // coinbase transaction (i == 0) doesn't have undo data
- const CTxUndo* txundo = (have_undo && i) ? &blockUndo.vtxundo.at(i - 1) : nullptr;
- UniValue objTx(UniValue::VOBJ);
- TxToUniv(*tx, uint256(), objTx, true, RPCSerializationFlags(), txundo);
- txs.push_back(objTx);
- }
- } else {
- for (const CTransactionRef& tx : block.vtx) {
- txs.push_back(tx->GetHash().GetHex());
- }
+
+ switch (verbosity) {
+ case TxVerbosity::SHOW_TXID:
+ for (const CTransactionRef& tx : block.vtx) {
+ txs.push_back(tx->GetHash().GetHex());
+ }
+ break;
+
+ case TxVerbosity::SHOW_DETAILS:
+ case TxVerbosity::SHOW_DETAILS_AND_PREVOUT:
+ CBlockUndo blockUndo;
+ const bool have_undo = !IsBlockPruned(blockindex) && UndoReadFromDisk(blockUndo, blockindex);
+
+ for (size_t i = 0; i < block.vtx.size(); ++i) {
+ const CTransactionRef& tx = block.vtx.at(i);
+ // coinbase transaction (i.e. i == 0) doesn't have undo data
+ const CTxUndo* txundo = (have_undo && i > 0) ? &blockUndo.vtxundo.at(i - 1) : nullptr;
+ UniValue objTx(UniValue::VOBJ);
+ TxToUniv(*tx, uint256(), objTx, true, RPCSerializationFlags(), txundo, verbosity);
+ txs.push_back(objTx);
+ }
}
+
result.pushKV("tx", txs);
return result;
@@ -509,7 +516,7 @@ static void entryToJSON(const CTxMemPool& pool, UniValue& info, const CTxMemPool
std::set<std::string> setDepends;
for (const CTxIn& txin : tx.vin)
{
- if (pool.exists(txin.prevout.hash))
+ if (pool.exists(GenTxid::Txid(txin.prevout.hash)))
setDepends.insert(txin.prevout.hash.ToString());
}
@@ -931,7 +938,8 @@ static RPCHelpMan getblock()
return RPCHelpMan{"getblock",
"\nIf verbosity is 0, returns a string that is serialized, hex-encoded data for block 'hash'.\n"
"If verbosity is 1, returns an Object with information about block <hash>.\n"
- "If verbosity is 2, returns an Object with information about block <hash> and information about each transaction. \n",
+ "If verbosity is 2, returns an Object with information about block <hash> and information about each transaction.\n"
+ "If verbosity is 3, returns an Object with information about block <hash> and information about each transaction, including prevout information for inputs (only for unpruned blocks in the current best chain).\n",
{
{"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash"},
{"verbosity|verbose", RPCArg::Type::NUM, RPCArg::Default{1}, "0 for hex-encoded data, 1 for a json object, and 2 for json object with transaction data"},
@@ -1018,7 +1026,16 @@ static RPCHelpMan getblock()
return strHex;
}
- return blockToJSON(block, tip, pblockindex, verbosity >= 2);
+ TxVerbosity tx_verbosity;
+ if (verbosity == 1) {
+ tx_verbosity = TxVerbosity::SHOW_TXID;
+ } else if (verbosity == 2) {
+ tx_verbosity = TxVerbosity::SHOW_DETAILS;
+ } else {
+ tx_verbosity = TxVerbosity::SHOW_DETAILS_AND_PREVOUT;
+ }
+
+ return blockToJSON(block, tip, pblockindex, tx_verbosity);
},
};
}
@@ -2537,15 +2554,15 @@ static RPCHelpMan dumptxoutset()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- const fs::path path = fsbridge::AbsPathJoin(gArgs.GetDataDirNet(), request.params[0].get_str());
+ const fs::path path = fsbridge::AbsPathJoin(gArgs.GetDataDirNet(), fs::u8path(request.params[0].get_str()));
// Write to a temporary path and then move into `path` on completion
// to avoid confusion due to an interruption.
- const fs::path temppath = fsbridge::AbsPathJoin(gArgs.GetDataDirNet(), request.params[0].get_str() + ".incomplete");
+ const fs::path temppath = fsbridge::AbsPathJoin(gArgs.GetDataDirNet(), fs::u8path(request.params[0].get_str() + ".incomplete"));
if (fs::exists(path)) {
throw JSONRPCError(
RPC_INVALID_PARAMETER,
- path.string() + " already exists. If you are sure this is what you want, "
+ path.u8string() + " already exists. If you are sure this is what you want, "
"move it out of the way first");
}
@@ -2555,7 +2572,7 @@ static RPCHelpMan dumptxoutset()
UniValue result = CreateUTXOSnapshot(node, node.chainman->ActiveChainstate(), afile);
fs::rename(temppath, path);
- result.pushKV("path", path.string());
+ result.pushKV("path", path.u8string());
return result;
},
};
diff --git a/src/rpc/blockchain.h b/src/rpc/blockchain.h
index 09e471afdd..d9c6761f47 100644
--- a/src/rpc/blockchain.h
+++ b/src/rpc/blockchain.h
@@ -6,6 +6,7 @@
#define BITCOIN_RPC_BLOCKCHAIN_H
#include <consensus/amount.h>
+#include <core_io.h>
#include <streams.h>
#include <sync.h>
@@ -38,7 +39,7 @@ double GetDifficulty(const CBlockIndex* blockindex);
void RPCNotifyBlockChange(const CBlockIndex*);
/** Block description to JSON */
-UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, bool txDetails = false) LOCKS_EXCLUDED(cs_main);
+UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, TxVerbosity verbosity) LOCKS_EXCLUDED(cs_main);
/** Mempool information to JSON */
UniValue MempoolInfoToJSON(const CTxMemPool& pool);
diff --git a/src/rpc/request.cpp b/src/rpc/request.cpp
index a7866474e1..3245e04cdf 100644
--- a/src/rpc/request.cpp
+++ b/src/rpc/request.cpp
@@ -70,7 +70,7 @@ static fs::path GetAuthCookieFile(bool temp=false)
if (temp) {
arg += ".tmp";
}
- return AbsPathForConfigVal(fs::path(arg));
+ return AbsPathForConfigVal(fs::PathFromString(arg));
}
bool GenerateAuthCookie(std::string *cookie_out)
@@ -87,7 +87,7 @@ bool GenerateAuthCookie(std::string *cookie_out)
fs::path filepath_tmp = GetAuthCookieFile(true);
file.open(filepath_tmp);
if (!file.is_open()) {
- LogPrintf("Unable to open cookie authentication file %s for writing\n", filepath_tmp.string());
+ LogPrintf("Unable to open cookie authentication file %s for writing\n", fs::PathToString(filepath_tmp));
return false;
}
file << cookie;
@@ -95,10 +95,10 @@ bool GenerateAuthCookie(std::string *cookie_out)
fs::path filepath = GetAuthCookieFile(false);
if (!RenameOver(filepath_tmp, filepath)) {
- LogPrintf("Unable to rename cookie authentication file %s to %s\n", filepath_tmp.string(), filepath.string());
+ LogPrintf("Unable to rename cookie authentication file %s to %s\n", fs::PathToString(filepath_tmp), fs::PathToString(filepath));
return false;
}
- LogPrintf("Generated RPC authentication cookie %s\n", filepath.string());
+ LogPrintf("Generated RPC authentication cookie %s\n", fs::PathToString(filepath));
if (cookie_out)
*cookie_out = cookie;
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
index 0d02ec5c47..9bcfba3507 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -239,7 +239,7 @@ static RPCHelpMan getrpcinfo()
UniValue result(UniValue::VOBJ);
result.pushKV("active_commands", active_commands);
- const std::string path = LogInstance().m_file_path.string();
+ const std::string path = LogInstance().m_file_path.u8string();
UniValue log_path(UniValue::VSTR, path);
result.pushKV("logpath", log_path);
diff --git a/src/support/allocators/secure.h b/src/support/allocators/secure.h
index 0e31ad3ce3..c4923dc56f 100644
--- a/src/support/allocators/secure.h
+++ b/src/support/allocators/secure.h
@@ -9,6 +9,7 @@
#include <support/lockedpool.h>
#include <support/cleanse.h>
+#include <memory>
#include <string>
//
@@ -17,15 +18,13 @@
//
template <typename T>
struct secure_allocator : public std::allocator<T> {
- // MSVC8 default copy constructor is broken
- typedef std::allocator<T> base;
- typedef typename base::size_type size_type;
- typedef typename base::difference_type difference_type;
- typedef typename base::pointer pointer;
- typedef typename base::const_pointer const_pointer;
- typedef typename base::reference reference;
- typedef typename base::const_reference const_reference;
- typedef typename base::value_type value_type;
+ using base = std::allocator<T>;
+ using traits = std::allocator_traits<base>;
+ using size_type = typename traits::size_type;
+ using difference_type = typename traits::difference_type;
+ using pointer = typename traits::pointer;
+ using const_pointer = typename traits::const_pointer;
+ using value_type = typename traits::value_type;
secure_allocator() noexcept {}
secure_allocator(const secure_allocator& a) noexcept : base(a) {}
template <typename U>
diff --git a/src/support/allocators/zeroafterfree.h b/src/support/allocators/zeroafterfree.h
index 418f0ee656..77de4b1e69 100644
--- a/src/support/allocators/zeroafterfree.h
+++ b/src/support/allocators/zeroafterfree.h
@@ -13,15 +13,13 @@
template <typename T>
struct zero_after_free_allocator : public std::allocator<T> {
- // MSVC8 default copy constructor is broken
- typedef std::allocator<T> base;
- typedef typename base::size_type size_type;
- typedef typename base::difference_type difference_type;
- typedef typename base::pointer pointer;
- typedef typename base::const_pointer const_pointer;
- typedef typename base::reference reference;
- typedef typename base::const_reference const_reference;
- typedef typename base::value_type value_type;
+ using base = std::allocator<T>;
+ using traits = std::allocator_traits<base>;
+ using size_type = typename traits::size_type;
+ using difference_type = typename traits::difference_type;
+ using pointer = typename traits::pointer;
+ using const_pointer = typename traits::const_pointer;
+ using value_type = typename traits::value_type;
zero_after_free_allocator() noexcept {}
zero_after_free_allocator(const zero_after_free_allocator& a) noexcept : base(a) {}
template <typename U>
diff --git a/src/test/bloom_tests.cpp b/src/test/bloom_tests.cpp
index 23ef2062ef..fe5ed0a3c8 100644
--- a/src/test/bloom_tests.cpp
+++ b/src/test/bloom_tests.cpp
@@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <bloom.h>
+#include <common/bloom.h>
#include <clientversion.h>
#include <key.h>
diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp
index 5b3b39fdb8..1483bd3cb3 100644
--- a/src/test/crypto_tests.cpp
+++ b/src/test/crypto_tests.cpp
@@ -694,8 +694,8 @@ BOOST_AUTO_TEST_CASE(chacha20_poly1305_aead_testvector)
TestChaCha20Poly1305AEAD(true, 0,
/* m */ "0000000000000000000000000000000000000000000000000000000000000000",
- /* k1 (payload) */ "0000000000000000000000000000000000000000000000000000000000000000",
- /* k2 (AAD) */ "0000000000000000000000000000000000000000000000000000000000000000",
+ /* k1 (AAD) */ "0000000000000000000000000000000000000000000000000000000000000000",
+ /* k2 (payload) */ "0000000000000000000000000000000000000000000000000000000000000000",
/* AAD keystream */ "76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc8b770dc7da41597c5157488d7724e03fb8d84a376a43b8f41518a11cc387b669b2ee6586",
/* encrypted message & MAC */ "76b8e09f07e7be5551387a98ba977c732d080dcb0f29a048e3656912c6533e32d2fc11829c1b6c1df1f551cd6131ff08",
/* encrypted message & MAC at sequence 999 */ "b0a03d5bd2855d60699e7d3a3133fa47be740fe4e4c1f967555e2d9271f31c3aaa7aa16ec62c5e24f040c08bb20c3598");
diff --git a/src/test/denialofservice_tests.cpp b/src/test/denialofservice_tests.cpp
index 0bfe6eecd9..668ff150ee 100644
--- a/src/test/denialofservice_tests.cpp
+++ b/src/test/denialofservice_tests.cpp
@@ -52,6 +52,8 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
{
const CChainParams& chainparams = Params();
auto connman = std::make_unique<CConnman>(0x1337, 0x1337, *m_node.addrman);
+ // Disable inactivity checks for this test to avoid interference
+ static_cast<ConnmanTestMsg*>(connman.get())->SetPeerConnectTimeout(99999);
auto peerLogic = PeerManager::make(chainparams, *connman, *m_node.addrman, nullptr,
*m_node.chainman, *m_node.mempool, false);
diff --git a/src/test/fs_tests.cpp b/src/test/fs_tests.cpp
index 526a3c27be..ecb838a7dd 100644
--- a/src/test/fs_tests.cpp
+++ b/src/test/fs_tests.cpp
@@ -11,6 +11,33 @@
BOOST_FIXTURE_TEST_SUITE(fs_tests, BasicTestingSetup)
+BOOST_AUTO_TEST_CASE(fsbridge_pathtostring)
+{
+ std::string u8_str = "fs_tests_₿_🏃";
+ BOOST_CHECK_EQUAL(fs::PathToString(fs::PathFromString(u8_str)), u8_str);
+ BOOST_CHECK_EQUAL(fs::u8path(u8_str).u8string(), u8_str);
+ BOOST_CHECK_EQUAL(fs::PathFromString(u8_str).u8string(), u8_str);
+ BOOST_CHECK_EQUAL(fs::PathToString(fs::u8path(u8_str)), u8_str);
+#ifndef WIN32
+ // On non-windows systems, verify that arbitrary byte strings containing
+ // invalid UTF-8 can be round tripped successfully with PathToString and
+ // PathFromString. On non-windows systems, paths are just byte strings so
+ // these functions do not do any encoding. On windows, paths are Unicode,
+ // and these functions do encoding and decoding, so the behavior of this
+ // test would be undefined.
+ std::string invalid_u8_str = "\xf0";
+ BOOST_CHECK_EQUAL(invalid_u8_str.size(), 1);
+ BOOST_CHECK_EQUAL(fs::PathToString(fs::PathFromString(invalid_u8_str)), invalid_u8_str);
+#endif
+}
+
+BOOST_AUTO_TEST_CASE(fsbridge_stem)
+{
+ std::string test_filename = "fs_tests_₿_🏃.dat";
+ std::string expected_stem = "fs_tests_₿_🏃";
+ BOOST_CHECK_EQUAL(fs::PathToString(fs::PathFromString(test_filename).stem()), expected_stem);
+}
+
BOOST_AUTO_TEST_CASE(fsbridge_fstream)
{
fs::path tmpfolder = m_args.GetDataDirBase();
diff --git a/src/test/fuzz/banman.cpp b/src/test/fuzz/banman.cpp
index 561cc83c72..fbba25c404 100644
--- a/src/test/fuzz/banman.cpp
+++ b/src/test/fuzz/banman.cpp
@@ -48,7 +48,7 @@ FUZZ_TARGET_INIT(banman, initialize_banman)
const bool start_with_corrupted_banlist{fuzzed_data_provider.ConsumeBool()};
bool force_read_and_write_to_err{false};
if (start_with_corrupted_banlist) {
- assert(WriteBinaryFile(banlist_file.string() + ".json",
+ assert(WriteBinaryFile(banlist_file + ".json",
fuzzed_data_provider.ConsumeRandomLengthString()));
} else {
force_read_and_write_to_err = fuzzed_data_provider.ConsumeBool();
@@ -111,5 +111,5 @@ FUZZ_TARGET_INIT(banman, initialize_banman)
assert(banmap == banmap_read);
}
}
- fs::remove(banlist_file.string() + ".json");
+ fs::remove(fs::PathToString(banlist_file + ".json"));
}
diff --git a/src/test/fuzz/bloom_filter.cpp b/src/test/fuzz/bloom_filter.cpp
index c5bb8744a4..746591a176 100644
--- a/src/test/fuzz/bloom_filter.cpp
+++ b/src/test/fuzz/bloom_filter.cpp
@@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <bloom.h>
+#include <common/bloom.h>
#include <primitives/transaction.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
diff --git a/src/test/fuzz/rolling_bloom_filter.cpp b/src/test/fuzz/rolling_bloom_filter.cpp
index b9ed497e68..9c18ad49cb 100644
--- a/src/test/fuzz/rolling_bloom_filter.cpp
+++ b/src/test/fuzz/rolling_bloom_filter.cpp
@@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <bloom.h>
+#include <common/bloom.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
diff --git a/src/test/fuzz/txrequest.cpp b/src/test/fuzz/txrequest.cpp
index 72438ff2d7..a73bbcfc25 100644
--- a/src/test/fuzz/txrequest.cpp
+++ b/src/test/fuzz/txrequest.cpp
@@ -204,7 +204,7 @@ public:
}
// Call TxRequestTracker's implementation.
- m_tracker.ReceivedInv(peer, GenTxid{is_wtxid, TXHASHES[txhash]}, preferred, reqtime);
+ m_tracker.ReceivedInv(peer, is_wtxid ? GenTxid::Wtxid(TXHASHES[txhash]) : GenTxid::Txid(TXHASHES[txhash]), preferred, reqtime);
}
void RequestedTx(int peer, int txhash, std::chrono::microseconds exptime)
@@ -252,7 +252,7 @@ public:
for (int peer2 = 0; peer2 < MAX_PEERS; ++peer2) {
Announcement& ann2 = m_announcements[txhash][peer2];
if (ann2.m_state == State::REQUESTED && ann2.m_time <= m_now) {
- expected_expired.emplace_back(peer2, GenTxid{ann2.m_is_wtxid, TXHASHES[txhash]});
+ expected_expired.emplace_back(peer2, ann2.m_is_wtxid ? GenTxid::Wtxid(TXHASHES[txhash]) : GenTxid::Txid(TXHASHES[txhash]));
ann2.m_state = State::COMPLETED;
break;
}
diff --git a/src/test/mempool_tests.cpp b/src/test/mempool_tests.cpp
index bf36f8a6c9..b3497b8ef8 100644
--- a/src/test/mempool_tests.cpp
+++ b/src/test/mempool_tests.cpp
@@ -444,12 +444,12 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
pool.addUnchecked(entry.Fee(5000LL).FromTx(tx2));
pool.TrimToSize(pool.DynamicMemoryUsage()); // should do nothing
- BOOST_CHECK(pool.exists(tx1.GetHash()));
- BOOST_CHECK(pool.exists(tx2.GetHash()));
+ BOOST_CHECK(pool.exists(GenTxid::Txid(tx1.GetHash())));
+ BOOST_CHECK(pool.exists(GenTxid::Txid(tx2.GetHash())));
pool.TrimToSize(pool.DynamicMemoryUsage() * 3 / 4); // should remove the lower-feerate transaction
- BOOST_CHECK(pool.exists(tx1.GetHash()));
- BOOST_CHECK(!pool.exists(tx2.GetHash()));
+ BOOST_CHECK(pool.exists(GenTxid::Txid(tx1.GetHash())));
+ BOOST_CHECK(!pool.exists(GenTxid::Txid(tx2.GetHash())));
pool.addUnchecked(entry.FromTx(tx2));
CMutableTransaction tx3 = CMutableTransaction();
@@ -462,14 +462,14 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
pool.addUnchecked(entry.Fee(20000LL).FromTx(tx3));
pool.TrimToSize(pool.DynamicMemoryUsage() * 3 / 4); // tx3 should pay for tx2 (CPFP)
- BOOST_CHECK(!pool.exists(tx1.GetHash()));
- BOOST_CHECK(pool.exists(tx2.GetHash()));
- BOOST_CHECK(pool.exists(tx3.GetHash()));
+ BOOST_CHECK(!pool.exists(GenTxid::Txid(tx1.GetHash())));
+ BOOST_CHECK(pool.exists(GenTxid::Txid(tx2.GetHash())));
+ BOOST_CHECK(pool.exists(GenTxid::Txid(tx3.GetHash())));
pool.TrimToSize(GetVirtualTransactionSize(CTransaction(tx1))); // mempool is limited to tx1's size in memory usage, so nothing fits
- BOOST_CHECK(!pool.exists(tx1.GetHash()));
- BOOST_CHECK(!pool.exists(tx2.GetHash()));
- BOOST_CHECK(!pool.exists(tx3.GetHash()));
+ BOOST_CHECK(!pool.exists(GenTxid::Txid(tx1.GetHash())));
+ BOOST_CHECK(!pool.exists(GenTxid::Txid(tx2.GetHash())));
+ BOOST_CHECK(!pool.exists(GenTxid::Txid(tx3.GetHash())));
CFeeRate maxFeeRateRemoved(25000, GetVirtualTransactionSize(CTransaction(tx3)) + GetVirtualTransactionSize(CTransaction(tx2)));
BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), maxFeeRateRemoved.GetFeePerK() + 1000);
@@ -529,19 +529,19 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
// we only require this to remove, at max, 2 txn, because it's not clear what we're really optimizing for aside from that
pool.TrimToSize(pool.DynamicMemoryUsage() - 1);
- BOOST_CHECK(pool.exists(tx4.GetHash()));
- BOOST_CHECK(pool.exists(tx6.GetHash()));
- BOOST_CHECK(!pool.exists(tx7.GetHash()));
+ BOOST_CHECK(pool.exists(GenTxid::Txid(tx4.GetHash())));
+ BOOST_CHECK(pool.exists(GenTxid::Txid(tx6.GetHash())));
+ BOOST_CHECK(!pool.exists(GenTxid::Txid(tx7.GetHash())));
- if (!pool.exists(tx5.GetHash()))
+ if (!pool.exists(GenTxid::Txid(tx5.GetHash())))
pool.addUnchecked(entry.Fee(1000LL).FromTx(tx5));
pool.addUnchecked(entry.Fee(9000LL).FromTx(tx7));
pool.TrimToSize(pool.DynamicMemoryUsage() / 2); // should maximize mempool size by only removing 5/7
- BOOST_CHECK(pool.exists(tx4.GetHash()));
- BOOST_CHECK(!pool.exists(tx5.GetHash()));
- BOOST_CHECK(pool.exists(tx6.GetHash()));
- BOOST_CHECK(!pool.exists(tx7.GetHash()));
+ BOOST_CHECK(pool.exists(GenTxid::Txid(tx4.GetHash())));
+ BOOST_CHECK(!pool.exists(GenTxid::Txid(tx5.GetHash())));
+ BOOST_CHECK(pool.exists(GenTxid::Txid(tx6.GetHash())));
+ BOOST_CHECK(!pool.exists(GenTxid::Txid(tx7.GetHash())));
pool.addUnchecked(entry.Fee(1000LL).FromTx(tx5));
pool.addUnchecked(entry.Fee(9000LL).FromTx(tx7));
diff --git a/src/test/settings_tests.cpp b/src/test/settings_tests.cpp
index 340ce33d91..15cba9e3e5 100644
--- a/src/test/settings_tests.cpp
+++ b/src/test/settings_tests.cpp
@@ -80,19 +80,19 @@ BOOST_AUTO_TEST_CASE(ReadWrite)
"dupe": "dupe"
})");
BOOST_CHECK(!util::ReadSettings(path, values, errors));
- std::vector<std::string> dup_keys = {strprintf("Found duplicate key dupe in settings file %s", path.string())};
+ std::vector<std::string> dup_keys = {strprintf("Found duplicate key dupe in settings file %s", fs::PathToString(path))};
BOOST_CHECK_EQUAL_COLLECTIONS(errors.begin(), errors.end(), dup_keys.begin(), dup_keys.end());
// Check non-kv json files not allowed
WriteText(path, R"("non-kv")");
BOOST_CHECK(!util::ReadSettings(path, values, errors));
- std::vector<std::string> non_kv = {strprintf("Found non-object value \"non-kv\" in settings file %s", path.string())};
+ std::vector<std::string> non_kv = {strprintf("Found non-object value \"non-kv\" in settings file %s", fs::PathToString(path))};
BOOST_CHECK_EQUAL_COLLECTIONS(errors.begin(), errors.end(), non_kv.begin(), non_kv.end());
// Check invalid json not allowed
WriteText(path, R"(invalid json)");
BOOST_CHECK(!util::ReadSettings(path, values, errors));
- std::vector<std::string> fail_parse = {strprintf("Unable to parse settings file %s", path.string())};
+ std::vector<std::string> fail_parse = {strprintf("Unable to parse settings file %s", fs::PathToString(path))};
BOOST_CHECK_EQUAL_COLLECTIONS(errors.begin(), errors.end(), fail_parse.begin(), fail_parse.end());
}
diff --git a/src/test/txrequest_tests.cpp b/src/test/txrequest_tests.cpp
index 1d137b03b1..99d41882c9 100644
--- a/src/test/txrequest_tests.cpp
+++ b/src/test/txrequest_tests.cpp
@@ -221,7 +221,7 @@ public:
/** Generate a random GenTxid; the txhash follows NewTxHash; the is_wtxid flag is random. */
GenTxid NewGTxid(const std::vector<std::vector<NodeId>>& orders = {})
{
- return {InsecureRandBool(), NewTxHash(orders)};
+ return InsecureRandBool() ? GenTxid::Wtxid(NewTxHash(orders)) : GenTxid::Txid(NewTxHash(orders));
}
/** Generate a new random NodeId to use as peer. The same NodeId is never returned twice
@@ -494,8 +494,8 @@ void BuildWtxidTest(Scenario& scenario, int config)
auto peerT = scenario.NewPeer();
auto peerW = scenario.NewPeer();
auto txhash = scenario.NewTxHash();
- GenTxid txid{false, txhash};
- GenTxid wtxid{true, txhash};
+ auto txid{GenTxid::Txid(txhash)};
+ auto wtxid{GenTxid::Wtxid(txhash)};
auto reqtimeT = InsecureRandBool() ? MIN_TIME : scenario.Now() + RandomTime8s();
auto reqtimeW = InsecureRandBool() ? MIN_TIME : scenario.Now() + RandomTime8s();
diff --git a/src/test/util/chainstate.h b/src/test/util/chainstate.h
index 81ea4c38f5..e95573022c 100644
--- a/src/test/util/chainstate.h
+++ b/src/test/util/chainstate.h
@@ -36,7 +36,7 @@ CreateAndActivateUTXOSnapshot(NodeContext& node, const fs::path root, F malleati
UniValue result = CreateUTXOSnapshot(node, node.chainman->ActiveChainstate(), auto_outfile);
BOOST_TEST_MESSAGE(
- "Wrote UTXO snapshot to " << snapshot_path.make_preferred().string() << ": " << result.write());
+ "Wrote UTXO snapshot to " << fs::PathToString(snapshot_path.make_preferred()) << ": " << result.write());
// Read the written snapshot in and then activate it.
//
diff --git a/src/test/util/net.h b/src/test/util/net.h
index 939ec322ed..d89fc34b75 100644
--- a/src/test/util/net.h
+++ b/src/test/util/net.h
@@ -17,6 +17,12 @@
struct ConnmanTestMsg : public CConnman {
using CConnman::CConnman;
+
+ void SetPeerConnectTimeout(int64_t timeout)
+ {
+ m_peer_connect_timeout = timeout;
+ }
+
void AddTestNode(CNode& node)
{
LOCK(cs_vNodes);
diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp
index ebefa9974e..a3c7564d76 100644
--- a/src/test/util/setup_common.cpp
+++ b/src/test/util/setup_common.cpp
@@ -91,8 +91,8 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName, const std::ve
extra_args);
util::ThreadRename("test");
fs::create_directories(m_path_root);
- m_args.ForceSetArg("-datadir", m_path_root.string());
- gArgs.ForceSetArg("-datadir", m_path_root.string());
+ m_args.ForceSetArg("-datadir", fs::PathToString(m_path_root));
+ gArgs.ForceSetArg("-datadir", fs::PathToString(m_path_root));
gArgs.ClearPathCache();
{
SetupServerArgs(*m_node.args);
diff --git a/src/test/util/wallet.cpp b/src/test/util/wallet.cpp
index 061659818f..76c1bf93a5 100644
--- a/src/test/util/wallet.cpp
+++ b/src/test/util/wallet.cpp
@@ -25,16 +25,4 @@ std::string getnewaddress(CWallet& w)
return EncodeDestination(dest);
}
-void importaddress(CWallet& wallet, const std::string& address)
-{
- auto spk_man = wallet.GetLegacyScriptPubKeyMan();
- LOCK2(wallet.cs_wallet, spk_man->cs_KeyStore);
- const auto dest = DecodeDestination(address);
- assert(IsValidDestination(dest));
- const auto script = GetScriptForDestination(dest);
- wallet.MarkDirty();
- assert(!spk_man->HaveWatchOnly(script));
- if (!spk_man->AddWatchOnly(script, 0 /* nCreateTime */)) assert(false);
- wallet.SetAddressBook(dest, /* label */ "", "receive");
-}
#endif // ENABLE_WALLET
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index b5088d3c33..b1300d06ba 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -51,23 +51,23 @@ BOOST_AUTO_TEST_CASE(util_datadir)
{
// Use local args variable instead of m_args to avoid making assumptions about test setup
ArgsManager args;
- args.ForceSetArg("-datadir", m_path_root.string());
+ args.ForceSetArg("-datadir", fs::PathToString(m_path_root));
const fs::path dd_norm = args.GetDataDirBase();
- args.ForceSetArg("-datadir", dd_norm.string() + "/");
+ args.ForceSetArg("-datadir", fs::PathToString(dd_norm) + "/");
args.ClearPathCache();
BOOST_CHECK_EQUAL(dd_norm, args.GetDataDirBase());
- args.ForceSetArg("-datadir", dd_norm.string() + "/.");
+ args.ForceSetArg("-datadir", fs::PathToString(dd_norm) + "/.");
args.ClearPathCache();
BOOST_CHECK_EQUAL(dd_norm, args.GetDataDirBase());
- args.ForceSetArg("-datadir", dd_norm.string() + "/./");
+ args.ForceSetArg("-datadir", fs::PathToString(dd_norm) + "/./");
args.ClearPathCache();
BOOST_CHECK_EQUAL(dd_norm, args.GetDataDirBase());
- args.ForceSetArg("-datadir", dd_norm.string() + "/.//");
+ args.ForceSetArg("-datadir", fs::PathToString(dd_norm) + "/.//");
args.ClearPathCache();
BOOST_CHECK_EQUAL(dd_norm, args.GetDataDirBase());
}
@@ -1181,13 +1181,13 @@ BOOST_AUTO_TEST_CASE(util_ReadWriteSettings)
{
// Test writing setting.
TestArgsManager args1;
- args1.ForceSetArg("-datadir", m_path_root.string());
+ args1.ForceSetArg("-datadir", fs::PathToString(m_path_root));
args1.LockSettings([&](util::Settings& settings) { settings.rw_settings["name"] = "value"; });
args1.WriteSettingsFile();
// Test reading setting.
TestArgsManager args2;
- args2.ForceSetArg("-datadir", m_path_root.string());
+ args2.ForceSetArg("-datadir", fs::PathToString(m_path_root));
args2.ReadSettingsFile();
args2.LockSettings([&](util::Settings& settings) { BOOST_CHECK_EQUAL(settings.rw_settings["name"].get_str(), "value"); });
diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp
index f9caf48df8..55618a5c57 100644
--- a/src/torcontrol.cpp
+++ b/src/torcontrol.cpp
@@ -318,7 +318,7 @@ TorController::TorController(struct event_base* _base, const std::string& tor_co
// Read service private key if cached
std::pair<bool,std::string> pkf = ReadBinaryFile(GetPrivateKeyFile());
if (pkf.first) {
- LogPrint(BCLog::TOR, "tor: Reading cached private key from %s\n", GetPrivateKeyFile().string());
+ LogPrint(BCLog::TOR, "tor: Reading cached private key from %s\n", fs::PathToString(GetPrivateKeyFile()));
private_key = pkf.second;
}
}
@@ -356,9 +356,9 @@ void TorController::add_onion_cb(TorControlConnection& _conn, const TorControlRe
service = LookupNumeric(std::string(service_id+".onion"), Params().GetDefaultPort());
LogPrintf("tor: Got service ID %s, advertising service %s\n", service_id, service.ToString());
if (WriteBinaryFile(GetPrivateKeyFile(), private_key)) {
- LogPrint(BCLog::TOR, "tor: Cached service private key to %s\n", GetPrivateKeyFile().string());
+ LogPrint(BCLog::TOR, "tor: Cached service private key to %s\n", fs::PathToString(GetPrivateKeyFile()));
} else {
- LogPrintf("tor: Error writing service private key to %s\n", GetPrivateKeyFile().string());
+ LogPrintf("tor: Error writing service private key to %s\n", fs::PathToString(GetPrivateKeyFile()));
}
AddLocal(service, LOCAL_MANUAL);
// ... onion requested - keep connection open
@@ -508,7 +508,7 @@ void TorController::protocolinfo_cb(TorControlConnection& _conn, const TorContro
} else if (methods.count("SAFECOOKIE")) {
// Cookie: hexdump -e '32/1 "%02x""\n"' ~/.tor/control_auth_cookie
LogPrint(BCLog::TOR, "tor: Using SAFECOOKIE authentication, reading cookie authentication from %s\n", cookiefile);
- std::pair<bool,std::string> status_cookie = ReadBinaryFile(cookiefile, TOR_COOKIE_SIZE);
+ std::pair<bool,std::string> status_cookie = ReadBinaryFile(fs::PathFromString(cookiefile), TOR_COOKIE_SIZE);
if (status_cookie.first && status_cookie.second.size() == TOR_COOKIE_SIZE) {
// _conn.Command("AUTHENTICATE " + HexStr(status_cookie.second), std::bind(&TorController::auth_cb, this, std::placeholders::_1, std::placeholders::_2));
cookie = std::vector<uint8_t>(status_cookie.second.begin(), status_cookie.second.end());
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index 5a93f30c8a..70084ea1d1 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -895,8 +895,6 @@ TxMempoolInfo CTxMemPool::info(const GenTxid& gtxid) const
return GetInfo(i);
}
-TxMempoolInfo CTxMemPool::info(const uint256& txid) const { return info(GenTxid{false, txid}); }
-
void CTxMemPool::PrioritiseTransaction(const uint256& hash, const CAmount& nFeeDelta)
{
{
@@ -969,7 +967,7 @@ CTxMemPool::setEntries CTxMemPool::GetIterSet(const std::set<uint256>& hashes) c
bool CTxMemPool::HasNoInputsOf(const CTransaction &tx) const
{
for (unsigned int i = 0; i < tx.vin.size(); i++)
- if (exists(tx.vin[i].prevout.hash))
+ if (exists(GenTxid::Txid(tx.vin[i].prevout.hash)))
return false;
return true;
}
@@ -1140,7 +1138,7 @@ void CTxMemPool::TrimToSize(size_t sizelimit, std::vector<COutPoint>* pvNoSpends
if (pvNoSpendsRemaining) {
for (const CTransaction& tx : txn) {
for (const CTxIn& txin : tx.vin) {
- if (exists(txin.prevout.hash)) continue;
+ if (exists(GenTxid::Txid(txin.prevout.hash))) continue;
pvNoSpendsRemaining->push_back(txin.prevout);
}
}
diff --git a/src/txmempool.h b/src/txmempool.h
index 0be51db181..c63522225a 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -542,7 +542,7 @@ public:
* By design, it is guaranteed that:
*
* 1. Locking both `cs_main` and `mempool.cs` will give a view of mempool
- * that is consistent with current chain tip (`::ChainActive()` and
+ * that is consistent with current chain tip (`ActiveChain()` and
* `CoinsTip()`) and is fully populated. Fully populated means that if the
* current active chain is missing transactions that were present in a
* previously active chain, all the missing transactions will have been
@@ -782,7 +782,6 @@ public:
}
return (mapTx.count(gtxid.GetHash()) != 0);
}
- bool exists(const uint256& txid) const { return exists(GenTxid{false, txid}); }
CTransactionRef get(const uint256& hash) const;
txiter get_iter_from_wtxid(const uint256& wtxid) const EXCLUSIVE_LOCKS_REQUIRED(cs)
@@ -790,7 +789,6 @@ public:
AssertLockHeld(cs);
return mapTx.project<0>(mapTx.get<index_by_wtxid>().find(wtxid));
}
- TxMempoolInfo info(const uint256& hash) const;
TxMempoolInfo info(const GenTxid& gtxid) const;
std::vector<TxMempoolInfo> infoAll() const;
@@ -802,7 +800,7 @@ public:
LOCK(cs);
// Sanity check the transaction is in the mempool & insert into
// unbroadcast set.
- if (exists(txid)) m_unbroadcast_txids.insert(txid);
+ if (exists(GenTxid::Txid(txid))) m_unbroadcast_txids.insert(txid);
};
/** Removes a transaction from the unbroadcast set */
diff --git a/src/txrequest.cpp b/src/txrequest.cpp
index f8d7a1ece8..7d478a5b26 100644
--- a/src/txrequest.cpp
+++ b/src/txrequest.cpp
@@ -300,7 +300,7 @@ std::map<uint256, TxHashInfo> ComputeTxHashInfo(const Index& index, const Priori
GenTxid ToGenTxid(const Announcement& ann)
{
- return {ann.m_is_wtxid, ann.m_txhash};
+ return ann.m_is_wtxid ? GenTxid::Wtxid(ann.m_txhash) : GenTxid::Txid(ann.m_txhash);
}
} // namespace
diff --git a/src/univalue/.cirrus.yml b/src/univalue/.cirrus.yml
new file mode 100644
index 0000000000..f140fee12b
--- /dev/null
+++ b/src/univalue/.cirrus.yml
@@ -0,0 +1,44 @@
+env:
+ MAKEJOBS: "-j4"
+ RUN_TESTS: "true"
+ BASE_OUTDIR: "$CIRRUS_WORKING_DIR/out_dir_base"
+ DEBIAN_FRONTEND: "noninteractive"
+
+task:
+ container:
+ image: ubuntu:focal
+ cpu: 1
+ memory: 1G
+ greedy: true # https://medium.com/cirruslabs/introducing-greedy-container-instances-29aad06dc2b4
+
+ matrix:
+ - name: "gcc"
+ env:
+ CC: "gcc"
+ CXX: "g++"
+ APT_PKGS: "gcc"
+ - name: "clang"
+ env:
+ CC: "clang"
+ CXX: "clang++"
+ APT_PKGS: "clang"
+ - name: "mingw"
+ env:
+ CC: ""
+ CXX: ""
+ UNIVALUE_CONFIG: "--host=x86_64-w64-mingw32"
+ APT_PKGS: "g++-mingw-w64-x86-64 gcc-mingw-w64-x86-64 binutils-mingw-w64-x86-64"
+ RUN_TESTS: "false"
+
+ install_script:
+ - apt update
+ - apt install -y pkg-config build-essential libtool autotools-dev automake bsdmainutils
+ - apt install -y $APT_PKGS
+ autogen_script:
+ - ./autogen.sh
+ configure_script:
+ - ./configure --cache-file=config.cache --bindir=$BASE_OUTDIR/bin --libdir=$BASE_OUTDIR/lib $UNIVALUE_CONFIG
+ make_script:
+ - make $MAKEJOBS V=1
+ test_script:
+ - if [ "$RUN_TESTS" = "true" ]; then make $MAKEJOBS distcheck; fi
diff --git a/src/univalue/.travis.yml b/src/univalue/.travis.yml
deleted file mode 100644
index 43a1ed362e..0000000000
--- a/src/univalue/.travis.yml
+++ /dev/null
@@ -1,51 +0,0 @@
-language: cpp
-
-compiler:
- - clang
- - gcc
-
-os:
- - linux
- - osx
-
-sudo: false
-
-env:
- global:
- - MAKEJOBS=-j3
- - RUN_TESTS=true
- - BASE_OUTDIR=$TRAVIS_BUILD_DIR/out
-
-cache:
- apt: true
-
-addons:
- apt:
- packages:
- - pkg-config
-
-before_script:
- - if [ -n "$USE_SHELL" ]; then export CONFIG_SHELL="$USE_SHELL"; fi
- - test -n "$USE_SHELL" && eval '"$USE_SHELL" -c "./autogen.sh"' || ./autogen.sh
-
-script:
- - if [ -n "$UNIVALUE_CONFIG" ]; then unset CC; unset CXX; fi
- - OUTDIR=$BASE_OUTDIR/$TRAVIS_PULL_REQUEST/$TRAVIS_JOB_NUMBER-$HOST
- - UNIVALUE_CONFIG_ALL="--prefix=$TRAVIS_BUILD_DIR/depends/$HOST --bindir=$OUTDIR/bin --libdir=$OUTDIR/lib"
- - ./configure --cache-file=config.cache $UNIVALUE_CONFIG_ALL $UNIVALUE_CONFIG || ( cat config.log && false)
- - make -s $MAKEJOBS $GOAL || ( echo "Build failure. Verbose build follows." && make $GOAL ; false )
- - export LD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/depends/$HOST/lib
- - if [ "$RUN_TESTS" = "true" ]; then make $MAKEJOBS distcheck; fi
-
-matrix:
- fast_finish: true
- include:
- - os: linux
- compiler: gcc
- env: UNIVALUE_CONFIG=--host=x86_64-w64-mingw32 RUN_TESTS=false
- addons:
- apt:
- packages:
- - g++-mingw-w64-x86-64
- - gcc-mingw-w64-x86-64
- - binutils-mingw-w64-x86-64
diff --git a/src/univalue/Makefile.am b/src/univalue/Makefile.am
index 0f5ba59954..476f14b922 100644
--- a/src/univalue/Makefile.am
+++ b/src/univalue/Makefile.am
@@ -1,20 +1,17 @@
+include sources.mk
ACLOCAL_AMFLAGS = -I build-aux/m4
-.PHONY: gen
+.PHONY: gen FORCE
.INTERMEDIATE: $(GENBIN)
-include_HEADERS = include/univalue.h
-noinst_HEADERS = lib/univalue_escapes.h lib/univalue_utffilter.h
+include_HEADERS = $(UNIVALUE_DIST_HEADERS_INT)
+noinst_HEADERS = $(UNIVALUE_LIB_HEADERS_INT)
lib_LTLIBRARIES = libunivalue.la
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = pc/libunivalue.pc
-libunivalue_la_SOURCES = \
- lib/univalue.cpp \
- lib/univalue_get.cpp \
- lib/univalue_read.cpp \
- lib/univalue_write.cpp
+libunivalue_la_SOURCES = $(UNIVALUE_LIB_SOURCES_INT)
libunivalue_la_LDFLAGS = \
-version-info $(LIBUNIVALUE_CURRENT):$(LIBUNIVALUE_REVISION):$(LIBUNIVALUE_AGE) \
@@ -30,89 +27,32 @@ $(GENBIN): $(GEN_SRCS)
@echo Building $@
$(AM_V_at)c++ -I$(top_srcdir)/include -o $@ $<
-gen: lib/univalue_escapes.h $(GENBIN)
- @echo Updating $<
+gen: $(GENBIN) FORCE
+ @echo Updating lib/univalue_escapes.h
$(AM_V_at)$(GENBIN) > lib/univalue_escapes.h
noinst_PROGRAMS = $(TESTS) test/test_json
-TEST_DATA_DIR=test
-
-test_unitester_SOURCES = test/unitester.cpp
+test_unitester_SOURCES = $(UNIVALUE_TEST_UNITESTER_INT)
test_unitester_LDADD = libunivalue.la
-test_unitester_CXXFLAGS = -I$(top_srcdir)/include -DJSON_TEST_SRC=\"$(srcdir)/$(TEST_DATA_DIR)\"
+test_unitester_CXXFLAGS = -I$(top_srcdir)/include -DJSON_TEST_SRC=\"$(srcdir)/$(UNIVALUE_TEST_DATA_DIR_INT)\"
test_unitester_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS)
-test_test_json_SOURCES = test/test_json.cpp
+test_test_json_SOURCES = $(UNIVALUE_TEST_JSON_INT)
test_test_json_LDADD = libunivalue.la
test_test_json_CXXFLAGS = -I$(top_srcdir)/include
test_test_json_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS)
-test_no_nul_SOURCES = test/no_nul.cpp
+test_no_nul_SOURCES = $(UNIVALUE_TEST_NO_NUL_INT)
test_no_nul_LDADD = libunivalue.la
test_no_nul_CXXFLAGS = -I$(top_srcdir)/include
test_no_nul_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS)
-test_object_SOURCES = test/object.cpp
+test_object_SOURCES = $(UNIVALUE_TEST_OBJECT_INT)
test_object_LDADD = libunivalue.la
test_object_CXXFLAGS = -I$(top_srcdir)/include
test_object_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS)
-TEST_FILES = \
- $(TEST_DATA_DIR)/fail10.json \
- $(TEST_DATA_DIR)/fail11.json \
- $(TEST_DATA_DIR)/fail12.json \
- $(TEST_DATA_DIR)/fail13.json \
- $(TEST_DATA_DIR)/fail14.json \
- $(TEST_DATA_DIR)/fail15.json \
- $(TEST_DATA_DIR)/fail16.json \
- $(TEST_DATA_DIR)/fail17.json \
- $(TEST_DATA_DIR)/fail18.json \
- $(TEST_DATA_DIR)/fail19.json \
- $(TEST_DATA_DIR)/fail1.json \
- $(TEST_DATA_DIR)/fail20.json \
- $(TEST_DATA_DIR)/fail21.json \
- $(TEST_DATA_DIR)/fail22.json \
- $(TEST_DATA_DIR)/fail23.json \
- $(TEST_DATA_DIR)/fail24.json \
- $(TEST_DATA_DIR)/fail25.json \
- $(TEST_DATA_DIR)/fail26.json \
- $(TEST_DATA_DIR)/fail27.json \
- $(TEST_DATA_DIR)/fail28.json \
- $(TEST_DATA_DIR)/fail29.json \
- $(TEST_DATA_DIR)/fail2.json \
- $(TEST_DATA_DIR)/fail30.json \
- $(TEST_DATA_DIR)/fail31.json \
- $(TEST_DATA_DIR)/fail32.json \
- $(TEST_DATA_DIR)/fail33.json \
- $(TEST_DATA_DIR)/fail34.json \
- $(TEST_DATA_DIR)/fail35.json \
- $(TEST_DATA_DIR)/fail36.json \
- $(TEST_DATA_DIR)/fail37.json \
- $(TEST_DATA_DIR)/fail38.json \
- $(TEST_DATA_DIR)/fail39.json \
- $(TEST_DATA_DIR)/fail40.json \
- $(TEST_DATA_DIR)/fail41.json \
- $(TEST_DATA_DIR)/fail42.json \
- $(TEST_DATA_DIR)/fail44.json \
- $(TEST_DATA_DIR)/fail45.json \
- $(TEST_DATA_DIR)/fail3.json \
- $(TEST_DATA_DIR)/fail4.json \
- $(TEST_DATA_DIR)/fail5.json \
- $(TEST_DATA_DIR)/fail6.json \
- $(TEST_DATA_DIR)/fail7.json \
- $(TEST_DATA_DIR)/fail8.json \
- $(TEST_DATA_DIR)/fail9.json \
- $(TEST_DATA_DIR)/pass1.json \
- $(TEST_DATA_DIR)/pass2.json \
- $(TEST_DATA_DIR)/pass3.json \
- $(TEST_DATA_DIR)/pass4.json \
- $(TEST_DATA_DIR)/round1.json \
- $(TEST_DATA_DIR)/round2.json \
- $(TEST_DATA_DIR)/round3.json \
- $(TEST_DATA_DIR)/round4.json \
- $(TEST_DATA_DIR)/round5.json \
- $(TEST_DATA_DIR)/round6.json \
- $(TEST_DATA_DIR)/round7.json
-
-EXTRA_DIST=$(TEST_FILES) $(GEN_SRCS)
+TEST_FILES = $(UNIVALUE_TEST_FILES_INT)
+
+EXTRA_DIST=$(UNIVALUE_TEST_FILES_INT) $(GEN_SRCS)
diff --git a/src/univalue/build-aux/m4/ax_cxx_compile_stdcxx.m4 b/src/univalue/build-aux/m4/ax_cxx_compile_stdcxx.m4
new file mode 100644
index 0000000000..f7e5137003
--- /dev/null
+++ b/src/univalue/build-aux/m4/ax_cxx_compile_stdcxx.m4
@@ -0,0 +1,962 @@
+# ===========================================================================
+# https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional])
+#
+# DESCRIPTION
+#
+# Check for baseline language coverage in the compiler for the specified
+# version of the C++ standard. If necessary, add switches to CXX and
+# CXXCPP to enable support. VERSION may be '11' (for the C++11 standard)
+# or '14' (for the C++14 standard).
+#
+# The second argument, if specified, indicates whether you insist on an
+# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
+# -std=c++11). If neither is specified, you get whatever works, with
+# preference for no added switch, and then for an extended mode.
+#
+# The third argument, if specified 'mandatory' or if left unspecified,
+# indicates that baseline support for the specified C++ standard is
+# required and that the macro should error out if no mode with that
+# support is found. If specified 'optional', then configuration proceeds
+# regardless, after defining HAVE_CXX${VERSION} if and only if a
+# supporting mode is found.
+#
+# LICENSE
+#
+# Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>
+# Copyright (c) 2012 Zack Weinberg <zackw@panix.com>
+# Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu>
+# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com>
+# Copyright (c) 2015 Paul Norman <penorman@mac.com>
+# Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu>
+# Copyright (c) 2016, 2018 Krzesimir Nowak <qdlacz@gmail.com>
+# Copyright (c) 2019 Enji Cooper <yaneurabeya@gmail.com>
+# Copyright (c) 2020 Jason Merrill <jason@redhat.com>
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
+
+#serial 12
+
+dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro
+dnl (serial version number 13).
+
+AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
+ m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"],
+ [$1], [14], [ax_cxx_compile_alternatives="14 1y"],
+ [$1], [17], [ax_cxx_compile_alternatives="17 1z"],
+ [m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl
+ m4_if([$2], [], [],
+ [$2], [ext], [],
+ [$2], [noext], [],
+ [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl
+ m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true],
+ [$3], [mandatory], [ax_cxx_compile_cxx$1_required=true],
+ [$3], [optional], [ax_cxx_compile_cxx$1_required=false],
+ [m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])])
+ AC_LANG_PUSH([C++])dnl
+ ac_success=no
+
+ m4_if([$2], [], [dnl
+ AC_CACHE_CHECK(whether $CXX supports C++$1 features by default,
+ ax_cv_cxx_compile_cxx$1,
+ [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
+ [ax_cv_cxx_compile_cxx$1=yes],
+ [ax_cv_cxx_compile_cxx$1=no])])
+ if test x$ax_cv_cxx_compile_cxx$1 = xyes; then
+ ac_success=yes
+ fi])
+
+ m4_if([$2], [noext], [], [dnl
+ if test x$ac_success = xno; then
+ for alternative in ${ax_cxx_compile_alternatives}; do
+ switch="-std=gnu++${alternative}"
+ cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
+ AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
+ $cachevar,
+ [ac_save_CXX="$CXX"
+ CXX="$CXX $switch"
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
+ [eval $cachevar=yes],
+ [eval $cachevar=no])
+ CXX="$ac_save_CXX"])
+ if eval test x\$$cachevar = xyes; then
+ CXX="$CXX $switch"
+ if test -n "$CXXCPP" ; then
+ CXXCPP="$CXXCPP $switch"
+ fi
+ ac_success=yes
+ break
+ fi
+ done
+ fi])
+
+ m4_if([$2], [ext], [], [dnl
+ if test x$ac_success = xno; then
+ dnl HP's aCC needs +std=c++11 according to:
+ dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf
+ dnl Cray's crayCC needs "-h std=c++11"
+ for alternative in ${ax_cxx_compile_alternatives}; do
+ for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do
+ cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
+ AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
+ $cachevar,
+ [ac_save_CXX="$CXX"
+ CXX="$CXX $switch"
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
+ [eval $cachevar=yes],
+ [eval $cachevar=no])
+ CXX="$ac_save_CXX"])
+ if eval test x\$$cachevar = xyes; then
+ CXX="$CXX $switch"
+ if test -n "$CXXCPP" ; then
+ CXXCPP="$CXXCPP $switch"
+ fi
+ ac_success=yes
+ break
+ fi
+ done
+ if test x$ac_success = xyes; then
+ break
+ fi
+ done
+ fi])
+ AC_LANG_POP([C++])
+ if test x$ax_cxx_compile_cxx$1_required = xtrue; then
+ if test x$ac_success = xno; then
+ AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.])
+ fi
+ fi
+ if test x$ac_success = xno; then
+ HAVE_CXX$1=0
+ AC_MSG_NOTICE([No compiler with C++$1 support was found])
+ else
+ HAVE_CXX$1=1
+ AC_DEFINE(HAVE_CXX$1,1,
+ [define if the compiler supports basic C++$1 syntax])
+ fi
+ AC_SUBST(HAVE_CXX$1)
+])
+
+
+dnl Test body for checking C++11 support
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11],
+ _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
+)
+
+
+dnl Test body for checking C++14 support
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14],
+ _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
+ _AX_CXX_COMPILE_STDCXX_testbody_new_in_14
+)
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17],
+ _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
+ _AX_CXX_COMPILE_STDCXX_testbody_new_in_14
+ _AX_CXX_COMPILE_STDCXX_testbody_new_in_17
+)
+
+dnl Tests for new features in C++11
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[
+
+// If the compiler admits that it is not ready for C++11, why torture it?
+// Hopefully, this will speed up the test.
+
+#ifndef __cplusplus
+
+#error "This is not a C++ compiler"
+
+#elif __cplusplus < 201103L
+
+#error "This is not a C++11 compiler"
+
+#else
+
+namespace cxx11
+{
+
+ namespace test_static_assert
+ {
+
+ template <typename T>
+ struct check
+ {
+ static_assert(sizeof(int) <= sizeof(T), "not big enough");
+ };
+
+ }
+
+ namespace test_final_override
+ {
+
+ struct Base
+ {
+ virtual ~Base() {}
+ virtual void f() {}
+ };
+
+ struct Derived : public Base
+ {
+ virtual ~Derived() override {}
+ virtual void f() override {}
+ };
+
+ }
+
+ namespace test_double_right_angle_brackets
+ {
+
+ template < typename T >
+ struct check {};
+
+ typedef check<void> single_type;
+ typedef check<check<void>> double_type;
+ typedef check<check<check<void>>> triple_type;
+ typedef check<check<check<check<void>>>> quadruple_type;
+
+ }
+
+ namespace test_decltype
+ {
+
+ int
+ f()
+ {
+ int a = 1;
+ decltype(a) b = 2;
+ return a + b;
+ }
+
+ }
+
+ namespace test_type_deduction
+ {
+
+ template < typename T1, typename T2 >
+ struct is_same
+ {
+ static const bool value = false;
+ };
+
+ template < typename T >
+ struct is_same<T, T>
+ {
+ static const bool value = true;
+ };
+
+ template < typename T1, typename T2 >
+ auto
+ add(T1 a1, T2 a2) -> decltype(a1 + a2)
+ {
+ return a1 + a2;
+ }
+
+ int
+ test(const int c, volatile int v)
+ {
+ static_assert(is_same<int, decltype(0)>::value == true, "");
+ static_assert(is_same<int, decltype(c)>::value == false, "");
+ static_assert(is_same<int, decltype(v)>::value == false, "");
+ auto ac = c;
+ auto av = v;
+ auto sumi = ac + av + 'x';
+ auto sumf = ac + av + 1.0;
+ static_assert(is_same<int, decltype(ac)>::value == true, "");
+ static_assert(is_same<int, decltype(av)>::value == true, "");
+ static_assert(is_same<int, decltype(sumi)>::value == true, "");
+ static_assert(is_same<int, decltype(sumf)>::value == false, "");
+ static_assert(is_same<int, decltype(add(c, v))>::value == true, "");
+ return (sumf > 0.0) ? sumi : add(c, v);
+ }
+
+ }
+
+ namespace test_noexcept
+ {
+
+ int f() { return 0; }
+ int g() noexcept { return 0; }
+
+ static_assert(noexcept(f()) == false, "");
+ static_assert(noexcept(g()) == true, "");
+
+ }
+
+ namespace test_constexpr
+ {
+
+ template < typename CharT >
+ unsigned long constexpr
+ strlen_c_r(const CharT *const s, const unsigned long acc) noexcept
+ {
+ return *s ? strlen_c_r(s + 1, acc + 1) : acc;
+ }
+
+ template < typename CharT >
+ unsigned long constexpr
+ strlen_c(const CharT *const s) noexcept
+ {
+ return strlen_c_r(s, 0UL);
+ }
+
+ static_assert(strlen_c("") == 0UL, "");
+ static_assert(strlen_c("1") == 1UL, "");
+ static_assert(strlen_c("example") == 7UL, "");
+ static_assert(strlen_c("another\0example") == 7UL, "");
+
+ }
+
+ namespace test_rvalue_references
+ {
+
+ template < int N >
+ struct answer
+ {
+ static constexpr int value = N;
+ };
+
+ answer<1> f(int&) { return answer<1>(); }
+ answer<2> f(const int&) { return answer<2>(); }
+ answer<3> f(int&&) { return answer<3>(); }
+
+ void
+ test()
+ {
+ int i = 0;
+ const int c = 0;
+ static_assert(decltype(f(i))::value == 1, "");
+ static_assert(decltype(f(c))::value == 2, "");
+ static_assert(decltype(f(0))::value == 3, "");
+ }
+
+ }
+
+ namespace test_uniform_initialization
+ {
+
+ struct test
+ {
+ static const int zero {};
+ static const int one {1};
+ };
+
+ static_assert(test::zero == 0, "");
+ static_assert(test::one == 1, "");
+
+ }
+
+ namespace test_lambdas
+ {
+
+ void
+ test1()
+ {
+ auto lambda1 = [](){};
+ auto lambda2 = lambda1;
+ lambda1();
+ lambda2();
+ }
+
+ int
+ test2()
+ {
+ auto a = [](int i, int j){ return i + j; }(1, 2);
+ auto b = []() -> int { return '0'; }();
+ auto c = [=](){ return a + b; }();
+ auto d = [&](){ return c; }();
+ auto e = [a, &b](int x) mutable {
+ const auto identity = [](int y){ return y; };
+ for (auto i = 0; i < a; ++i)
+ a += b--;
+ return x + identity(a + b);
+ }(0);
+ return a + b + c + d + e;
+ }
+
+ int
+ test3()
+ {
+ const auto nullary = [](){ return 0; };
+ const auto unary = [](int x){ return x; };
+ using nullary_t = decltype(nullary);
+ using unary_t = decltype(unary);
+ const auto higher1st = [](nullary_t f){ return f(); };
+ const auto higher2nd = [unary](nullary_t f1){
+ return [unary, f1](unary_t f2){ return f2(unary(f1())); };
+ };
+ return higher1st(nullary) + higher2nd(nullary)(unary);
+ }
+
+ }
+
+ namespace test_variadic_templates
+ {
+
+ template <int...>
+ struct sum;
+
+ template <int N0, int... N1toN>
+ struct sum<N0, N1toN...>
+ {
+ static constexpr auto value = N0 + sum<N1toN...>::value;
+ };
+
+ template <>
+ struct sum<>
+ {
+ static constexpr auto value = 0;
+ };
+
+ static_assert(sum<>::value == 0, "");
+ static_assert(sum<1>::value == 1, "");
+ static_assert(sum<23>::value == 23, "");
+ static_assert(sum<1, 2>::value == 3, "");
+ static_assert(sum<5, 5, 11>::value == 21, "");
+ static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, "");
+
+ }
+
+ // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
+ // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function
+ // because of this.
+ namespace test_template_alias_sfinae
+ {
+
+ struct foo {};
+
+ template<typename T>
+ using member = typename T::member_type;
+
+ template<typename T>
+ void func(...) {}
+
+ template<typename T>
+ void func(member<T>*) {}
+
+ void test();
+
+ void test() { func<foo>(0); }
+
+ }
+
+} // namespace cxx11
+
+#endif // __cplusplus >= 201103L
+
+]])
+
+
+dnl Tests for new features in C++14
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[
+
+// If the compiler admits that it is not ready for C++14, why torture it?
+// Hopefully, this will speed up the test.
+
+#ifndef __cplusplus
+
+#error "This is not a C++ compiler"
+
+#elif __cplusplus < 201402L
+
+#error "This is not a C++14 compiler"
+
+#else
+
+namespace cxx14
+{
+
+ namespace test_polymorphic_lambdas
+ {
+
+ int
+ test()
+ {
+ const auto lambda = [](auto&&... args){
+ const auto istiny = [](auto x){
+ return (sizeof(x) == 1UL) ? 1 : 0;
+ };
+ const int aretiny[] = { istiny(args)... };
+ return aretiny[0];
+ };
+ return lambda(1, 1L, 1.0f, '1');
+ }
+
+ }
+
+ namespace test_binary_literals
+ {
+
+ constexpr auto ivii = 0b0000000000101010;
+ static_assert(ivii == 42, "wrong value");
+
+ }
+
+ namespace test_generalized_constexpr
+ {
+
+ template < typename CharT >
+ constexpr unsigned long
+ strlen_c(const CharT *const s) noexcept
+ {
+ auto length = 0UL;
+ for (auto p = s; *p; ++p)
+ ++length;
+ return length;
+ }
+
+ static_assert(strlen_c("") == 0UL, "");
+ static_assert(strlen_c("x") == 1UL, "");
+ static_assert(strlen_c("test") == 4UL, "");
+ static_assert(strlen_c("another\0test") == 7UL, "");
+
+ }
+
+ namespace test_lambda_init_capture
+ {
+
+ int
+ test()
+ {
+ auto x = 0;
+ const auto lambda1 = [a = x](int b){ return a + b; };
+ const auto lambda2 = [a = lambda1(x)](){ return a; };
+ return lambda2();
+ }
+
+ }
+
+ namespace test_digit_separators
+ {
+
+ constexpr auto ten_million = 100'000'000;
+ static_assert(ten_million == 100000000, "");
+
+ }
+
+ namespace test_return_type_deduction
+ {
+
+ auto f(int& x) { return x; }
+ decltype(auto) g(int& x) { return x; }
+
+ template < typename T1, typename T2 >
+ struct is_same
+ {
+ static constexpr auto value = false;
+ };
+
+ template < typename T >
+ struct is_same<T, T>
+ {
+ static constexpr auto value = true;
+ };
+
+ int
+ test()
+ {
+ auto x = 0;
+ static_assert(is_same<int, decltype(f(x))>::value, "");
+ static_assert(is_same<int&, decltype(g(x))>::value, "");
+ return x;
+ }
+
+ }
+
+} // namespace cxx14
+
+#endif // __cplusplus >= 201402L
+
+]])
+
+
+dnl Tests for new features in C++17
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[
+
+// If the compiler admits that it is not ready for C++17, why torture it?
+// Hopefully, this will speed up the test.
+
+#ifndef __cplusplus
+
+#error "This is not a C++ compiler"
+
+#elif __cplusplus < 201703L
+
+#error "This is not a C++17 compiler"
+
+#else
+
+#include <initializer_list>
+#include <utility>
+#include <type_traits>
+
+namespace cxx17
+{
+
+ namespace test_constexpr_lambdas
+ {
+
+ constexpr int foo = [](){return 42;}();
+
+ }
+
+ namespace test::nested_namespace::definitions
+ {
+
+ }
+
+ namespace test_fold_expression
+ {
+
+ template<typename... Args>
+ int multiply(Args... args)
+ {
+ return (args * ... * 1);
+ }
+
+ template<typename... Args>
+ bool all(Args... args)
+ {
+ return (args && ...);
+ }
+
+ }
+
+ namespace test_extended_static_assert
+ {
+
+ static_assert (true);
+
+ }
+
+ namespace test_auto_brace_init_list
+ {
+
+ auto foo = {5};
+ auto bar {5};
+
+ static_assert(std::is_same<std::initializer_list<int>, decltype(foo)>::value);
+ static_assert(std::is_same<int, decltype(bar)>::value);
+ }
+
+ namespace test_typename_in_template_template_parameter
+ {
+
+ template<template<typename> typename X> struct D;
+
+ }
+
+ namespace test_fallthrough_nodiscard_maybe_unused_attributes
+ {
+
+ int f1()
+ {
+ return 42;
+ }
+
+ [[nodiscard]] int f2()
+ {
+ [[maybe_unused]] auto unused = f1();
+
+ switch (f1())
+ {
+ case 17:
+ f1();
+ [[fallthrough]];
+ case 42:
+ f1();
+ }
+ return f1();
+ }
+
+ }
+
+ namespace test_extended_aggregate_initialization
+ {
+
+ struct base1
+ {
+ int b1, b2 = 42;
+ };
+
+ struct base2
+ {
+ base2() {
+ b3 = 42;
+ }
+ int b3;
+ };
+
+ struct derived : base1, base2
+ {
+ int d;
+ };
+
+ derived d1 {{1, 2}, {}, 4}; // full initialization
+ derived d2 {{}, {}, 4}; // value-initialized bases
+
+ }
+
+ namespace test_general_range_based_for_loop
+ {
+
+ struct iter
+ {
+ int i;
+
+ int& operator* ()
+ {
+ return i;
+ }
+
+ const int& operator* () const
+ {
+ return i;
+ }
+
+ iter& operator++()
+ {
+ ++i;
+ return *this;
+ }
+ };
+
+ struct sentinel
+ {
+ int i;
+ };
+
+ bool operator== (const iter& i, const sentinel& s)
+ {
+ return i.i == s.i;
+ }
+
+ bool operator!= (const iter& i, const sentinel& s)
+ {
+ return !(i == s);
+ }
+
+ struct range
+ {
+ iter begin() const
+ {
+ return {0};
+ }
+
+ sentinel end() const
+ {
+ return {5};
+ }
+ };
+
+ void f()
+ {
+ range r {};
+
+ for (auto i : r)
+ {
+ [[maybe_unused]] auto v = i;
+ }
+ }
+
+ }
+
+ namespace test_lambda_capture_asterisk_this_by_value
+ {
+
+ struct t
+ {
+ int i;
+ int foo()
+ {
+ return [*this]()
+ {
+ return i;
+ }();
+ }
+ };
+
+ }
+
+ namespace test_enum_class_construction
+ {
+
+ enum class byte : unsigned char
+ {};
+
+ byte foo {42};
+
+ }
+
+ namespace test_constexpr_if
+ {
+
+ template <bool cond>
+ int f ()
+ {
+ if constexpr(cond)
+ {
+ return 13;
+ }
+ else
+ {
+ return 42;
+ }
+ }
+
+ }
+
+ namespace test_selection_statement_with_initializer
+ {
+
+ int f()
+ {
+ return 13;
+ }
+
+ int f2()
+ {
+ if (auto i = f(); i > 0)
+ {
+ return 3;
+ }
+
+ switch (auto i = f(); i + 4)
+ {
+ case 17:
+ return 2;
+
+ default:
+ return 1;
+ }
+ }
+
+ }
+
+ namespace test_template_argument_deduction_for_class_templates
+ {
+
+ template <typename T1, typename T2>
+ struct pair
+ {
+ pair (T1 p1, T2 p2)
+ : m1 {p1},
+ m2 {p2}
+ {}
+
+ T1 m1;
+ T2 m2;
+ };
+
+ void f()
+ {
+ [[maybe_unused]] auto p = pair{13, 42u};
+ }
+
+ }
+
+ namespace test_non_type_auto_template_parameters
+ {
+
+ template <auto n>
+ struct B
+ {};
+
+ B<5> b1;
+ B<'a'> b2;
+
+ }
+
+ namespace test_structured_bindings
+ {
+
+ int arr[2] = { 1, 2 };
+ std::pair<int, int> pr = { 1, 2 };
+
+ auto f1() -> int(&)[2]
+ {
+ return arr;
+ }
+
+ auto f2() -> std::pair<int, int>&
+ {
+ return pr;
+ }
+
+ struct S
+ {
+ int x1 : 2;
+ volatile double y1;
+ };
+
+ S f3()
+ {
+ return {};
+ }
+
+ auto [ x1, y1 ] = f1();
+ auto& [ xr1, yr1 ] = f1();
+ auto [ x2, y2 ] = f2();
+ auto& [ xr2, yr2 ] = f2();
+ const auto [ x3, y3 ] = f3();
+
+ }
+
+ namespace test_exception_spec_type_system
+ {
+
+ struct Good {};
+ struct Bad {};
+
+ void g1() noexcept;
+ void g2();
+
+ template<typename T>
+ Bad
+ f(T*, T*);
+
+ template<typename T1, typename T2>
+ Good
+ f(T1*, T2*);
+
+ static_assert (std::is_same_v<Good, decltype(f(g1, g2))>);
+
+ }
+
+ namespace test_inline_variables
+ {
+
+ template<class T> void f(T)
+ {}
+
+ template<class T> inline T g(T)
+ {
+ return T{};
+ }
+
+ template<> inline void f<>(int)
+ {}
+
+ template<> int g<>(int)
+ {
+ return 5;
+ }
+
+ }
+
+} // namespace cxx17
+
+#endif // __cplusplus < 201703L
+
+]])
diff --git a/src/univalue/configure.ac b/src/univalue/configure.ac
index 8298332ac1..495b25a53d 100644
--- a/src/univalue/configure.ac
+++ b/src/univalue/configure.ac
@@ -1,7 +1,7 @@
m4_define([libunivalue_major_version], [1])
m4_define([libunivalue_minor_version], [1])
-m4_define([libunivalue_micro_version], [3])
-m4_define([libunivalue_interface_age], [3])
+m4_define([libunivalue_micro_version], [4])
+m4_define([libunivalue_interface_age], [4])
# If you need a modifier for the version number.
# Normally empty, but can be used to make "fixup" releases.
m4_define([libunivalue_extraversion], [])
@@ -14,7 +14,7 @@ m4_define([libunivalue_age], [m4_eval(libunivalue_binary_age - libunivalue_inter
m4_define([libunivalue_version], [libunivalue_major_version().libunivalue_minor_version().libunivalue_micro_version()libunivalue_extraversion()])
-AC_INIT([univalue], [1.0.3],
+AC_INIT([univalue], [1.0.4],
[http://github.com/jgarzik/univalue/])
dnl make the compilation flags quiet unless V=1 is used
@@ -45,6 +45,9 @@ AC_SUBST(LIBUNIVALUE_AGE)
LT_INIT
LT_LANG([C++])
+dnl Require C++11 compiler (no GNU extensions)
+AX_CXX_COMPILE_STDCXX([11], [noext], [mandatory], [nodefault])
+
case $host in
*mingw*)
LIBTOOL_APP_LDFLAGS="$LIBTOOL_APP_LDFLAGS -all-static"
diff --git a/src/univalue/gen/gen.cpp b/src/univalue/gen/gen.cpp
index 85fe20924a..b8a6c73f4e 100644
--- a/src/univalue/gen/gen.cpp
+++ b/src/univalue/gen/gen.cpp
@@ -1,6 +1,6 @@
// Copyright 2014 BitPay Inc.
// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or https://opensource.org/licenses/mit-license.php.
//
// To re-create univalue_escapes.h:
@@ -45,7 +45,7 @@ static void outputEscape()
for (unsigned int i = 0; i < 256; i++) {
if (escapes[i].empty()) {
- printf("\tNULL,\n");
+ printf("\tnullptr,\n");
} else {
printf("\t\"");
diff --git a/src/univalue/include/univalue.h b/src/univalue/include/univalue.h
index 048e162f7d..fc5cf402be 100644
--- a/src/univalue/include/univalue.h
+++ b/src/univalue/include/univalue.h
@@ -1,7 +1,7 @@
// Copyright 2014 BitPay Inc.
// Copyright 2015 Bitcoin Core Developers
// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or https://opensource.org/licenses/mit-license.php.
#ifndef __UNIVALUE_H__
#define __UNIVALUE_H__
@@ -14,8 +14,6 @@
#include <map>
#include <cassert>
-#include <sstream> // .get_int64()
-
class UniValue {
public:
enum VType { VNULL, VOBJ, VARR, VSTR, VNUM, VBOOL, };
diff --git a/src/univalue/lib/univalue.cpp b/src/univalue/lib/univalue.cpp
index 4c9c15d63e..c4e59fae74 100644
--- a/src/univalue/lib/univalue.cpp
+++ b/src/univalue/lib/univalue.cpp
@@ -1,7 +1,7 @@
// Copyright 2014 BitPay Inc.
// Copyright 2015 Bitcoin Core Developers
// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or https://opensource.org/licenses/mit-license.php.
#include <stdint.h>
#include <iomanip>
@@ -178,17 +178,19 @@ bool UniValue::findKey(const std::string& key, size_t& retIdx) const
bool UniValue::checkObject(const std::map<std::string,UniValue::VType>& t) const
{
- if (typ != VOBJ)
+ if (typ != VOBJ) {
return false;
+ }
- for (std::map<std::string,UniValue::VType>::const_iterator it = t.begin();
- it != t.end(); ++it) {
+ for (const auto& object: t) {
size_t idx = 0;
- if (!findKey(it->first, idx))
+ if (!findKey(object.first, idx)) {
return false;
+ }
- if (values.at(idx).getType() != it->second)
+ if (values.at(idx).getType() != object.second) {
return false;
+ }
}
return true;
@@ -228,7 +230,7 @@ const char *uvTypeName(UniValue::VType t)
}
// not reached
- return NULL;
+ return nullptr;
}
const UniValue& find_value(const UniValue& obj, const std::string& name)
diff --git a/src/univalue/lib/univalue_escapes.h b/src/univalue/lib/univalue_escapes.h
index 74596aab6d..3f714f8e5b 100644
--- a/src/univalue/lib/univalue_escapes.h
+++ b/src/univalue/lib/univalue_escapes.h
@@ -34,229 +34,229 @@ static const char *escapes[256] = {
"\\u001d",
"\\u001e",
"\\u001f",
- NULL,
- NULL,
+ nullptr,
+ nullptr,
"\\\"",
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
"\\\\",
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
"\\u007f",
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
};
#endif // BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H
diff --git a/src/univalue/lib/univalue_get.cpp b/src/univalue/lib/univalue_get.cpp
index 0ad6146545..5af89a3561 100644
--- a/src/univalue/lib/univalue_get.cpp
+++ b/src/univalue/lib/univalue_get.cpp
@@ -1,7 +1,7 @@
// Copyright 2014 BitPay Inc.
// Copyright 2015 Bitcoin Core Developers
// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or https://opensource.org/licenses/mit-license.php.
#include <stdint.h>
#include <errno.h>
@@ -11,6 +11,7 @@
#include <vector>
#include <limits>
#include <string>
+#include <sstream>
#include "univalue.h"
@@ -31,7 +32,7 @@ bool ParseInt32(const std::string& str, int32_t *out)
{
if (!ParsePrechecks(str))
return false;
- char *endp = NULL;
+ char *endp = nullptr;
errno = 0; // strtol will not set errno if valid
long int n = strtol(str.c_str(), &endp, 10);
if(out) *out = (int32_t)n;
@@ -47,7 +48,7 @@ bool ParseInt64(const std::string& str, int64_t *out)
{
if (!ParsePrechecks(str))
return false;
- char *endp = NULL;
+ char *endp = nullptr;
errno = 0; // strtoll will not set errno if valid
long long int n = strtoll(str.c_str(), &endp, 10);
if(out) *out = (int64_t)n;
diff --git a/src/univalue/lib/univalue_read.cpp b/src/univalue/lib/univalue_read.cpp
index 5c6a1acf75..be39bfe57a 100644
--- a/src/univalue/lib/univalue_read.cpp
+++ b/src/univalue/lib/univalue_read.cpp
@@ -1,6 +1,6 @@
// Copyright 2014 BitPay Inc.
// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or https://opensource.org/licenses/mit-license.php.
#include <string.h>
#include <vector>
@@ -227,7 +227,7 @@ enum jtokentype getJsonToken(std::string& tokenVal, unsigned int& consumed,
}
else {
- writer.push_back(*raw);
+ writer.push_back(static_cast<unsigned char>(*raw));
raw++;
}
}
@@ -244,7 +244,7 @@ enum jtokentype getJsonToken(std::string& tokenVal, unsigned int& consumed,
}
}
-enum expect_bits {
+enum expect_bits : unsigned {
EXP_OBJ_NAME = (1U << 0),
EXP_COLON = (1U << 1),
EXP_ARR_VALUE = (1U << 2),
diff --git a/src/univalue/lib/univalue_utffilter.h b/src/univalue/lib/univalue_utffilter.h
index 20d4043009..c24ac58eaf 100644
--- a/src/univalue/lib/univalue_utffilter.h
+++ b/src/univalue/lib/univalue_utffilter.h
@@ -1,6 +1,6 @@
// Copyright 2016 Wladimir J. van der Laan
// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or https://opensource.org/licenses/mit-license.php.
#ifndef UNIVALUE_UTFFILTER_H
#define UNIVALUE_UTFFILTER_H
diff --git a/src/univalue/lib/univalue_write.cpp b/src/univalue/lib/univalue_write.cpp
index 827eb9b271..3a2c580c7f 100644
--- a/src/univalue/lib/univalue_write.cpp
+++ b/src/univalue/lib/univalue_write.cpp
@@ -1,9 +1,8 @@
// Copyright 2014 BitPay Inc.
// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or https://opensource.org/licenses/mit-license.php.
#include <iomanip>
-#include <sstream>
#include <stdio.h>
#include "univalue.h"
#include "univalue_escapes.h"
@@ -14,13 +13,13 @@ static std::string json_escape(const std::string& inS)
outS.reserve(inS.size() * 2);
for (unsigned int i = 0; i < inS.size(); i++) {
- unsigned char ch = inS[i];
+ unsigned char ch = static_cast<unsigned char>(inS[i]);
const char *escStr = escapes[ch];
if (escStr)
outS += escStr;
else
- outS += ch;
+ outS += static_cast<char>(ch);
}
return outS;
diff --git a/src/univalue/sources.mk b/src/univalue/sources.mk
new file mode 100644
index 0000000000..efab6d277f
--- /dev/null
+++ b/src/univalue/sources.mk
@@ -0,0 +1,95 @@
+# - All variables are namespaced with UNIVALUE_ to avoid colliding with
+# downstream makefiles.
+# - All Variables ending in _HEADERS or _SOURCES confuse automake, so the
+# _INT postfix is applied.
+# - Convenience variables, for example a UNIVALUE_TEST_DIR should not be used
+# as they interfere with automatic dependency generation
+# - The %reldir% is the relative path from the Makefile.am. This allows
+# downstreams to use these variables without having to manually account for
+# the path change.
+
+UNIVALUE_INCLUDE_DIR_INT = %reldir%/include
+
+UNIVALUE_DIST_HEADERS_INT =
+UNIVALUE_DIST_HEADERS_INT += %reldir%/include/univalue.h
+
+UNIVALUE_LIB_HEADERS_INT =
+UNIVALUE_LIB_HEADERS_INT += %reldir%/lib/univalue_utffilter.h
+UNIVALUE_LIB_HEADERS_INT += %reldir%/lib/univalue_escapes.h
+
+UNIVALUE_LIB_SOURCES_INT =
+UNIVALUE_LIB_SOURCES_INT += %reldir%/lib/univalue.cpp
+UNIVALUE_LIB_SOURCES_INT += %reldir%/lib/univalue_get.cpp
+UNIVALUE_LIB_SOURCES_INT += %reldir%/lib/univalue_read.cpp
+UNIVALUE_LIB_SOURCES_INT += %reldir%/lib/univalue_write.cpp
+
+UNIVALUE_TEST_DATA_DIR_INT = %reldir%/test
+
+UNIVALUE_TEST_UNITESTER_INT =
+UNIVALUE_TEST_UNITESTER_INT += %reldir%/test/unitester.cpp
+
+UNIVALUE_TEST_JSON_INT =
+UNIVALUE_TEST_JSON_INT += %reldir%/test/test_json.cpp
+
+UNIVALUE_TEST_NO_NUL_INT =
+UNIVALUE_TEST_NO_NUL_INT += %reldir%/test/no_nul.cpp
+
+UNIVALUE_TEST_OBJECT_INT =
+UNIVALUE_TEST_OBJECT_INT += %reldir%/test/object.cpp
+
+UNIVALUE_TEST_FILES_INT =
+UNIVALUE_TEST_FILES_INT += %reldir%/test/fail1.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/fail2.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/fail3.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/fail4.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/fail5.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/fail6.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/fail7.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/fail8.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/fail9.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/fail10.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/fail11.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/fail12.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/fail13.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/fail14.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/fail15.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/fail16.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/fail17.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/fail18.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/fail19.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/fail20.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/fail21.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/fail22.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/fail23.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/fail24.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/fail25.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/fail26.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/fail27.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/fail28.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/fail29.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/fail30.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/fail31.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/fail32.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/fail33.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/fail34.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/fail35.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/fail36.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/fail37.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/fail38.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/fail39.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/fail40.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/fail41.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/fail42.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/fail44.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/fail45.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/pass1.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/pass2.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/pass3.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/pass4.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/round1.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/round2.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/round3.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/round4.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/round5.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/round6.json
+UNIVALUE_TEST_FILES_INT += %reldir%/test/round7.json
diff --git a/src/univalue/test/object.cpp b/src/univalue/test/object.cpp
index ccc1344836..c2f52f83ac 100644
--- a/src/univalue/test/object.cpp
+++ b/src/univalue/test/object.cpp
@@ -1,7 +1,7 @@
// Copyright (c) 2014 BitPay Inc.
// 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.
+// file COPYING or https://opensource.org/licenses/mit-license.php.
#include <stdint.h>
#include <vector>
diff --git a/src/univalue/test/unitester.cpp b/src/univalue/test/unitester.cpp
index 2308afbcdf..02e1a83c6d 100644
--- a/src/univalue/test/unitester.cpp
+++ b/src/univalue/test/unitester.cpp
@@ -1,6 +1,6 @@
// Copyright 2014 BitPay Inc.
// Distributed under the MIT/X11 software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or https://opensource.org/licenses/mit-license.php.
#include <stdlib.h>
#include <stdio.h>
@@ -58,7 +58,7 @@ static void runtest_file(const char *filename_)
std::string basename(filename_);
std::string filename = srcdir + "/" + basename;
FILE *f = fopen(filename.c_str(), "r");
- assert(f != NULL);
+ assert(f != nullptr);
std::string jdata;
diff --git a/src/util/asmap.cpp b/src/util/asmap.cpp
index 5695c62012..b696c65e9d 100644
--- a/src/util/asmap.cpp
+++ b/src/util/asmap.cpp
@@ -201,7 +201,7 @@ std::vector<bool> DecodeAsmap(fs::path path)
}
fseek(filestr, 0, SEEK_END);
int length = ftell(filestr);
- LogPrintf("Opened asmap file %s (%d bytes) from disk\n", path, length);
+ LogPrintf("Opened asmap file %s (%d bytes) from disk\n", fs::quoted(fs::PathToString(path)), length);
fseek(filestr, 0, SEEK_SET);
uint8_t cur_byte;
for (int i = 0; i < length; ++i) {
@@ -211,7 +211,7 @@ std::vector<bool> DecodeAsmap(fs::path path)
}
}
if (!SanityCheckASMap(bits, 128)) {
- LogPrintf("Sanity check of asmap file %s failed\n", path);
+ LogPrintf("Sanity check of asmap file %s failed\n", fs::quoted(fs::PathToString(path)));
return {};
}
return bits;
diff --git a/src/util/settings.cpp b/src/util/settings.cpp
index 846b34089d..7fb35c073e 100644
--- a/src/util/settings.cpp
+++ b/src/util/settings.cpp
@@ -66,24 +66,24 @@ bool ReadSettings(const fs::path& path, std::map<std::string, SettingsValue>& va
fsbridge::ifstream file;
file.open(path);
if (!file.is_open()) {
- errors.emplace_back(strprintf("%s. Please check permissions.", path.string()));
+ errors.emplace_back(strprintf("%s. Please check permissions.", fs::PathToString(path)));
return false;
}
SettingsValue in;
if (!in.read(std::string{std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>()})) {
- errors.emplace_back(strprintf("Unable to parse settings file %s", path.string()));
+ errors.emplace_back(strprintf("Unable to parse settings file %s", fs::PathToString(path)));
return false;
}
if (file.fail()) {
- errors.emplace_back(strprintf("Failed reading settings file %s", path.string()));
+ errors.emplace_back(strprintf("Failed reading settings file %s", fs::PathToString(path)));
return false;
}
file.close(); // Done with file descriptor. Release while copying data.
if (!in.isObject()) {
- errors.emplace_back(strprintf("Found non-object value %s in settings file %s", in.write(), path.string()));
+ errors.emplace_back(strprintf("Found non-object value %s in settings file %s", in.write(), fs::PathToString(path)));
return false;
}
@@ -92,7 +92,7 @@ bool ReadSettings(const fs::path& path, std::map<std::string, SettingsValue>& va
for (size_t i = 0; i < in_keys.size(); ++i) {
auto inserted = values.emplace(in_keys[i], in_values[i]);
if (!inserted.second) {
- errors.emplace_back(strprintf("Found duplicate key %s in settings file %s", in_keys[i], path.string()));
+ errors.emplace_back(strprintf("Found duplicate key %s in settings file %s", in_keys[i], fs::PathToString(path)));
}
}
return errors.empty();
@@ -109,7 +109,7 @@ bool WriteSettings(const fs::path& path,
fsbridge::ofstream file;
file.open(path);
if (file.fail()) {
- errors.emplace_back(strprintf("Error: Unable to open settings file %s for writing", path.string()));
+ errors.emplace_back(strprintf("Error: Unable to open settings file %s for writing", fs::PathToString(path)));
return false;
}
file << out.write(/* prettyIndent= */ 1, /* indentLevel= */ 4) << std::endl;
diff --git a/src/util/syscall_sandbox.cpp b/src/util/syscall_sandbox.cpp
index b361b09568..bc69df44f4 100644
--- a/src/util/syscall_sandbox.cpp
+++ b/src/util/syscall_sandbox.cpp
@@ -169,6 +169,10 @@ const std::map<uint32_t, std::string> LINUX_SYSCALLS{
{__NR_ftruncate, "ftruncate"},
{__NR_futex, "futex"},
{__NR_futimesat, "futimesat"},
+ {__NR_get_kernel_syms, "get_kernel_syms"},
+ {__NR_get_mempolicy, "get_mempolicy"},
+ {__NR_get_robust_list, "get_robust_list"},
+ {__NR_get_thread_area, "get_thread_area"},
{__NR_getcpu, "getcpu"},
{__NR_getcwd, "getcwd"},
{__NR_getdents, "getdents"},
@@ -178,8 +182,6 @@ const std::map<uint32_t, std::string> LINUX_SYSCALLS{
{__NR_getgid, "getgid"},
{__NR_getgroups, "getgroups"},
{__NR_getitimer, "getitimer"},
- {__NR_get_kernel_syms, "get_kernel_syms"},
- {__NR_get_mempolicy, "get_mempolicy"},
{__NR_getpeername, "getpeername"},
{__NR_getpgid, "getpgid"},
{__NR_getpgrp, "getpgrp"},
@@ -191,12 +193,10 @@ const std::map<uint32_t, std::string> LINUX_SYSCALLS{
{__NR_getresgid, "getresgid"},
{__NR_getresuid, "getresuid"},
{__NR_getrlimit, "getrlimit"},
- {__NR_get_robust_list, "get_robust_list"},
{__NR_getrusage, "getrusage"},
{__NR_getsid, "getsid"},
{__NR_getsockname, "getsockname"},
{__NR_getsockopt, "getsockopt"},
- {__NR_get_thread_area, "get_thread_area"},
{__NR_gettid, "gettid"},
{__NR_gettimeofday, "gettimeofday"},
{__NR_getuid, "getuid"},
@@ -207,15 +207,15 @@ const std::map<uint32_t, std::string> LINUX_SYSCALLS{
{__NR_inotify_init1, "inotify_init1"},
{__NR_inotify_rm_watch, "inotify_rm_watch"},
{__NR_io_cancel, "io_cancel"},
- {__NR_ioctl, "ioctl"},
{__NR_io_destroy, "io_destroy"},
{__NR_io_getevents, "io_getevents"},
+ {__NR_io_setup, "io_setup"},
+ {__NR_io_submit, "io_submit"},
+ {__NR_ioctl, "ioctl"},
{__NR_ioperm, "ioperm"},
{__NR_iopl, "iopl"},
{__NR_ioprio_get, "ioprio_get"},
{__NR_ioprio_set, "ioprio_set"},
- {__NR_io_setup, "io_setup"},
- {__NR_io_submit, "io_submit"},
{__NR_kcmp, "kcmp"},
{__NR_kexec_file_load, "kexec_file_load"},
{__NR_kexec_load, "kexec_load"},
@@ -271,8 +271,8 @@ const std::map<uint32_t, std::string> LINUX_SYSCALLS{
{__NR_newfstatat, "newfstatat"},
{__NR_nfsservctl, "nfsservctl"},
{__NR_open, "open"},
- {__NR_openat, "openat"},
{__NR_open_by_handle_at, "open_by_handle_at"},
+ {__NR_openat, "openat"},
{__NR_pause, "pause"},
{__NR_perf_event_open, "perf_event_open"},
{__NR_personality, "personality"},
@@ -307,6 +307,7 @@ const std::map<uint32_t, std::string> LINUX_SYSCALLS{
#ifdef __NR_pwritev2
{__NR_pwritev2, "pwritev2"},
#endif
+ {__NR__sysctl, "_sysctl"},
{__NR_query_module, "query_module"},
{__NR_quotactl, "quotactl"},
{__NR_read, "read"},
@@ -334,11 +335,11 @@ const std::map<uint32_t, std::string> LINUX_SYSCALLS{
{__NR_rt_sigsuspend, "rt_sigsuspend"},
{__NR_rt_sigtimedwait, "rt_sigtimedwait"},
{__NR_rt_tgsigqueueinfo, "rt_tgsigqueueinfo"},
+ {__NR_sched_get_priority_max, "sched_get_priority_max"},
+ {__NR_sched_get_priority_min, "sched_get_priority_min"},
{__NR_sched_getaffinity, "sched_getaffinity"},
{__NR_sched_getattr, "sched_getattr"},
{__NR_sched_getparam, "sched_getparam"},
- {__NR_sched_get_priority_max, "sched_get_priority_max"},
- {__NR_sched_get_priority_min, "sched_get_priority_min"},
{__NR_sched_getscheduler, "sched_getscheduler"},
{__NR_sched_rr_get_interval, "sched_rr_get_interval"},
{__NR_sched_setaffinity, "sched_setaffinity"},
@@ -357,6 +358,10 @@ const std::map<uint32_t, std::string> LINUX_SYSCALLS{
{__NR_sendmmsg, "sendmmsg"},
{__NR_sendmsg, "sendmsg"},
{__NR_sendto, "sendto"},
+ {__NR_set_mempolicy, "set_mempolicy"},
+ {__NR_set_robust_list, "set_robust_list"},
+ {__NR_set_thread_area, "set_thread_area"},
+ {__NR_set_tid_address, "set_tid_address"},
{__NR_setdomainname, "setdomainname"},
{__NR_setfsgid, "setfsgid"},
{__NR_setfsuid, "setfsuid"},
@@ -364,7 +369,6 @@ const std::map<uint32_t, std::string> LINUX_SYSCALLS{
{__NR_setgroups, "setgroups"},
{__NR_sethostname, "sethostname"},
{__NR_setitimer, "setitimer"},
- {__NR_set_mempolicy, "set_mempolicy"},
{__NR_setns, "setns"},
{__NR_setpgid, "setpgid"},
{__NR_setpriority, "setpriority"},
@@ -373,11 +377,8 @@ const std::map<uint32_t, std::string> LINUX_SYSCALLS{
{__NR_setresuid, "setresuid"},
{__NR_setreuid, "setreuid"},
{__NR_setrlimit, "setrlimit"},
- {__NR_set_robust_list, "set_robust_list"},
{__NR_setsid, "setsid"},
{__NR_setsockopt, "setsockopt"},
- {__NR_set_thread_area, "set_thread_area"},
- {__NR_set_tid_address, "set_tid_address"},
{__NR_settimeofday, "settimeofday"},
{__NR_setuid, "setuid"},
{__NR_setxattr, "setxattr"},
@@ -402,7 +403,6 @@ const std::map<uint32_t, std::string> LINUX_SYSCALLS{
{__NR_sync, "sync"},
{__NR_sync_file_range, "sync_file_range"},
{__NR_syncfs, "syncfs"},
- {__NR__sysctl, "_sysctl"},
{__NR_sysfs, "sysfs"},
{__NR_sysinfo, "sysinfo"},
{__NR_syslog, "syslog"},
@@ -411,12 +411,12 @@ const std::map<uint32_t, std::string> LINUX_SYSCALLS{
{__NR_time, "time"},
{__NR_timer_create, "timer_create"},
{__NR_timer_delete, "timer_delete"},
- {__NR_timerfd_create, "timerfd_create"},
- {__NR_timerfd_gettime, "timerfd_gettime"},
- {__NR_timerfd_settime, "timerfd_settime"},
{__NR_timer_getoverrun, "timer_getoverrun"},
{__NR_timer_gettime, "timer_gettime"},
{__NR_timer_settime, "timer_settime"},
+ {__NR_timerfd_create, "timerfd_create"},
+ {__NR_timerfd_gettime, "timerfd_gettime"},
+ {__NR_timerfd_settime, "timerfd_settime"},
{__NR_times, "times"},
{__NR_tkill, "tkill"},
{__NR_truncate, "truncate"},
@@ -650,6 +650,7 @@ public:
{
allowed_syscalls.insert(__NR_clock_getres); // find the resolution (precision) of the specified clock
allowed_syscalls.insert(__NR_clock_gettime); // retrieve the time of the specified clock
+ allowed_syscalls.insert(__NR_gettimeofday); // get timeval
}
void AllowGlobalProcessEnvironment()
diff --git a/src/util/system.cpp b/src/util/system.cpp
index 79c08816fa..12d7dc49b2 100644
--- a/src/util/system.cpp
+++ b/src/util/system.cpp
@@ -98,7 +98,7 @@ bool LockDirectory(const fs::path& directory, const std::string lockfile_name, b
fs::path pathLockFile = directory / lockfile_name;
// If a lock for this directory already exists in the map, don't try to re-lock it
- if (dir_locks.count(pathLockFile.string())) {
+ if (dir_locks.count(fs::PathToString(pathLockFile))) {
return true;
}
@@ -107,11 +107,11 @@ bool LockDirectory(const fs::path& directory, const std::string lockfile_name, b
if (file) fclose(file);
auto lock = std::make_unique<fsbridge::FileLock>(pathLockFile);
if (!lock->TryLock()) {
- return error("Error while attempting to lock directory %s: %s", directory.string(), lock->GetReason());
+ return error("Error while attempting to lock directory %s: %s", fs::PathToString(directory), lock->GetReason());
}
if (!probe_only) {
// Lock successful and we're not just probing, put it into the map
- dir_locks.emplace(pathLockFile.string(), std::move(lock));
+ dir_locks.emplace(fs::PathToString(pathLockFile), std::move(lock));
}
return true;
}
@@ -119,7 +119,7 @@ bool LockDirectory(const fs::path& directory, const std::string lockfile_name, b
void UnlockDirectory(const fs::path& directory, const std::string& lockfile_name)
{
LOCK(cs_dir_locks);
- dir_locks.erase((directory / lockfile_name).string());
+ dir_locks.erase(fs::PathToString(directory / lockfile_name));
}
void ReleaseDirectoryLocks()
@@ -242,7 +242,7 @@ namespace {
fs::path StripRedundantLastElementsOfPath(const fs::path& path)
{
auto result = path;
- while (result.filename().string() == ".") {
+ while (fs::PathToString(result.filename()) == ".") {
result = result.parent_path();
}
@@ -402,7 +402,7 @@ const fs::path& ArgsManager::GetBlocksDirPath() const
if (!path.empty()) return path;
if (IsArgSet("-blocksdir")) {
- path = fs::system_complete(GetArg("-blocksdir", ""));
+ path = fs::system_complete(fs::PathFromString(GetArg("-blocksdir", "")));
if (!fs::is_directory(path)) {
path = "";
return path;
@@ -411,7 +411,7 @@ const fs::path& ArgsManager::GetBlocksDirPath() const
path = GetDataDirBase();
}
- path /= BaseParams().DataDir();
+ path /= fs::PathFromString(BaseParams().DataDir());
path /= "blocks";
fs::create_directories(path);
path = StripRedundantLastElementsOfPath(path);
@@ -429,7 +429,7 @@ const fs::path& ArgsManager::GetDataDir(bool net_specific) const
std::string datadir = GetArg("-datadir", "");
if (!datadir.empty()) {
- path = fs::system_complete(datadir);
+ path = fs::system_complete(fs::PathFromString(datadir));
if (!fs::is_directory(path)) {
path = "";
return path;
@@ -438,7 +438,7 @@ const fs::path& ArgsManager::GetDataDir(bool net_specific) const
path = GetDefaultDataDir();
}
if (net_specific)
- path /= BaseParams().DataDir();
+ path /= fs::PathFromString(BaseParams().DataDir());
if (fs::create_directories(path)) {
// This is the first run, create wallets subdirectory too
@@ -517,7 +517,7 @@ bool ArgsManager::GetSettingsPath(fs::path* filepath, bool temp) const
}
if (filepath) {
std::string settings = GetArg("-settings", BITCOIN_SETTINGS_FILENAME);
- *filepath = fsbridge::AbsPathJoin(GetDataDirNet(), temp ? settings + ".tmp" : settings);
+ *filepath = fsbridge::AbsPathJoin(GetDataDirNet(), fs::PathFromString(temp ? settings + ".tmp" : settings));
}
return true;
}
@@ -572,7 +572,7 @@ bool ArgsManager::WriteSettingsFile(std::vector<std::string>* errors) const
return false;
}
if (!RenameOver(path_tmp, path)) {
- SaveErrors({strprintf("Failed renaming settings file %s to %s\n", path_tmp.string(), path.string())}, errors);
+ SaveErrors({strprintf("Failed renaming settings file %s to %s\n", fs::PathToString(path_tmp), fs::PathToString(path))}, errors);
return false;
}
return true;
@@ -809,12 +809,12 @@ fs::path GetDefaultDataDir()
bool CheckDataDirOption()
{
std::string datadir = gArgs.GetArg("-datadir", "");
- return datadir.empty() || fs::is_directory(fs::system_complete(datadir));
+ return datadir.empty() || fs::is_directory(fs::system_complete(fs::PathFromString(datadir)));
}
fs::path GetConfigFile(const std::string& confPath)
{
- return AbsPathForConfigVal(fs::path(confPath), false);
+ return AbsPathForConfigVal(fs::PathFromString(confPath), false);
}
static bool GetConfigOptions(std::istream& stream, const std::string& filepath, std::string& error, std::vector<std::pair<std::string, std::string>>& options, std::list<SectionInfo>& sections)
@@ -1065,7 +1065,7 @@ bool RenameOver(fs::path src, fs::path dest)
return MoveFileExW(src.wstring().c_str(), dest.wstring().c_str(),
MOVEFILE_REPLACE_EXISTING) != 0;
#else
- int rc = std::rename(src.string().c_str(), dest.string().c_str());
+ int rc = std::rename(src.c_str(), dest.c_str());
return (rc == 0);
#endif /* WIN32 */
}
diff --git a/src/validation.cpp b/src/validation.cpp
index 14dcd2c24b..8d64a9a460 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -219,7 +219,7 @@ bool TestLockPointValidity(CChain& active_chain, const LockPoints* lp)
// If there are relative lock times then the maxInputBlock will be set
// If there are no relative lock times, the LockPoints don't depend on the chain
if (lp->maxInputBlock) {
- // Check whether ::ChainActive() is an extension of the block at which the LockPoints
+ // Check whether active_chain is an extension of the block at which the LockPoints
// calculation was valid. If not LockPoints are no longer valid
if (!active_chain.Contains(lp->maxInputBlock)) {
return false;
@@ -355,7 +355,7 @@ void CChainState::MaybeUpdateMempoolForReorg(
// If the transaction doesn't make it in to the mempool, remove any
// transactions that depend on it (which would now be orphans).
m_mempool->removeRecursive(**it, MemPoolRemovalReason::REORG);
- } else if (m_mempool->exists((*it)->GetHash())) {
+ } else if (m_mempool->exists(GenTxid::Txid((*it)->GetHash()))) {
vHashUpdate.push_back((*it)->GetHash());
}
++it;
@@ -585,10 +585,10 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
if (!CheckFinalTx(m_active_chainstate.m_chain.Tip(), tx, STANDARD_LOCKTIME_VERIFY_FLAGS))
return state.Invalid(TxValidationResult::TX_PREMATURE_SPEND, "non-final");
- if (m_pool.exists(GenTxid(true, tx.GetWitnessHash()))) {
+ if (m_pool.exists(GenTxid::Wtxid(tx.GetWitnessHash()))) {
// Exact transaction already exists in the mempool.
return state.Invalid(TxValidationResult::TX_CONFLICT, "txn-already-in-mempool");
- } else if (m_pool.exists(GenTxid(false, tx.GetHash()))) {
+ } else if (m_pool.exists(GenTxid::Txid(tx.GetHash()))) {
// Transaction with the same non-witness data but different witness (same txid, different
// wtxid) already exists in the mempool.
return state.Invalid(TxValidationResult::TX_CONFLICT, "txn-same-nonwitness-data-in-mempool");
@@ -908,7 +908,7 @@ bool MemPoolAccept::Finalize(const ATMPArgs& args, Workspace& ws)
// trim mempool and check if tx was trimmed
if (!bypass_limits) {
LimitMempoolSize(m_pool, m_active_chainstate.CoinsTip(), gArgs.GetIntArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, std::chrono::hours{gArgs.GetIntArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY)});
- if (!m_pool.exists(hash))
+ if (!m_pool.exists(GenTxid::Txid(hash)))
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "mempool full");
}
return true;
@@ -1877,14 +1877,13 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
int64_t nTime5 = GetTimeMicros(); nTimeIndex += nTime5 - nTime4;
LogPrint(BCLog::BENCH, " - Index writing: %.2fms [%.2fs (%.2fms/blk)]\n", MILLI * (nTime5 - nTime4), nTimeIndex * MICRO, nTimeIndex * MILLI / nBlocksTotal);
- TRACE7(validation, block_connected,
- block.GetHash().ToString().c_str(),
+ TRACE6(validation, block_connected,
+ block.GetHash().data(),
pindex->nHeight,
block.vtx.size(),
nInputs,
nSigOpsCost,
- GetTimeMicros() - nTimeStart, // in microseconds (µs)
- block.GetHash().data()
+ GetTimeMicros() - nTimeStart // in microseconds (µs)
);
return true;
@@ -2029,8 +2028,8 @@ bool CChainState::FlushStateToDisk(
}
// Flush best chain related state. This can only be done if the blocks / block index write was also done.
if (fDoFullFlush && !CoinsTip().GetBestBlock().IsNull()) {
- LOG_TIME_SECONDS(strprintf("write coins cache to disk (%d coins, %.2fkB)",
- coins_count, coins_mem_usage / 1000));
+ LOG_TIME_MILLIS_WITH_CATEGORY(strprintf("write coins cache to disk (%d coins, %.2fkB)",
+ coins_count, coins_mem_usage / 1000), BCLog::BENCH);
// Typical Coin structures on disk are around 48 bytes in size.
// Pushing a new one to the database can cause it to be written
@@ -3205,7 +3204,7 @@ bool BlockManager::AcceptBlockHeader(const CBlockHeader& block, BlockValidationS
if (ppindex)
*ppindex = pindex;
if (pindex->nStatus & BLOCK_FAILED_MASK) {
- LogPrintf("ERROR: %s: block %s is marked invalid\n", __func__, hash.ToString());
+ LogPrint(BCLog::VALIDATION, "%s: block %s is marked invalid\n", __func__, hash.ToString());
return state.Invalid(BlockValidationResult::BLOCK_CACHED_INVALID, "duplicate");
}
return true;
@@ -3220,16 +3219,18 @@ bool BlockManager::AcceptBlockHeader(const CBlockHeader& block, BlockValidationS
CBlockIndex* pindexPrev = nullptr;
BlockMap::iterator mi = m_block_index.find(block.hashPrevBlock);
if (mi == m_block_index.end()) {
- LogPrintf("ERROR: %s: prev block not found\n", __func__);
+ LogPrint(BCLog::VALIDATION, "%s: %s prev block not found\n", __func__, hash.ToString());
return state.Invalid(BlockValidationResult::BLOCK_MISSING_PREV, "prev-blk-not-found");
}
pindexPrev = (*mi).second;
if (pindexPrev->nStatus & BLOCK_FAILED_MASK) {
- LogPrintf("ERROR: %s: prev block invalid\n", __func__);
+ LogPrint(BCLog::VALIDATION, "%s: %s prev block invalid\n", __func__, hash.ToString());
return state.Invalid(BlockValidationResult::BLOCK_INVALID_PREV, "bad-prevblk");
}
- if (!ContextualCheckBlockHeader(block, state, *this, chainparams, pindexPrev, GetAdjustedTime()))
- return error("%s: Consensus::ContextualCheckBlockHeader: %s, %s", __func__, hash.ToString(), state.ToString());
+ if (!ContextualCheckBlockHeader(block, state, *this, chainparams, pindexPrev, GetAdjustedTime())) {
+ LogPrint(BCLog::VALIDATION, "%s: Consensus::ContextualCheckBlockHeader: %s, %s\n", __func__, hash.ToString(), state.ToString());
+ return false;
+ }
/* Determine if this block descends from any block which has been found
* invalid (m_failed_blocks), then mark pindexPrev and any blocks between
@@ -3264,7 +3265,7 @@ bool BlockManager::AcceptBlockHeader(const CBlockHeader& block, BlockValidationS
setDirtyBlockIndex.insert(invalid_walk);
invalid_walk = invalid_walk->pprev;
}
- LogPrintf("ERROR: %s: prev block invalid\n", __func__);
+ LogPrint(BCLog::VALIDATION, "%s: %s prev block invalid\n", __func__, hash.ToString());
return state.Invalid(BlockValidationResult::BLOCK_INVALID_PREV, "bad-prevblk");
}
}
@@ -4499,7 +4500,7 @@ bool LoadMempool(CTxMemPool& pool, CChainState& active_chainstate, FopenFn mocka
// wallet(s) having loaded it while we were processing
// mempool transactions; consider these as valid, instead of
// failed, but mark them as 'already there'
- if (pool.exists(tx->GetHash())) {
+ if (pool.exists(GenTxid::Txid(tx->GetHash()))) {
++already_there;
} else {
++failed;
diff --git a/src/validation.h b/src/validation.h
index b10050f931..1c23b3ad5c 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -75,7 +75,7 @@ static const char* const DEFAULT_BLOCKFILTERINDEX = "0";
static const bool DEFAULT_PERSIST_MEMPOOL = true;
/** Default for -stopatheight */
static const int DEFAULT_STOPATHEIGHT = 0;
-/** Block files containing a block-height within MIN_BLOCKS_TO_KEEP of ::ChainActive().Tip() will not be pruned. */
+/** Block files containing a block-height within MIN_BLOCKS_TO_KEEP of ActiveChain().Tip() will not be pruned. */
static const unsigned int MIN_BLOCKS_TO_KEEP = 288;
static const signed int DEFAULT_CHECKBLOCKS = 6;
static const unsigned int DEFAULT_CHECKLEVEL = 3;
diff --git a/src/wallet/bdb.cpp b/src/wallet/bdb.cpp
index 2eb4d3106c..2290e119fd 100644
--- a/src/wallet/bdb.cpp
+++ b/src/wallet/bdb.cpp
@@ -61,9 +61,9 @@ bool WalletDatabaseFileId::operator==(const WalletDatabaseFileId& rhs) const
std::shared_ptr<BerkeleyEnvironment> GetBerkeleyEnv(const fs::path& env_directory)
{
LOCK(cs_db);
- auto inserted = g_dbenvs.emplace(env_directory.string(), std::weak_ptr<BerkeleyEnvironment>());
+ auto inserted = g_dbenvs.emplace(fs::PathToString(env_directory), std::weak_ptr<BerkeleyEnvironment>());
if (inserted.second) {
- auto env = std::make_shared<BerkeleyEnvironment>(env_directory.string());
+ auto env = std::make_shared<BerkeleyEnvironment>(env_directory);
inserted.first->second = env;
return env;
}
@@ -101,7 +101,7 @@ void BerkeleyEnvironment::Close()
if (error_file) fclose(error_file);
- UnlockDirectory(strPath, ".walletlock");
+ UnlockDirectory(fs::PathFromString(strPath), ".walletlock");
}
void BerkeleyEnvironment::Reset()
@@ -111,7 +111,7 @@ void BerkeleyEnvironment::Reset()
fMockDb = false;
}
-BerkeleyEnvironment::BerkeleyEnvironment(const fs::path& dir_path) : strPath(dir_path.string())
+BerkeleyEnvironment::BerkeleyEnvironment(const fs::path& dir_path) : strPath(fs::PathToString(dir_path))
{
Reset();
}
@@ -129,24 +129,24 @@ bool BerkeleyEnvironment::Open(bilingual_str& err)
return true;
}
- fs::path pathIn = strPath;
+ fs::path pathIn = fs::PathFromString(strPath);
TryCreateDirectories(pathIn);
if (!LockDirectory(pathIn, ".walletlock")) {
LogPrintf("Cannot obtain a lock on wallet directory %s. Another instance of bitcoin may be using it.\n", strPath);
- err = strprintf(_("Error initializing wallet database environment %s!"), Directory());
+ err = strprintf(_("Error initializing wallet database environment %s!"), fs::quoted(fs::PathToString(Directory())));
return false;
}
fs::path pathLogDir = pathIn / "database";
TryCreateDirectories(pathLogDir);
fs::path pathErrorFile = pathIn / "db.log";
- LogPrintf("BerkeleyEnvironment::Open: LogDir=%s ErrorFile=%s\n", pathLogDir.string(), pathErrorFile.string());
+ LogPrintf("BerkeleyEnvironment::Open: LogDir=%s ErrorFile=%s\n", fs::PathToString(pathLogDir), fs::PathToString(pathErrorFile));
unsigned int nEnvFlags = 0;
if (gArgs.GetBoolArg("-privdb", DEFAULT_WALLET_PRIVDB))
nEnvFlags |= DB_PRIVATE;
- dbenv->set_lg_dir(pathLogDir.string().c_str());
+ dbenv->set_lg_dir(fs::PathToString(pathLogDir).c_str());
dbenv->set_cachesize(0, 0x100000, 1); // 1 MiB should be enough for just the wallet
dbenv->set_lg_bsize(0x10000);
dbenv->set_lg_max(1048576);
@@ -173,7 +173,7 @@ bool BerkeleyEnvironment::Open(bilingual_str& err)
LogPrintf("BerkeleyEnvironment::Open: Error %d closing failed database environment: %s\n", ret2, DbEnv::strerror(ret2));
}
Reset();
- err = strprintf(_("Error initializing wallet database environment %s!"), Directory());
+ err = strprintf(_("Error initializing wallet database environment %s!"), fs::quoted(fs::PathToString(Directory())));
if (ret == DB_RUNRECOVERY) {
err += Untranslated(" ") + _("This error could occur if this wallet was not shutdown cleanly and was last loaded using a build with a newer version of Berkeley DB. If so, please use the software that last loaded this wallet");
}
@@ -261,7 +261,7 @@ bool BerkeleyDatabase::Verify(bilingual_str& errorStr)
fs::path file_path = walletDir / strFile;
LogPrintf("Using BerkeleyDB version %s\n", BerkeleyDatabaseVersion());
- LogPrintf("Using wallet %s\n", file_path.string());
+ LogPrintf("Using wallet %s\n", fs::PathToString(file_path));
if (!env->Open(errorStr)) {
return false;
@@ -274,7 +274,7 @@ bool BerkeleyDatabase::Verify(bilingual_str& errorStr)
Db db(env->dbenv.get(), 0);
int result = db.verify(strFile.c_str(), nullptr, nullptr, 0);
if (result != 0) {
- errorStr = strprintf(_("%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring a backup."), file_path);
+ errorStr = strprintf(_("%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring a backup."), fs::quoted(fs::PathToString(file_path)));
return false;
}
}
@@ -566,7 +566,7 @@ void BerkeleyEnvironment::Flush(bool fShutdown)
dbenv->log_archive(&listp, DB_ARCH_REMOVE);
Close();
if (!fMockDb) {
- fs::remove_all(fs::path(strPath) / "database");
+ fs::remove_all(fs::PathFromString(strPath) / "database");
}
}
}
@@ -614,21 +614,21 @@ bool BerkeleyDatabase::Backup(const std::string& strDest) const
// Copy wallet file
fs::path pathSrc = env->Directory() / strFile;
- fs::path pathDest(strDest);
+ fs::path pathDest(fs::PathFromString(strDest));
if (fs::is_directory(pathDest))
- pathDest /= strFile;
+ pathDest /= fs::PathFromString(strFile);
try {
if (fs::equivalent(pathSrc, pathDest)) {
- LogPrintf("cannot backup to wallet source file %s\n", pathDest.string());
+ LogPrintf("cannot backup to wallet source file %s\n", fs::PathToString(pathDest));
return false;
}
fs::copy_file(pathSrc, pathDest, fs::copy_option::overwrite_if_exists);
- LogPrintf("copied %s to %s\n", strFile, pathDest.string());
+ LogPrintf("copied %s to %s\n", strFile, fs::PathToString(pathDest));
return true;
} catch (const fs::filesystem_error& e) {
- LogPrintf("error copying %s to %s - %s\n", strFile, pathDest.string(), fsbridge::get_filesystem_error_message(e));
+ LogPrintf("error copying %s to %s - %s\n", strFile, fs::PathToString(pathDest), fsbridge::get_filesystem_error_message(e));
return false;
}
}
@@ -828,10 +828,10 @@ std::unique_ptr<BerkeleyDatabase> MakeBerkeleyDatabase(const fs::path& path, con
std::unique_ptr<BerkeleyDatabase> db;
{
LOCK(cs_db); // Lock env.m_databases until insert in BerkeleyDatabase constructor
- std::string data_filename = data_file.filename().string();
+ std::string data_filename = fs::PathToString(data_file.filename());
std::shared_ptr<BerkeleyEnvironment> env = GetBerkeleyEnv(data_file.parent_path());
if (env->m_databases.count(data_filename)) {
- error = Untranslated(strprintf("Refusing to load database. Data file '%s' is already loaded.", (env->Directory() / data_filename).string()));
+ error = Untranslated(strprintf("Refusing to load database. Data file '%s' is already loaded.", fs::PathToString(env->Directory() / data_filename)));
status = DatabaseStatus::FAILED_ALREADY_LOADED;
return nullptr;
}
diff --git a/src/wallet/bdb.h b/src/wallet/bdb.h
index a8209587d7..b666a8e73a 100644
--- a/src/wallet/bdb.h
+++ b/src/wallet/bdb.h
@@ -63,7 +63,7 @@ public:
bool IsMock() const { return fMockDb; }
bool IsInitialized() const { return fDbEnvInit; }
- fs::path Directory() const { return strPath; }
+ fs::path Directory() const { return fs::PathFromString(strPath); }
bool Open(bilingual_str& error);
void Close();
@@ -141,7 +141,7 @@ public:
bool Verify(bilingual_str& error);
/** Return path to main database filename */
- std::string Filename() override { return (env->Directory() / strFile).string(); }
+ std::string Filename() override { return fs::PathToString(env->Directory() / strFile); }
std::string Format() override { return "bdb"; }
/**
diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp
index 8d5316e0af..c74c69ed09 100644
--- a/src/wallet/db.cpp
+++ b/src/wallet/db.cpp
@@ -12,7 +12,7 @@
std::vector<fs::path> ListDatabases(const fs::path& wallet_dir)
{
- const size_t offset = wallet_dir.string().size() + (wallet_dir == wallet_dir.root_name() ? 0 : 1);
+ const size_t offset = wallet_dir.native().size() + (wallet_dir == wallet_dir.root_name() ? 0 : 1);
std::vector<fs::path> paths;
boost::system::error_code ec;
@@ -20,9 +20,9 @@ std::vector<fs::path> ListDatabases(const fs::path& wallet_dir)
if (ec) {
if (fs::is_directory(*it)) {
it.no_push();
- LogPrintf("%s: %s %s -- skipping.\n", __func__, ec.message(), it->path().string());
+ LogPrintf("%s: %s %s -- skipping.\n", __func__, ec.message(), fs::PathToString(it->path()));
} else {
- LogPrintf("%s: %s %s\n", __func__, ec.message(), it->path().string());
+ LogPrintf("%s: %s %s\n", __func__, ec.message(), fs::PathToString(it->path()));
}
continue;
}
@@ -30,7 +30,8 @@ std::vector<fs::path> ListDatabases(const fs::path& wallet_dir)
try {
// Get wallet path relative to walletdir by removing walletdir from the wallet path.
// This can be replaced by boost::filesystem::lexically_relative once boost is bumped to 1.60.
- const fs::path path = it->path().string().substr(offset);
+ const auto path_str = it->path().native().substr(offset);
+ const fs::path path{path_str.begin(), path_str.end()};
if (it->status().type() == fs::directory_file &&
(IsBDBFile(BDBDataFile(it->path())) || IsSQLiteFile(SQLiteDataFile(it->path())))) {
@@ -50,7 +51,7 @@ std::vector<fs::path> ListDatabases(const fs::path& wallet_dir)
}
}
} catch (const std::exception& e) {
- LogPrintf("%s: Error scanning %s: %s\n", __func__, it->path().string(), e.what());
+ LogPrintf("%s: Error scanning %s: %s\n", __func__, fs::PathToString(it->path()), e.what());
it.no_push();
}
}
@@ -85,7 +86,7 @@ bool IsBDBFile(const fs::path& path)
// This check also prevents opening lock files.
boost::system::error_code ec;
auto size = fs::file_size(path, ec);
- if (ec) LogPrintf("%s: %s %s\n", __func__, ec.message(), path.string());
+ if (ec) LogPrintf("%s: %s %s\n", __func__, ec.message(), fs::PathToString(path));
if (size < 4096) return false;
fsbridge::ifstream file(path, std::ios::binary);
@@ -109,7 +110,7 @@ bool IsSQLiteFile(const fs::path& path)
// A SQLite Database file is at least 512 bytes.
boost::system::error_code ec;
auto size = fs::file_size(path, ec);
- if (ec) LogPrintf("%s: %s %s\n", __func__, ec.message(), path.string());
+ if (ec) LogPrintf("%s: %s %s\n", __func__, ec.message(), fs::PathToString(path));
if (size < 512) return false;
fsbridge::ifstream file(path, std::ios::binary);
diff --git a/src/wallet/dump.cpp b/src/wallet/dump.cpp
index c39c0c7e73..08d94b76d9 100644
--- a/src/wallet/dump.cpp
+++ b/src/wallet/dump.cpp
@@ -19,16 +19,16 @@ bool DumpWallet(CWallet& wallet, bilingual_str& error)
return false;
}
- fs::path path = dump_filename;
+ fs::path path = fs::PathFromString(dump_filename);
path = fs::absolute(path);
if (fs::exists(path)) {
- error = strprintf(_("File %s already exists. If you are sure this is what you want, move it out of the way first."), path.string());
+ error = strprintf(_("File %s already exists. If you are sure this is what you want, move it out of the way first."), fs::PathToString(path));
return false;
}
fsbridge::ofstream dump_file;
dump_file.open(path);
if (dump_file.fail()) {
- error = strprintf(_("Unable to open %s for writing"), path.string());
+ error = strprintf(_("Unable to open %s for writing"), fs::PathToString(path));
return false;
}
@@ -114,10 +114,10 @@ bool CreateFromDump(const std::string& name, const fs::path& wallet_path, biling
return false;
}
- fs::path dump_path = dump_filename;
+ fs::path dump_path = fs::PathFromString(dump_filename);
dump_path = fs::absolute(dump_path);
if (!fs::exists(dump_path)) {
- error = strprintf(_("Dump file %s does not exist."), dump_path.string());
+ error = strprintf(_("Dump file %s does not exist."), fs::PathToString(dump_path));
return false;
}
fsbridge::ifstream dump_file(dump_path);
diff --git a/src/wallet/interfaces.cpp b/src/wallet/interfaces.cpp
index 7d0cdb6934..57f1a6a67a 100644
--- a/src/wallet/interfaces.cpp
+++ b/src/wallet/interfaces.cpp
@@ -551,13 +551,13 @@ public:
}
std::string getWalletDir() override
{
- return GetWalletDir().string();
+ return fs::PathToString(GetWalletDir());
}
std::vector<std::string> listWalletDir() override
{
std::vector<std::string> paths;
for (auto& path : ListDatabases(GetWalletDir())) {
- paths.push_back(path.string());
+ paths.push_back(fs::PathToString(path));
}
return paths;
}
diff --git a/src/wallet/load.cpp b/src/wallet/load.cpp
index 1b841026b8..7ef5a0cf55 100644
--- a/src/wallet/load.cpp
+++ b/src/wallet/load.cpp
@@ -25,25 +25,25 @@ bool VerifyWallets(WalletContext& context)
ArgsManager& args = *Assert(context.args);
if (args.IsArgSet("-walletdir")) {
- fs::path wallet_dir = args.GetArg("-walletdir", "");
+ fs::path wallet_dir = fs::PathFromString(args.GetArg("-walletdir", ""));
boost::system::error_code error;
// The canonical path cleans the path, preventing >1 Berkeley environment instances for the same directory
fs::path canonical_wallet_dir = fs::canonical(wallet_dir, error);
if (error || !fs::exists(wallet_dir)) {
- chain.initError(strprintf(_("Specified -walletdir \"%s\" does not exist"), wallet_dir.string()));
+ chain.initError(strprintf(_("Specified -walletdir \"%s\" does not exist"), fs::PathToString(wallet_dir)));
return false;
} else if (!fs::is_directory(wallet_dir)) {
- chain.initError(strprintf(_("Specified -walletdir \"%s\" is not a directory"), wallet_dir.string()));
+ chain.initError(strprintf(_("Specified -walletdir \"%s\" is not a directory"), fs::PathToString(wallet_dir)));
return false;
// The canonical path transforms relative paths into absolute ones, so we check the non-canonical version
} else if (!wallet_dir.is_absolute()) {
- chain.initError(strprintf(_("Specified -walletdir \"%s\" is a relative path"), wallet_dir.string()));
+ chain.initError(strprintf(_("Specified -walletdir \"%s\" is a relative path"), fs::PathToString(wallet_dir)));
return false;
}
- args.ForceSetArg("-walletdir", canonical_wallet_dir.string());
+ args.ForceSetArg("-walletdir", fs::PathToString(canonical_wallet_dir));
}
- LogPrintf("Using wallet directory %s\n", GetWalletDir().string());
+ LogPrintf("Using wallet directory %s\n", fs::PathToString(GetWalletDir()));
chain.initMessage(_("Verifying wallet(s)…").translated);
@@ -70,7 +70,7 @@ bool VerifyWallets(WalletContext& context)
for (const auto& wallet : chain.getSettingsList("wallet")) {
const auto& wallet_file = wallet.get_str();
- const fs::path path = fsbridge::AbsPathJoin(GetWalletDir(), wallet_file);
+ const fs::path path = fsbridge::AbsPathJoin(GetWalletDir(), fs::PathFromString(wallet_file));
if (!wallet_paths.insert(path).second) {
chain.initWarning(strprintf(_("Ignoring duplicate -wallet %s."), wallet_file));
@@ -102,7 +102,7 @@ bool LoadWallets(WalletContext& context)
std::set<fs::path> wallet_paths;
for (const auto& wallet : chain.getSettingsList("wallet")) {
const auto& name = wallet.get_str();
- if (!wallet_paths.insert(name).second) {
+ if (!wallet_paths.insert(fs::PathFromString(name)).second) {
continue;
}
DatabaseOptions options;
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index 4d7fb2d38c..9b09bc23d6 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -550,7 +550,7 @@ RPCHelpMan importwallet()
EnsureWalletIsUnlocked(*pwallet);
fsbridge::ifstream file;
- file.open(request.params[0].get_str(), std::ios::in | std::ios::ate);
+ file.open(fs::u8path(request.params[0].get_str()), std::ios::in | std::ios::ate);
if (!file.is_open()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file");
}
@@ -745,7 +745,7 @@ RPCHelpMan dumpwallet()
EnsureWalletIsUnlocked(wallet);
- fs::path filepath = request.params[0].get_str();
+ fs::path filepath = fs::u8path(request.params[0].get_str());
filepath = fs::absolute(filepath);
/* Prevent arbitrary files from being overwritten. There have been reports
@@ -754,7 +754,7 @@ RPCHelpMan dumpwallet()
* It may also avoid other security issues.
*/
if (fs::exists(filepath)) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, filepath.string() + " already exists. If you are sure this is what you want, move it out of the way first");
+ throw JSONRPCError(RPC_INVALID_PARAMETER, filepath.u8string() + " already exists. If you are sure this is what you want, move it out of the way first");
}
fsbridge::ofstream file;
@@ -844,7 +844,7 @@ RPCHelpMan dumpwallet()
file.close();
UniValue reply(UniValue::VOBJ);
- reply.pushKV("filename", filepath.string());
+ reply.pushKV("filename", filepath.u8string());
return reply;
},
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 8b481bc29c..f2f28c83ff 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -1389,8 +1389,9 @@ static const std::vector<RPCResult> TransactionDescriptionString()
{
return{{RPCResult::Type::NUM, "confirmations", "The number of confirmations for the transaction. Negative confirmations means the\n"
"transaction conflicted that many blocks ago."},
- {RPCResult::Type::BOOL, "generated", /* optional */ true, "Only present if transaction only input is a coinbase one."},
- {RPCResult::Type::BOOL, "trusted", /* optional */ true, "Only present if we consider transaction to be trusted and so safe to spend from."},
+ {RPCResult::Type::BOOL, "generated", /* optional */ true, "Only present if the transaction's only input is a coinbase one."},
+ {RPCResult::Type::BOOL, "trusted", /* optional */ true, "Whether we consider the transaction to be trusted and safe to spend from.\n"
+ "Only present when the transaction has 0 confirmations (or negative confirmations, if conflicted)."},
{RPCResult::Type::STR_HEX, "blockhash", /* optional */ true, "The block hash containing the transaction."},
{RPCResult::Type::NUM, "blockheight", /* optional */ true, "The block height containing the transaction."},
{RPCResult::Type::NUM, "blockindex", /* optional */ true, "The index of the transaction in the block that includes it."},
@@ -1408,7 +1409,7 @@ static const std::vector<RPCResult> TransactionDescriptionString()
{RPCResult::Type::NUM_TIME, "timereceived", "The time received expressed in " + UNIX_EPOCH_TIME + "."},
{RPCResult::Type::STR, "comment", /* optional */ true, "If a comment is associated with the transaction, only present if not empty."},
{RPCResult::Type::STR, "bip125-replaceable", "(\"yes|no|unknown\") Whether this transaction could be replaced due to BIP125 (replace-by-fee);\n"
- "may be unknown for unconfirmed transactions not in the mempool"}};
+ "may be unknown for unconfirmed transactions not in the mempool."}};
}
static RPCHelpMan listtransactions()
@@ -1854,7 +1855,7 @@ static RPCHelpMan keypoolrefill()
"\nFills the keypool."+
HELP_REQUIRING_PASSPHRASE,
{
- {"newsize", RPCArg::Type::NUM, RPCArg::Default{100}, "The new keypool size"},
+ {"newsize", RPCArg::Type::NUM, RPCArg::DefaultHint{strprintf("%u, or as set by -keypool", DEFAULT_KEYPOOL_SIZE)}, "The new keypool size"},
},
RPCResult{RPCResult::Type::NONE, "", ""},
RPCExamples{
@@ -1893,6 +1894,33 @@ static RPCHelpMan keypoolrefill()
}
+static RPCHelpMan newkeypool()
+{
+ return RPCHelpMan{"newkeypool",
+ "\nEntirely clears and refills the keypool."+
+ HELP_REQUIRING_PASSPHRASE,
+ {},
+ RPCResult{RPCResult::Type::NONE, "", ""},
+ RPCExamples{
+ HelpExampleCli("newkeypool", "")
+ + HelpExampleRpc("newkeypool", "")
+ },
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
+ std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!pwallet) return NullUniValue;
+
+ LOCK(pwallet->cs_wallet);
+
+ LegacyScriptPubKeyMan& spk_man = EnsureLegacyScriptPubKeyMan(*pwallet, true);
+ spk_man.NewKeyPool();
+
+ return NullUniValue;
+},
+ };
+}
+
+
static RPCHelpMan walletpassphrase()
{
return RPCHelpMan{"walletpassphrase",
@@ -2555,7 +2583,7 @@ static RPCHelpMan listwalletdir()
UniValue wallets(UniValue::VARR);
for (const auto& path : ListDatabases(GetWalletDir())) {
UniValue wallet(UniValue::VOBJ);
- wallet.pushKV("name", path.string());
+ wallet.pushKV("name", path.u8string());
wallets.push_back(wallet);
}
@@ -2743,7 +2771,7 @@ static RPCHelpMan createwallet()
{"blank", RPCArg::Type::BOOL, RPCArg::Default{false}, "Create a blank wallet. A blank wallet has no keys or HD seed. One can be set using sethdseed."},
{"passphrase", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "Encrypt the wallet with this passphrase."},
{"avoid_reuse", RPCArg::Type::BOOL, RPCArg::Default{false}, "Keep track of coin reuse, and treat dirty and clean coins differently with privacy considerations in mind."},
- {"descriptors", RPCArg::Type::BOOL, RPCArg::Default{false}, "Create a native descriptor wallet. The wallet will use descriptors internally to handle address creation"},
+ {"descriptors", RPCArg::Type::BOOL, RPCArg::Default{true}, "Create a native descriptor wallet. The wallet will use descriptors internally to handle address creation"},
{"load_on_startup", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED_NAMED_ARG, "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."},
{"external_signer", RPCArg::Type::BOOL, RPCArg::Default{false}, "Use an external signer such as a hardware wallet. Requires -signer to be configured. Wallet creation will fail if keys cannot be fetched. Requires disable_private_keys and descriptors set to true."},
},
@@ -2785,12 +2813,11 @@ static RPCHelpMan createwallet()
if (!request.params[4].isNull() && request.params[4].get_bool()) {
flags |= WALLET_FLAG_AVOID_REUSE;
}
- if (!request.params[5].isNull() && request.params[5].get_bool()) {
+ if (request.params[5].isNull() || request.params[5].get_bool()) {
#ifndef USE_SQLITE
throw JSONRPCError(RPC_WALLET_ERROR, "Compiled without sqlite support (required for descriptor wallets)");
#endif
flags |= WALLET_FLAG_DESCRIPTORS;
- warnings.emplace_back(Untranslated("Wallet is an experimental descriptor wallet"));
}
if (!request.params[7].isNull() && request.params[7].get_bool()) {
#ifdef ENABLE_EXTERNAL_SIGNER
@@ -2856,7 +2883,7 @@ static RPCHelpMan restorewallet()
WalletContext& context = EnsureWalletContext(request.context);
- std::string backup_file = request.params[1].get_str();
+ auto backup_file = fs::u8path(request.params[1].get_str());
if (!fs::exists(backup_file)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Backup file does not exist");
@@ -2864,14 +2891,14 @@ static RPCHelpMan restorewallet()
std::string wallet_name = request.params[0].get_str();
- const fs::path wallet_path = fsbridge::AbsPathJoin(GetWalletDir(), wallet_name);
+ const fs::path wallet_path = fsbridge::AbsPathJoin(GetWalletDir(), fs::u8path(wallet_name));
if (fs::exists(wallet_path)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Wallet name already exists.");
}
if (!TryCreateDirectories(wallet_path)) {
- throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Failed to create database path '%s'. Database already exists.", wallet_path.string()));
+ throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Failed to create database path '%s'. Database already exists.", wallet_path.u8string()));
}
auto wallet_file = wallet_path / "wallet.dat";
@@ -4875,6 +4902,7 @@ static const CRPCCommand commands[] =
{ "wallet", &listwallets, },
{ "wallet", &loadwallet, },
{ "wallet", &lockunspent, },
+ { "wallet", &newkeypool, },
{ "wallet", &removeprunedfunds, },
{ "wallet", &rescanblockchain, },
{ "wallet", &send, },
diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp
index fdfb36bb0a..619ebc8b4f 100644
--- a/src/wallet/scriptpubkeyman.cpp
+++ b/src/wallet/scriptpubkeyman.cpp
@@ -489,7 +489,7 @@ bool LegacyScriptPubKeyMan::Upgrade(int prev_version, int new_version, bilingual
}
// Regenerate the keypool if upgraded to HD
if (hd_upgrade) {
- if (!TopUp()) {
+ if (!NewKeyPool()) {
error = _("Unable to generate keys");
return false;
}
diff --git a/src/wallet/sqlite.cpp b/src/wallet/sqlite.cpp
index 815d17967c..650e083e8e 100644
--- a/src/wallet/sqlite.cpp
+++ b/src/wallet/sqlite.cpp
@@ -67,7 +67,7 @@ static void SetPragma(sqlite3* db, const std::string& key, const std::string& va
}
SQLiteDatabase::SQLiteDatabase(const fs::path& dir_path, const fs::path& file_path, bool mock)
- : WalletDatabase(), m_mock(mock), m_dir_path(dir_path.string()), m_file_path(file_path.string())
+ : WalletDatabase(), m_mock(mock), m_dir_path(fs::PathToString(dir_path)), m_file_path(fs::PathToString(file_path))
{
{
LOCK(g_sqlite_mutex);
@@ -206,7 +206,7 @@ void SQLiteDatabase::Open()
if (m_db == nullptr) {
if (!m_mock) {
- TryCreateDirectories(m_dir_path);
+ TryCreateDirectories(fs::PathFromString(m_dir_path));
}
int ret = sqlite3_open_v2(m_file_path.c_str(), &m_db, flags, nullptr);
if (ret != SQLITE_OK) {
diff --git a/src/wallet/test/coinselector_tests.cpp b/src/wallet/test/coinselector_tests.cpp
index f80c4637b8..e880e13845 100644
--- a/src/wallet/test/coinselector_tests.cpp
+++ b/src/wallet/test/coinselector_tests.cpp
@@ -28,19 +28,9 @@ BOOST_FIXTURE_TEST_SUITE(coinselector_tests, WalletTestingSetup)
typedef std::set<CInputCoin> CoinSet;
-static std::vector<COutput> vCoins;
-static NodeContext testNode;
-static auto testChain = interfaces::MakeChain(testNode);
-static CWallet testWallet(testChain.get(), "", CreateDummyWalletDatabase());
-static CAmount balance = 0;
-
-CoinEligibilityFilter filter_standard(1, 6, 0);
-CoinEligibilityFilter filter_confirmed(1, 1, 0);
-CoinEligibilityFilter filter_standard_extra(6, 6, 0);
-CoinSelectionParams coin_selection_params(/* change_output_size= */ 0,
- /* change_spend_size= */ 0, /* effective_feerate= */ CFeeRate(0),
- /* long_term_feerate= */ CFeeRate(0), /* discard_feerate= */ CFeeRate(0),
- /* tx_noinputs_size= */ 0, /* avoid_partial= */ false);
+static const CoinEligibilityFilter filter_standard(1, 6, 0);
+static const CoinEligibilityFilter filter_confirmed(1, 1, 0);
+static const CoinEligibilityFilter filter_standard_extra(6, 6, 0);
static void add_coin(const CAmount& nValue, int nInput, std::vector<CInputCoin>& set)
{
@@ -62,9 +52,8 @@ static void add_coin(const CAmount& nValue, int nInput, CoinSet& set, CAmount fe
set.insert(coin);
}
-static void add_coin(CWallet& wallet, const CAmount& nValue, int nAge = 6*24, bool fIsFromMe = false, int nInput=0, bool spendable = false)
+static void add_coin(std::vector<COutput>& coins, CWallet& wallet, const CAmount& nValue, int nAge = 6*24, bool fIsFromMe = false, int nInput=0, bool spendable = false)
{
- balance += nValue;
static int nextLockTime = 0;
CMutableTransaction tx;
tx.nLockTime = nextLockTime++; // so all transactions get different hashes
@@ -89,17 +78,7 @@ static void add_coin(CWallet& wallet, const CAmount& nValue, int nAge = 6*24, bo
wtx->m_is_cache_empty = false;
}
COutput output(wallet, *wtx, nInput, nAge, true /* spendable */, true /* solvable */, true /* safe */);
- vCoins.push_back(output);
-}
-static void add_coin(const CAmount& nValue, int nAge = 6*24, bool fIsFromMe = false, int nInput=0, bool spendable = false)
-{
- add_coin(testWallet, nValue, nAge, fIsFromMe, nInput, spendable);
-}
-
-static void empty_wallet(void)
-{
- vCoins.clear();
- balance = 0;
+ coins.push_back(output);
}
static bool equal_sets(CoinSet a, CoinSet b)
@@ -142,20 +121,20 @@ inline std::vector<OutputGroup>& GroupCoins(const std::vector<COutput>& coins)
return static_groups;
}
-inline std::vector<OutputGroup>& KnapsackGroupOutputs(const CoinEligibilityFilter& filter)
+inline std::vector<OutputGroup>& KnapsackGroupOutputs(const std::vector<COutput>& coins, CWallet& wallet, const CoinEligibilityFilter& filter)
{
+ CoinSelectionParams coin_selection_params(/* change_output_size= */ 0,
+ /* change_spend_size= */ 0, /* effective_feerate= */ CFeeRate(0),
+ /* long_term_feerate= */ CFeeRate(0), /* discard_feerate= */ CFeeRate(0),
+ /* tx_noinputs_size= */ 0, /* avoid_partial= */ false);
static std::vector<OutputGroup> static_groups;
- static_groups = GroupOutputs(testWallet, vCoins, coin_selection_params, filter, /* positive_only */false);
+ static_groups = GroupOutputs(wallet, coins, coin_selection_params, filter, /* positive_only */false);
return static_groups;
}
// Branch and bound coin selection tests
BOOST_AUTO_TEST_CASE(bnb_search_test)
{
-
- LOCK(testWallet.cs_wallet);
- testWallet.SetupLegacyScriptPubKeyMan();
-
// Setup
std::vector<CInputCoin> utxo_pool;
CoinSet selection;
@@ -288,196 +267,213 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
/* change_spend_size= */ 0, /* effective_feerate= */ CFeeRate(3000),
/* long_term_feerate= */ CFeeRate(1000), /* discard_feerate= */ CFeeRate(1000),
/* tx_noinputs_size= */ 0, /* avoid_partial= */ false);
- CoinSet setCoinsRet;
- CAmount nValueRet;
- empty_wallet();
- add_coin(1);
- vCoins.at(0).nInputBytes = 40; // Make sure that it has a negative effective value. The next check should assert if this somehow got through. Otherwise it will fail
- BOOST_CHECK(!SelectCoinsBnB(GroupCoins(vCoins), 1 * CENT, coin_selection_params_bnb.m_cost_of_change, setCoinsRet, nValueRet));
-
- // Test fees subtracted from output:
- empty_wallet();
- add_coin(1 * CENT);
- vCoins.at(0).nInputBytes = 40;
- coin_selection_params_bnb.m_subtract_fee_outputs = true;
- BOOST_CHECK(SelectCoinsBnB(GroupCoins(vCoins), 1 * CENT, coin_selection_params_bnb.m_cost_of_change, setCoinsRet, nValueRet));
- BOOST_CHECK_EQUAL(nValueRet, 1 * CENT);
-
- // Make sure that can use BnB when there are preset inputs
- empty_wallet();
{
std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(m_node.chain.get(), "", CreateMockWalletDatabase());
wallet->LoadWallet();
- wallet->SetupLegacyScriptPubKeyMan();
LOCK(wallet->cs_wallet);
- add_coin(*wallet, 5 * CENT, 6 * 24, false, 0, true);
- add_coin(*wallet, 3 * CENT, 6 * 24, false, 0, true);
- add_coin(*wallet, 2 * CENT, 6 * 24, false, 0, true);
+ wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
+ wallet->SetupDescriptorScriptPubKeyMans();
+
+ std::vector<COutput> coins;
+ CoinSet setCoinsRet;
+ CAmount nValueRet;
+
+ add_coin(coins, *wallet, 1);
+ coins.at(0).nInputBytes = 40; // Make sure that it has a negative effective value. The next check should assert if this somehow got through. Otherwise it will fail
+ BOOST_CHECK(!SelectCoinsBnB(GroupCoins(coins), 1 * CENT, coin_selection_params_bnb.m_cost_of_change, setCoinsRet, nValueRet));
+
+ // Test fees subtracted from output:
+ coins.clear();
+ add_coin(coins, *wallet, 1 * CENT);
+ coins.at(0).nInputBytes = 40;
+ coin_selection_params_bnb.m_subtract_fee_outputs = true;
+ BOOST_CHECK(SelectCoinsBnB(GroupCoins(coins), 1 * CENT, coin_selection_params_bnb.m_cost_of_change, setCoinsRet, nValueRet));
+ BOOST_CHECK_EQUAL(nValueRet, 1 * CENT);
+ }
+
+ {
+ std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(m_node.chain.get(), "", CreateMockWalletDatabase());
+ wallet->LoadWallet();
+ LOCK(wallet->cs_wallet);
+ wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
+ wallet->SetupDescriptorScriptPubKeyMans();
+
+ std::vector<COutput> coins;
+ CoinSet setCoinsRet;
+ CAmount nValueRet;
+
+ add_coin(coins, *wallet, 5 * CENT, 6 * 24, false, 0, true);
+ add_coin(coins, *wallet, 3 * CENT, 6 * 24, false, 0, true);
+ add_coin(coins, *wallet, 2 * CENT, 6 * 24, false, 0, true);
CCoinControl coin_control;
coin_control.fAllowOtherInputs = true;
- coin_control.Select(COutPoint(vCoins.at(0).tx->GetHash(), vCoins.at(0).i));
+ coin_control.Select(COutPoint(coins.at(0).tx->GetHash(), coins.at(0).i));
coin_selection_params_bnb.m_effective_feerate = CFeeRate(0);
- BOOST_CHECK(SelectCoins(*wallet, vCoins, 10 * CENT, setCoinsRet, nValueRet, coin_control, coin_selection_params_bnb));
+ BOOST_CHECK(SelectCoins(*wallet, coins, 10 * CENT, setCoinsRet, nValueRet, coin_control, coin_selection_params_bnb));
}
}
BOOST_AUTO_TEST_CASE(knapsack_solver_test)
{
+ std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(m_node.chain.get(), "", CreateMockWalletDatabase());
+ wallet->LoadWallet();
+ LOCK(wallet->cs_wallet);
+ wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
+ wallet->SetupDescriptorScriptPubKeyMans();
+
CoinSet setCoinsRet, setCoinsRet2;
CAmount nValueRet;
-
- LOCK(testWallet.cs_wallet);
- testWallet.SetupLegacyScriptPubKeyMan();
+ std::vector<COutput> coins;
// test multiple times to allow for differences in the shuffle order
for (int i = 0; i < RUN_TESTS; i++)
{
- empty_wallet();
+ coins.clear();
// with an empty wallet we can't even pay one cent
- BOOST_CHECK(!KnapsackSolver(1 * CENT, KnapsackGroupOutputs(filter_standard), setCoinsRet, nValueRet));
+ BOOST_CHECK(!KnapsackSolver(1 * CENT, KnapsackGroupOutputs(coins, *wallet, filter_standard), setCoinsRet, nValueRet));
- add_coin(1*CENT, 4); // add a new 1 cent coin
+ add_coin(coins, *wallet, 1*CENT, 4); // add a new 1 cent coin
// with a new 1 cent coin, we still can't find a mature 1 cent
- BOOST_CHECK(!KnapsackSolver(1 * CENT, KnapsackGroupOutputs(filter_standard), setCoinsRet, nValueRet));
+ BOOST_CHECK(!KnapsackSolver(1 * CENT, KnapsackGroupOutputs(coins, *wallet, filter_standard), setCoinsRet, nValueRet));
// but we can find a new 1 cent
- BOOST_CHECK(KnapsackSolver(1 * CENT, KnapsackGroupOutputs(filter_confirmed), setCoinsRet, nValueRet));
+ BOOST_CHECK(KnapsackSolver(1 * CENT, KnapsackGroupOutputs(coins, *wallet, filter_confirmed), setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 1 * CENT);
- add_coin(2*CENT); // add a mature 2 cent coin
+ add_coin(coins, *wallet, 2*CENT); // add a mature 2 cent coin
// we can't make 3 cents of mature coins
- BOOST_CHECK(!KnapsackSolver(3 * CENT, KnapsackGroupOutputs(filter_standard), setCoinsRet, nValueRet));
+ BOOST_CHECK(!KnapsackSolver(3 * CENT, KnapsackGroupOutputs(coins, *wallet, filter_standard), setCoinsRet, nValueRet));
// we can make 3 cents of new coins
- BOOST_CHECK(KnapsackSolver(3 * CENT, KnapsackGroupOutputs(filter_confirmed), setCoinsRet, nValueRet));
+ BOOST_CHECK(KnapsackSolver(3 * CENT, KnapsackGroupOutputs(coins, *wallet, filter_confirmed), setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 3 * CENT);
- add_coin(5*CENT); // add a mature 5 cent coin,
- add_coin(10*CENT, 3, true); // a new 10 cent coin sent from one of our own addresses
- add_coin(20*CENT); // and a mature 20 cent coin
+ add_coin(coins, *wallet, 5*CENT); // add a mature 5 cent coin,
+ add_coin(coins, *wallet, 10*CENT, 3, true); // a new 10 cent coin sent from one of our own addresses
+ add_coin(coins, *wallet, 20*CENT); // and a mature 20 cent coin
// now we have new: 1+10=11 (of which 10 was self-sent), and mature: 2+5+20=27. total = 38
// we can't make 38 cents only if we disallow new coins:
- BOOST_CHECK(!KnapsackSolver(38 * CENT, KnapsackGroupOutputs(filter_standard), setCoinsRet, nValueRet));
+ BOOST_CHECK(!KnapsackSolver(38 * CENT, KnapsackGroupOutputs(coins, *wallet, filter_standard), setCoinsRet, nValueRet));
// we can't even make 37 cents if we don't allow new coins even if they're from us
- BOOST_CHECK(!KnapsackSolver(38 * CENT, KnapsackGroupOutputs(filter_standard_extra), setCoinsRet, nValueRet));
+ BOOST_CHECK(!KnapsackSolver(38 * CENT, KnapsackGroupOutputs(coins, *wallet, filter_standard_extra), setCoinsRet, nValueRet));
// but we can make 37 cents if we accept new coins from ourself
- BOOST_CHECK(KnapsackSolver(37 * CENT, KnapsackGroupOutputs(filter_standard), setCoinsRet, nValueRet));
+ BOOST_CHECK(KnapsackSolver(37 * CENT, KnapsackGroupOutputs(coins, *wallet, filter_standard), setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 37 * CENT);
// and we can make 38 cents if we accept all new coins
- BOOST_CHECK(KnapsackSolver(38 * CENT, KnapsackGroupOutputs(filter_confirmed), setCoinsRet, nValueRet));
+ BOOST_CHECK(KnapsackSolver(38 * CENT, KnapsackGroupOutputs(coins, *wallet, filter_confirmed), setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 38 * CENT);
// try making 34 cents from 1,2,5,10,20 - we can't do it exactly
- BOOST_CHECK(KnapsackSolver(34 * CENT, KnapsackGroupOutputs(filter_confirmed), setCoinsRet, nValueRet));
+ BOOST_CHECK(KnapsackSolver(34 * CENT, KnapsackGroupOutputs(coins, *wallet, filter_confirmed), setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 35 * CENT); // but 35 cents is closest
BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U); // the best should be 20+10+5. it's incredibly unlikely the 1 or 2 got included (but possible)
// when we try making 7 cents, the smaller coins (1,2,5) are enough. We should see just 2+5
- BOOST_CHECK(KnapsackSolver(7 * CENT, KnapsackGroupOutputs(filter_confirmed), setCoinsRet, nValueRet));
+ BOOST_CHECK(KnapsackSolver(7 * CENT, KnapsackGroupOutputs(coins, *wallet, filter_confirmed), setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 7 * CENT);
BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U);
// when we try making 8 cents, the smaller coins (1,2,5) are exactly enough.
- BOOST_CHECK(KnapsackSolver(8 * CENT, KnapsackGroupOutputs(filter_confirmed), setCoinsRet, nValueRet));
+ BOOST_CHECK(KnapsackSolver(8 * CENT, KnapsackGroupOutputs(coins, *wallet, filter_confirmed), setCoinsRet, nValueRet));
BOOST_CHECK(nValueRet == 8 * CENT);
BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U);
// when we try making 9 cents, no subset of smaller coins is enough, and we get the next bigger coin (10)
- BOOST_CHECK(KnapsackSolver(9 * CENT, KnapsackGroupOutputs(filter_confirmed), setCoinsRet, nValueRet));
+ BOOST_CHECK(KnapsackSolver(9 * CENT, KnapsackGroupOutputs(coins, *wallet, filter_confirmed), setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 10 * CENT);
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);
// now clear out the wallet and start again to test choosing between subsets of smaller coins and the next biggest coin
- empty_wallet();
+ coins.clear();
- add_coin( 6*CENT);
- add_coin( 7*CENT);
- add_coin( 8*CENT);
- add_coin(20*CENT);
- add_coin(30*CENT); // now we have 6+7+8+20+30 = 71 cents total
+ add_coin(coins, *wallet, 6*CENT);
+ add_coin(coins, *wallet, 7*CENT);
+ add_coin(coins, *wallet, 8*CENT);
+ add_coin(coins, *wallet, 20*CENT);
+ add_coin(coins, *wallet, 30*CENT); // now we have 6+7+8+20+30 = 71 cents total
// check that we have 71 and not 72
- BOOST_CHECK(KnapsackSolver(71 * CENT, KnapsackGroupOutputs(filter_confirmed), setCoinsRet, nValueRet));
- BOOST_CHECK(!KnapsackSolver(72 * CENT, KnapsackGroupOutputs(filter_confirmed), setCoinsRet, nValueRet));
+ BOOST_CHECK(KnapsackSolver(71 * CENT, KnapsackGroupOutputs(coins, *wallet, filter_confirmed), setCoinsRet, nValueRet));
+ BOOST_CHECK(!KnapsackSolver(72 * CENT, KnapsackGroupOutputs(coins, *wallet, filter_confirmed), setCoinsRet, nValueRet));
// now try making 16 cents. the best smaller coins can do is 6+7+8 = 21; not as good at the next biggest coin, 20
- BOOST_CHECK(KnapsackSolver(16 * CENT, KnapsackGroupOutputs(filter_confirmed), setCoinsRet, nValueRet));
+ BOOST_CHECK(KnapsackSolver(16 * CENT, KnapsackGroupOutputs(coins, *wallet, filter_confirmed), setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 20 * CENT); // we should get 20 in one coin
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);
- add_coin( 5*CENT); // now we have 5+6+7+8+20+30 = 75 cents total
+ add_coin(coins, *wallet, 5*CENT); // now we have 5+6+7+8+20+30 = 75 cents total
// now if we try making 16 cents again, the smaller coins can make 5+6+7 = 18 cents, better than the next biggest coin, 20
- BOOST_CHECK(KnapsackSolver(16 * CENT, KnapsackGroupOutputs(filter_confirmed), setCoinsRet, nValueRet));
+ BOOST_CHECK(KnapsackSolver(16 * CENT, KnapsackGroupOutputs(coins, *wallet, filter_confirmed), setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 18 * CENT); // we should get 18 in 3 coins
BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U);
- add_coin( 18*CENT); // now we have 5+6+7+8+18+20+30
+ add_coin(coins, *wallet, 18*CENT); // now we have 5+6+7+8+18+20+30
// and now if we try making 16 cents again, the smaller coins can make 5+6+7 = 18 cents, the same as the next biggest coin, 18
- BOOST_CHECK(KnapsackSolver(16 * CENT, KnapsackGroupOutputs(filter_confirmed), setCoinsRet, nValueRet));
+ BOOST_CHECK(KnapsackSolver(16 * CENT, KnapsackGroupOutputs(coins, *wallet, filter_confirmed), setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 18 * CENT); // we should get 18 in 1 coin
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); // because in the event of a tie, the biggest coin wins
// now try making 11 cents. we should get 5+6
- BOOST_CHECK(KnapsackSolver(11 * CENT, KnapsackGroupOutputs(filter_confirmed), setCoinsRet, nValueRet));
+ BOOST_CHECK(KnapsackSolver(11 * CENT, KnapsackGroupOutputs(coins, *wallet, filter_confirmed), setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 11 * CENT);
BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U);
// check that the smallest bigger coin is used
- add_coin( 1*COIN);
- add_coin( 2*COIN);
- add_coin( 3*COIN);
- add_coin( 4*COIN); // now we have 5+6+7+8+18+20+30+100+200+300+400 = 1094 cents
- BOOST_CHECK(KnapsackSolver(95 * CENT, KnapsackGroupOutputs(filter_confirmed), setCoinsRet, nValueRet));
+ add_coin(coins, *wallet, 1*COIN);
+ add_coin(coins, *wallet, 2*COIN);
+ add_coin(coins, *wallet, 3*COIN);
+ add_coin(coins, *wallet, 4*COIN); // now we have 5+6+7+8+18+20+30+100+200+300+400 = 1094 cents
+ BOOST_CHECK(KnapsackSolver(95 * CENT, KnapsackGroupOutputs(coins, *wallet, filter_confirmed), setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 1 * COIN); // we should get 1 BTC in 1 coin
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);
- BOOST_CHECK(KnapsackSolver(195 * CENT, KnapsackGroupOutputs(filter_confirmed), setCoinsRet, nValueRet));
+ BOOST_CHECK(KnapsackSolver(195 * CENT, KnapsackGroupOutputs(coins, *wallet, filter_confirmed), setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 2 * COIN); // we should get 2 BTC in 1 coin
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);
// empty the wallet and start again, now with fractions of a cent, to test small change avoidance
- empty_wallet();
- add_coin(MIN_CHANGE * 1 / 10);
- add_coin(MIN_CHANGE * 2 / 10);
- add_coin(MIN_CHANGE * 3 / 10);
- add_coin(MIN_CHANGE * 4 / 10);
- add_coin(MIN_CHANGE * 5 / 10);
+ coins.clear();
+ add_coin(coins, *wallet, MIN_CHANGE * 1 / 10);
+ add_coin(coins, *wallet, MIN_CHANGE * 2 / 10);
+ add_coin(coins, *wallet, MIN_CHANGE * 3 / 10);
+ add_coin(coins, *wallet, MIN_CHANGE * 4 / 10);
+ add_coin(coins, *wallet, MIN_CHANGE * 5 / 10);
// try making 1 * MIN_CHANGE from the 1.5 * MIN_CHANGE
// we'll get change smaller than MIN_CHANGE whatever happens, so can expect MIN_CHANGE exactly
- BOOST_CHECK(KnapsackSolver(MIN_CHANGE, KnapsackGroupOutputs(filter_confirmed), setCoinsRet, nValueRet));
+ BOOST_CHECK(KnapsackSolver(MIN_CHANGE, KnapsackGroupOutputs(coins, *wallet, filter_confirmed), setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, MIN_CHANGE);
// but if we add a bigger coin, small change is avoided
- add_coin(1111*MIN_CHANGE);
+ add_coin(coins, *wallet, 1111*MIN_CHANGE);
// try making 1 from 0.1 + 0.2 + 0.3 + 0.4 + 0.5 + 1111 = 1112.5
- BOOST_CHECK(KnapsackSolver(1 * MIN_CHANGE, KnapsackGroupOutputs(filter_confirmed), setCoinsRet, nValueRet));
+ BOOST_CHECK(KnapsackSolver(1 * MIN_CHANGE, KnapsackGroupOutputs(coins, *wallet, filter_confirmed), setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 1 * MIN_CHANGE); // we should get the exact amount
// if we add more small coins:
- add_coin(MIN_CHANGE * 6 / 10);
- add_coin(MIN_CHANGE * 7 / 10);
+ add_coin(coins, *wallet, MIN_CHANGE * 6 / 10);
+ add_coin(coins, *wallet, MIN_CHANGE * 7 / 10);
// and try again to make 1.0 * MIN_CHANGE
- BOOST_CHECK(KnapsackSolver(1 * MIN_CHANGE, KnapsackGroupOutputs(filter_confirmed), setCoinsRet, nValueRet));
+ BOOST_CHECK(KnapsackSolver(1 * MIN_CHANGE, KnapsackGroupOutputs(coins, *wallet, filter_confirmed), setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 1 * MIN_CHANGE); // we should get the exact amount
// run the 'mtgox' test (see https://blockexplorer.com/tx/29a3efd3ef04f9153d47a990bd7b048a4b2d213daaa5fb8ed670fb85f13bdbcf)
// they tried to consolidate 10 50k coins into one 500k coin, and ended up with 50k in change
- empty_wallet();
+ coins.clear();
for (int j = 0; j < 20; j++)
- add_coin(50000 * COIN);
+ add_coin(coins, *wallet, 50000 * COIN);
- BOOST_CHECK(KnapsackSolver(500000 * COIN, KnapsackGroupOutputs(filter_confirmed), setCoinsRet, nValueRet));
+ BOOST_CHECK(KnapsackSolver(500000 * COIN, KnapsackGroupOutputs(coins, *wallet, filter_confirmed), setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 500000 * COIN); // we should get the exact amount
BOOST_CHECK_EQUAL(setCoinsRet.size(), 10U); // in ten coins
@@ -485,79 +481,79 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
// we need to try finding an exact subset anyway
// sometimes it will fail, and so we use the next biggest coin:
- empty_wallet();
- add_coin(MIN_CHANGE * 5 / 10);
- add_coin(MIN_CHANGE * 6 / 10);
- add_coin(MIN_CHANGE * 7 / 10);
- add_coin(1111 * MIN_CHANGE);
- BOOST_CHECK(KnapsackSolver(1 * MIN_CHANGE, KnapsackGroupOutputs(filter_confirmed), setCoinsRet, nValueRet));
+ coins.clear();
+ add_coin(coins, *wallet, MIN_CHANGE * 5 / 10);
+ add_coin(coins, *wallet, MIN_CHANGE * 6 / 10);
+ add_coin(coins, *wallet, MIN_CHANGE * 7 / 10);
+ add_coin(coins, *wallet, 1111 * MIN_CHANGE);
+ BOOST_CHECK(KnapsackSolver(1 * MIN_CHANGE, KnapsackGroupOutputs(coins, *wallet, filter_confirmed), setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 1111 * MIN_CHANGE); // we get the bigger coin
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);
// but sometimes it's possible, and we use an exact subset (0.4 + 0.6 = 1.0)
- empty_wallet();
- add_coin(MIN_CHANGE * 4 / 10);
- add_coin(MIN_CHANGE * 6 / 10);
- add_coin(MIN_CHANGE * 8 / 10);
- add_coin(1111 * MIN_CHANGE);
- BOOST_CHECK(KnapsackSolver(MIN_CHANGE, KnapsackGroupOutputs(filter_confirmed), setCoinsRet, nValueRet));
+ coins.clear();
+ add_coin(coins, *wallet, MIN_CHANGE * 4 / 10);
+ add_coin(coins, *wallet, MIN_CHANGE * 6 / 10);
+ add_coin(coins, *wallet, MIN_CHANGE * 8 / 10);
+ add_coin(coins, *wallet, 1111 * MIN_CHANGE);
+ BOOST_CHECK(KnapsackSolver(MIN_CHANGE, KnapsackGroupOutputs(coins, *wallet, filter_confirmed), setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, MIN_CHANGE); // we should get the exact amount
BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U); // in two coins 0.4+0.6
// test avoiding small change
- empty_wallet();
- add_coin(MIN_CHANGE * 5 / 100);
- add_coin(MIN_CHANGE * 1);
- add_coin(MIN_CHANGE * 100);
+ coins.clear();
+ add_coin(coins, *wallet, MIN_CHANGE * 5 / 100);
+ add_coin(coins, *wallet, MIN_CHANGE * 1);
+ add_coin(coins, *wallet, MIN_CHANGE * 100);
// trying to make 100.01 from these three coins
- BOOST_CHECK(KnapsackSolver(MIN_CHANGE * 10001 / 100, KnapsackGroupOutputs(filter_confirmed), setCoinsRet, nValueRet));
+ BOOST_CHECK(KnapsackSolver(MIN_CHANGE * 10001 / 100, KnapsackGroupOutputs(coins, *wallet, filter_confirmed), setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, MIN_CHANGE * 10105 / 100); // we should get all coins
BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U);
// but if we try to make 99.9, we should take the bigger of the two small coins to avoid small change
- BOOST_CHECK(KnapsackSolver(MIN_CHANGE * 9990 / 100, KnapsackGroupOutputs(filter_confirmed), setCoinsRet, nValueRet));
+ BOOST_CHECK(KnapsackSolver(MIN_CHANGE * 9990 / 100, KnapsackGroupOutputs(coins, *wallet, filter_confirmed), setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 101 * MIN_CHANGE);
BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U);
- }
-
- // test with many inputs
- for (CAmount amt=1500; amt < COIN; amt*=10) {
- empty_wallet();
- // Create 676 inputs (= (old MAX_STANDARD_TX_SIZE == 100000) / 148 bytes per input)
- for (uint16_t j = 0; j < 676; j++)
- add_coin(amt);
-
- // We only create the wallet once to save time, but we still run the coin selection RUN_TESTS times.
- for (int i = 0; i < RUN_TESTS; i++) {
- BOOST_CHECK(KnapsackSolver(2000, KnapsackGroupOutputs(filter_confirmed), setCoinsRet, nValueRet));
-
- if (amt - 2000 < MIN_CHANGE) {
- // needs more than one input:
- uint16_t returnSize = std::ceil((2000.0 + MIN_CHANGE)/amt);
- CAmount returnValue = amt * returnSize;
- BOOST_CHECK_EQUAL(nValueRet, returnValue);
- BOOST_CHECK_EQUAL(setCoinsRet.size(), returnSize);
- } else {
- // one input is sufficient:
- BOOST_CHECK_EQUAL(nValueRet, amt);
- BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);
- }
- }
- }
-
- // test randomness
- {
- empty_wallet();
- for (int i2 = 0; i2 < 100; i2++)
- add_coin(COIN);
-
- // Again, we only create the wallet once to save time, but we still run the coin selection RUN_TESTS times.
- for (int i = 0; i < RUN_TESTS; i++) {
+ }
+
+ // test with many inputs
+ for (CAmount amt=1500; amt < COIN; amt*=10) {
+ coins.clear();
+ // Create 676 inputs (= (old MAX_STANDARD_TX_SIZE == 100000) / 148 bytes per input)
+ for (uint16_t j = 0; j < 676; j++)
+ add_coin(coins, *wallet, amt);
+
+ // We only create the wallet once to save time, but we still run the coin selection RUN_TESTS times.
+ for (int i = 0; i < RUN_TESTS; i++) {
+ BOOST_CHECK(KnapsackSolver(2000, KnapsackGroupOutputs(coins, *wallet, filter_confirmed), setCoinsRet, nValueRet));
+
+ if (amt - 2000 < MIN_CHANGE) {
+ // needs more than one input:
+ uint16_t returnSize = std::ceil((2000.0 + MIN_CHANGE)/amt);
+ CAmount returnValue = amt * returnSize;
+ BOOST_CHECK_EQUAL(nValueRet, returnValue);
+ BOOST_CHECK_EQUAL(setCoinsRet.size(), returnSize);
+ } else {
+ // one input is sufficient:
+ BOOST_CHECK_EQUAL(nValueRet, amt);
+ BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);
+ }
+ }
+ }
+
+ // test randomness
+ {
+ coins.clear();
+ for (int i2 = 0; i2 < 100; i2++)
+ add_coin(coins, *wallet, COIN);
+
+ // Again, we only create the wallet once to save time, but we still run the coin selection RUN_TESTS times.
+ for (int i = 0; i < RUN_TESTS; i++) {
// picking 50 from 100 coins doesn't depend on the shuffle,
// but does depend on randomness in the stochastic approximation code
- BOOST_CHECK(KnapsackSolver(50 * COIN, GroupCoins(vCoins), setCoinsRet, nValueRet));
- BOOST_CHECK(KnapsackSolver(50 * COIN, GroupCoins(vCoins), setCoinsRet2, nValueRet));
+ BOOST_CHECK(KnapsackSolver(50 * COIN, GroupCoins(coins), setCoinsRet, nValueRet));
+ BOOST_CHECK(KnapsackSolver(50 * COIN, GroupCoins(coins), setCoinsRet2, nValueRet));
BOOST_CHECK(!equal_sets(setCoinsRet, setCoinsRet2));
int fails = 0;
@@ -567,66 +563,67 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
// When choosing 1 from 100 identical coins, 1% of the time, this test will choose the same coin twice
// which will cause it to fail.
// To avoid that issue, run the test RANDOM_REPEATS times and only complain if all of them fail
- BOOST_CHECK(KnapsackSolver(COIN, GroupCoins(vCoins), setCoinsRet, nValueRet));
- BOOST_CHECK(KnapsackSolver(COIN, GroupCoins(vCoins), setCoinsRet2, nValueRet));
+ BOOST_CHECK(KnapsackSolver(COIN, GroupCoins(coins), setCoinsRet, nValueRet));
+ BOOST_CHECK(KnapsackSolver(COIN, GroupCoins(coins), setCoinsRet2, nValueRet));
if (equal_sets(setCoinsRet, setCoinsRet2))
fails++;
}
BOOST_CHECK_NE(fails, RANDOM_REPEATS);
- }
-
- // add 75 cents in small change. not enough to make 90 cents,
- // then try making 90 cents. there are multiple competing "smallest bigger" coins,
- // one of which should be picked at random
- add_coin(5 * CENT);
- add_coin(10 * CENT);
- add_coin(15 * CENT);
- add_coin(20 * CENT);
- add_coin(25 * CENT);
-
- for (int i = 0; i < RUN_TESTS; i++) {
+ }
+
+ // add 75 cents in small change. not enough to make 90 cents,
+ // then try making 90 cents. there are multiple competing "smallest bigger" coins,
+ // one of which should be picked at random
+ add_coin(coins, *wallet, 5 * CENT);
+ add_coin(coins, *wallet, 10 * CENT);
+ add_coin(coins, *wallet, 15 * CENT);
+ add_coin(coins, *wallet, 20 * CENT);
+ add_coin(coins, *wallet, 25 * CENT);
+
+ for (int i = 0; i < RUN_TESTS; i++) {
int fails = 0;
for (int j = 0; j < RANDOM_REPEATS; j++)
{
- BOOST_CHECK(KnapsackSolver(90*CENT, GroupCoins(vCoins), setCoinsRet, nValueRet));
- BOOST_CHECK(KnapsackSolver(90*CENT, GroupCoins(vCoins), setCoinsRet2, nValueRet));
+ BOOST_CHECK(KnapsackSolver(90*CENT, GroupCoins(coins), setCoinsRet, nValueRet));
+ BOOST_CHECK(KnapsackSolver(90*CENT, GroupCoins(coins), setCoinsRet2, nValueRet));
if (equal_sets(setCoinsRet, setCoinsRet2))
fails++;
}
BOOST_CHECK_NE(fails, RANDOM_REPEATS);
- }
- }
-
- empty_wallet();
+ }
+ }
}
BOOST_AUTO_TEST_CASE(ApproximateBestSubset)
{
+ std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(m_node.chain.get(), "", CreateMockWalletDatabase());
+ wallet->LoadWallet();
+ LOCK(wallet->cs_wallet);
+ wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
+ wallet->SetupDescriptorScriptPubKeyMans();
+
CoinSet setCoinsRet;
CAmount nValueRet;
-
- LOCK(testWallet.cs_wallet);
- testWallet.SetupLegacyScriptPubKeyMan();
-
- empty_wallet();
+ std::vector<COutput> coins;
// Test vValue sort order
for (int i = 0; i < 1000; i++)
- add_coin(1000 * COIN);
- add_coin(3 * COIN);
+ add_coin(coins, *wallet, 1000 * COIN);
+ add_coin(coins, *wallet, 3 * COIN);
- BOOST_CHECK(KnapsackSolver(1003 * COIN, KnapsackGroupOutputs(filter_standard), setCoinsRet, nValueRet));
+ BOOST_CHECK(KnapsackSolver(1003 * COIN, KnapsackGroupOutputs(coins, *wallet, filter_standard), setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 1003 * COIN);
BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U);
-
- empty_wallet();
}
// Tests that with the ideal conditions, the coin selector will always be able to find a solution that can pay the target value
BOOST_AUTO_TEST_CASE(SelectCoins_test)
{
- LOCK(testWallet.cs_wallet);
- testWallet.SetupLegacyScriptPubKeyMan();
+ std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(m_node.chain.get(), "", CreateMockWalletDatabase());
+ wallet->LoadWallet();
+ LOCK(wallet->cs_wallet);
+ wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
+ wallet->SetupDescriptorScriptPubKeyMans();
// Random generator stuff
std::default_random_engine generator;
@@ -636,12 +633,15 @@ BOOST_AUTO_TEST_CASE(SelectCoins_test)
// Run this test 100 times
for (int i = 0; i < 100; ++i)
{
- empty_wallet();
+ std::vector<COutput> coins;
+ CAmount balance{0};
// Make a wallet with 1000 exponentially distributed random inputs
for (int j = 0; j < 1000; ++j)
{
- add_coin((CAmount)(distribution(generator)*10000000));
+ CAmount val = distribution(generator)*10000000;
+ add_coin(coins, *wallet, val);
+ balance += val;
}
// Generate a random fee rate in the range of 100 - 400
@@ -658,7 +658,7 @@ BOOST_AUTO_TEST_CASE(SelectCoins_test)
CoinSet out_set;
CAmount out_value = 0;
CCoinControl cc;
- BOOST_CHECK(SelectCoins(testWallet, vCoins, target, out_set, out_value, cc, cs_params));
+ BOOST_CHECK(SelectCoins(*wallet, coins, target, out_set, out_value, cc, cs_params));
BOOST_CHECK_GE(out_value, target);
}
}
diff --git a/src/wallet/test/db_tests.cpp b/src/wallet/test/db_tests.cpp
index 16cb7e0baf..dba3f35025 100644
--- a/src/wallet/test/db_tests.cpp
+++ b/src/wallet/test/db_tests.cpp
@@ -16,7 +16,7 @@ BOOST_FIXTURE_TEST_SUITE(db_tests, BasicTestingSetup)
static std::shared_ptr<BerkeleyEnvironment> GetWalletEnv(const fs::path& path, std::string& database_filename)
{
fs::path data_file = BDBDataFile(path);
- database_filename = data_file.filename().string();
+ database_filename = fs::PathToString(data_file.filename());
return GetBerkeleyEnv(data_file.parent_path());
}
@@ -25,11 +25,7 @@ BOOST_AUTO_TEST_CASE(getwalletenv_file)
std::string test_name = "test_name.dat";
const fs::path datadir = gArgs.GetDataDirNet();
fs::path file_path = datadir / test_name;
-#if BOOST_VERSION >= 107700
- std::ofstream f(BOOST_FILESYSTEM_C_STR(file_path));
-#else
- std::ofstream f(file_path.BOOST_FILESYSTEM_C_STR);
-#endif // BOOST_VERSION >= 107700
+ fs::ofstream f(file_path);
f.close();
std::string filename;
diff --git a/src/wallet/test/init_test_fixture.cpp b/src/wallet/test/init_test_fixture.cpp
index 53c972c46d..170675c035 100644
--- a/src/wallet/test/init_test_fixture.cpp
+++ b/src/wallet/test/init_test_fixture.cpp
@@ -32,11 +32,7 @@ InitWalletDirTestingSetup::InitWalletDirTestingSetup(const std::string& chainNam
fs::create_directories(m_walletdir_path_cases["default"]);
fs::create_directories(m_walletdir_path_cases["custom"]);
fs::create_directories(m_walletdir_path_cases["relative"]);
-#if BOOST_VERSION >= 107700
- std::ofstream f(BOOST_FILESYSTEM_C_STR(m_walletdir_path_cases["file"]));
-#else
- std::ofstream f(m_walletdir_path_cases["file"].BOOST_FILESYSTEM_C_STR);
-#endif // BOOST_VERSION >= 107700
+ fs::ofstream f(m_walletdir_path_cases["file"]);
f.close();
}
@@ -50,5 +46,5 @@ InitWalletDirTestingSetup::~InitWalletDirTestingSetup()
void InitWalletDirTestingSetup::SetWalletDir(const fs::path& walletdir_path)
{
- gArgs.ForceSetArg("-walletdir", walletdir_path.string());
+ gArgs.ForceSetArg("-walletdir", fs::PathToString(walletdir_path));
}
diff --git a/src/wallet/test/init_tests.cpp b/src/wallet/test/init_tests.cpp
index 45e1b8c4b8..222c2bf4b7 100644
--- a/src/wallet/test/init_tests.cpp
+++ b/src/wallet/test/init_tests.cpp
@@ -17,7 +17,7 @@ BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_default)
SetWalletDir(m_walletdir_path_cases["default"]);
bool result = m_wallet_client->verify();
BOOST_CHECK(result == true);
- fs::path walletdir = gArgs.GetArg("-walletdir", "");
+ fs::path walletdir = fs::PathFromString(gArgs.GetArg("-walletdir", ""));
fs::path expected_path = fs::canonical(m_walletdir_path_cases["default"]);
BOOST_CHECK_EQUAL(walletdir, expected_path);
}
@@ -27,7 +27,7 @@ BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_custom)
SetWalletDir(m_walletdir_path_cases["custom"]);
bool result = m_wallet_client->verify();
BOOST_CHECK(result == true);
- fs::path walletdir = gArgs.GetArg("-walletdir", "");
+ fs::path walletdir = fs::PathFromString(gArgs.GetArg("-walletdir", ""));
fs::path expected_path = fs::canonical(m_walletdir_path_cases["custom"]);
BOOST_CHECK_EQUAL(walletdir, expected_path);
}
@@ -67,7 +67,7 @@ BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_no_trailing)
SetWalletDir(m_walletdir_path_cases["trailing"]);
bool result = m_wallet_client->verify();
BOOST_CHECK(result == true);
- fs::path walletdir = gArgs.GetArg("-walletdir", "");
+ fs::path walletdir = fs::PathFromString(gArgs.GetArg("-walletdir", ""));
fs::path expected_path = fs::canonical(m_walletdir_path_cases["default"]);
BOOST_CHECK_EQUAL(walletdir, expected_path);
}
@@ -77,7 +77,7 @@ BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_no_trailing2)
SetWalletDir(m_walletdir_path_cases["trailing2"]);
bool result = m_wallet_client->verify();
BOOST_CHECK(result == true);
- fs::path walletdir = gArgs.GetArg("-walletdir", "");
+ fs::path walletdir = fs::PathFromString(gArgs.GetArg("-walletdir", ""));
fs::path expected_path = fs::canonical(m_walletdir_path_cases["default"]);
BOOST_CHECK_EQUAL(walletdir, expected_path);
}
diff --git a/src/wallet/test/psbt_wallet_tests.cpp b/src/wallet/test/psbt_wallet_tests.cpp
index 8a97f7779d..120a20749e 100644
--- a/src/wallet/test/psbt_wallet_tests.cpp
+++ b/src/wallet/test/psbt_wallet_tests.cpp
@@ -13,10 +13,21 @@
BOOST_FIXTURE_TEST_SUITE(psbt_wallet_tests, WalletTestingSetup)
+static void import_descriptor(CWallet& wallet, const std::string& descriptor)
+{
+ LOCK(wallet.cs_wallet);
+ FlatSigningProvider provider;
+ std::string error;
+ std::unique_ptr<Descriptor> desc = Parse(descriptor, provider, error, /* require_checksum=*/ false);
+ assert(desc);
+ WalletDescriptor w_desc(std::move(desc), 0, 0, 10, 0);
+ wallet.AddWalletDescriptor(w_desc, provider, "", false);
+}
+
BOOST_AUTO_TEST_CASE(psbt_updater_test)
{
- auto spk_man = m_wallet.GetOrCreateLegacyScriptPubKeyMan();
- LOCK2(m_wallet.cs_wallet, spk_man->cs_KeyStore);
+ LOCK(m_wallet.cs_wallet);
+ m_wallet.SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
// Create prevtxs and add to wallet
CDataStream s_prev_tx1(ParseHex("0200000000010158e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7501000000171600145f275f436b09a8cc9a2eb2a2f528485c68a56323feffffff02d8231f1b0100000017a914aed962d6654f9a2b36608eb9d64d2b260db4f1118700c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e88702483045022100a22edcc6e5bc511af4cc4ae0de0fcd75c7e04d8c1c3a8aa9d820ed4b967384ec02200642963597b9b1bc22c75e9f3e117284a962188bf5e8a74c895089046a20ad770121035509a48eb623e10aace8bfd0212fdb8a8e5af3c94b0b133b95e114cab89e4f7965000000"), SER_NETWORK, PROTOCOL_VERSION);
@@ -29,27 +40,10 @@ BOOST_AUTO_TEST_CASE(psbt_updater_test)
s_prev_tx2 >> prev_tx2;
m_wallet.mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(prev_tx2->GetHash()), std::forward_as_tuple(prev_tx2));
- // Add scripts
- CScript rs1;
- CDataStream s_rs1(ParseHex("475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae"), SER_NETWORK, PROTOCOL_VERSION);
- s_rs1 >> rs1;
- spk_man->AddCScript(rs1);
-
- CScript rs2;
- CDataStream s_rs2(ParseHex("2200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903"), SER_NETWORK, PROTOCOL_VERSION);
- s_rs2 >> rs2;
- spk_man->AddCScript(rs2);
-
- CScript ws1;
- CDataStream s_ws1(ParseHex("47522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae"), SER_NETWORK, PROTOCOL_VERSION);
- s_ws1 >> ws1;
- spk_man->AddCScript(ws1);
-
- // Add hd seed
- CKey key = DecodeSecret("5KSSJQ7UNfFGwVgpCZDSHm5rVNhMFcFtvWM3zQ8mW4qNDEN7LFd"); // Mainnet and uncompressed form of cUkG8i1RFfWGWy5ziR11zJ5V4U4W3viSFCfyJmZnvQaUsd1xuF3T
- CPubKey master_pub_key = spk_man->DeriveNewSeed(key);
- spk_man->SetHDSeed(master_pub_key);
- spk_man->NewKeyPool();
+ // Import descriptors for keys and scripts
+ import_descriptor(m_wallet, "sh(multi(2,xprv9s21ZrQH143K2LE7W4Xf3jATf9jECxSb7wj91ZnmY4qEJrS66Qru9RFqq8xbkgT32ya6HqYJweFdJUEDf5Q6JFV7jMiUws7kQfe6Tv4RbfN/0h/0h/0h,xprv9s21ZrQH143K2LE7W4Xf3jATf9jECxSb7wj91ZnmY4qEJrS66Qru9RFqq8xbkgT32ya6HqYJweFdJUEDf5Q6JFV7jMiUws7kQfe6Tv4RbfN/0h/0h/1h))");
+ import_descriptor(m_wallet, "sh(wsh(multi(2,xprv9s21ZrQH143K2LE7W4Xf3jATf9jECxSb7wj91ZnmY4qEJrS66Qru9RFqq8xbkgT32ya6HqYJweFdJUEDf5Q6JFV7jMiUws7kQfe6Tv4RbfN/0h/0h/2h,xprv9s21ZrQH143K2LE7W4Xf3jATf9jECxSb7wj91ZnmY4qEJrS66Qru9RFqq8xbkgT32ya6HqYJweFdJUEDf5Q6JFV7jMiUws7kQfe6Tv4RbfN/0h/0h/3h)))");
+ import_descriptor(m_wallet, "wpkh(xprv9s21ZrQH143K2LE7W4Xf3jATf9jECxSb7wj91ZnmY4qEJrS66Qru9RFqq8xbkgT32ya6HqYJweFdJUEDf5Q6JFV7jMiUws7kQfe6Tv4RbfN/0h/0h/*h)");
// Call FillPSBT
PartiallySignedTransaction psbtx;
@@ -71,7 +65,8 @@ BOOST_AUTO_TEST_CASE(psbt_updater_test)
// Try to sign the mutated input
SignatureData sigdata;
- BOOST_CHECK(spk_man->FillPSBT(psbtx, PrecomputePSBTData(psbtx), SIGHASH_ALL, true, true) != TransactionError::OK);
+ BOOST_CHECK(m_wallet.FillPSBT(psbtx, complete, SIGHASH_ALL, true, true) != TransactionError::OK);
+ //BOOST_CHECK(spk_man->FillPSBT(psbtx, PrecomputePSBTData(psbtx), SIGHASH_ALL, true, true) != TransactionError::OK);
}
BOOST_AUTO_TEST_CASE(parse_hd_keypath)
diff --git a/src/wallet/test/spend_tests.cpp b/src/wallet/test/spend_tests.cpp
index becef70729..d88d8eabdb 100644
--- a/src/wallet/test/spend_tests.cpp
+++ b/src/wallet/test/spend_tests.cpp
@@ -33,6 +33,8 @@ BOOST_FIXTURE_TEST_CASE(SubtractFee, TestChain100Setup)
CCoinControl coin_control;
coin_control.m_feerate.emplace(10000);
coin_control.fOverrideFeeRate = true;
+ // We need to use a change type with high cost of change so that the leftover amount will be dropped to fee instead of added as a change output
+ coin_control.m_change_type = OutputType::LEGACY;
FeeCalculation fee_calc;
BOOST_CHECK(CreateTransaction(*wallet, {recipient}, tx, fee, change_pos, error, coin_control, fee_calc));
BOOST_CHECK_EQUAL(tx->vout.size(), 1);
diff --git a/src/wallet/test/util.cpp b/src/wallet/test/util.cpp
index c3061b93c0..2990fc8f8d 100644
--- a/src/wallet/test/util.cpp
+++ b/src/wallet/test/util.cpp
@@ -6,6 +6,7 @@
#include <chain.h>
#include <key.h>
+#include <key_io.h>
#include <test/util/setup_common.h>
#include <wallet/wallet.h>
#include <wallet/walletdb.h>
@@ -23,9 +24,16 @@ std::unique_ptr<CWallet> CreateSyncedWallet(interfaces::Chain& chain, CChain& cc
}
wallet->LoadWallet();
{
- auto spk_man = wallet->GetOrCreateLegacyScriptPubKeyMan();
- LOCK2(wallet->cs_wallet, spk_man->cs_KeyStore);
- spk_man->AddKeyPubKey(key, key.GetPubKey());
+ LOCK(wallet->cs_wallet);
+ wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
+ wallet->SetupDescriptorScriptPubKeyMans();
+
+ FlatSigningProvider provider;
+ std::string error;
+ std::unique_ptr<Descriptor> desc = Parse("combo(" + EncodeSecret(key) + ")", provider, error, /* require_checksum=*/ false);
+ assert(desc);
+ WalletDescriptor w_desc(std::move(desc), 0, 0, 1, 1);
+ if (!wallet->AddWalletDescriptor(w_desc, provider, "", false)) assert(false);
}
WalletRescanReserver reserver(*wallet);
reserver.reserve();
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index 9938380369..0965128ade 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -11,6 +11,7 @@
#include <vector>
#include <interfaces/chain.h>
+#include <key_io.h>
#include <node/blockstorage.h>
#include <node/context.h>
#include <policy/policy.h>
@@ -43,6 +44,7 @@ BOOST_FIXTURE_TEST_SUITE(wallet_tests, WalletTestingSetup)
static std::shared_ptr<CWallet> TestLoadWallet(WalletContext& context)
{
DatabaseOptions options;
+ options.create_flags = WALLET_FLAG_DESCRIPTORS;
DatabaseStatus status;
bilingual_str error;
std::vector<bilingual_str> warnings;
@@ -77,9 +79,13 @@ static CMutableTransaction TestSimpleSpend(const CTransaction& from, uint32_t in
static void AddKey(CWallet& wallet, const CKey& key)
{
- auto spk_man = wallet.GetOrCreateLegacyScriptPubKeyMan();
- LOCK2(wallet.cs_wallet, spk_man->cs_KeyStore);
- spk_man->AddKeyPubKey(key, key.GetPubKey());
+ LOCK(wallet.cs_wallet);
+ FlatSigningProvider provider;
+ std::string error;
+ std::unique_ptr<Descriptor> desc = Parse("combo(" + EncodeSecret(key) + ")", provider, error, /* require_checksum=*/ false);
+ assert(desc);
+ WalletDescriptor w_desc(std::move(desc), 0, 0, 1, 1);
+ if (!wallet.AddWalletDescriptor(w_desc, provider, "", false)) assert(false);
}
BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
@@ -95,6 +101,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
CWallet wallet(m_node.chain.get(), "", CreateDummyWalletDatabase());
{
LOCK(wallet.cs_wallet);
+ wallet.SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
wallet.SetLastBlockProcessed(m_node.chainman->ActiveChain().Height(), m_node.chainman->ActiveChain().Tip()->GetBlockHash());
}
AddKey(wallet, coinbaseKey);
@@ -114,6 +121,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
CWallet wallet(m_node.chain.get(), "", CreateDummyWalletDatabase());
{
LOCK(wallet.cs_wallet);
+ wallet.SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
wallet.SetLastBlockProcessed(m_node.chainman->ActiveChain().Height(), m_node.chainman->ActiveChain().Tip()->GetBlockHash());
}
AddKey(wallet, coinbaseKey);
@@ -140,6 +148,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
CWallet wallet(m_node.chain.get(), "", CreateDummyWalletDatabase());
{
LOCK(wallet.cs_wallet);
+ wallet.SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
wallet.SetLastBlockProcessed(m_node.chainman->ActiveChain().Height(), m_node.chainman->ActiveChain().Tip()->GetBlockHash());
}
AddKey(wallet, coinbaseKey);
@@ -165,6 +174,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
CWallet wallet(m_node.chain.get(), "", CreateDummyWalletDatabase());
{
LOCK(wallet.cs_wallet);
+ wallet.SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
wallet.SetLastBlockProcessed(m_node.chainman->ActiveChain().Height(), m_node.chainman->ActiveChain().Tip()->GetBlockHash());
}
AddKey(wallet, coinbaseKey);
@@ -258,7 +268,7 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
SetMockTime(KEY_TIME);
m_coinbase_txns.emplace_back(CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]);
- std::string backup_file = (gArgs.GetDataDirNet() / "wallet.backup").string();
+ std::string backup_file = fs::PathToString(gArgs.GetDataDirNet() / "wallet.backup");
// Import key into wallet and call dumpwallet to create backup file.
{
@@ -320,10 +330,12 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
BOOST_FIXTURE_TEST_CASE(coin_mark_dirty_immature_credit, TestChain100Setup)
{
CWallet wallet(m_node.chain.get(), "", CreateDummyWalletDatabase());
- auto spk_man = wallet.GetOrCreateLegacyScriptPubKeyMan();
CWalletTx wtx(m_coinbase_txns.back());
- LOCK2(wallet.cs_wallet, spk_man->cs_KeyStore);
+ LOCK(wallet.cs_wallet);
+ wallet.SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
+ wallet.SetupDescriptorScriptPubKeyMans();
+
wallet.SetLastBlockProcessed(m_node.chainman->ActiveChain().Height(), m_node.chainman->ActiveChain().Tip()->GetBlockHash());
CWalletTx::Confirmation confirm(CWalletTx::Status::CONFIRMED, m_node.chainman->ActiveChain().Height(), m_node.chainman->ActiveChain().Tip()->GetBlockHash(), 0);
@@ -336,7 +348,7 @@ BOOST_FIXTURE_TEST_CASE(coin_mark_dirty_immature_credit, TestChain100Setup)
// Invalidate the cached value, add the key, and make sure a new immature
// credit amount is calculated.
wtx.MarkDirty();
- BOOST_CHECK(spk_man->AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey()));
+ AddKey(wallet, coinbaseKey);
BOOST_CHECK_EQUAL(CachedTxGetImmatureCredit(wallet, wtx), 50*COIN);
}
@@ -593,14 +605,26 @@ BOOST_FIXTURE_TEST_CASE(ListCoinsTest, ListCoinsTestingSetup)
BOOST_FIXTURE_TEST_CASE(wallet_disableprivkeys, TestChain100Setup)
{
- std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(m_node.chain.get(), "", CreateDummyWalletDatabase());
- wallet->SetupLegacyScriptPubKeyMan();
- wallet->SetMinVersion(FEATURE_LATEST);
- wallet->SetWalletFlag(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
- BOOST_CHECK(!wallet->TopUpKeyPool(1000));
- CTxDestination dest;
- bilingual_str error;
- BOOST_CHECK(!wallet->GetNewDestination(OutputType::BECH32, "", dest, error));
+ {
+ std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(m_node.chain.get(), "", CreateDummyWalletDatabase());
+ wallet->SetupLegacyScriptPubKeyMan();
+ wallet->SetMinVersion(FEATURE_LATEST);
+ wallet->SetWalletFlag(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
+ BOOST_CHECK(!wallet->TopUpKeyPool(1000));
+ CTxDestination dest;
+ bilingual_str error;
+ BOOST_CHECK(!wallet->GetNewDestination(OutputType::BECH32, "", dest, error));
+ }
+ {
+ std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(m_node.chain.get(), "", CreateDummyWalletDatabase());
+ LOCK(wallet->cs_wallet);
+ wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
+ wallet->SetMinVersion(FEATURE_LATEST);
+ wallet->SetWalletFlag(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
+ CTxDestination dest;
+ bilingual_str error;
+ BOOST_CHECK(!wallet->GetNewDestination(OutputType::BECH32, "", dest, error));
+ }
}
// Explicit calculation which is used to test the wallet constant
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index abfe9d7dba..803e88cda2 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -1294,7 +1294,7 @@ void CWallet::updatedBlockTip()
void CWallet::BlockUntilSyncedToCurrentChain() const {
AssertLockNotHeld(cs_wallet);
// Skip the queue-draining stuff if we know we're caught up with
- // ::ChainActive().Tip(), otherwise put a callback in the validation interface queue and wait
+ // chain().Tip(), otherwise put a callback in the validation interface queue and wait
// for the queue to drain enough to execute it (indicating we are caught up
// at least with the time we entered this function).
uint256 last_block_hash = WITH_LOCK(cs_wallet, return m_last_block_processed);
@@ -2515,16 +2515,16 @@ std::unique_ptr<WalletDatabase> MakeWalletDatabase(const std::string& name, cons
// 2. Path to an existing directory.
// 3. Path to a symlink to a directory.
// 4. For backwards compatibility, the name of a data file in -walletdir.
- const fs::path wallet_path = fsbridge::AbsPathJoin(GetWalletDir(), name);
+ const fs::path wallet_path = fsbridge::AbsPathJoin(GetWalletDir(), fs::PathFromString(name));
fs::file_type path_type = fs::symlink_status(wallet_path).type();
if (!(path_type == fs::file_not_found || path_type == fs::directory_file ||
(path_type == fs::symlink_file && fs::is_directory(wallet_path)) ||
- (path_type == fs::regular_file && fs::path(name).filename() == name))) {
+ (path_type == fs::regular_file && fs::PathFromString(name).filename() == fs::PathFromString(name)))) {
error_string = Untranslated(strprintf(
"Invalid -wallet path '%s'. -wallet path should point to a directory where wallet.dat and "
"database/log.?????????? files can be stored, a location where such a directory could be created, "
"or (for backwards compatibility) the name of an existing data file in -walletdir (%s)",
- name, GetWalletDir()));
+ name, fs::quoted(fs::PathToString(GetWalletDir()))));
status = DatabaseStatus::FAILED_BAD_PATH;
return nullptr;
}
@@ -3235,7 +3235,8 @@ void CWallet::LoadActiveScriptPubKeyMan(uint256 id, OutputType type, bool intern
auto spk_man = m_spk_managers.at(id).get();
spk_mans[type] = spk_man;
- if (spk_mans_other[type] == spk_man) {
+ const auto it = spk_mans_other.find(type);
+ if (it != spk_mans_other.end() && it->second == spk_man) {
spk_mans_other.erase(type);
}
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index 8ff09a0878..a6839f1f78 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -1106,7 +1106,7 @@ std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const Databas
try {
exists = fs::symlink_status(path).type() != fs::file_not_found;
} catch (const fs::filesystem_error& e) {
- error = Untranslated(strprintf("Failed to access database path '%s': %s", path.string(), fsbridge::get_filesystem_error_message(e)));
+ error = Untranslated(strprintf("Failed to access database path '%s': %s", fs::PathToString(path), fsbridge::get_filesystem_error_message(e)));
status = DatabaseStatus::FAILED_BAD_PATH;
return nullptr;
}
@@ -1118,33 +1118,33 @@ std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const Databas
}
if (IsSQLiteFile(SQLiteDataFile(path))) {
if (format) {
- error = Untranslated(strprintf("Failed to load database path '%s'. Data is in ambiguous format.", path.string()));
+ error = Untranslated(strprintf("Failed to load database path '%s'. Data is in ambiguous format.", fs::PathToString(path)));
status = DatabaseStatus::FAILED_BAD_FORMAT;
return nullptr;
}
format = DatabaseFormat::SQLITE;
}
} else if (options.require_existing) {
- error = Untranslated(strprintf("Failed to load database path '%s'. Path does not exist.", path.string()));
+ error = Untranslated(strprintf("Failed to load database path '%s'. Path does not exist.", fs::PathToString(path)));
status = DatabaseStatus::FAILED_NOT_FOUND;
return nullptr;
}
if (!format && options.require_existing) {
- error = Untranslated(strprintf("Failed to load database path '%s'. Data is not in recognized format.", path.string()));
+ error = Untranslated(strprintf("Failed to load database path '%s'. Data is not in recognized format.", fs::PathToString(path)));
status = DatabaseStatus::FAILED_BAD_FORMAT;
return nullptr;
}
if (format && options.require_create) {
- error = Untranslated(strprintf("Failed to create database path '%s'. Database already exists.", path.string()));
+ error = Untranslated(strprintf("Failed to create database path '%s'. Database already exists.", fs::PathToString(path)));
status = DatabaseStatus::FAILED_ALREADY_EXISTS;
return nullptr;
}
// A db already exists so format is set, but options also specifies the format, so make sure they agree
if (format && options.require_format && format != options.require_format) {
- error = Untranslated(strprintf("Failed to load database path '%s'. Data is not in required format.", path.string()));
+ error = Untranslated(strprintf("Failed to load database path '%s'. Data is not in required format.", fs::PathToString(path)));
status = DatabaseStatus::FAILED_BAD_FORMAT;
return nullptr;
}
@@ -1166,7 +1166,7 @@ std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const Databas
#ifdef USE_SQLITE
return MakeSQLiteDatabase(path, options, status, error);
#endif
- error = Untranslated(strprintf("Failed to open database path '%s'. Build does not support SQLite database format.", path.string()));
+ error = Untranslated(strprintf("Failed to open database path '%s'. Build does not support SQLite database format.", fs::PathToString(path)));
status = DatabaseStatus::FAILED_BAD_FORMAT;
return nullptr;
}
@@ -1174,7 +1174,7 @@ std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const Databas
#ifdef USE_BDB
return MakeBerkeleyDatabase(path, options, status, error);
#endif
- error = Untranslated(strprintf("Failed to open database path '%s'. Build does not support Berkeley DB database format.", path.string()));
+ error = Untranslated(strprintf("Failed to open database path '%s'. Build does not support Berkeley DB database format.", fs::PathToString(path)));
status = DatabaseStatus::FAILED_BAD_FORMAT;
return nullptr;
}
diff --git a/src/wallet/wallettool.cpp b/src/wallet/wallettool.cpp
index e3cb5cee5d..88f0a2ce20 100644
--- a/src/wallet/wallettool.cpp
+++ b/src/wallet/wallettool.cpp
@@ -120,17 +120,33 @@ bool ExecuteWalletToolFunc(const ArgsManager& args, const std::string& command)
tfm::format(std::cerr, "The -descriptors option can only be used with the 'create' command.\n");
return false;
}
+ if (args.IsArgSet("-legacy") && command != "create") {
+ tfm::format(std::cerr, "The -legacy option can only be used with the 'create' command.\n");
+ return false;
+ }
if (command == "create" && !args.IsArgSet("-wallet")) {
tfm::format(std::cerr, "Wallet name must be provided when creating a new wallet.\n");
return false;
}
const std::string name = args.GetArg("-wallet", "");
- const fs::path path = fsbridge::AbsPathJoin(GetWalletDir(), name);
+ const fs::path path = fsbridge::AbsPathJoin(GetWalletDir(), fs::PathFromString(name));
if (command == "create") {
DatabaseOptions options;
options.require_create = true;
- if (args.GetBoolArg("-descriptors", false)) {
+ // If -legacy is set, use it. Otherwise default to false.
+ bool make_legacy = args.GetBoolArg("-legacy", false);
+ // If neither -legacy nor -descriptors is set, default to true. If -descriptors is set, use its value.
+ bool make_descriptors = (!args.IsArgSet("-descriptors") && !args.IsArgSet("-legacy")) || (args.IsArgSet("-descriptors") && args.GetBoolArg("-descriptors", true));
+ if (make_legacy && make_descriptors) {
+ tfm::format(std::cerr, "Only one of -legacy or -descriptors can be set to true, not both\n");
+ return false;
+ }
+ if (!make_legacy && !make_descriptors) {
+ tfm::format(std::cerr, "One of -legacy or -descriptors must be set to true (or omitted)\n");
+ return false;
+ }
+ if (make_descriptors) {
options.create_flags |= WALLET_FLAG_DESCRIPTORS;
options.require_format = DatabaseFormat::SQLITE;
}
diff --git a/src/wallet/walletutil.cpp b/src/wallet/walletutil.cpp
index 1c518daba6..7f813432b3 100644
--- a/src/wallet/walletutil.cpp
+++ b/src/wallet/walletutil.cpp
@@ -12,7 +12,7 @@ fs::path GetWalletDir()
fs::path path;
if (gArgs.IsArgSet("-walletdir")) {
- path = gArgs.GetArg("-walletdir", "");
+ path = fs::PathFromString(gArgs.GetArg("-walletdir", ""));
if (!fs::is_directory(path)) {
// If the path specified doesn't exist, we return the deliberately
// invalid empty string.
diff --git a/test/README.md b/test/README.md
index acd68d8d8f..c9e15c4968 100644
--- a/test/README.md
+++ b/test/README.md
@@ -275,12 +275,15 @@ Use the `-v` option for verbose output.
#### Dependencies
-| Lint test | Dependency | Version [used by CI](../ci/lint/04_install.sh) | Installation
-|-----------|:----------:|:-------------------------------------------:|--------------
-| [`lint-python.sh`](lint/lint-python.sh) | [flake8](https://gitlab.com/pycqa/flake8) | [3.8.3](https://github.com/bitcoin/bitcoin/pull/19348) | `pip3 install flake8==3.8.3`
-| [`lint-python.sh`](lint/lint-python.sh) | [mypy](https://github.com/python/mypy) | [0.781](https://github.com/bitcoin/bitcoin/pull/19348) | `pip3 install mypy==0.781`
-| [`lint-shell.sh`](lint/lint-shell.sh) | [ShellCheck](https://github.com/koalaman/shellcheck) | [0.7.2](https://github.com/bitcoin/bitcoin/pull/21749) | [details...](https://github.com/koalaman/shellcheck#installing)
-| [`lint-spelling.sh`](lint/lint-spelling.sh) | [codespell](https://github.com/codespell-project/codespell) | [2.0.0](https://github.com/bitcoin/bitcoin/pull/20817) | `pip3 install codespell==2.0.0`
+| Lint test | Dependency |
+|-----------|:----------:|
+| [`lint-python.sh`](lint/lint-python.sh) | [flake8](https://gitlab.com/pycqa/flake8)
+| [`lint-python.sh`](lint/lint-python.sh) | [mypy](https://github.com/python/mypy)
+| [`lint-python.sh`](lint/lint-python.sh) | [pyzmq](https://github.com/zeromq/pyzmq)
+| [`lint-shell.sh`](lint/lint-shell.sh) | [ShellCheck](https://github.com/koalaman/shellcheck)
+| [`lint-spelling.sh`](lint/lint-spelling.sh) | [codespell](https://github.com/codespell-project/codespell)
+
+In use versions and install instructions are available in the [CI setup](../ci/lint/04_install.sh).
Please be aware that on Linux distributions all dependencies are usually available as packages, but could be outdated.
diff --git a/test/functional/combine_logs.py b/test/functional/combine_logs.py
index 00f2833f55..71dfb4c01a 100755
--- a/test/functional/combine_logs.py
+++ b/test/functional/combine_logs.py
@@ -188,7 +188,7 @@ def print_logs_plain(log_events, colors):
def print_logs_html(log_events):
"""Renders the iterator of log events into html."""
try:
- import jinja2
+ import jinja2 #type:ignore
except ImportError:
print("jinja2 not found. Try `pip install jinja2`")
sys.exit(1)
diff --git a/test/functional/data/__init__.py b/test/functional/data/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/functional/data/__init__.py
diff --git a/test/functional/feature_rbf.py b/test/functional/feature_rbf.py
index 4eaaf46454..420147542e 100755
--- a/test/functional/feature_rbf.py
+++ b/test/functional/feature_rbf.py
@@ -539,7 +539,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
assert_equal(json1["vin"][0]["sequence"], 4294967295)
if self.is_wallet_compiled():
- self.init_wallet(0)
+ self.init_wallet(node=0)
rawtx2 = self.nodes[0].createrawtransaction([], outs)
frawtx2a = self.nodes[0].fundrawtransaction(rawtx2, {"replaceable": True})
frawtx2b = self.nodes[0].fundrawtransaction(rawtx2, {"replaceable": False})
diff --git a/test/functional/interface_rest.py b/test/functional/interface_rest.py
index adc33bd9df..868bb42604 100755
--- a/test/functional/interface_rest.py
+++ b/test/functional/interface_rest.py
@@ -318,6 +318,15 @@ class RESTTest (BitcoinTestFramework):
if 'coinbase' not in tx['vin'][0]}
assert_equal(non_coinbase_txs, set(txs))
+ # Verify that the non-coinbase tx has "prevout" key set
+ for tx_obj in json_obj["tx"]:
+ for vin in tx_obj["vin"]:
+ if "coinbase" not in vin:
+ assert "prevout" in vin
+ assert_equal(vin["prevout"]["generated"], False)
+ else:
+ assert "prevout" not in vin
+
# Check the same but without tx details
json_obj = self.test_rest_request(f"/block/notxdetails/{newblockhash[0]}")
for tx in txs:
diff --git a/test/functional/mempool_package_limits.py b/test/functional/mempool_package_limits.py
index 2217628858..89a5c83826 100755
--- a/test/functional/mempool_package_limits.py
+++ b/test/functional/mempool_package_limits.py
@@ -244,7 +244,7 @@ class MempoolPackageLimitsTest(BitcoinTestFramework):
assert_equal(txres["package-error"], "package-mempool-limits")
# Clear mempool and check that the package passes now
- node.generate(1)
+ self.generate(node, 1)
assert all([res["allowed"] for res in node.testmempoolaccept(rawtxs=package_hex)])
def test_anc_count_limits(self):
diff --git a/test/functional/mempool_packages.py b/test/functional/mempool_packages.py
index 3943bba489..ff5e45519f 100755
--- a/test/functional/mempool_packages.py
+++ b/test/functional/mempool_packages.py
@@ -65,8 +65,7 @@ class MempoolPackagesTest(BitcoinTestFramework):
value = sent_value
chain.append(txid)
# We need the wtxids to check P2P announcements
- fulltx = self.nodes[0].getrawtransaction(txid)
- witnesstx = self.nodes[0].decoderawtransaction(fulltx, True)
+ witnesstx = self.nodes[0].gettransaction(txid=txid, verbose=True)['decoded']
witness_chain.append(witnesstx['hash'])
# Check that listunspent ancestor{count, size, fees} yield the correct results
diff --git a/test/functional/mining_prioritisetransaction.py b/test/functional/mining_prioritisetransaction.py
index da85ee54be..35274d3500 100755
--- a/test/functional/mining_prioritisetransaction.py
+++ b/test/functional/mining_prioritisetransaction.py
@@ -13,7 +13,7 @@ from test_framework.util import assert_equal, assert_raises_rpc_error, create_co
class PrioritiseTransactionTest(BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = True
- self.num_nodes = 2
+ self.num_nodes = 1
self.extra_args = [[
"-printpriority=1",
"-acceptnonstdtxn=1",
diff --git a/test/functional/p2p_invalid_messages.py b/test/functional/p2p_invalid_messages.py
index f3b80abb59..82c7e94c59 100755
--- a/test/functional/p2p_invalid_messages.py
+++ b/test/functional/p2p_invalid_messages.py
@@ -209,7 +209,7 @@ class InvalidMessagesTest(BitcoinTestFramework):
self.test_addrv2('unrecognized network',
[
'received: addrv2 (25 bytes)',
- 'IP 9.9.9.9 mapped',
+ '9.9.9.9:8333 mapped',
'Added 1 addresses',
],
bytes.fromhex(
diff --git a/test/functional/p2p_ping.py b/test/functional/p2p_ping.py
index 888e986fba..d67e97acf7 100755
--- a/test/functional/p2p_ping.py
+++ b/test/functional/p2p_ping.py
@@ -30,11 +30,16 @@ class NodeNoPong(P2PInterface):
pass
+TIMEOUT_INTERVAL = 20 * 60
+
+
class PingPongTest(BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 1
- self.extra_args = [['-peertimeout=3']]
+ # Set the peer connection timeout low. It does not matter for this
+ # test, as long as it is less than TIMEOUT_INTERVAL.
+ self.extra_args = [['-peertimeout=1']]
def check_peer_info(self, *, pingtime, minping, pingwait):
stats = self.nodes[0].getpeerinfo()[0]
@@ -110,8 +115,11 @@ class PingPongTest(BitcoinTestFramework):
self.nodes[0].ping()
no_pong_node.wait_until(lambda: 'ping' in no_pong_node.last_message)
with self.nodes[0].assert_debug_log(['ping timeout: 1201.000000s']):
- self.mock_forward(20 * 60 + 1)
- time.sleep(4) # peertimeout + 1
+ self.mock_forward(TIMEOUT_INTERVAL // 2)
+ # Check that sending a ping does not prevent the disconnect
+ no_pong_node.sync_with_ping()
+ self.mock_forward(TIMEOUT_INTERVAL // 2 + 1)
+ no_pong_node.wait_for_disconnect()
if __name__ == '__main__':
diff --git a/test/functional/rpc_blockchain.py b/test/functional/rpc_blockchain.py
index c3c6ade684..eea9ee26cb 100755
--- a/test/functional/rpc_blockchain.py
+++ b/test/functional/rpc_blockchain.py
@@ -434,17 +434,55 @@ class BlockchainTest(BitcoinTestFramework):
miniwallet.send_self_transfer(fee_rate=fee_per_kb, from_node=node)
blockhash = self.generate(node, 1)[0]
- self.log.info("Test getblock with verbosity 1 doesn't include fee")
- block = node.getblock(blockhash, 1)
- assert 'fee' not in block['tx'][1]
-
- self.log.info('Test getblock with verbosity 2 includes expected fee')
- block = node.getblock(blockhash, 2)
- tx = block['tx'][1]
- assert 'fee' in tx
- assert_equal(tx['fee'], tx['vsize'] * fee_per_byte)
-
- self.log.info("Test getblock with verbosity 2 still works with pruned Undo data")
+ def assert_fee_not_in_block(verbosity):
+ block = node.getblock(blockhash, verbosity)
+ assert 'fee' not in block['tx'][1]
+
+ def assert_fee_in_block(verbosity):
+ block = node.getblock(blockhash, verbosity)
+ tx = block['tx'][1]
+ assert 'fee' in tx
+ assert_equal(tx['fee'], tx['vsize'] * fee_per_byte)
+
+ def assert_vin_contains_prevout(verbosity):
+ block = node.getblock(blockhash, verbosity)
+ tx = block["tx"][1]
+ total_vin = Decimal("0.00000000")
+ total_vout = Decimal("0.00000000")
+ for vin in tx["vin"]:
+ assert "prevout" in vin
+ assert_equal(set(vin["prevout"].keys()), set(("value", "height", "generated", "scriptPubKey")))
+ assert_equal(vin["prevout"]["generated"], True)
+ total_vin += vin["prevout"]["value"]
+ for vout in tx["vout"]:
+ total_vout += vout["value"]
+ assert_equal(total_vin, total_vout + tx["fee"])
+
+ def assert_vin_does_not_contain_prevout(verbosity):
+ block = node.getblock(blockhash, verbosity)
+ tx = block["tx"][1]
+ if isinstance(tx, str):
+ # In verbosity level 1, only the transaction hashes are written
+ pass
+ else:
+ for vin in tx["vin"]:
+ assert "prevout" not in vin
+
+ self.log.info("Test that getblock with verbosity 1 doesn't include fee")
+ assert_fee_not_in_block(1)
+
+ self.log.info('Test that getblock with verbosity 2 and 3 includes expected fee')
+ assert_fee_in_block(2)
+ assert_fee_in_block(3)
+
+ self.log.info("Test that getblock with verbosity 1 and 2 does not include prevout")
+ assert_vin_does_not_contain_prevout(1)
+ assert_vin_does_not_contain_prevout(2)
+
+ self.log.info("Test that getblock with verbosity 3 includes prevout")
+ assert_vin_contains_prevout(3)
+
+ self.log.info("Test that getblock with verbosity 2 and 3 still works with pruned Undo data")
datadir = get_datadir_path(self.options.tmpdir, 0)
self.log.info("Test getblock with invalid verbosity type returns proper error message")
@@ -458,8 +496,10 @@ class BlockchainTest(BitcoinTestFramework):
# Move instead of deleting so we can restore chain state afterwards
move_block_file('rev00000.dat', 'rev_wrong')
- block = node.getblock(blockhash, 2)
- assert 'fee' not in block['tx'][1]
+ assert_fee_not_in_block(2)
+ assert_fee_not_in_block(3)
+ assert_vin_does_not_contain_prevout(2)
+ assert_vin_does_not_contain_prevout(3)
# Restore chain state
move_block_file('rev_wrong', 'rev00000.dat')
diff --git a/test/functional/rpc_invalid_address_message.py b/test/functional/rpc_invalid_address_message.py
index 7ab5a5e90d..085f6582b5 100755
--- a/test/functional/rpc_invalid_address_message.py
+++ b/test/functional/rpc_invalid_address_message.py
@@ -90,7 +90,7 @@ class InvalidAddressErrorMessageTest(BitcoinTestFramework):
self.test_validateaddress()
if self.is_wallet_compiled():
- self.init_wallet(0)
+ self.init_wallet(node=0)
self.test_getaddressinfo()
diff --git a/test/functional/rpc_misc.py b/test/functional/rpc_misc.py
index ac2a7a309b..e32e562bce 100755
--- a/test/functional/rpc_misc.py
+++ b/test/functional/rpc_misc.py
@@ -57,7 +57,7 @@ class RpcMiscTest(BitcoinTestFramework):
self.log.info("test logging rpc and help")
# Test logging RPC returns the expected number of logging categories.
- assert_equal(len(node.logging()), 26)
+ assert_equal(len(node.logging()), 27)
# Test toggling a logging category on/off/on with the logging RPC.
assert_equal(node.logging()['qt'], True)
diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py
index d87d0cacfd..ec3561b1f2 100755
--- a/test/functional/test_framework/test_framework.py
+++ b/test/functional/test_framework/test_framework.py
@@ -423,12 +423,12 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
def import_deterministic_coinbase_privkeys(self):
for i in range(self.num_nodes):
- self.init_wallet(i)
+ self.init_wallet(node=i)
- def init_wallet(self, i):
- wallet_name = self.default_wallet_name if self.wallet_names is None else self.wallet_names[i] if i < len(self.wallet_names) else False
+ def init_wallet(self, *, node):
+ wallet_name = self.default_wallet_name if self.wallet_names is None else self.wallet_names[node] if node < len(self.wallet_names) else False
if wallet_name is not False:
- n = self.nodes[i]
+ n = self.nodes[node]
if wallet_name is not None:
n.createwallet(wallet_name=wallet_name, descriptors=self.options.descriptors, load_on_startup=True)
n.importprivkey(privkey=n.get_deterministic_priv_key().key, label='coinbase')
@@ -628,19 +628,19 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
self.sync_all()
def generate(self, generator, *args, **kwargs):
- blocks = generator.generate(*args, **kwargs)
+ blocks = generator.generate(*args, invalid_call=False, **kwargs)
return blocks
def generateblock(self, generator, *args, **kwargs):
- blocks = generator.generateblock(*args, **kwargs)
+ blocks = generator.generateblock(*args, invalid_call=False, **kwargs)
return blocks
def generatetoaddress(self, generator, *args, **kwargs):
- blocks = generator.generatetoaddress(*args, **kwargs)
+ blocks = generator.generatetoaddress(*args, invalid_call=False, **kwargs)
return blocks
def generatetodescriptor(self, generator, *args, **kwargs):
- blocks = generator.generatetodescriptor(*args, **kwargs)
+ blocks = generator.generatetodescriptor(*args, invalid_call=False, **kwargs)
return blocks
def sync_blocks(self, nodes=None, wait=1, timeout=60):
diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py
index f9e2cfa2f5..e8ff41a46d 100755
--- a/test/functional/test_framework/test_node.py
+++ b/test/functional/test_framework/test_node.py
@@ -297,9 +297,21 @@ class TestNode():
time.sleep(1.0 / poll_per_s)
self._raise_assertion_error("Unable to retrieve cookie credentials after {}s".format(self.rpc_timeout))
- def generate(self, nblocks, maxtries=1000000):
+ def generate(self, nblocks, maxtries=1000000, **kwargs):
self.log.debug("TestNode.generate() dispatches `generate` call to `generatetoaddress`")
- return self.generatetoaddress(nblocks=nblocks, address=self.get_deterministic_priv_key().address, maxtries=maxtries)
+ return self.generatetoaddress(nblocks=nblocks, address=self.get_deterministic_priv_key().address, maxtries=maxtries, **kwargs)
+
+ def generateblock(self, *args, invalid_call, **kwargs):
+ assert not invalid_call
+ return self.__getattr__('generateblock')(*args, **kwargs)
+
+ def generatetoaddress(self, *args, invalid_call, **kwargs):
+ assert not invalid_call
+ return self.__getattr__('generatetoaddress')(*args, **kwargs)
+
+ def generatetodescriptor(self, *args, invalid_call, **kwargs):
+ assert not invalid_call
+ return self.__getattr__('generatetodescriptor')(*args, **kwargs)
def get_wallet_rpc(self, wallet_name):
if self.use_cli:
diff --git a/test/functional/test_framework/wallet.py b/test/functional/test_framework/wallet.py
index b0b578e544..81aad20079 100644
--- a/test/functional/test_framework/wallet.py
+++ b/test/functional/test_framework/wallet.py
@@ -111,9 +111,9 @@ class MiniWallet:
break
tx.vin[0].scriptSig = CScript([der_sig + bytes(bytearray([SIGHASH_ALL]))])
- def generate(self, num_blocks):
+ def generate(self, num_blocks, **kwargs):
"""Generate blocks with coinbase outputs to the internal address, and append the outputs to the internal list"""
- blocks = self._test_node.generatetodescriptor(num_blocks, self.get_descriptor())
+ blocks = self._test_node.generatetodescriptor(num_blocks, self.get_descriptor(), **kwargs)
for b in blocks:
cb_tx = self._test_node.getblock(blockhash=b, verbosity=2)['tx'][0]
self._utxos.append({'txid': cb_tx['txid'], 'vout': 0, 'value': cb_tx['vout'][0]['value']})
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index c5f08b27f2..b91b294108 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -40,7 +40,7 @@ except UnicodeDecodeError:
CROSS = "x "
CIRCLE = "o "
-if os.name != 'nt' or sys.getwindowsversion() >= (10, 0, 14393):
+if os.name != 'nt' or sys.getwindowsversion() >= (10, 0, 14393): #type:ignore
if os.name == 'nt':
import ctypes
kernel32 = ctypes.windll.kernel32 # type: ignore
@@ -207,6 +207,7 @@ BASE_SCRIPTS = [
'feature_assumevalid.py',
'example_test.py',
'wallet_txn_doublespend.py --legacy-wallet',
+ 'wallet_multisig_descriptor_psbt.py',
'wallet_txn_doublespend.py --descriptors',
'feature_backwards_compatibility.py --legacy-wallet',
'feature_backwards_compatibility.py --descriptors',
diff --git a/test/functional/tool_wallet.py b/test/functional/tool_wallet.py
index 4bf3927879..3a0daf04ad 100755
--- a/test/functional/tool_wallet.py
+++ b/test/functional/tool_wallet.py
@@ -31,8 +31,8 @@ class ToolWalletTest(BitcoinTestFramework):
def bitcoin_wallet_process(self, *args):
binary = self.config["environment"]["BUILDDIR"] + '/src/bitcoin-wallet' + self.config["environment"]["EXEEXT"]
default_args = ['-datadir={}'.format(self.nodes[0].datadir), '-chain=%s' % self.chain]
- if self.options.descriptors and 'create' in args:
- default_args.append('-descriptors')
+ if not self.options.descriptors and 'create' in args:
+ default_args.append('-legacy')
return subprocess.Popen([binary] + default_args + list(args), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
diff --git a/test/functional/wallet_abandonconflict.py b/test/functional/wallet_abandonconflict.py
index 70ca5a2fe4..8f54e50598 100755
--- a/test/functional/wallet_abandonconflict.py
+++ b/test/functional/wallet_abandonconflict.py
@@ -120,6 +120,14 @@ class AbandonConflictTest(BitcoinTestFramework):
assert_equal(newbalance, balance + Decimal("30"))
balance = newbalance
+ self.log.info("Check abandoned transactions in listsinceblock")
+ listsinceblock = self.nodes[0].listsinceblock()
+ txAB1_listsinceblock = [d for d in listsinceblock['transactions'] if d['txid'] == txAB1 and d['category'] == 'send']
+ for tx in txAB1_listsinceblock:
+ assert_equal(tx['abandoned'], True)
+ assert_equal(tx['confirmations'], 0)
+ assert_equal(tx['trusted'], False)
+
# Verify that even with a low min relay fee, the tx is not reaccepted from wallet on startup once abandoned
self.restart_node(0, extra_args=["-minrelaytxfee=0.00001"])
assert self.nodes[0].getmempoolinfo()['loaded']
@@ -205,7 +213,7 @@ class AbandonConflictTest(BitcoinTestFramework):
#assert_equal(newbalance, balance - Decimal("10"))
self.log.info("If balance has not declined after invalidateblock then out of mempool wallet tx which is no longer")
self.log.info("conflicted has not resumed causing its inputs to be seen as spent. See Issue #7315")
- self.log.info(str(balance) + " -> " + str(newbalance) + " ?")
+ assert_equal(balance, newbalance)
if __name__ == '__main__':
diff --git a/test/functional/wallet_address_types.py b/test/functional/wallet_address_types.py
index bdee22e62b..7a448e8590 100755
--- a/test/functional/wallet_address_types.py
+++ b/test/functional/wallet_address_types.py
@@ -204,8 +204,7 @@ class AddressTypeTest(BitcoinTestFramework):
def test_change_output_type(self, node_sender, destinations, expected_type):
txid = self.nodes[node_sender].sendmany(dummy="", amounts=dict.fromkeys(destinations, 0.001))
- raw_tx = self.nodes[node_sender].getrawtransaction(txid)
- tx = self.nodes[node_sender].decoderawtransaction(raw_tx)
+ tx = self.nodes[node_sender].gettransaction(txid=txid, verbose=True)['decoded']
# Make sure the transaction has change:
assert_equal(len(tx["vout"]), len(destinations) + 1)
diff --git a/test/functional/wallet_backup.py b/test/functional/wallet_backup.py
index bc6d6206e5..a07c28c8a4 100755
--- a/test/functional/wallet_backup.py
+++ b/test/functional/wallet_backup.py
@@ -124,9 +124,9 @@ class WalletBackupTest(BitcoinTestFramework):
assert_raises_rpc_error(-8, "Wallet name already exists.", node.restorewallet, wallet_name, wallet_file)
def init_three(self):
- self.init_wallet(0)
- self.init_wallet(1)
- self.init_wallet(2)
+ self.init_wallet(node=0)
+ self.init_wallet(node=1)
+ self.init_wallet(node=2)
def run_test(self):
self.log.info("Generating initial blockchain")
diff --git a/test/functional/wallet_basic.py b/test/functional/wallet_basic.py
index 599e506f98..92da54d97c 100755
--- a/test/functional/wallet_basic.py
+++ b/test/functional/wallet_basic.py
@@ -666,7 +666,7 @@ class WalletTest(BitcoinTestFramework):
self.generate(self.nodes[0], 1)
destination = self.nodes[1].getnewaddress()
txid = self.nodes[0].sendtoaddress(destination, 0.123)
- tx = self.nodes[0].decoderawtransaction(self.nodes[0].gettransaction(txid)['hex'])
+ tx = self.nodes[0].gettransaction(txid=txid, verbose=True)['decoded']
output_addresses = [vout['scriptPubKey']['address'] for vout in tx["vout"]]
assert len(output_addresses) > 1
for address in output_addresses:
diff --git a/test/functional/wallet_bumpfee.py b/test/functional/wallet_bumpfee.py
index a1676fffa5..46a5df4a8e 100755
--- a/test/functional/wallet_bumpfee.py
+++ b/test/functional/wallet_bumpfee.py
@@ -32,6 +32,8 @@ from test_framework.util import (
assert_greater_than,
assert_raises_rpc_error,
)
+from test_framework.wallet import MiniWallet
+
WALLET_PASSPHRASE = "test"
WALLET_PASSPHRASE_TIMEOUT = 3600
@@ -265,6 +267,14 @@ def test_bumpfee_with_descendant_fails(self, rbf_node, rbf_node_address, dest_ad
tx = rbf_node.signrawtransactionwithwallet(tx)
rbf_node.sendrawtransaction(tx["hex"])
assert_raises_rpc_error(-8, "Transaction has descendants in the wallet", rbf_node.bumpfee, parent_id)
+
+ # create tx with descendant in the mempool by using MiniWallet
+ miniwallet = MiniWallet(rbf_node)
+ parent_id = spend_one_input(rbf_node, miniwallet.get_address())
+ tx = rbf_node.gettransaction(txid=parent_id, verbose=True)['decoded']
+ miniwallet.scan_tx(tx)
+ miniwallet.send_self_transfer(from_node=rbf_node)
+ assert_raises_rpc_error(-8, "Transaction has descendants in the mempool", rbf_node.bumpfee, parent_id)
self.clear_mempool()
diff --git a/test/functional/wallet_create_tx.py b/test/functional/wallet_create_tx.py
index c8b92ef1bf..00ee08002e 100755
--- a/test/functional/wallet_create_tx.py
+++ b/test/functional/wallet_create_tx.py
@@ -34,13 +34,13 @@ class CreateTxWalletTest(BitcoinTestFramework):
self.log.info('Check that we have some (old) blocks and that anti-fee-sniping is disabled')
assert_equal(self.nodes[0].getblockchaininfo()['blocks'], 200)
txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
- tx = self.nodes[0].decoderawtransaction(self.nodes[0].gettransaction(txid)['hex'])
+ tx = self.nodes[0].gettransaction(txid=txid, verbose=True)['decoded']
assert_equal(tx['locktime'], 0)
self.log.info('Check that anti-fee-sniping is enabled when we mine a recent block')
self.generate(self.nodes[0], 1)
txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
- tx = self.nodes[0].decoderawtransaction(self.nodes[0].gettransaction(txid)['hex'])
+ tx = self.nodes[0].gettransaction(txid=txid, verbose=True)['decoded']
assert 0 < tx['locktime'] <= 201
def test_tx_size_too_large(self):
diff --git a/test/functional/wallet_descriptor.py b/test/functional/wallet_descriptor.py
index 17a4c79da3..4ec44a8a6c 100755
--- a/test/functional/wallet_descriptor.py
+++ b/test/functional/wallet_descriptor.py
@@ -84,7 +84,7 @@ class WalletDescriptorTest(BitcoinTestFramework):
send_wrpc = self.nodes[0].get_wallet_rpc("desc1")
# Generate some coins
- self.generatetoaddress(send_wrpc, COINBASE_MATURITY + 1, send_wrpc.getnewaddress())
+ self.generatetoaddress(self.nodes[0], COINBASE_MATURITY + 1, send_wrpc.getnewaddress())
# Make transactions
self.log.info("Test sending and receiving")
diff --git a/test/functional/wallet_hd.py b/test/functional/wallet_hd.py
index 974ce7f381..f54ae89c04 100755
--- a/test/functional/wallet_hd.py
+++ b/test/functional/wallet_hd.py
@@ -129,7 +129,7 @@ class WalletHDTest(BitcoinTestFramework):
# send a tx and make sure its using the internal chain for the changeoutput
txid = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1)
- outs = self.nodes[1].decoderawtransaction(self.nodes[1].gettransaction(txid)['hex'])['vout']
+ outs = self.nodes[1].gettransaction(txid=txid, verbose=True)['decoded']['vout']
keypath = ""
for out in outs:
if out['value'] != 1:
diff --git a/test/functional/wallet_import_rescan.py b/test/functional/wallet_import_rescan.py
index cbe3e9bfdd..27a2a42dac 100755
--- a/test/functional/wallet_import_rescan.py
+++ b/test/functional/wallet_import_rescan.py
@@ -99,7 +99,7 @@ class Variant(collections.namedtuple("Variant", "call data address_type rescan p
assert_equal(tx["label"], self.label)
assert_equal(tx["txid"], txid)
assert_equal(tx["confirmations"], 1 + current_height - confirmation_height)
- assert_equal("trusted" not in tx, True)
+ assert "trusted" not in tx
address, = [ad for ad in addresses if txid in ad["txids"]]
assert_equal(address["address"], self.address["address"])
diff --git a/test/functional/wallet_importdescriptors.py b/test/functional/wallet_importdescriptors.py
index d86c3737fe..fc9eac1d74 100755
--- a/test/functional/wallet_importdescriptors.py
+++ b/test/functional/wallet_importdescriptors.py
@@ -74,7 +74,7 @@ class ImportDescriptorsTest(BitcoinTestFramework):
assert_equal(wpriv.getwalletinfo()['keypoolsize'], 0)
self.log.info('Mining coins')
- self.generatetoaddress(w0, COINBASE_MATURITY + 1, w0.getnewaddress())
+ self.generatetoaddress(self.nodes[0], COINBASE_MATURITY + 1, w0.getnewaddress())
# RPC importdescriptors -----------------------------------------------
@@ -405,7 +405,7 @@ class ImportDescriptorsTest(BitcoinTestFramework):
solvable=True,
ismine=True)
txid = w0.sendtoaddress(address, 49.99995540)
- self.generatetoaddress(w0, 6, w0.getnewaddress())
+ self.generatetoaddress(self.nodes[0], 6, w0.getnewaddress())
self.sync_blocks()
tx = wpriv.createrawtransaction([{"txid": txid, "vout": 0}], {w0.getnewaddress(): 49.999})
signed_tx = wpriv.signrawtransactionwithwallet(tx)
@@ -454,7 +454,7 @@ class ImportDescriptorsTest(BitcoinTestFramework):
self.generate(self.nodes[0], 6)
self.sync_all()
send_txid = wmulti_priv.sendtoaddress(w0.getnewaddress(), 8)
- decoded = wmulti_priv.decoderawtransaction(wmulti_priv.gettransaction(send_txid)['hex'])
+ decoded = wmulti_priv.gettransaction(txid=send_txid, verbose=True)['decoded']
assert_equal(len(decoded['vin'][0]['txinwitness']), 4)
self.generate(self.nodes[0], 6)
self.sync_all()
@@ -586,7 +586,7 @@ class ImportDescriptorsTest(BitcoinTestFramework):
self.sync_all()
# It is standard and would relay.
txid = wmulti_priv_big.sendtoaddress(w0.getnewaddress(), 9.999)
- decoded = wmulti_priv_big.decoderawtransaction(wmulti_priv_big.gettransaction(txid)['hex'])
+ decoded = wmulti_priv_big.gettransaction(txid=txid, verbose=True)['decoded']
# 20 sigs + dummy + witness script
assert_equal(len(decoded['vin'][0]['txinwitness']), 22)
@@ -620,12 +620,8 @@ class ImportDescriptorsTest(BitcoinTestFramework):
self.generate(self.nodes[0], 6)
self.sync_all()
# It is standard and would relay.
- txid = multi_priv_big.sendtoaddress(w0.getnewaddress(), 10, "", "",
- True)
- decoded = multi_priv_big.decoderawtransaction(
- multi_priv_big.gettransaction(txid)['hex']
- )
-
+ txid = multi_priv_big.sendtoaddress(w0.getnewaddress(), 10, "", "", True)
+ decoded = multi_priv_big.gettransaction(txid=txid, verbose=True)['decoded']
self.log.info("Amending multisig with new private keys")
self.nodes[1].createwallet(wallet_name="wmulti_priv3", descriptors=True)
diff --git a/test/functional/wallet_keypool.py b/test/functional/wallet_keypool.py
index c714993234..79235646b0 100755
--- a/test/functional/wallet_keypool.py
+++ b/test/functional/wallet_keypool.py
@@ -138,6 +138,20 @@ class KeyPoolTest(BitcoinTestFramework):
assert_equal(wi['keypoolsize_hd_internal'], 100)
assert_equal(wi['keypoolsize'], 100)
+ if not self.options.descriptors:
+ # Check that newkeypool entirely flushes the keypool
+ start_keypath = nodes[0].getaddressinfo(nodes[0].getnewaddress())['hdkeypath']
+ start_change_keypath = nodes[0].getaddressinfo(nodes[0].getrawchangeaddress())['hdkeypath']
+ # flush keypool and get new addresses
+ nodes[0].newkeypool()
+ end_keypath = nodes[0].getaddressinfo(nodes[0].getnewaddress())['hdkeypath']
+ end_change_keypath = nodes[0].getaddressinfo(nodes[0].getrawchangeaddress())['hdkeypath']
+ # The new keypath index should be 100 more than the old one
+ new_index = int(start_keypath.rsplit('/', 1)[1][:-1]) + 100
+ new_change_index = int(start_change_keypath.rsplit('/', 1)[1][:-1]) + 100
+ assert_equal(end_keypath, "m/0'/0'/" + str(new_index) + "'")
+ assert_equal(end_change_keypath, "m/0'/1'/" + str(new_change_index) + "'")
+
# create a blank wallet
nodes[0].createwallet(wallet_name='w2', blank=True, disable_private_keys=True)
w2 = nodes[0].get_wallet_rpc('w2')
diff --git a/test/functional/wallet_listdescriptors.py b/test/functional/wallet_listdescriptors.py
index 221f5262d9..436bbdcfcc 100755
--- a/test/functional/wallet_listdescriptors.py
+++ b/test/functional/wallet_listdescriptors.py
@@ -23,7 +23,7 @@ class ListDescriptorsTest(BitcoinTestFramework):
self.skip_if_no_sqlite()
# do not create any wallet by default
- def init_wallet(self, i):
+ def init_wallet(self, *, node):
return
def run_test(self):
diff --git a/test/functional/wallet_listsinceblock.py b/test/functional/wallet_listsinceblock.py
index bd3b29c81c..f4a00a8ec8 100755
--- a/test/functional/wallet_listsinceblock.py
+++ b/test/functional/wallet_listsinceblock.py
@@ -44,6 +44,14 @@ class ListSinceBlockTest(BitcoinTestFramework):
def test_no_blockhash(self):
self.log.info("Test no blockhash")
txid = self.nodes[2].sendtoaddress(self.nodes[0].getnewaddress(), 1)
+ self.sync_all()
+ assert_array_result(self.nodes[0].listtransactions(), {"txid": txid}, {
+ "category": "receive",
+ "amount": 1,
+ "confirmations": 0,
+ "trusted": False,
+ })
+
blockhash, = self.generate(self.nodes[2], 1)
blockheight = self.nodes[2].getblockheader(blockhash)['height']
self.sync_all()
@@ -56,6 +64,9 @@ class ListSinceBlockTest(BitcoinTestFramework):
"blockheight": blockheight,
"confirmations": 1,
})
+ assert_equal(len(txs), 1)
+ assert "trusted" not in txs[0]
+
assert_equal(
self.nodes[0].listsinceblock(),
{"lastblock": blockhash,
diff --git a/test/functional/wallet_listtransactions.py b/test/functional/wallet_listtransactions.py
index a14bfe345c..ca6a6ab540 100755
--- a/test/functional/wallet_listtransactions.py
+++ b/test/functional/wallet_listtransactions.py
@@ -31,10 +31,10 @@ class ListTransactionsTest(BitcoinTestFramework):
self.sync_all()
assert_array_result(self.nodes[0].listtransactions(),
{"txid": txid},
- {"category": "send", "amount": Decimal("-0.1"), "confirmations": 0})
+ {"category": "send", "amount": Decimal("-0.1"), "confirmations": 0, "trusted": True})
assert_array_result(self.nodes[1].listtransactions(),
{"txid": txid},
- {"category": "receive", "amount": Decimal("0.1"), "confirmations": 0})
+ {"category": "receive", "amount": Decimal("0.1"), "confirmations": 0, "trusted": False})
self.log.info("Test confirmations change after mining a block")
blockhash = self.generate(self.nodes[0], 1)[0]
blockheight = self.nodes[0].getblockheader(blockhash)['height']
@@ -204,6 +204,15 @@ class ListTransactionsTest(BitcoinTestFramework):
assert_equal(n.gettransaction(txid_3b)["bip125-replaceable"], "yes")
assert_equal(n.gettransaction(txid_4)["bip125-replaceable"], "unknown")
+ self.log.info("Test bip125-replaceable status with listsinceblock")
+ for n in self.nodes[0:2]:
+ txs = {tx['txid']: tx['bip125-replaceable'] for tx in n.listsinceblock()['transactions']}
+ assert_equal(txs[txid_1], "no")
+ assert_equal(txs[txid_2], "no")
+ assert_equal(txs[txid_3], "yes")
+ assert_equal(txs[txid_3b], "yes")
+ assert_equal(txs[txid_4], "unknown")
+
self.log.info("Test mined transactions are no longer bip125-replaceable")
self.generate(self.nodes[0], 1)
assert txid_3b not in self.nodes[0].getrawmempool()
diff --git a/test/functional/wallet_multisig_descriptor_psbt.py b/test/functional/wallet_multisig_descriptor_psbt.py
new file mode 100755
index 0000000000..ed855d2525
--- /dev/null
+++ b/test/functional/wallet_multisig_descriptor_psbt.py
@@ -0,0 +1,163 @@
+#!/usr/bin/env python3
+# Copyright (c) 2021 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""Test a basic M-of-N multisig setup between multiple people using descriptor wallets and PSBTs, as well as a signing flow.
+
+This is meant to be documentation as much as functional tests, so it is kept as simple and readable as possible.
+"""
+
+from test_framework.address import base58_to_byte
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (
+ assert_approx,
+ assert_equal,
+)
+
+
+class WalletMultisigDescriptorPSBTTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.num_nodes = 3
+ self.setup_clean_chain = True
+ self.wallet_names = []
+ self.extra_args = [["-keypool=100"]] * self.num_nodes
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+ self.skip_if_no_sqlite()
+
+ @staticmethod
+ def _get_xpub(wallet):
+ """Extract the wallet's xpubs using `listdescriptors` and pick the one from the `pkh` descriptor since it's least likely to be accidentally reused (legacy addresses)."""
+ descriptor = next(filter(lambda d: d["desc"].startswith("pkh"), wallet.listdescriptors()["descriptors"]))
+ return descriptor["desc"].split("]")[-1].split("/")[0]
+
+ @staticmethod
+ def _check_psbt(psbt, to, value, multisig):
+ """Helper function for any of the N participants to check the psbt with decodepsbt and verify it is OK before signing."""
+ tx = multisig.decodepsbt(psbt)["tx"]
+ amount = 0
+ for vout in tx["vout"]:
+ address = vout["scriptPubKey"]["address"]
+ assert_equal(multisig.getaddressinfo(address)["ischange"], address != to)
+ if address == to:
+ amount += vout["value"]
+ assert_approx(amount, float(value), vspan=0.001)
+
+ def participants_create_multisigs(self, xpubs):
+ """The multisig is created by importing the following descriptors. The resulting wallet is watch-only and every participant can do this."""
+ # some simple validation
+ assert_equal(len(xpubs), self.N)
+ # a sanity-check/assertion, this will throw if the base58 checksum of any of the provided xpubs are invalid
+ for xpub in xpubs:
+ base58_to_byte(xpub)
+
+ for i, node in enumerate(self.nodes):
+ node.createwallet(wallet_name=f"{self.name}_{i}", blank=True, descriptors=True, disable_private_keys=True)
+ multisig = node.get_wallet_rpc(f"{self.name}_{i}")
+ external = multisig.getdescriptorinfo(f"wsh(sortedmulti({self.M},{f'/0/*,'.join(xpubs)}/0/*))")
+ internal = multisig.getdescriptorinfo(f"wsh(sortedmulti({self.M},{f'/1/*,'.join(xpubs)}/1/*))")
+ result = multisig.importdescriptors([
+ { # receiving addresses (internal: False)
+ "desc": external["descriptor"],
+ "active": True,
+ "internal": False,
+ "timestamp": "now",
+ },
+ { # change addresses (internal: True)
+ "desc": internal["descriptor"],
+ "active": True,
+ "internal": True,
+ "timestamp": "now",
+ },
+ ])
+ assert all(r["success"] for r in result)
+ yield multisig
+
+ def run_test(self):
+ self.M = 2
+ self.N = self.num_nodes
+ self.name = f"{self.M}_of_{self.N}_multisig"
+ self.log.info(f"Testing {self.name}...")
+
+ participants = {
+ # Every participant generates an xpub. The most straightforward way is to create a new descriptor wallet.
+ # This wallet will be the participant's `signer` for the resulting multisig. Avoid reusing this wallet for any other purpose (for privacy reasons).
+ "signers": [node.get_wallet_rpc(node.createwallet(wallet_name=f"participant_{self.nodes.index(node)}", descriptors=True)["name"]) for node in self.nodes],
+ # After participants generate and exchange their xpubs they will each create their own watch-only multisig.
+ # Note: these multisigs are all the same, this justs highlights that each participant can independently verify everything on their own node.
+ "multisigs": []
+ }
+
+ self.log.info("Generate and exchange xpubs...")
+ xpubs = [self._get_xpub(signer) for signer in participants["signers"]]
+
+ self.log.info("Every participant imports the following descriptors to create the watch-only multisig...")
+ participants["multisigs"] = list(self.participants_create_multisigs(xpubs))
+
+ self.log.info("Check that every participant's multisig generates the same addresses...")
+ for _ in range(10): # we check that the first 10 generated addresses are the same for all participant's multisigs
+ receive_addresses = [multisig.getnewaddress() for multisig in participants["multisigs"]]
+ all(address == receive_addresses[0] for address in receive_addresses)
+ change_addresses = [multisig.getrawchangeaddress() for multisig in participants["multisigs"]]
+ all(address == change_addresses[0] for address in change_addresses)
+
+ self.log.info("Get a mature utxo to send to the multisig...")
+ coordinator_wallet = participants["signers"][0]
+ self.generatetoaddress(self.nodes[0], 101, coordinator_wallet.getnewaddress())
+
+ deposit_amount = 6.15
+ multisig_receiving_address = participants["multisigs"][0].getnewaddress()
+ self.log.info("Send funds to the resulting multisig receiving address...")
+ coordinator_wallet.sendtoaddress(multisig_receiving_address, deposit_amount)
+ self.generate(self.nodes[0], 1)
+ self.sync_all()
+ for participant in participants["multisigs"]:
+ assert_approx(participant.getbalance(), deposit_amount, vspan=0.001)
+
+ self.log.info("Send a transaction from the multisig!")
+ to = participants["signers"][self.N - 1].getnewaddress()
+ value = 1
+ self.log.info("First, make a sending transaction, created using `walletcreatefundedpsbt` (anyone can initiate this)...")
+ psbt = participants["multisigs"][0].walletcreatefundedpsbt(inputs=[], outputs={to: value}, options={"feeRate": 0.00010})
+
+ psbts = []
+ self.log.info("Now at least M users check the psbt with decodepsbt and (if OK) signs it with walletprocesspsbt...")
+ for m in range(self.M):
+ signers_multisig = participants["multisigs"][m]
+ self._check_psbt(psbt["psbt"], to, value, signers_multisig)
+ signing_wallet = participants["signers"][m]
+ partially_signed_psbt = signing_wallet.walletprocesspsbt(psbt["psbt"])
+ psbts.append(partially_signed_psbt["psbt"])
+
+ self.log.info("Finally, collect the signed PSBTs with combinepsbt, finalizepsbt, then broadcast the resulting transaction...")
+ combined = coordinator_wallet.combinepsbt(psbts)
+ finalized = coordinator_wallet.finalizepsbt(combined)
+ coordinator_wallet.sendrawtransaction(finalized["hex"])
+
+ self.log.info("Check that balances are correct after the transaction has been included in a block.")
+ self.generate(self.nodes[0], 1)
+ self.sync_all()
+ assert_approx(participants["multisigs"][0].getbalance(), deposit_amount - value, vspan=0.001)
+ assert_equal(participants["signers"][self.N - 1].getbalance(), value)
+
+ self.log.info("Send another transaction from the multisig, this time with a daisy chained signing flow (one after another in series)!")
+ psbt = participants["multisigs"][0].walletcreatefundedpsbt(inputs=[], outputs={to: value}, options={"feeRate": 0.00010})
+ for m in range(self.M):
+ signers_multisig = participants["multisigs"][m]
+ self._check_psbt(psbt["psbt"], to, value, signers_multisig)
+ signing_wallet = participants["signers"][m]
+ psbt = signing_wallet.walletprocesspsbt(psbt["psbt"])
+ assert_equal(psbt["complete"], m == self.M - 1)
+ finalized = coordinator_wallet.finalizepsbt(psbt["psbt"])
+ coordinator_wallet.sendrawtransaction(finalized["hex"])
+
+ self.log.info("Check that balances are correct after the transaction has been included in a block.")
+ self.generate(self.nodes[0], 1)
+ self.sync_all()
+ assert_approx(participants["multisigs"][0].getbalance(), deposit_amount - (value * 2), vspan=0.001)
+ assert_equal(participants["signers"][self.N - 1].getbalance(), value * 2)
+
+
+if __name__ == "__main__":
+ WalletMultisigDescriptorPSBTTest().main()
diff --git a/test/functional/wallet_taproot.py b/test/functional/wallet_taproot.py
index 4f84dbd125..80c125df97 100755
--- a/test/functional/wallet_taproot.py
+++ b/test/functional/wallet_taproot.py
@@ -185,7 +185,7 @@ class WalletTaprootTest(BitcoinTestFramework):
def setup_network(self):
self.setup_nodes()
- def init_wallet(self, i):
+ def init_wallet(self, *, node):
pass
@staticmethod
diff --git a/test/functional/wallet_transactiontime_rescan.py b/test/functional/wallet_transactiontime_rescan.py
index 78859e6131..afa5139da7 100755
--- a/test/functional/wallet_transactiontime_rescan.py
+++ b/test/functional/wallet_transactiontime_rescan.py
@@ -63,7 +63,7 @@ class TransactionTimeRescanTest(BitcoinTestFramework):
# generate some btc to create transactions and check blockcount
initial_mine = COINBASE_MATURITY + 1
- minernode.generatetoaddress(initial_mine, m1)
+ self.generatetoaddress(minernode, initial_mine, m1)
assert_equal(minernode.getblockcount(), initial_mine + 200)
# synchronize nodes and time
@@ -76,7 +76,7 @@ class TransactionTimeRescanTest(BitcoinTestFramework):
miner_wallet.sendtoaddress(wo1, 10)
# generate blocks and check blockcount
- minernode.generatetoaddress(COINBASE_MATURITY, m1)
+ self.generatetoaddress(minernode, COINBASE_MATURITY, m1)
assert_equal(minernode.getblockcount(), initial_mine + 300)
# synchronize nodes and time
@@ -89,7 +89,7 @@ class TransactionTimeRescanTest(BitcoinTestFramework):
miner_wallet.sendtoaddress(wo2, 5)
# generate blocks and check blockcount
- minernode.generatetoaddress(COINBASE_MATURITY, m1)
+ self.generatetoaddress(minernode, COINBASE_MATURITY, m1)
assert_equal(minernode.getblockcount(), initial_mine + 400)
# synchronize nodes and time
@@ -102,7 +102,7 @@ class TransactionTimeRescanTest(BitcoinTestFramework):
miner_wallet.sendtoaddress(wo3, 1)
# generate more blocks and check blockcount
- minernode.generatetoaddress(COINBASE_MATURITY, m1)
+ self.generatetoaddress(minernode, COINBASE_MATURITY, m1)
assert_equal(minernode.getblockcount(), initial_mine + 500)
self.log.info('Check user\'s final balance and transaction count')
diff --git a/test/functional/wallet_upgradewallet.py b/test/functional/wallet_upgradewallet.py
index ed98db55c9..5800880830 100755
--- a/test/functional/wallet_upgradewallet.py
+++ b/test/functional/wallet_upgradewallet.py
@@ -234,18 +234,13 @@ class UpgradeWalletTest(BitcoinTestFramework):
assert_equal(1, hd_chain_version)
seed_id = bytearray(seed_id)
seed_id.reverse()
- old_kvs = new_kvs
- # First 2 keys should still be non-HD
- for i in range(0, 2):
- info = wallet.getaddressinfo(wallet.getnewaddress())
- assert 'hdkeypath' not in info
- assert 'hdseedid' not in info
- # Next key should be HD
+
+ # New keys (including change) should be HD (the two old keys have been flushed)
info = wallet.getaddressinfo(wallet.getnewaddress())
assert_equal(seed_id.hex(), info['hdseedid'])
assert_equal('m/0\'/0\'/0\'', info['hdkeypath'])
prev_seed_id = info['hdseedid']
- # Change key should be the same keypool
+ # Change key should be HD and from the same keypool
info = wallet.getaddressinfo(wallet.getrawchangeaddress())
assert_equal(prev_seed_id, info['hdseedid'])
assert_equal('m/0\'/0\'/1\'', info['hdkeypath'])
@@ -291,14 +286,7 @@ class UpgradeWalletTest(BitcoinTestFramework):
hd_chain_version, external_counter, seed_id, internal_counter = struct.unpack('<iI20sI', hd_chain)
assert_equal(2, hd_chain_version)
assert_equal(2, internal_counter)
- # Drain the keypool by fetching one external key and one change key. Should still be the same keypool
- info = wallet.getaddressinfo(wallet.getnewaddress())
- assert 'hdseedid' not in info
- assert 'hdkeypath' not in info
- info = wallet.getaddressinfo(wallet.getrawchangeaddress())
- assert 'hdseedid' not in info
- assert 'hdkeypath' not in info
- # The next addresses are HD and should be on different HD chains
+ # The next addresses are HD and should be on different HD chains (the one remaining key in each pool should have been flushed)
info = wallet.getaddressinfo(wallet.getnewaddress())
ext_id = info['hdseedid']
assert_equal('m/0\'/0\'/0\'', info['hdkeypath'])
diff --git a/test/lint/lint-python.sh b/test/lint/lint-python.sh
index c448fa6f9a..3d22407fd1 100755
--- a/test/lint/lint-python.sh
+++ b/test/lint/lint-python.sh
@@ -102,7 +102,7 @@ if ! PYTHONWARNINGS="ignore" flake8 --ignore=B,C,E,F,I,N,W --select=$(IFS=","; e
EXIT_CODE=1
fi
-if ! mypy --ignore-missing-imports --show-error-codes $(git ls-files "test/functional/*.py" "contrib/devtools/*.py"); then
+if ! mypy --show-error-codes $(git ls-files "test/functional/*.py" "contrib/devtools/*.py"); then
EXIT_CODE=1
fi
diff --git a/test/sanitizer_suppressions/ubsan b/test/sanitizer_suppressions/ubsan
index b52e105a33..1d608b9ec1 100644
--- a/test/sanitizer_suppressions/ubsan
+++ b/test/sanitizer_suppressions/ubsan
@@ -22,7 +22,7 @@ unsigned-integer-overflow:arith_uint256.h
unsigned-integer-overflow:basic_string.h
unsigned-integer-overflow:bench/bench.h
unsigned-integer-overflow:bitcoin-tx.cpp
-unsigned-integer-overflow:bloom.cpp
+unsigned-integer-overflow:common/bloom.cpp
unsigned-integer-overflow:chain.cpp
unsigned-integer-overflow:chain.h
unsigned-integer-overflow:coded_stream.h
@@ -48,7 +48,7 @@ implicit-integer-sign-change:*/new_allocator.h
implicit-integer-sign-change:addrman.h
implicit-integer-sign-change:arith_uint256.cpp
implicit-integer-sign-change:bech32.cpp
-implicit-integer-sign-change:bloom.cpp
+implicit-integer-sign-change:common/bloom.cpp
implicit-integer-sign-change:chain.cpp
implicit-integer-sign-change:chain.h
implicit-integer-sign-change:coins.h