aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml8
-rw-r--r--build-aux/m4/bitcoin_qt.m411
-rw-r--r--build_msvc/README.md4
-rwxr-xr-xcontrib/devtools/symbol-check.py15
-rw-r--r--depends/packages/expat.mk11
-rw-r--r--depends/packages/freetype.mk8
-rw-r--r--depends/packages/libXau.mk4
-rw-r--r--depends/packages/libxcb.mk24
-rw-r--r--depends/packages/libxcb_util.mk32
-rw-r--r--depends/packages/libxcb_util_image.mk31
-rw-r--r--depends/packages/libxcb_util_keysyms.mk31
-rw-r--r--depends/packages/libxcb_util_render.mk31
-rw-r--r--depends/packages/libxcb_util_wm.mk31
-rw-r--r--depends/packages/packages.mk2
-rw-r--r--depends/packages/qt.mk39
-rw-r--r--depends/packages/xcb_proto.mk11
-rw-r--r--depends/packages/xproto.mk4
-rw-r--r--depends/patches/qt/dont_hardcode_x86_64.patch34
-rw-r--r--depends/patches/qt/fix_android_jni_static.patch2
-rw-r--r--depends/patches/qt/fix_android_pch.patch10
-rw-r--r--depends/patches/qt/fix_bigsur_style.patch90
-rw-r--r--depends/patches/qt/fix_lib_paths.patch193
-rw-r--r--depends/patches/qt/fix_limits_header.patch36
-rw-r--r--depends/patches/qt/fix_qt_pkgconfig.patch14
-rw-r--r--depends/patches/qt/no-xlib.patch13
-rw-r--r--depends/patches/qt/qtbase-moc-ignore-gcc-macro.patch2
-rw-r--r--depends/patches/qt/support_new_android_ndks.patch122
-rw-r--r--doc/dependencies.md3
-rw-r--r--src/Makefile.am3
-rw-r--r--src/base58.cpp2
-rw-r--r--src/blockfilter.cpp8
-rw-r--r--src/compressor.h8
-rw-r--r--src/net.cpp5
-rw-r--r--src/net_processing.cpp2
-rw-r--r--src/netaddress.cpp10
-rw-r--r--src/netaddress.h2
-rw-r--r--src/policy/fees.cpp11
-rw-r--r--src/policy/fees.h40
-rw-r--r--src/policy/policy.cpp2
-rw-r--r--src/psbt.h2
-rw-r--r--src/pubkey.h6
-rw-r--r--src/qt/guiutil.h9
-rw-r--r--src/qt/rpcconsole.cpp4
-rw-r--r--src/rpc/misc.cpp51
-rw-r--r--src/rpc/net.cpp147
-rw-r--r--src/rpc/util.cpp2
-rw-r--r--src/script/descriptor.cpp8
-rw-r--r--src/script/interpreter.cpp6
-rw-r--r--src/script/sign.cpp2
-rw-r--r--src/script/sign.h2
-rw-r--r--src/signet.cpp4
-rw-r--r--src/span.h24
-rw-r--r--src/streams.h35
-rw-r--r--src/test/crypto_tests.cpp4
-rw-r--r--src/test/fuzz/asmap.cpp2
-rw-r--r--src/test/fuzz/golomb_rice.cpp8
-rw-r--r--src/test/fuzz/rpc.cpp18
-rw-r--r--src/test/fuzz/script_assets_test_minimizer.cpp4
-rw-r--r--src/test/fuzz/utxo_snapshot.cpp2
-rw-r--r--src/test/key_io_tests.cpp2
-rw-r--r--src/test/net_tests.cpp140
-rw-r--r--src/test/script_tests.cpp10
-rw-r--r--src/test/streams_tests.cpp6
-rw-r--r--src/test/util_tests.cpp6
-rw-r--r--src/txmempool.cpp12
-rw-r--r--src/txmempool.h6
-rw-r--r--src/validation.cpp19
-rw-r--r--src/validation.h7
-rw-r--r--src/wallet/rpc/backup.cpp (renamed from src/wallet/rpcdump.cpp)107
-rw-r--r--src/wallet/rpc/encrypt.cpp248
-rw-r--r--src/wallet/rpc/util.cpp32
-rw-r--r--src/wallet/rpc/util.h4
-rw-r--r--src/wallet/rpcwallet.cpp386
-rw-r--r--src/wallet/scriptpubkeyman.cpp36
-rw-r--r--src/wallet/scriptpubkeyman.h28
-rw-r--r--src/wallet/test/wallet_tests.cpp27
-rw-r--r--src/wallet/wallet.cpp78
-rw-r--r--src/wallet/wallet.h12
-rwxr-xr-xtest/functional/feature_coinstatsindex.py8
-rwxr-xr-xtest/functional/wallet_listtransactions.py66
80 files changed, 1304 insertions, 1185 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index 460906817e..98b78592e2 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -84,9 +84,9 @@ task:
CI_VCPKG_TAG: '2021.05.12'
VCPKG_DOWNLOADS: 'C:\Users\ContainerAdministrator\AppData\Local\vcpkg\downloads'
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'
+ QT_DOWNLOAD_URL: 'https://download.qt.io/official_releases/qt/5.15/5.15.2/single/qt-everywhere-src-5.15.2.zip'
+ QT_LOCAL_PATH: 'C:\qt-everywhere-src-5.15.2.zip'
+ QT_SOURCE_DIR: 'C:\qt-everywhere-src-5.15.2'
QTBASEDIR: 'C:\Qt_static'
x64_NATIVE_TOOLS: '"C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Auxiliary\Build\vcvars64.bat"'
IgnoreWarnIntDirInTempDetected: 'true'
@@ -115,7 +115,7 @@ task:
- cd %QT_SOURCE_DIR%
- mkdir build
- cd build
- - ..\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%
+ - ..\configure -release -silent -opensource -confirm-license -opengl desktop -static -static-runtime -mp -qt-zlib -qt-pcre -qt-libpng -nomake examples -nomake tests -nomake tools -no-angle -no-dbus -no-gif -no-gtk -no-ico -no-icu -no-libjpeg -no-libudev -no-sql-sqlite -no-sql-odbc -no-sqlite -no-vulkan -skip qt3d -skip qtactiveqt -skip qtandroidextras -skip qtcharts -skip qtconnectivity -skip qtdatavis3d -skip qtdeclarative -skip doc -skip qtdoc -skip qtgamepad -skip qtgraphicaleffects -skip qtimageformats -skip qtlocation -skip qtlottie -skip qtmacextras -skip qtmultimedia -skip qtnetworkauth -skip qtpurchasing -skip qtquick3d -skip qtquickcontrols -skip qtquickcontrols2 -skip qtquicktimeline -skip qtremoteobjects -skip qtscript -skip qtscxml -skip qtsensors -skip qtserialbus -skip qtserialport -skip qtspeech -skip qtsvg -skip qtvirtualkeyboard -skip qtwayland -skip qtwebchannel -skip qtwebengine -skip qtwebglplugin -skip qtwebsockets -skip qtwebview -skip qtx11extras -skip qtxmlpatterns -no-openssl -no-feature-bearermanagement -no-feature-printdialog -no-feature-printer -no-feature-printpreviewdialog -no-feature-printpreviewwidget -no-feature-sql -no-feature-sqlmodel -no-feature-textbrowser -no-feature-textmarkdownwriter -no-feature-textodfwriter -no-feature-xml -prefix %QTBASEDIR%
- jom
- jom install
vcpkg_tools_cache:
diff --git a/build-aux/m4/bitcoin_qt.m4 b/build-aux/m4/bitcoin_qt.m4
index 8b90ee3dc4..8346e549b8 100644
--- a/build-aux/m4/bitcoin_qt.m4
+++ b/build-aux/m4/bitcoin_qt.m4
@@ -67,10 +67,11 @@ AC_DEFUN([BITCOIN_QT_INIT],[
AS_IF([test "x$with_gui" = xqt5_debug],
[AS_CASE([$host],
[*darwin*], [qt_lib_suffix=_debug],
- [*mingw*], [qt_lib_suffix=d],
[qt_lib_suffix= ]); bitcoin_qt_want_version=qt5],
[qt_lib_suffix= ])
+ AS_CASE([$host], [*android*], [qt_lib_suffix=_$ANDROID_ARCH])
+
AC_ARG_WITH([qt-incdir],[AS_HELP_STRING([--with-qt-incdir=INC_DIR],[specify qt include path (overridden by pkgconfig)])], [qt_include_path=$withval], [])
AC_ARG_WITH([qt-libdir],[AS_HELP_STRING([--with-qt-libdir=LIB_DIR],[specify qt lib path (overridden by pkgconfig)])], [qt_lib_path=$withval], [])
AC_ARG_WITH([qt-plugindir],[AS_HELP_STRING([--with-qt-plugindir=PLUGIN_DIR],[specify qt plugin path (overridden by pkgconfig)])], [qt_plugin_path=$withval], [])
@@ -149,8 +150,6 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[
_BITCOIN_QT_CHECK_STATIC_PLUGIN([QWindowsVistaStylePlugin], [-lqwindowsvistastyle])
AC_DEFINE([QT_QPA_PLATFORM_WINDOWS], [1], [Define this symbol if the qt platform is windows])
elif test "x$TARGET_OS" = xlinux; then
- dnl workaround for https://bugreports.qt.io/browse/QTBUG-74874
- AX_CHECK_LINK_FLAG([-lxcb-shm], [QT_LIBS="$QT_LIBS -lxcb-shm"], [AC_MSG_ERROR([could not link against -lxcb-shm])])
_BITCOIN_QT_CHECK_STATIC_PLUGIN([QXcbIntegrationPlugin], [-lqxcb])
AC_DEFINE([QT_QPA_PLATFORM_XCB], [1], [Define this symbol if the qt platform is xcb])
elif test "x$TARGET_OS" = xdarwin; then
@@ -162,7 +161,7 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[
_BITCOIN_QT_CHECK_STATIC_PLUGIN([QMacStylePlugin], [-lqmacstyle])
AC_DEFINE([QT_QPA_PLATFORM_COCOA], [1], [Define this symbol if the qt platform is cocoa])
elif test "x$TARGET_OS" = xandroid; then
- QT_LIBS="-Wl,--export-dynamic,--undefined=JNI_OnLoad -lqtforandroid -ljnigraphics -landroid -lqtfreetype $QT_LIBS"
+ QT_LIBS="-Wl,--export-dynamic,--undefined=JNI_OnLoad -lplugins_platforms_qtforandroid_$ANDROID_ARCH -ljnigraphics -landroid -lqtfreetype_$ANDROID_ARCH $QT_LIBS"
AC_DEFINE([QT_QPA_PLATFORM_ANDROID], [1], [Define this symbol if the qt platform is android])
fi
fi
@@ -353,6 +352,7 @@ AC_DEFUN([_BITCOIN_QT_CHECK_STATIC_LIBS], [
PKG_CHECK_MODULES([QT_INPUT], [${qt_lib_prefix}InputSupport], [QT_LIBS="$QT_INPUT_LIBS $QT_LIBS"])
PKG_CHECK_MODULES([QT_SERVICE], [${qt_lib_prefix}ServiceSupport], [QT_LIBS="$QT_SERVICE_LIBS $QT_LIBS"])
PKG_CHECK_MODULES([QT_XCBQPA], [${qt_lib_prefix}XcbQpa], [QT_LIBS="$QT_XCBQPA_LIBS $QT_LIBS"])
+ PKG_CHECK_MODULES([QT_XKBCOMMON], [${qt_lib_prefix}XkbCommonSupport], [QT_LIBS="$QT_XKBCOMMON_LIBS $QT_LIBS"])
elif test "x$TARGET_OS" = xdarwin; then
PKG_CHECK_MODULES([QT_CLIPBOARD], [${qt_lib_prefix}ClipboardSupport${qt_lib_suffix}], [QT_LIBS="$QT_CLIPBOARD_LIBS $QT_LIBS"])
PKG_CHECK_MODULES([QT_GRAPHICS], [${qt_lib_prefix}GraphicsSupport${qt_lib_suffix}], [QT_LIBS="$QT_GRAPHICS_LIBS $QT_LIBS"])
@@ -360,7 +360,8 @@ AC_DEFUN([_BITCOIN_QT_CHECK_STATIC_LIBS], [
elif test "x$TARGET_OS" = xwindows; then
PKG_CHECK_MODULES([QT_WINDOWSUIAUTOMATION], [${qt_lib_prefix}WindowsUIAutomationSupport${qt_lib_suffix}], [QT_LIBS="$QT_WINDOWSUIAUTOMATION_LIBS $QT_LIBS"])
elif test "x$TARGET_OS" = xandroid; then
- PKG_CHECK_MODULES([QT_EGL], [${qt_lib_prefix}EglSupport], [QT_LIBS="$QT_EGL_LIBS $QT_LIBS"])
+ PKG_CHECK_MODULES([QT_EGL], [${qt_lib_prefix}EglSupport${qt_lib_suffix}], [QT_LIBS="$QT_EGL_LIBS $QT_LIBS"])
+ PKG_CHECK_MODULES([QT_SERVICE], [${qt_lib_prefix}ServiceSupport${qt_lib_suffix}], [QT_LIBS="$QT_SERVICE_LIBS $QT_LIBS"])
fi
])
diff --git a/build_msvc/README.md b/build_msvc/README.md
index 36fb942c8e..cabe4d55ec 100644
--- a/build_msvc/README.md
+++ b/build_msvc/README.md
@@ -28,14 +28,14 @@ Qt
---------------------
To build Bitcoin Core with the GUI, a static build of Qt is required.
-1. Download a single ZIP archive of Qt source code from https://download.qt.io/official_releases/qt/ (e.g., [`qt-everywhere-src-5.12.11.zip`](https://download.qt.io/official_releases/qt/5.12/5.12.11/single/qt-everywhere-src-5.12.11.zip)), and expand it into a dedicated folder. The following instructions assume that this folder is `C:\dev\qt-source`.
+1. Download a single ZIP archive of Qt source code from https://download.qt.io/official_releases/qt/ (e.g., [`qt-everywhere-src-5.15.2.zip`](https://download.qt.io/official_releases/qt/5.15/5.15.2/single/qt-everywhere-src-5.15.2.zip)), and expand it into a dedicated folder. The following instructions assume that this folder is `C:\dev\qt-source`.
2. Open "x64 Native Tools Command Prompt for VS 2019", and input the following commands:
```cmd
cd C:\dev\qt-source
mkdir build
cd build
-..\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 C:\Qt_static
+..\configure -release -silent -opensource -confirm-license -opengl desktop -static -static-runtime -mp -qt-zlib -qt-pcre -qt-libpng -nomake examples -nomake tests -nomake tools -no-angle -no-dbus -no-gif -no-gtk -no-ico -no-icu -no-libjpeg -no-libudev -no-sql-sqlite -no-sql-odbc -no-sqlite -no-vulkan -skip qt3d -skip qtactiveqt -skip qtandroidextras -skip qtcharts -skip qtconnectivity -skip qtdatavis3d -skip qtdeclarative -skip doc -skip qtdoc -skip qtgamepad -skip qtgraphicaleffects -skip qtimageformats -skip qtlocation -skip qtlottie -skip qtmacextras -skip qtmultimedia -skip qtnetworkauth -skip qtpurchasing -skip qtquick3d -skip qtquickcontrols -skip qtquickcontrols2 -skip qtquicktimeline -skip qtremoteobjects -skip qtscript -skip qtscxml -skip qtsensors -skip qtserialbus -skip qtserialport -skip qtspeech -skip qtsvg -skip qtvirtualkeyboard -skip qtwayland -skip qtwebchannel -skip qtwebengine -skip qtwebglplugin -skip qtwebsockets -skip qtwebview -skip qtx11extras -skip qtxmlpatterns -no-openssl -no-feature-bearermanagement -no-feature-printdialog -no-feature-printer -no-feature-printpreviewdialog -no-feature-printpreviewwidget -no-feature-sql -no-feature-sqlmodel -no-feature-textbrowser -no-feature-textmarkdownwriter -no-feature-textodfwriter -no-feature-xml -prefix C:\Qt_static
nmake
nmake install
```
diff --git a/contrib/devtools/symbol-check.py b/contrib/devtools/symbol-check.py
index 15d4e729ac..ec3b7691e9 100755
--- a/contrib/devtools/symbol-check.py
+++ b/contrib/devtools/symbol-check.py
@@ -105,7 +105,19 @@ ELF_ALLOWED_LIBRARIES = {
'libxkbcommon-x11.so.0', # keyboard keymapping
'libfontconfig.so.1', # font support
'libfreetype.so.6', # font parsing
-'libdl.so.2' # programming interface to dynamic linker
+'libdl.so.2', # programming interface to dynamic linker
+'libxcb-icccm.so.4',
+'libxcb-image.so.0',
+'libxcb-shm.so.0',
+'libxcb-keysyms.so.1',
+'libxcb-randr.so.0',
+'libxcb-render-util.so.0',
+'libxcb-render.so.0',
+'libxcb-shape.so.0',
+'libxcb-sync.so.1',
+'libxcb-xfixes.so.0',
+'libxcb-xinerama.so.0',
+'libxcb-xkb.so.1',
}
MACHO_ALLOWED_LIBRARIES = {
@@ -116,6 +128,7 @@ MACHO_ALLOWED_LIBRARIES = {
'AppKit', # user interface
'ApplicationServices', # common application tasks.
'Carbon', # deprecated c back-compat API
+'ColorSync',
'CoreFoundation', # low level func, data types
'CoreGraphics', # 2D rendering
'CoreServices', # operating system services
diff --git a/depends/packages/expat.mk b/depends/packages/expat.mk
index 41c1114be0..c2089d1ccb 100644
--- a/depends/packages/expat.mk
+++ b/depends/packages/expat.mk
@@ -1,12 +1,13 @@
package=expat
-$(package)_version=2.2.7
-$(package)_download_path=https://github.com/libexpat/libexpat/releases/download/R_2_2_7/
-$(package)_file_name=$(package)-$($(package)_version).tar.bz2
-$(package)_sha256_hash=cbc9102f4a31a8dafd42d642e9a3aa31e79a0aedaa1f6efd2795ebc83174ec18
+$(package)_version=2.4.1
+$(package)_download_path=https://github.com/libexpat/libexpat/releases/download/R_2_4_1/
+$(package)_file_name=$(package)-$($(package)_version).tar.xz
+$(package)_sha256_hash=cf032d0dba9b928636548e32b327a2d66b1aab63c4f4a13dd132c2d1d2f2fb6a
define $(package)_set_vars
$(package)_config_opts=--disable-shared --without-docbook --without-tests --without-examples
$(package)_config_opts += --disable-dependency-tracking --enable-option-checking
+ $(package)_config_opts += --without-xmlwf
$(package)_config_opts_linux=--with-pic
endef
@@ -23,5 +24,5 @@ define $(package)_stage_cmds
endef
define $(package)_postprocess_cmds
- rm -rf share lib/*.la
+ rm -rf share lib/cmake lib/*.la
endef
diff --git a/depends/packages/freetype.mk b/depends/packages/freetype.mk
index aebc8a5f3b..6f5dbe0f01 100644
--- a/depends/packages/freetype.mk
+++ b/depends/packages/freetype.mk
@@ -1,12 +1,12 @@
package=freetype
-$(package)_version=2.7.1
+$(package)_version=2.11.0
$(package)_download_path=https://download.savannah.gnu.org/releases/$(package)
-$(package)_file_name=$(package)-$($(package)_version).tar.bz2
-$(package)_sha256_hash=3a3bb2c4e15ffb433f2032f50a5b5a92558206822e22bfe8cbe339af4aa82f88
+$(package)_file_name=$(package)-$($(package)_version).tar.xz
+$(package)_sha256_hash=8bee39bd3968c4804b70614a0a3ad597299ad0e824bc8aad5ce8aaf48067bde7
define $(package)_set_vars
$(package)_config_opts=--without-zlib --without-png --without-harfbuzz --without-bzip2 --disable-static
- $(package)_config_opts += --enable-option-checking
+ $(package)_config_opts += --enable-option-checking --without-brotli
$(package)_config_opts_linux=--with-pic
endef
diff --git a/depends/packages/libXau.mk b/depends/packages/libXau.mk
index 24e0e9d325..b7e032c0b2 100644
--- a/depends/packages/libXau.mk
+++ b/depends/packages/libXau.mk
@@ -1,8 +1,8 @@
package=libXau
-$(package)_version=1.0.8
+$(package)_version=1.0.9
$(package)_download_path=https://xorg.freedesktop.org/releases/individual/lib/
$(package)_file_name=$(package)-$($(package)_version).tar.bz2
-$(package)_sha256_hash=fdd477320aeb5cdd67272838722d6b7d544887dfe7de46e1e7cc0c27c2bea4f2
+$(package)_sha256_hash=ccf8cbf0dbf676faa2ea0a6d64bcc3b6746064722b606c8c52917ed00dcb73ec
$(package)_dependencies=xproto
# When updating this package, check the default value of
diff --git a/depends/packages/libxcb.mk b/depends/packages/libxcb.mk
index 710f43959c..99a7ee2fbd 100644
--- a/depends/packages/libxcb.mk
+++ b/depends/packages/libxcb.mk
@@ -1,25 +1,21 @@
package=libxcb
-$(package)_version=1.10
+$(package)_version=1.14
$(package)_download_path=https://xcb.freedesktop.org/dist
-$(package)_file_name=$(package)-$($(package)_version).tar.bz2
-$(package)_sha256_hash=98d9ab05b636dd088603b64229dd1ab2d2cc02ab807892e107d674f9c3f2d5b5
+$(package)_file_name=$(package)-$($(package)_version).tar.xz
+$(package)_sha256_hash=a55ed6db98d43469801262d81dc2572ed124edc3db31059d4e9916eb9f844c34
$(package)_dependencies=xcb_proto libXau
define $(package)_set_vars
-$(package)_config_opts=--disable-static --disable-build-docs --without-doxygen --without-launchd
+$(package)_config_opts=--disable-static --disable-devel-docs --without-doxygen --without-launchd
$(package)_config_opts += --disable-dependency-tracking --enable-option-checking
-# Because we pass -qt-xcb to Qt, it will compile in a set of xcb helper libraries and extensions,
-# so we skip building all of the extensions here.
-# More info is available from: https://doc.qt.io/qt-5.9/linux-requirements.html
+# Disable uneeded extensions.
+# More info is available from: https://doc.qt.io/qt-5.15/linux-requirements.html
$(package)_config_opts += --disable-composite --disable-damage --disable-dpms
$(package)_config_opts += --disable-dri2 --disable-dri3 --disable-glx
-$(package)_config_opts += --disable-present --disable-randr --disable-record
-$(package)_config_opts += --disable-render --disable-resource --disable-screensaver
-$(package)_config_opts += --disable-shape --disable-sync
-$(package)_config_opts += --disable-xevie --disable-xfixes --disable-xfree86-dri
-$(package)_config_opts += --disable-xinerama --disable-xinput
-$(package)_config_opts += --disable-xprint --disable-selinux --disable-xtest
-$(package)_config_opts += --disable-xv --disable-xvmc
+$(package)_config_opts += --disable-present --disable-record --disable-resource
+$(package)_config_opts += --disable-screensaver --disable-xevie --disable-xfree86-dri
+$(package)_config_opts += --disable-xinput --disable-xprint --disable-selinux
+$(package)_config_opts += --disable-xtest --disable-xv --disable-xvmc
endef
define $(package)_preprocess_cmds
diff --git a/depends/packages/libxcb_util.mk b/depends/packages/libxcb_util.mk
new file mode 100644
index 0000000000..2b65b58597
--- /dev/null
+++ b/depends/packages/libxcb_util.mk
@@ -0,0 +1,32 @@
+package=libxcb_util
+$(package)_version=0.4.0
+$(package)_download_path=https://xcb.freedesktop.org/dist
+$(package)_file_name=xcb-util-$($(package)_version).tar.bz2
+$(package)_sha256_hash=46e49469cb3b594af1d33176cd7565def2be3fa8be4371d62271fabb5eae50e9
+$(package)_dependencies=libxcb
+
+define $(package)_set_vars
+$(package)_config_opts = --disable-shared --disable-devel-docs --without-doxygen
+$(package)_config_opts += --disable-dependency-tracking --enable-option-checking
+$(package)_cflags += -fPIC
+endef
+
+define $(package)_preprocess_cmds
+ cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub .
+endef
+
+define $(package)_config_cmds
+ $($(package)_autoconf)
+endef
+
+define $(package)_build_cmds
+ $(MAKE)
+endef
+
+define $(package)_stage_cmds
+ $(MAKE) DESTDIR=$($(package)_staging_dir) install
+endef
+
+define $(package)_postprocess_cmds
+ rm -rf share/man share/doc lib/*.la
+endef
diff --git a/depends/packages/libxcb_util_image.mk b/depends/packages/libxcb_util_image.mk
new file mode 100644
index 0000000000..d12d67e8e8
--- /dev/null
+++ b/depends/packages/libxcb_util_image.mk
@@ -0,0 +1,31 @@
+package=libxcb_util_image
+$(package)_version=0.4.0
+$(package)_download_path=https://xcb.freedesktop.org/dist
+$(package)_file_name=xcb-util-image-$($(package)_version).tar.bz2
+$(package)_sha256_hash=2db96a37d78831d643538dd1b595d7d712e04bdccf8896a5e18ce0f398ea2ffc
+$(package)_dependencies=libxcb libxcb_util
+
+define $(package)_set_vars
+$(package)_config_opts=--disable-static --disable-devel-docs --without-doxygen
+$(package)_config_opts+= --disable-dependency-tracking --enable-option-checking
+endef
+
+define $(package)_preprocess_cmds
+ cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub .
+endef
+
+define $(package)_config_cmds
+ $($(package)_autoconf)
+endef
+
+define $(package)_build_cmds
+ $(MAKE)
+endef
+
+define $(package)_stage_cmds
+ $(MAKE) DESTDIR=$($(package)_staging_dir) install
+endef
+
+define $(package)_postprocess_cmds
+ rm -rf share/man share/doc lib/*.la
+endef
diff --git a/depends/packages/libxcb_util_keysyms.mk b/depends/packages/libxcb_util_keysyms.mk
new file mode 100644
index 0000000000..d4f72dedbe
--- /dev/null
+++ b/depends/packages/libxcb_util_keysyms.mk
@@ -0,0 +1,31 @@
+package=libxcb_util_keysyms
+$(package)_version=0.4.0
+$(package)_download_path=https://xcb.freedesktop.org/dist
+$(package)_file_name=xcb-util-keysyms-$($(package)_version).tar.bz2
+$(package)_sha256_hash=0ef8490ff1dede52b7de533158547f8b454b241aa3e4dcca369507f66f216dd9
+$(package)_dependencies=libxcb xproto
+
+define $(package)_set_vars
+$(package)_config_opts=--disable-static --disable-devel-docs --without-doxygen
+$(package)_config_opts += --disable-dependency-tracking --enable-option-checking
+endef
+
+define $(package)_preprocess_cmds
+ cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub .
+endef
+
+define $(package)_config_cmds
+ $($(package)_autoconf)
+endef
+
+define $(package)_build_cmds
+ $(MAKE)
+endef
+
+define $(package)_stage_cmds
+ $(MAKE) DESTDIR=$($(package)_staging_dir) install
+endef
+
+define $(package)_postprocess_cmds
+ rm -rf share/man share/doc lib/*.la
+endef
diff --git a/depends/packages/libxcb_util_render.mk b/depends/packages/libxcb_util_render.mk
new file mode 100644
index 0000000000..28f1fb073c
--- /dev/null
+++ b/depends/packages/libxcb_util_render.mk
@@ -0,0 +1,31 @@
+package=libxcb_util_render
+$(package)_version=0.3.9
+$(package)_download_path=https://xcb.freedesktop.org/dist
+$(package)_file_name=xcb-util-renderutil-$($(package)_version).tar.bz2
+$(package)_sha256_hash=c6e97e48fb1286d6394dddb1c1732f00227c70bd1bedb7d1acabefdd340bea5b
+$(package)_dependencies=libxcb
+
+define $(package)_set_vars
+$(package)_config_opts=--disable-static --disable-devel-docs --without-doxygen
+$(package)_config_opts += --disable-dependency-tracking --enable-option-checking
+endef
+
+define $(package)_preprocess_cmds
+ cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub .
+endef
+
+define $(package)_config_cmds
+ $($(package)_autoconf)
+endef
+
+define $(package)_build_cmds
+ $(MAKE)
+endef
+
+define $(package)_stage_cmds
+ $(MAKE) DESTDIR=$($(package)_staging_dir) install
+endef
+
+define $(package)_postprocess_cmds
+ rm -rf share/man share/doc lib/*.la
+endef
diff --git a/depends/packages/libxcb_util_wm.mk b/depends/packages/libxcb_util_wm.mk
new file mode 100644
index 0000000000..3b905ba4ec
--- /dev/null
+++ b/depends/packages/libxcb_util_wm.mk
@@ -0,0 +1,31 @@
+package=libxcb_util_wm
+$(package)_version=0.4.1
+$(package)_download_path=https://xcb.freedesktop.org/dist
+$(package)_file_name=xcb-util-wm-$($(package)_version).tar.bz2
+$(package)_sha256_hash=28bf8179640eaa89276d2b0f1ce4285103d136be6c98262b6151aaee1d3c2a3f
+$(package)_dependencies=libxcb
+
+define $(package)_set_vars
+$(package)_config_opts=--disable-static --disable-devel-docs --without-doxygen
+$(package)_config_opts += --disable-dependency-tracking --enable-option-checking
+endef
+
+define $(package)_preprocess_cmds
+ cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub .
+endef
+
+define $(package)_config_cmds
+ $($(package)_autoconf)
+endef
+
+define $(package)_build_cmds
+ $(MAKE)
+endef
+
+define $(package)_stage_cmds
+ $(MAKE) DESTDIR=$($(package)_staging_dir) install
+endef
+
+define $(package)_postprocess_cmds
+ rm -rf share/man share/doc lib/*.la
+endef
diff --git a/depends/packages/packages.mk b/depends/packages/packages.mk
index 9094e327ef..426fa2e748 100644
--- a/depends/packages/packages.mk
+++ b/depends/packages/packages.mk
@@ -2,7 +2,7 @@ packages:=boost libevent
qrencode_packages = qrencode
-qt_linux_packages:=qt expat libxcb xcb_proto libXau xproto freetype fontconfig libxkbcommon
+qt_linux_packages:=qt expat libxcb xcb_proto libXau xproto freetype fontconfig libxkbcommon libxcb_util libxcb_util_render libxcb_util_keysyms libxcb_util_image libxcb_util_wm
qt_android_packages=qt
qt_darwin_packages=qt
diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk
index ea110b1653..c379e74f9f 100644
--- a/depends/packages/qt.mk
+++ b/depends/packages/qt.mk
@@ -1,25 +1,24 @@
-PACKAGE=qt
-$(package)_version=5.12.11
-$(package)_download_path=https://download.qt.io/official_releases/qt/5.12/$($(package)_version)/submodules
+package=qt
+$(package)_version=5.15.2
+$(package)_download_path=https://download.qt.io/official_releases/qt/5.15/$($(package)_version)/submodules
$(package)_suffix=everywhere-src-$($(package)_version).tar.xz
$(package)_file_name=qtbase-$($(package)_suffix)
-$(package)_sha256_hash=1c1b4e33137ca77881074c140d54c3c9747e845a31338cfe8680f171f0bc3a39
-$(package)_linux_dependencies=freetype fontconfig libxcb libxkbcommon
+$(package)_sha256_hash=909fad2591ee367993a75d7e2ea50ad4db332f05e1c38dd7a5a274e156a4e0f8
+$(package)_linux_dependencies=freetype fontconfig libxcb libxkbcommon libxcb_util libxcb_util_render libxcb_util_keysyms libxcb_util_image libxcb_util_wm
$(package)_qt_libs=corelib network widgets gui plugins testlib
$(package)_linguist_tools = lrelease lupdate lconvert
$(package)_patches = qt.pro qttools_src.pro
$(package)_patches += fix_qt_pkgconfig.patch mac-qmake.conf fix_no_printer.patch no-xlib.patch
-$(package)_patches += support_new_android_ndks.patch fix_android_jni_static.patch dont_hardcode_pwd.patch
-$(package)_patches += dont_hardcode_x86_64.patch
-$(package)_patches+= fix_lib_paths.patch fix_android_pch.patch
-$(package)_patches+= qtbase-moc-ignore-gcc-macro.patch fix_limits_header.patch
-$(package)_patches+= fix_montery_include.patch
+$(package)_patches += dont_hardcode_x86_64.patch fix_montery_include.patch
+$(package)_patches += fix_android_jni_static.patch dont_hardcode_pwd.patch
+$(package)_patches += qtbase-moc-ignore-gcc-macro.patch fix_limits_header.patch
+$(package)_patches += fix_bigsur_style.patch
$(package)_qttranslations_file_name=qttranslations-$($(package)_suffix)
-$(package)_qttranslations_sha256_hash=577b0668a777eb2b451c61e8d026d79285371597ce9df06b6dee6c814164b7c3
+$(package)_qttranslations_sha256_hash=d5788e86257b21d5323f1efd94376a213e091d1e5e03b45a95dd052b5f570db8
$(package)_qttools_file_name=qttools-$($(package)_suffix)
-$(package)_qttools_sha256_hash=98b2aaca230458f65996f3534fd471d2ffd038dd58ac997c0589c06dc2385b4f
+$(package)_qttools_sha256_hash=c189d0ce1ff7c739db9a3ace52ac3e24cb8fd6dbf234e49f075249b38f43c1cc
$(package)_extra_sources = $($(package)_qttranslations_file_name)
$(package)_extra_sources += $($(package)_qttools_file_name)
@@ -30,14 +29,14 @@ $(package)_config_opts_release += -silent
$(package)_config_opts_debug = -debug
$(package)_config_opts_debug += -optimized-tools
$(package)_config_opts += -bindir $(build_prefix)/bin
-$(package)_config_opts += -c++std c++1z
+$(package)_config_opts += -c++std c++17
$(package)_config_opts += -confirm-license
$(package)_config_opts += -hostprefix $(build_prefix)
$(package)_config_opts += -no-compile-examples
$(package)_config_opts += -no-cups
$(package)_config_opts += -no-egl
$(package)_config_opts += -no-eglfs
-$(package)_config_opts += -no-freetype
+$(package)_config_opts += -no-evdev
$(package)_config_opts += -no-gif
$(package)_config_opts += -no-glib
$(package)_config_opts += -no-icu
@@ -52,6 +51,7 @@ $(package)_config_opts += -no-mtdev
$(package)_config_opts += -no-openssl
$(package)_config_opts += -no-openvg
$(package)_config_opts += -no-reduce-relocations
+$(package)_config_opts += -no-schannel
$(package)_config_opts += -no-sctp
$(package)_config_opts += -no-securetransport
$(package)_config_opts += -no-sql-db2
@@ -65,6 +65,7 @@ $(package)_config_opts += -no-sql-sqlite
$(package)_config_opts += -no-sql-sqlite2
$(package)_config_opts += -no-system-proxies
$(package)_config_opts += -no-use-gold-linker
+$(package)_config_opts += -no-zstd
$(package)_config_opts += -nomake examples
$(package)_config_opts += -nomake tests
$(package)_config_opts += -nomake tools
@@ -102,6 +103,7 @@ $(package)_config_opts += -no-feature-sqlmodel
$(package)_config_opts += -no-feature-statemachine
$(package)_config_opts += -no-feature-syntaxhighlighter
$(package)_config_opts += -no-feature-textbrowser
+$(package)_config_opts += -no-feature-textmarkdownwriter
$(package)_config_opts += -no-feature-textodfwriter
$(package)_config_opts += -no-feature-topleveldomain
$(package)_config_opts += -no-feature-udpsocket
@@ -117,6 +119,7 @@ $(package)_config_opts_darwin = -no-dbus
$(package)_config_opts_darwin += -no-opengl
$(package)_config_opts_darwin += -pch
$(package)_config_opts_darwin += -no-feature-corewlan
+$(package)_config_opts_darwin += -no-freetype
$(package)_config_opts_darwin += QMAKE_MACOSX_DEPLOYMENT_TARGET=$(OSX_MIN_VERSION)
ifneq ($(build_os),darwin)
@@ -133,7 +136,7 @@ $(package)_config_opts_aarch64_darwin += -device-option QMAKE_APPLE_DEVICE_ARCHS
$(package)_config_opts_x86_64_darwin += -device-option QMAKE_APPLE_DEVICE_ARCHS=x86_64
endif
-$(package)_config_opts_linux = -qt-xcb
+$(package)_config_opts_linux = -xcb
$(package)_config_opts_linux += -no-xcb-xlib
$(package)_config_opts_linux += -no-feature-xlib
$(package)_config_opts_linux += -system-freetype
@@ -152,6 +155,7 @@ $(package)_config_opts_s390x_linux = -platform linux-g++ -xplatform bitcoin-linu
$(package)_config_opts_mingw32 = -no-opengl
$(package)_config_opts_mingw32 += -no-dbus
+$(package)_config_opts_mingw32 += -no-freetype
$(package)_config_opts_mingw32 += -xplatform win32-g++
$(package)_config_opts_mingw32 += "QMAKE_CFLAGS = '$($(package)_cflags) $($(package)_cppflags)'"
$(package)_config_opts_mingw32 += "QMAKE_CXXFLAGS = '$($(package)_cflags) $($(package)_cppflags)'"
@@ -166,7 +170,6 @@ $(package)_config_opts_android += -android-ndk-platform android-$(ANDROID_API_LE
$(package)_config_opts_android += -device-option CROSS_COMPILE="$(host)-"
$(package)_config_opts_android += -egl
$(package)_config_opts_android += -qpa xcb
-$(package)_config_opts_android += -no-eglfs
$(package)_config_opts_android += -no-dbus
$(package)_config_opts_android += -opengl es2
$(package)_config_opts_android += -qt-freetype
@@ -227,15 +230,13 @@ define $(package)_preprocess_cmds
patch -p1 -i $($(package)_patch_dir)/dont_hardcode_pwd.patch && \
patch -p1 -i $($(package)_patch_dir)/fix_qt_pkgconfig.patch && \
patch -p1 -i $($(package)_patch_dir)/fix_no_printer.patch && \
- patch -p1 -i $($(package)_patch_dir)/support_new_android_ndks.patch && \
patch -p1 -i $($(package)_patch_dir)/fix_android_jni_static.patch && \
- patch -p1 -i $($(package)_patch_dir)/fix_android_pch.patch && \
patch -p1 -i $($(package)_patch_dir)/no-xlib.patch && \
patch -p1 -i $($(package)_patch_dir)/dont_hardcode_x86_64.patch && \
- patch -p1 -i $($(package)_patch_dir)/fix_lib_paths.patch && \
patch -p1 -i $($(package)_patch_dir)/qtbase-moc-ignore-gcc-macro.patch && \
patch -p1 -i $($(package)_patch_dir)/fix_limits_header.patch && \
patch -p1 -i $($(package)_patch_dir)/fix_montery_include.patch && \
+ patch -p1 -i $($(package)_patch_dir)/fix_bigsur_style.patch && \
mkdir -p qtbase/mkspecs/macx-clang-linux &&\
cp -f qtbase/mkspecs/macx-clang/qplatformdefs.h qtbase/mkspecs/macx-clang-linux/ &&\
cp -f $($(package)_patch_dir)/mac-qmake.conf qtbase/mkspecs/macx-clang-linux/qmake.conf && \
diff --git a/depends/packages/xcb_proto.mk b/depends/packages/xcb_proto.mk
index 01203a0718..9be822506d 100644
--- a/depends/packages/xcb_proto.mk
+++ b/depends/packages/xcb_proto.mk
@@ -1,8 +1,8 @@
package=xcb_proto
-$(package)_version=1.10
-$(package)_download_path=https://xcb.freedesktop.org/dist
-$(package)_file_name=xcb-proto-$($(package)_version).tar.bz2
-$(package)_sha256_hash=7ef40ddd855b750bc597d2a435da21e55e502a0fefa85b274f2c922800baaf05
+$(package)_version=1.14.1
+$(package)_download_path=https://xorg.freedesktop.org/archive/individual/proto
+$(package)_file_name=xcb-proto-$($(package)_version).tar.xz
+$(package)_sha256_hash=f04add9a972ac334ea11d9d7eb4fc7f8883835da3e4859c9afa971efdf57fcc3
define $(package)_config_cmds
$($(package)_autoconf)
@@ -17,6 +17,5 @@ define $(package)_stage_cmds
endef
define $(package)_postprocess_cmds
- find -name "*.pyc" -delete && \
- find -name "*.pyo" -delete
+ rm -rf lib/python*/site-packages/xcbgen/__pycache__
endef
diff --git a/depends/packages/xproto.mk b/depends/packages/xproto.mk
index 6bd867d02b..7a43c52faf 100644
--- a/depends/packages/xproto.mk
+++ b/depends/packages/xproto.mk
@@ -1,8 +1,8 @@
package=xproto
-$(package)_version=7.0.26
+$(package)_version=7.0.31
$(package)_download_path=https://xorg.freedesktop.org/releases/individual/proto
$(package)_file_name=$(package)-$($(package)_version).tar.bz2
-$(package)_sha256_hash=636162c1759805a5a0114a369dffdeccb8af8c859ef6e1445f26a4e6e046514f
+$(package)_sha256_hash=c6f9747da0bd3a95f86b17fb8dd5e717c8f3ab7f0ece3ba1b247899ec1ef7747
define $(package)_set_vars
$(package)_config_opts=--without-fop --without-xmlto --without-xsltproc --disable-specs
diff --git a/depends/patches/qt/dont_hardcode_x86_64.patch b/depends/patches/qt/dont_hardcode_x86_64.patch
index 0e1ca6acda..5c1e030fa4 100644
--- a/depends/patches/qt/dont_hardcode_x86_64.patch
+++ b/depends/patches/qt/dont_hardcode_x86_64.patch
@@ -9,14 +9,14 @@ https://codereview.qt-project.org/q/I70db7e4c27f0d3da5d0af33cb491d72c312d3fa8
--- old/qtbase/configure.json
+++ new/qtbase/configure.json
-@@ -208,11 +208,18 @@
+@@ -244,11 +244,18 @@
"testTypeDependencies": {
- "linkerSupportsFlag": [ "use_gold_linker" ],
-- "verifySpec": [ "shared", "use_gold_linker", "compiler-flags", "qmakeargs", "commit" ],
+ "linkerSupportsFlag": [ "use_bfd_linker", "use_gold_linker", "use_lld_linker" ],
+- "verifySpec": [ "shared", "use_bfd_linker", "use_gold_linker", "use_lld_linker", "compiler-flags", "qmakeargs", "commit" ],
+ "verifySpec": [
+ "shared",
-+ "use_gold_linker",
++ "use_bfd_linker", "use_gold_linker", "use_lld_linker",
+ "compiler-flags", "qmakeargs",
+ "simulator_and_device",
+ "thread",
@@ -30,7 +30,7 @@ https://codereview.qt-project.org/q/I70db7e4c27f0d3da5d0af33cb491d72c312d3fa8
},
"testTypeAliases": {
-@@ -653,7 +660,7 @@
+@@ -762,7 +769,7 @@
},
"architecture": {
"label": "Architecture",
@@ -40,11 +40,10 @@ https://codereview.qt-project.org/q/I70db7e4c27f0d3da5d0af33cb491d72c312d3fa8
"pkg-config": {
"label": "Using pkg-config",
diff --git a/configure.pri b/configure.pri
-index 33c90a8c2f..71767e29d6 100644
-
+index 49755f7abfd..8be9b10d7d4 100644
--- old/qtbase/configure.pri
+++ new/qtbase/configure.pri
-@@ -642,6 +642,13 @@ defineTest(qtConfOutput_commitOptions) {
+@@ -662,6 +662,13 @@ defineTest(qtConfOutput_commitOptions) {
write_file($$QT_BUILD_TREE/mkspecs/qdevice.pri, $${currentConfig}.output.devicePro)|error()
}
@@ -59,24 +58,22 @@ index 33c90a8c2f..71767e29d6 100644
defineTest(processQtPath) {
out_var = config.rel_input.$${2}
diff --git a/mkspecs/common/macx.conf b/mkspecs/common/macx.conf
-index 7d4a406134..de96c12fc9 100644
-
+index d16b77acb8e..4ba0a8eaa36 100644
--- old/qtbase/mkspecs/common/macx.conf
+++ new/qtbase/mkspecs/common/macx.conf
@@ -6,7 +6,6 @@ QMAKE_PLATFORM += macos osx macx
QMAKE_MAC_SDK = macosx
- QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.12
+ QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.13
-QMAKE_APPLE_DEVICE_ARCHS = x86_64
- QT_MAC_SDK_VERSION_MIN = 10.13
- QT_MAC_SDK_VERSION_MAX = 11.0
+ # Should be 10.15, but as long as the CI builds with
+ # older SDKs we have to keep this.
diff --git a/mkspecs/features/mac/default_post.prf b/mkspecs/features/mac/default_post.prf
-index d052808c14..0a89effe87 100644
-
+index 92a9112bca6..d888731ec8d 100644
--- old/qtbase/mkspecs/features/mac/default_post.prf
+++ new/qtbase/mkspecs/features/mac/default_post.prf
-@@ -89,6 +89,11 @@ app_extension_api_only {
+@@ -90,6 +90,11 @@ app_extension_api_only {
QMAKE_LFLAGS += $$QMAKE_CFLAGS_APPLICATION_EXTENSION
}
@@ -88,7 +85,7 @@ index d052808c14..0a89effe87 100644
macx-xcode {
qmake_pkginfo_typeinfo.name = QMAKE_PKGINFO_TYPEINFO
!isEmpty(QMAKE_PKGINFO_TYPEINFO): \
-@@ -144,9 +149,6 @@ macx-xcode {
+@@ -145,9 +150,6 @@ macx-xcode {
simulator: VALID_SIMULATOR_ARCHS = $$QMAKE_APPLE_SIMULATOR_ARCHS
VALID_ARCHS = $$VALID_DEVICE_ARCHS $$VALID_SIMULATOR_ARCHS
@@ -99,8 +96,7 @@ index d052808c14..0a89effe87 100644
ACTIVE_ARCHS = $(filter $(EXPORT_VALID_ARCHS), $(ARCHS))
diff --git a/mkspecs/features/toolchain.prf b/mkspecs/features/toolchain.prf
-index 5003679bd0..c7c080cb07 100644
-
+index efbe7c1e55b..8add6dc8043 100644
--- old/qtbase/mkspecs/features/toolchain.prf
+++ new/qtbase/mkspecs/features/toolchain.prf
@@ -182,9 +182,14 @@ isEmpty($${target_prefix}.INCDIRS) {
diff --git a/depends/patches/qt/fix_android_jni_static.patch b/depends/patches/qt/fix_android_jni_static.patch
index a186aeb8f6..bb64661761 100644
--- a/depends/patches/qt/fix_android_jni_static.patch
+++ b/depends/patches/qt/fix_android_jni_static.patch
@@ -1,6 +1,6 @@
--- old/qtbase/src/plugins/platforms/android/androidjnimain.cpp
+++ new/qtbase/src/plugins/platforms/android/androidjnimain.cpp
-@@ -898,6 +898,14 @@
+@@ -914,6 +914,14 @@ Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void */*reserved*/)
__android_log_print(ANDROID_LOG_FATAL, "Qt", "registerNatives failed");
return -1;
}
diff --git a/depends/patches/qt/fix_android_pch.patch b/depends/patches/qt/fix_android_pch.patch
deleted file mode 100644
index 195e1c5e59..0000000000
--- a/depends/patches/qt/fix_android_pch.patch
+++ /dev/null
@@ -1,10 +0,0 @@
---- old/qtbase/mkspecs/common/android-base-head.conf
-+++ new/qtbase/mkspecs/common/android-base-head.conf
-@@ -72,6 +72,6 @@ CROSS_COMPILE = $$NDK_TOOLCHAIN_PATH/bin/$$NDK_TOOLS_PREFIX-
- QMAKE_PCH_OUTPUT_EXT = .gch
-
- QMAKE_CFLAGS_PRECOMPILE = -x c-header -c ${QMAKE_PCH_INPUT} -o ${QMAKE_PCH_OUTPUT}
--QMAKE_CFLAGS_USE_PRECOMPILE = -include ${QMAKE_PCH_OUTPUT_BASE}
-+QMAKE_CFLAGS_USE_PRECOMPILE = -include-pch ${QMAKE_PCH_OUTPUT}
- QMAKE_CXXFLAGS_PRECOMPILE = -x c++-header -c ${QMAKE_PCH_INPUT} -o ${QMAKE_PCH_OUTPUT}
- QMAKE_CXXFLAGS_USE_PRECOMPILE = $$QMAKE_CFLAGS_USE_PRECOMPILE
diff --git a/depends/patches/qt/fix_bigsur_style.patch b/depends/patches/qt/fix_bigsur_style.patch
new file mode 100644
index 0000000000..0f6c848bb0
--- /dev/null
+++ b/depends/patches/qt/fix_bigsur_style.patch
@@ -0,0 +1,90 @@
+Fix rendering in macOS BigSur
+
+See: https://bugreports.qt.io/browse/QTBUG-86513.
+
+Upstream commits (combined in this patch):
+ - Qt 6.0: 40fb97e97f550b8afd13ecc3a038d9d0c2d82bbb
+ - Qt 6.0: 3857f104cac127f62e64e55a20613f0ac2e6b843
+ - Qt 6.1: abee4cdd5925a8513f51784754fca8fa35031732
+
+--- old/qtbase/src/plugins/styles/mac/qmacstyle_mac.mm
++++ new/qtbase/src/plugins/styles/mac/qmacstyle_mac.mm
+@@ -3870,6 +3870,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
+ const auto cs = d->effectiveAquaSizeConstrain(opt, w);
+ // Extra hacks to get the proper pressed appreance when not selected or selected and inactive
+ const bool needsInactiveHack = (!isActive && isSelected);
++ const bool isBigSurOrAbove = QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSBigSur;
+ const auto ct = !needsInactiveHack && (isSelected || tp == QStyleOptionTab::OnlyOneTab) ?
+ QMacStylePrivate::Button_PushButton :
+ QMacStylePrivate::Button_PopupButton;
+@@ -3878,6 +3879,12 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
+ auto *pb = static_cast<NSButton *>(d->cocoaControl(cw));
+
+ auto vOffset = isPopupButton ? 1 : 2;
++ if (isBigSurOrAbove) {
++ // Make it 1, otherwise, offset is very visible compared
++ // to selected tab (which is not a popup button).
++ vOffset = 1;
++ }
++
+ if (tabDirection == QMacStylePrivate::East)
+ vOffset -= 1;
+ const auto outerAdjust = isPopupButton ? 1 : 4;
+@@ -3894,9 +3901,22 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
+ frameRect = frameRect.adjusted(-innerAdjust, 0, outerAdjust, 0);
+ else
+ frameRect = frameRect.adjusted(-outerAdjust, 0, innerAdjust, 0);
++
++ if (isSelected && isBigSurOrAbove) {
++ // 1 pixed of 'roundness' is still visible on the right
++ // (the left is OK, it's rounded).
++ frameRect = frameRect.adjusted(0, 0, 1, 0);
++ }
++
+ break;
+ case QStyleOptionTab::Middle:
+ frameRect = frameRect.adjusted(-innerAdjust, 0, innerAdjust, 0);
++
++ if (isSelected && isBigSurOrAbove) {
++ // 1 pixel of 'roundness' is still visible on both
++ // sides - left and right.
++ frameRect = frameRect.adjusted(-1, 0, 1, 0);
++ }
+ break;
+ case QStyleOptionTab::End:
+ // Pressed state hack: tweak adjustments in preparation for flip below
+@@ -3904,6 +3924,11 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
+ frameRect = frameRect.adjusted(-innerAdjust, 0, outerAdjust, 0);
+ else
+ frameRect = frameRect.adjusted(-outerAdjust, 0, innerAdjust, 0);
++
++ if (isSelected && isBigSurOrAbove) {
++ // 1 pixel of 'roundness' is still visible on the left.
++ frameRect = frameRect.adjusted(-1, 0, 0, 0);
++ }
+ break;
+ case QStyleOptionTab::OnlyOneTab:
+ frameRect = frameRect.adjusted(-outerAdjust, 0, outerAdjust, 0);
+@@ -3951,7 +3976,10 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
+ NSPopUpArrowPosition oldPosition = NSPopUpArrowAtCenter;
+ NSPopUpButtonCell *pbCell = nil;
+ auto rAdjusted = r;
+- if (isPopupButton && tp == QStyleOptionTab::OnlyOneTab) {
++ if (isPopupButton && (tp == QStyleOptionTab::OnlyOneTab || isBigSurOrAbove)) {
++ // Note: starting from macOS BigSur NSPopupButton has this
++ // arrow 'button' in a different place and it became
++ // quite visible 'in between' inactive tabs.
+ pbCell = static_cast<NSPopUpButtonCell *>(pb.cell);
+ oldPosition = pbCell.arrowPosition;
+ pbCell.arrowPosition = NSPopUpNoArrow;
+@@ -3959,6 +3987,10 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
+ // NSPopUpButton in this state is smaller.
+ rAdjusted.origin.x -= 3;
+ rAdjusted.size.width += 6;
++ if (isBigSurOrAbove) {
++ if (tp == QStyleOptionTab::End)
++ rAdjusted.origin.x -= 2;
++ }
+ }
+ }
+
diff --git a/depends/patches/qt/fix_lib_paths.patch b/depends/patches/qt/fix_lib_paths.patch
deleted file mode 100644
index d1a15373f4..0000000000
--- a/depends/patches/qt/fix_lib_paths.patch
+++ /dev/null
@@ -1,193 +0,0 @@
---- old/qtbase/mkspecs/common/mac.conf
-+++ new/qtbase/mkspecs/common/mac.conf
-@@ -14,7 +14,6 @@
-
- QMAKE_RESOURCE = /Developer/Tools/Rez
- QMAKE_EXTENSION_SHLIB = dylib
--QMAKE_EXTENSIONS_AUX_SHLIB = tbd
- QMAKE_LIBDIR =
-
- # sdk.prf will prefix the proper SDK sysroot
-
---- old/qtbase/mkspecs/features/qmake_use.prf
-+++ new/qtbase/mkspecs/features/qmake_use.prf
-@@ -22,6 +22,8 @@
- !defined(QMAKE_LIBS_$$nu, var): \
- error("Library '$$lower($$replace(nu, _, -))' is not defined.")
-
-+ QMAKE_LIBDIR += $$eval(QMAKE_LIBDIR_$$nu)
-+
- debug: \
- LIBS$${suffix} += $$eval(QMAKE_LIBS_$${nu}_DEBUG) $$eval(QMAKE_LIBS_$$nu)
- else: \
-
---- old/qtbase/mkspecs/features/qt_configure.prf
-+++ new/qtbase/mkspecs/features/qt_configure.prf
-@@ -526,98 +526,23 @@
- return($$sysrootified)
- }
-
--# libs-var, libs, in-paths, out-paths-var
-+# libs-var, libs, in-paths
- defineTest(qtConfResolveLibs) {
-- ret = true
-- paths = $$3
-- out =
-- copy = false
-- for (l, 2) {
-- $$copy {
-- copy = false
-- out += $$l
-- } else: equals(l, "-s") {
-- # em++ flag to link libraries from emscripten-ports; passed on literally.
-- copy = true
-- out += $$l
-- } else: contains(l, "^-L.*") {
-- lp = $$replace(l, "^-L", )
-- gcc: lp = $$qtGccSysrootifiedPath($$lp)
-- !exists($$lp/.) {
-- qtLog("Library path $$val_escape(lp) is invalid.")
-- ret = false
-- } else {
-- paths += $$lp
-- }
-- } else: contains(l, "^-l.*") {
-- lib = $$replace(l, "^-l", )
-- lcan =
-- integrity:contains(lib, "^.*\\.a") {
-- # INTEGRITY compiler searches for exact filename
-- # if -l argument has .a suffix
-- lcan += $${lib}
-- } else: contains(lib, "^:.*") {
-- # Use exact filename when -l:filename syntax is used.
-- lib ~= s/^://
-- lcan += $${lib}
-- } else: unix {
-- # Under UNIX, we look for actual shared libraries, in addition
-- # to static ones.
-- shexts = $$QMAKE_EXTENSION_SHLIB $$QMAKE_EXTENSIONS_AUX_SHLIB
-- for (ext, shexts) {
-- lcan += $${QMAKE_PREFIX_SHLIB}$${lib}.$${ext}
-- }
-- lcan += \
-- $${QMAKE_PREFIX_STATICLIB}$${lib}.$${QMAKE_EXTENSION_STATICLIB}
-- } else {
-- # Under Windows, we look only for static libraries, as even for DLLs
-- # one actually links against a static import library.
-- mingw {
-- lcan += \
-- # MinGW supports UNIX-style library naming in addition to
-- # the MSVC style.
-- lib$${lib}.dll.a lib$${lib}.a \
-- # Fun fact: prefix-less libraries are also supported.
-- $${lib}.dll.a $${lib}.a
-- }
-- lcan += $${lib}.lib
-- }
-- l = $$qtConfFindInPathList($$lcan, $$paths $$EXTRA_LIBDIR $$QMAKE_DEFAULT_LIBDIRS)
-- isEmpty(l) {
-- qtLog("None of [$$val_escape(lcan)] found in [$$val_escape(paths)] and global paths.")
-- ret = false
-- } else {
-- out += $$l
-- }
-- } else {
-- out += $$l
-- }
-- }
-- $$1 = $$out
-+ for (path, 3): \
-+ pre_lflags += -L$$path
-+ $$1 = $$pre_lflags $$2
- export($$1)
-- !isEmpty(4) {
-- $$4 = $$paths
-- export($$4)
-- }
-- return($$ret)
--}
--
--# source-var
--defineTest(qtConfResolveAllLibs) {
-- ret = true
-- !qtConfResolveLibs($${1}.libs, $$eval($${1}.libs), , $${1}.libdirs): \
-- ret = false
-- for (b, $${1}.builds._KEYS_): \
-- !qtConfResolveLibs($${1}.builds.$${b}, $$eval($${1}.builds.$${b}), $$eval($${1}.libdirs), ): \
-- ret = false
-- return($$ret)
-+ return(true)
- }
-
- # libs-var, in-paths, libs
- defineTest(qtConfResolvePathLibs) {
- ret = true
-- gcc: 2 = $$qtGccSysrootifiedPaths($$2)
-- for (libdir, 2) {
-+ gcc: \
-+ local_paths = $$qtGccSysrootifiedPaths($$2)
-+ else: \
-+ local_paths = $$2
-+ for (libdir, local_paths) {
- !exists($$libdir/.) {
- qtLog("Library path $$val_escape(libdir) is invalid.")
- ret = false
-@@ -667,8 +592,11 @@
- # includes-var, in-paths, test-object-var
- defineTest(qtConfResolvePathIncs) {
- ret = true
-- gcc: 2 = $$qtGccSysrootifiedPaths($$2)
-- for (incdir, 2) {
-+ gcc: \
-+ local_paths = $$qtGccSysrootifiedPaths($$2)
-+ else: \
-+ local_paths = $$2
-+ for (incdir, local_paths) {
- !exists($$incdir/.) {
- qtLog("Include path $$val_escape(incdir) is invalid.")
- ret = false
-@@ -727,6 +655,7 @@
- vars += $$eval(config.commandline.rev_assignments.$${iv})
- defined(config.input.$${iv}, var) {
- eval($${1}.builds.$${b} = $$eval(config.input.$${iv}))
-+ export($${1}.builds.$${b})
- $${1}.builds._KEYS_ *= $${b}
- any = true
- } else {
-@@ -741,11 +670,14 @@
- export($${1}.builds._KEYS_)
- # we also reset the generic libs, to avoid surprises.
- $${1}.libs =
-+ export($${1}.libs)
- }
-
- # direct libs. overwrites inline libs.
-- defined(config.input.$${input}.libs, var): \
-+ defined(config.input.$${input}.libs, var) {
- eval($${1}.libs = $$eval(config.input.$${input}.libs))
-+ export($${1}.libs)
-+ }
-
- includes = $$eval(config.input.$${input}.incdir)
-
-@@ -754,6 +686,7 @@
- !isEmpty(prefix) {
- includes += $$prefix/include
- $${1}.libs = -L$$prefix/lib $$eval($${1}.libs)
-+ export($${1}.libs)
- }
-
- libdir = $$eval(config.input.$${input}.libdir)
-@@ -762,11 +695,9 @@
- for (ld, libdir): \
- libs += -L$$ld
- $${1}.libs = $$libs $$eval($${1}.libs)
-+ export($${1}.libs)
- }
-
-- !qtConfResolveAllLibs($$1): \
-- return(false)
--
- !qtConfResolvePathIncs($${1}.includedir, $$includes, $$2): \
- return(false)
-
diff --git a/depends/patches/qt/fix_limits_header.patch b/depends/patches/qt/fix_limits_header.patch
index e4313770e5..cb5a8cd1b5 100644
--- a/depends/patches/qt/fix_limits_header.patch
+++ b/depends/patches/qt/fix_limits_header.patch
@@ -19,17 +19,16 @@ Upstream commits:
#include <stdlib.h>
#include <string.h>
---- old/qtbase/src/corelib/tools/qbytearraymatcher.h
-+++ new/qtbase/src/corelib/tools/qbytearraymatcher.h
-@@ -42,6 +42,8 @@
-
- #include <QtCore/qbytearray.h>
+--- old/qtbase/src/corelib/global/qfloat16.h
++++ new/qtbase/src/corelib/global/qfloat16.h
+@@ -43,6 +43,7 @@
+ #include <QtCore/qglobal.h>
+ #include <QtCore/qmetatype.h>
+#include <limits>
-+
- QT_BEGIN_NAMESPACE
-
+ #include <string.h>
+ #if defined(QT_COMPILER_SUPPORTS_F16C) && defined(__AVX2__) && !defined(__F16C__)
--- old/qtbase/src/tools/moc/generator.cpp
+++ new/qtbase/src/tools/moc/generator.cpp
@@ -42,3 +41,24 @@ Upstream commits:
#include <math.h>
#include <stdio.h>
+--- old/qtbase/src/corelib/text/qbytearraymatcher.h
++++ new/qtbase/src/corelib/text/qbytearraymatcher.h
+@@ -42,6 +42,8 @@
+
+ #include <QtCore/qbytearray.h>
+
++#include <limits>
++
+ QT_BEGIN_NAMESPACE
+
+
+--- old/qtbase/src/corelib/tools/qoffsetstringarray_p.h
++++ new/qtbase/src/corelib/tools/qoffsetstringarray_p.h
+@@ -55,6 +55,7 @@
+
+ #include <tuple>
+ #include <array>
++#include <limits>
+
+ QT_BEGIN_NAMESPACE
+
diff --git a/depends/patches/qt/fix_qt_pkgconfig.patch b/depends/patches/qt/fix_qt_pkgconfig.patch
index a5de2b4b9e..73f4d89f73 100644
--- a/depends/patches/qt/fix_qt_pkgconfig.patch
+++ b/depends/patches/qt/fix_qt_pkgconfig.patch
@@ -4,20 +4,8 @@
load(qt_targets)
# this builds on top of qt_common
--!internal_module:if(unix|mingw) {
+-!internal_module:if(unix|mingw):!if(darwin:debug_and_release:CONFIG(debug, debug|release)) {
+if(unix|mingw):!if(darwin:debug_and_release:CONFIG(debug, debug|release)) {
CONFIG += create_pc
QMAKE_PKGCONFIG_DESTDIR = pkgconfig
host_build: \
-@@ -284,9 +284,9 @@ load(qt_targets)
- QMAKE_PKGCONFIG_CFLAGS = -D$$MODULE_DEFINE -I${includedir}/$$MODULE_INCNAME
- }
- QMAKE_PKGCONFIG_NAME = $$replace(TARGET, ^Qt, "Qt$$QT_MAJOR_VERSION ")
-- QMAKE_PKGCONFIG_FILE = $$replace(TARGET, ^Qt, Qt$$QT_MAJOR_VERSION)
-+ QMAKE_PKGCONFIG_FILE = $$replace(TARGET, ^Qt, Qt$$QT_MAJOR_VERSION)$$qtPlatformTargetSuffix()
- for(i, MODULE_DEPENDS): \
-- QMAKE_PKGCONFIG_REQUIRES += $$replace(QT.$${i}.name, ^Qt, Qt$$section(QT.$${i}.VERSION, ., 0, 0))
-+ QMAKE_PKGCONFIG_REQUIRES += $$replace(QT.$${i}.name, ^Qt, Qt$$section(QT.$${i}.VERSION, ., 0, 0))$$qtPlatformTargetSuffix()
- isEmpty(QMAKE_PKGCONFIG_DESCRIPTION): \
- QMAKE_PKGCONFIG_DESCRIPTION = $$replace(TARGET, ^Qt, "Qt ") module
- !isEmpty(lib_replace0.match) {
diff --git a/depends/patches/qt/no-xlib.patch b/depends/patches/qt/no-xlib.patch
index f4a6f09ee4..d6846aaca2 100644
--- a/depends/patches/qt/no-xlib.patch
+++ b/depends/patches/qt/no-xlib.patch
@@ -22,7 +22,7 @@ index 7c62c2e2b3..c05c6c0a07 100644
#include <xcb/xfixes.h>
#include <xcb/xcb_image.h>
-@@ -391,6 +393,7 @@ void QXcbCursor::changeCursor(QCursor *cursor, QWindow *window)
+@@ -391,6 +391,7 @@ void QXcbCursor::changeCursor(QCursor *cursor, QWindow *window)
xcb_flush(xcb_connection());
}
@@ -30,7 +30,7 @@ index 7c62c2e2b3..c05c6c0a07 100644
static int cursorIdForShape(int cshape)
{
int cursorId = 0;
-@@ -444,6 +447,7 @@ static int cursorIdForShape(int cshape)
+@@ -444,6 +445,7 @@ static int cursorIdForShape(int cshape)
}
return cursorId;
}
@@ -38,7 +38,7 @@ index 7c62c2e2b3..c05c6c0a07 100644
xcb_cursor_t QXcbCursor::createNonStandardCursor(int cshape)
{
-@@ -556,7 +560,9 @@ static xcb_cursor_t loadCursor(void *dpy, int cshape)
+@@ -556,7 +558,9 @@ static xcb_cursor_t loadCursor(void *dpy, int cshape)
xcb_cursor_t QXcbCursor::createFontCursor(int cshape)
{
xcb_connection_t *conn = xcb_connection();
@@ -48,16 +48,15 @@ index 7c62c2e2b3..c05c6c0a07 100644
xcb_cursor_t cursor = XCB_NONE;
// Try Xcursor first
-@@ -585,7 +591,7 @@ xcb_cursor_t QXcbCursor::createFontCursor(int cshape)
-
+@@ -586,6 +590,7 @@ xcb_cursor_t QXcbCursor::createFontCursor(int cshape)
// Non-standard X11 cursors are created from bitmaps
cursor = createNonStandardCursor(cshape);
--
+
+#if QT_CONFIG(xcb_xlib) && QT_CONFIG(library)
// Create a glpyh cursor if everything else failed
if (!cursor && cursorId) {
cursor = xcb_generate_id(conn);
-@@ -593,6 +599,7 @@ xcb_cursor_t QXcbCursor::createFontCursor(int cshape)
+@@ -593,6 +598,7 @@ xcb_cursor_t QXcbCursor::createFontCursor(int cshape)
cursorId, cursorId + 1,
0xFFFF, 0xFFFF, 0xFFFF, 0, 0, 0);
}
diff --git a/depends/patches/qt/qtbase-moc-ignore-gcc-macro.patch b/depends/patches/qt/qtbase-moc-ignore-gcc-macro.patch
index 0358bea6e9..f0c14a9400 100644
--- a/depends/patches/qt/qtbase-moc-ignore-gcc-macro.patch
+++ b/depends/patches/qt/qtbase-moc-ignore-gcc-macro.patch
@@ -7,7 +7,7 @@ Upstream report: https://bugreports.qt.io/browse/QTBUG-83160
diff --git a/qtbase/src/tools/moc/main.cpp b/qtbase/src/tools/moc/main.cpp
--- a/qtbase/src/tools/moc/main.cpp
+++ b/qtbase/src/tools/moc/main.cpp
-@@ -188,6 +188,7 @@ int runMoc(int argc, char **argv)
+@@ -238,6 +238,7 @@ int runMoc(int argc, char **argv)
dummyVariadicFunctionMacro.arguments += Symbol(0, PP_IDENTIFIER, "__VA_ARGS__");
pp.macros["__attribute__"] = dummyVariadicFunctionMacro;
pp.macros["__declspec"] = dummyVariadicFunctionMacro;
diff --git a/depends/patches/qt/support_new_android_ndks.patch b/depends/patches/qt/support_new_android_ndks.patch
deleted file mode 100644
index 85c8ae2132..0000000000
--- a/depends/patches/qt/support_new_android_ndks.patch
+++ /dev/null
@@ -1,122 +0,0 @@
-Follow Google's BuildSystemMaintainers doc to support future NDK releases.
-
-Upstream commit:
- - Qt 5.14: 9b14950ff600a4ce5a8698b67ab38907c50417f1
-
---- old/qtbase/mkspecs/android-clang/qmake.conf
-+++ new/qtbase/mkspecs/android-clang/qmake.conf
-@@ -14,43 +14,29 @@
- QMAKE_CC = $$NDK_LLVM_PATH/bin/clang
- QMAKE_CXX = $$NDK_LLVM_PATH/bin/clang++
-
-+# Follow https://android.googlesource.com/platform/ndk/+/ndk-release-r20/docs/BuildSystemMaintainers.md
-+
- equals(ANDROID_TARGET_ARCH, armeabi-v7a): \
-- QMAKE_CFLAGS += -target armv7-none-linux-androideabi
--else: equals(ANDROID_TARGET_ARCH, armeabi): \
-- QMAKE_CFLAGS += -target armv5te-none-linux-androideabi
-+ QMAKE_CFLAGS = -target armv7a-linux-androideabi$$replace(ANDROID_PLATFORM, "android-", "")
- else: equals(ANDROID_TARGET_ARCH, arm64-v8a): \
-- QMAKE_CFLAGS += -target aarch64-none-linux-android
-+ QMAKE_CFLAGS = -target aarch64-linux-android$$replace(ANDROID_PLATFORM, "android-", "")
- else: equals(ANDROID_TARGET_ARCH, x86): \
-- QMAKE_CFLAGS += -target i686-none-linux-android -mstackrealign
-+ QMAKE_CFLAGS = -target i686-linux-android$$replace(ANDROID_PLATFORM, "android-", "") -mstackrealign
- else: equals(ANDROID_TARGET_ARCH, x86_64): \
-- QMAKE_CFLAGS += -target x86_64-none-linux-android
--else: equals(ANDROID_TARGET_ARCH, mips): \
-- QMAKE_CFLAGS += -target mipsel-none-linux-android
--else: equals(ANDROID_TARGET_ARCH, mips64): \
-- QMAKE_CFLAGS += -target mips64el-none-linux-android
--
--QMAKE_CFLAGS += -gcc-toolchain $$NDK_TOOLCHAIN_PATH -fno-limit-debug-info
--
--QMAKE_LINK = $$QMAKE_CXX $$QMAKE_CFLAGS -Wl,--exclude-libs,libgcc.a -Wl,--exclude-libs,libatomic.a -nostdlib++
--equals(ANDROID_TARGET_ARCH, armeabi-v7a): QMAKE_LINK += -Wl,--exclude-libs,libunwind.a
--
--QMAKE_CFLAGS += -DANDROID_HAS_WSTRING --sysroot=$$NDK_ROOT/sysroot \
-- -isystem $$NDK_ROOT/sysroot/usr/include/$$NDK_TOOLS_PREFIX \
-- -isystem $$NDK_ROOT/sources/cxx-stl/llvm-libc++/include \
-- -isystem $$NDK_ROOT/sources/android/support/include \
-- -isystem $$NDK_ROOT/sources/cxx-stl/llvm-libc++abi/include
-+ QMAKE_CFLAGS = -target x86_64-linux-android$$replace(ANDROID_PLATFORM, "android-", "")
-
--ANDROID_SOURCES_CXX_STL_LIBDIR = $$NDK_ROOT/sources/cxx-stl/llvm-libc++/libs/$$ANDROID_TARGET_ARCH
-+QMAKE_CFLAGS += -fno-limit-debug-info
-
--ANDROID_STDCPP_PATH = $$ANDROID_SOURCES_CXX_STL_LIBDIR/libc++_shared.so
-+QMAKE_LINK = $$QMAKE_CXX $$QMAKE_CFLAGS
-
--ANDROID_USE_LLVM = true
-+ANDROID_STDCPP_PATH = $$NDK_LLVM_PATH/sysroot/usr/lib/$$NDK_TOOLS_PREFIX/libc++_shared.so
-
--exists($$ANDROID_SOURCES_CXX_STL_LIBDIR/libc++.so): \
-- ANDROID_CXX_STL_LIBS = -lc++
--else: \
-- ANDROID_CXX_STL_LIBS = $$ANDROID_SOURCES_CXX_STL_LIBDIR/libc++.so.$$replace(ANDROID_PLATFORM, "android-", "")
-+ANDROID_USE_LLVM = true
-
--QMAKE_CFLAGS_OPTIMIZE_SIZE = -Oz
-+QMAKE_CFLAGS_OPTIMIZE_SIZE = -Oz
-+QMAKE_LIBDIR_POST =
-+QMAKE_LFLAGS =
-+QMAKE_LIBS_PRIVATE =
-+ANDROID_CXX_STL_LIBS =
-
- include(../common/android-base-tail.conf)
-
---- old/qtbase/mkspecs/common/android-base-head.conf
-+++ new/qtbase/mkspecs/common/android-base-head.conf
-@@ -64,7 +58,6 @@
- }
-
- CONFIG += $$ANDROID_PLATFORM
--QMAKE_CFLAGS = -D__ANDROID_API__=$$replace(ANDROID_PLATFORM, "android-", "")
-
- ANDROID_PLATFORM_ROOT_PATH = $$NDK_ROOT/platforms/$$ANDROID_PLATFORM/arch-$$ANDROID_ARCHITECTURE/
-
---- old/qtbase/mkspecs/common/android-base-tail.conf
-+++ new/qtbase/mkspecs/common/android-base-tail.conf
-@@ -6,22 +6,17 @@
- QMAKE_CFLAGS += -fstack-protector-strong -DANDROID
-
- equals(ANDROID_TARGET_ARCH, armeabi-v7a): \
-- QMAKE_CFLAGS += -march=armv7-a -mfloat-abi=softfp -mfpu=vfp -fno-builtin-memmove
-+ QMAKE_CFLAGS += -march=armv7-a -mfloat-abi=softfp -mfpu=vfp
- else: equals(ANDROID_TARGET_ARCH, armeabi): \
-- QMAKE_CFLAGS += -march=armv5te -mtune=xscale -msoft-float -fno-builtin-memmove
--# -fno-builtin-memmove is used to workaround https://code.google.com/p/android/issues/detail?id=81692
-+ QMAKE_CFLAGS += -march=armv5te -mtune=xscale -msoft-float
-
- QMAKE_CFLAGS_WARN_ON = -Wall -W
- QMAKE_CFLAGS_WARN_OFF =
- equals(ANDROID_TARGET_ARCH, armeabi-v7a) | equals(ANDROID_TARGET_ARCH, armeabi) {
- CONFIG += optimize_size
- QMAKE_CFLAGS_DEBUG = -g -marm -O0
-- equals(ANDROID_TARGET_ARCH, armeabi):if(equals(NDK_TOOLCHAIN_VERSION, 4.8)|equals(NDK_TOOLCHAIN_VERSION, 4.9)) {
-- DEFINES += QT_OS_ANDROID_GCC_48_WORKAROUND
-- } else {
-- QMAKE_CFLAGS_RELEASE += -mthumb
-- QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO += -mthumb
-- }
-+ QMAKE_CFLAGS_RELEASE += -mthumb
-+ QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO += -mthumb
- }
-
- QMAKE_CFLAGS_SHLIB = -fPIC
-@@ -61,15 +56,12 @@
- QMAKE_RANLIB = $${CROSS_COMPILE}ranlib
-
- QMAKE_INCDIR_POST =
--QMAKE_LIBDIR_POST = $$ANDROID_SOURCES_CXX_STL_LIBDIR
- QMAKE_INCDIR_X11 =
- QMAKE_LIBDIR_X11 =
- QMAKE_INCDIR_OPENGL =
- QMAKE_LIBDIR_OPENGL =
-
- QMAKE_LINK_SHLIB = $$QMAKE_LINK
--QMAKE_LFLAGS = --sysroot=$$ANDROID_PLATFORM_ROOT_PATH
--equals(ANDROID_TARGET_ARCH, x86_64) QMAKE_LFLAGS += -L$$ANDROID_PLATFORM_ROOT_PATH/usr/lib64
- QMAKE_LFLAGS_APP = -Wl,--no-undefined -Wl,-z,noexecstack -shared
- QMAKE_LFLAGS_SHLIB = -Wl,--no-undefined -Wl,-z,noexecstack -shared
- QMAKE_LFLAGS_PLUGIN = $$QMAKE_LFLAGS_SHLIB
diff --git a/doc/dependencies.md b/doc/dependencies.md
index 6ccb53f6b3..f2b6760ac2 100644
--- a/doc/dependencies.md
+++ b/doc/dependencies.md
@@ -8,9 +8,8 @@ These are the dependencies currently used by Bitcoin Core. You can find instruct
| Berkeley DB | [4.8.30](https://www.oracle.com/technetwork/database/database-technologies/berkeleydb/downloads/index.html) | 4.8.x | No | | |
| Boost | [1.71.0](https://www.boost.org/users/download/) | [1.64.0](https://github.com/bitcoin/bitcoin/pull/22320) | No | | |
| Clang<sup>[ \* ](#note1)</sup> | | [7.0](https://releases.llvm.org/download.html) (C++17 & std::filesystem support) | | | |
-| Expat | [2.2.7](https://libexpat.github.io/) | | No | Yes | |
| fontconfig | [2.12.1](https://www.freedesktop.org/software/fontconfig/release/) | | No | Yes | |
-| FreeType | [2.7.1](https://download.savannah.gnu.org/releases/freetype) | | No | | [Yes](https://github.com/bitcoin/bitcoin/blob/master/depends/packages/qt.mk) (Android only) |
+| FreeType | [2.11.0](https://download.savannah.gnu.org/releases/freetype) | | No | | [Yes](https://github.com/bitcoin/bitcoin/blob/master/depends/packages/qt.mk) (Android only) |
| GCC | | [8.1](https://gcc.gnu.org/) (C++17 & std::filesystem support) | | | |
| glibc | | [2.18](https://www.gnu.org/software/libc/) | | | | |
| HarfBuzz-NG | | | | | [Yes](https://github.com/bitcoin/bitcoin/blob/master/depends/packages/qt.mk) |
diff --git a/src/Makefile.am b/src/Makefile.am
index 4a60ce8b90..72f548c192 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -410,9 +410,10 @@ libbitcoin_wallet_a_SOURCES = \
wallet/interfaces.cpp \
wallet/load.cpp \
wallet/receive.cpp \
+ wallet/rpc/backup.cpp \
+ wallet/rpc/encrypt.cpp \
wallet/rpc/signmessage.cpp \
wallet/rpc/util.cpp \
- wallet/rpcdump.cpp \
wallet/rpcwallet.cpp \
wallet/scriptpubkeyman.cpp \
wallet/spend.cpp \
diff --git a/src/base58.cpp b/src/base58.cpp
index fb04673c5c..b122e0055e 100644
--- a/src/base58.cpp
+++ b/src/base58.cpp
@@ -149,7 +149,7 @@ std::string EncodeBase58Check(Span<const unsigned char> input)
return false;
}
// re-calculate the checksum, ensure it matches the included 4-byte checksum
- uint256 hash = Hash(MakeSpan(vchRet).first(vchRet.size() - 4));
+ uint256 hash = Hash(Span{vchRet}.first(vchRet.size() - 4));
if (memcmp(&hash, &vchRet[vchRet.size() - 4], 4) != 0) {
vchRet.clear();
return false;
diff --git a/src/blockfilter.cpp b/src/blockfilter.cpp
index 41fa0b6fa0..31a1e62d6b 100644
--- a/src/blockfilter.cpp
+++ b/src/blockfilter.cpp
@@ -81,7 +81,7 @@ GCSFilter::GCSFilter(const Params& params)
GCSFilter::GCSFilter(const Params& params, std::vector<unsigned char> encoded_filter)
: m_params(params), m_encoded(std::move(encoded_filter))
{
- VectorReader stream(GCS_SER_TYPE, GCS_SER_VERSION, m_encoded, 0);
+ SpanReader stream{GCS_SER_TYPE, GCS_SER_VERSION, m_encoded, 0};
uint64_t N = ReadCompactSize(stream);
m_N = static_cast<uint32_t>(N);
@@ -92,7 +92,7 @@ GCSFilter::GCSFilter(const Params& params, std::vector<unsigned char> encoded_fi
// Verify that the encoded filter contains exactly N elements. If it has too much or too little
// data, a std::ios_base::failure exception will be raised.
- BitStreamReader<VectorReader> bitreader(stream);
+ BitStreamReader<SpanReader> bitreader{stream};
for (uint64_t i = 0; i < m_N; ++i) {
GolombRiceDecode(bitreader, m_params.m_P);
}
@@ -133,13 +133,13 @@ GCSFilter::GCSFilter(const Params& params, const ElementSet& elements)
bool GCSFilter::MatchInternal(const uint64_t* element_hashes, size_t size) const
{
- VectorReader stream(GCS_SER_TYPE, GCS_SER_VERSION, m_encoded, 0);
+ SpanReader stream{GCS_SER_TYPE, GCS_SER_VERSION, m_encoded, 0};
// Seek forward by size of N
uint64_t N = ReadCompactSize(stream);
assert(N == m_N);
- BitStreamReader<VectorReader> bitreader(stream);
+ BitStreamReader<SpanReader> bitreader{stream};
uint64_t value = 0;
size_t hashes_index = 0;
diff --git a/src/compressor.h b/src/compressor.h
index 40b2496f06..00b777a111 100644
--- a/src/compressor.h
+++ b/src/compressor.h
@@ -65,12 +65,12 @@ struct ScriptCompression
void Ser(Stream &s, const CScript& script) {
CompressedScript compr;
if (CompressScript(script, compr)) {
- s << MakeSpan(compr);
+ s << Span{compr};
return;
}
unsigned int nSize = script.size() + nSpecialScripts;
s << VARINT(nSize);
- s << MakeSpan(script);
+ s << Span{script};
}
template<typename Stream>
@@ -79,7 +79,7 @@ struct ScriptCompression
s >> VARINT(nSize);
if (nSize < nSpecialScripts) {
CompressedScript vch(GetSpecialScriptSize(nSize), 0x00);
- s >> MakeSpan(vch);
+ s >> Span{vch};
DecompressScript(script, nSize, vch);
return;
}
@@ -90,7 +90,7 @@ struct ScriptCompression
s.ignore(nSize);
} else {
script.resize(nSize);
- s >> MakeSpan(script);
+ s >> Span{script};
}
}
};
diff --git a/src/net.cpp b/src/net.cpp
index f6d40a7854..2d9e69b6fb 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -761,7 +761,7 @@ CNetMessage V1TransportDeserializer::GetMessage(const std::chrono::microseconds
if (memcmp(hash.begin(), hdr.pchChecksum, CMessageHeader::CHECKSUM_SIZE) != 0) {
LogPrint(BCLog::NET, "Header error: Wrong checksum (%s, %u bytes), expected %s was %s, peer=%d\n",
SanitizeString(msg.m_command), msg.m_message_size,
- HexStr(Span<uint8_t>(hash.begin(), hash.begin() + CMessageHeader::CHECKSUM_SIZE)),
+ HexStr(Span{hash}.first(CMessageHeader::CHECKSUM_SIZE)),
HexStr(hdr.pchChecksum),
m_node_id);
reject_message = true;
@@ -1583,8 +1583,9 @@ void CConnman::SocketHandlerConnected(const std::vector<CNode*>& nodes,
if (nBytes > 0)
{
bool notify = false;
- if (!pnode->ReceiveMsgBytes(Span<const uint8_t>(pchBuf, nBytes), notify))
+ if (!pnode->ReceiveMsgBytes({pchBuf, (size_t)nBytes}, notify)) {
pnode->CloseSocketDisconnect();
+ }
RecordBytesRecv(nBytes);
if (notify) {
size_t nSizeAdded = 0;
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 3f755eb178..d832ff016b 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -1815,7 +1815,7 @@ void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv&
if (!ReadRawBlockFromDisk(block_data, pindex, m_chainparams.MessageStart())) {
assert(!"cannot load block from disk");
}
- m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::BLOCK, MakeSpan(block_data)));
+ m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::BLOCK, Span{block_data}));
// Don't set pblock as we've sent the block
} else {
// Send block from disk
diff --git a/src/netaddress.cpp b/src/netaddress.cpp
index 7f1dd698b0..f6bc7fbb94 100644
--- a/src/netaddress.cpp
+++ b/src/netaddress.cpp
@@ -196,7 +196,7 @@ static void Checksum(Span<const uint8_t> addr_pubkey, uint8_t (&checksum)[CHECKS
SHA3_256 hasher;
- hasher.Write(MakeSpan(prefix).first(prefix_len));
+ hasher.Write(Span{prefix}.first(prefix_len));
hasher.Write(addr_pubkey);
hasher.Write(VERSION);
@@ -303,7 +303,7 @@ CNetAddr::CNetAddr(const struct in_addr& ipv4Addr)
CNetAddr::CNetAddr(const struct in6_addr& ipv6Addr, const uint32_t scope)
{
- SetLegacyIPv6(Span<const uint8_t>(reinterpret_cast<const uint8_t*>(&ipv6Addr), sizeof(ipv6Addr)));
+ SetLegacyIPv6({reinterpret_cast<const uint8_t*>(&ipv6Addr), sizeof(ipv6Addr)});
m_scope_id = scope;
}
@@ -693,13 +693,13 @@ uint32_t CNetAddr::GetLinkedIPv4() const
return ReadBE32(m_addr.data());
} else if (IsRFC6052() || IsRFC6145()) {
// mapped IPv4, SIIT translated IPv4: the IPv4 address is the last 4 bytes of the address
- return ReadBE32(MakeSpan(m_addr).last(ADDR_IPV4_SIZE).data());
+ return ReadBE32(Span{m_addr}.last(ADDR_IPV4_SIZE).data());
} else if (IsRFC3964()) {
// 6to4 tunneled IPv4: the IPv4 address is in bytes 2-6
- return ReadBE32(MakeSpan(m_addr).subspan(2, ADDR_IPV4_SIZE).data());
+ return ReadBE32(Span{m_addr}.subspan(2, ADDR_IPV4_SIZE).data());
} else if (IsRFC4380()) {
// Teredo tunneled IPv4: the IPv4 address is in the last 4 bytes of the address, but bitflipped
- return ~ReadBE32(MakeSpan(m_addr).last(ADDR_IPV4_SIZE).data());
+ return ~ReadBE32(Span{m_addr}.last(ADDR_IPV4_SIZE).data());
}
assert(false);
}
diff --git a/src/netaddress.h b/src/netaddress.h
index a5b74eb35b..c8af4a9605 100644
--- a/src/netaddress.h
+++ b/src/netaddress.h
@@ -433,7 +433,7 @@ private:
if (SetNetFromBIP155Network(bip155_net, address_size)) {
m_addr.resize(address_size);
- s >> MakeSpan(m_addr);
+ s >> Span{m_addr};
if (m_net != NET_IPV6) {
return;
diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp
index d8c21bd833..36cf786bd5 100644
--- a/src/policy/fees.cpp
+++ b/src/policy/fees.cpp
@@ -493,6 +493,12 @@ void TxConfirmStats::removeTx(unsigned int entryHeight, unsigned int nBestSeenHe
bool CBlockPolicyEstimator::removeTx(uint256 hash, bool inBlock)
{
LOCK(m_cs_fee_estimator);
+ return _removeTx(hash, inBlock);
+}
+
+bool CBlockPolicyEstimator::_removeTx(const uint256& hash, bool inBlock)
+{
+ AssertLockHeld(m_cs_fee_estimator);
std::map<uint256, TxStatsInfo>::iterator pos = mapMemPoolTxs.find(hash);
if (pos != mapMemPoolTxs.end()) {
feeStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex, inBlock);
@@ -576,7 +582,8 @@ void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, boo
bool CBlockPolicyEstimator::processBlockTx(unsigned int nBlockHeight, const CTxMemPoolEntry* entry)
{
- if (!removeTx(entry->GetTx().GetHash(), true)) {
+ AssertLockHeld(m_cs_fee_estimator);
+ if (!_removeTx(entry->GetTx().GetHash(), true)) {
// This transaction wasn't being tracked for fee estimation
return false;
}
@@ -985,7 +992,7 @@ void CBlockPolicyEstimator::FlushUnconfirmed() {
// Remove every entry in mapMemPoolTxs
while (!mapMemPoolTxs.empty()) {
auto mi = mapMemPoolTxs.begin();
- removeTx(mi->first, false); // this calls erase() on mapMemPoolTxs
+ _removeTx(mi->first, false); // this calls erase() on mapMemPoolTxs
}
int64_t endclear = GetTimeMicros();
LogPrint(BCLog::ESTIMATEFEE, "Recorded %u unconfirmed txs from mempool in %gs\n", num_entries, (endclear - startclear)*0.000001);
diff --git a/src/policy/fees.h b/src/policy/fees.h
index 27f9120c64..37a7051045 100644
--- a/src/policy/fees.h
+++ b/src/policy/fees.h
@@ -186,47 +186,59 @@ public:
/** Process all the transactions that have been included in a block */
void processBlock(unsigned int nBlockHeight,
- std::vector<const CTxMemPoolEntry*>& entries);
+ std::vector<const CTxMemPoolEntry*>& entries)
+ EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
/** Process a transaction accepted to the mempool*/
- void processTransaction(const CTxMemPoolEntry& entry, bool validFeeEstimate);
+ void processTransaction(const CTxMemPoolEntry& entry, bool validFeeEstimate)
+ EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
/** Remove a transaction from the mempool tracking stats*/
- bool removeTx(uint256 hash, bool inBlock);
+ bool removeTx(uint256 hash, bool inBlock)
+ EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
/** DEPRECATED. Return a feerate estimate */
- CFeeRate estimateFee(int confTarget) const;
+ CFeeRate estimateFee(int confTarget) const
+ EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
/** Estimate feerate needed to get be included in a block within confTarget
* blocks. If no answer can be given at confTarget, return an estimate at
* the closest target where one can be given. 'conservative' estimates are
* valid over longer time horizons also.
*/
- CFeeRate estimateSmartFee(int confTarget, FeeCalculation *feeCalc, bool conservative) const;
+ CFeeRate estimateSmartFee(int confTarget, FeeCalculation *feeCalc, bool conservative) const
+ EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
/** Return a specific fee estimate calculation with a given success
* threshold and time horizon, and optionally return detailed data about
* calculation
*/
- CFeeRate estimateRawFee(int confTarget, double successThreshold, FeeEstimateHorizon horizon, EstimationResult *result = nullptr) const;
+ CFeeRate estimateRawFee(int confTarget, double successThreshold, FeeEstimateHorizon horizon,
+ EstimationResult* result = nullptr) const
+ EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
/** Write estimation data to a file */
- bool Write(CAutoFile& fileout) const;
+ bool Write(CAutoFile& fileout) const
+ EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
/** Read estimation data from a file */
- bool Read(CAutoFile& filein);
+ bool Read(CAutoFile& filein)
+ EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
/** Empty mempool transactions on shutdown to record failure to confirm for txs still in mempool */
- void FlushUnconfirmed();
+ void FlushUnconfirmed()
+ EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
/** Calculation of highest target that estimates are tracked for */
- unsigned int HighestTargetTracked(FeeEstimateHorizon horizon) const;
+ unsigned int HighestTargetTracked(FeeEstimateHorizon horizon) const
+ EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
/** Drop still unconfirmed transactions and record current estimations, if the fee estimation file is present. */
- void Flush();
+ void Flush()
+ EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
private:
- mutable RecursiveMutex m_cs_fee_estimator;
+ mutable Mutex m_cs_fee_estimator;
unsigned int nBestSeenHeight GUARDED_BY(m_cs_fee_estimator);
unsigned int firstRecordedHeight GUARDED_BY(m_cs_fee_estimator);
@@ -267,6 +279,10 @@ private:
unsigned int HistoricalBlockSpan() const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator);
/** Calculation of highest target that reasonable estimate can be provided for */
unsigned int MaxUsableEstimate() const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator);
+
+ /** A non-thread-safe helper for the removeTx function */
+ bool _removeTx(const uint256& hash, bool inBlock)
+ EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator);
};
class FeeFilterRounder
diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp
index 2c30b20d5b..5d0bb68ec6 100644
--- a/src/policy/policy.cpp
+++ b/src/policy/policy.cpp
@@ -251,7 +251,7 @@ bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
// - No annexes
if (witnessversion == 1 && witnessprogram.size() == WITNESS_V1_TAPROOT_SIZE && !p2sh) {
// Taproot spend (non-P2SH-wrapped, version 1, witness program size 32; see BIP 341)
- auto stack = MakeSpan(tx.vin[i].scriptWitness.stack);
+ Span stack{tx.vin[i].scriptWitness.stack};
if (stack.size() >= 2 && !stack.back().empty() && stack.back()[0] == ANNEX_TAG) {
// Annexes are nonstandard as long as no semantics are defined for them.
return false;
diff --git a/src/psbt.h b/src/psbt.h
index 7808a247c0..1171ecf1dd 100644
--- a/src/psbt.h
+++ b/src/psbt.h
@@ -81,7 +81,7 @@ struct PSBTInput
if (final_script_sig.empty() && final_script_witness.IsNull()) {
// Write any partial signatures
for (auto sig_pair : partial_sigs) {
- SerializeToVector(s, PSBT_IN_PARTIAL_SIG, MakeSpan(sig_pair.second.first));
+ SerializeToVector(s, PSBT_IN_PARTIAL_SIG, Span{sig_pair.second.first});
s << sig_pair.second.second;
}
diff --git a/src/pubkey.h b/src/pubkey.h
index ae6356c246..2453c92d92 100644
--- a/src/pubkey.h
+++ b/src/pubkey.h
@@ -157,13 +157,13 @@ public:
//! Get the KeyID of this public key (hash of its serialization)
CKeyID GetID() const
{
- return CKeyID(Hash160(MakeSpan(vch).first(size())));
+ return CKeyID(Hash160(Span{vch}.first(size())));
}
//! Get the 256-bit hash of this public key.
uint256 GetHash() const
{
- return Hash(MakeSpan(vch).first(size()));
+ return Hash(Span{vch}.first(size()));
}
/*
@@ -240,7 +240,7 @@ public:
explicit XOnlyPubKey(Span<const unsigned char> bytes);
/** Construct an x-only pubkey from a normal pubkey. */
- explicit XOnlyPubKey(const CPubKey& pubkey) : XOnlyPubKey(Span<const unsigned char>(pubkey.begin() + 1, pubkey.begin() + 33)) {}
+ explicit XOnlyPubKey(const CPubKey& pubkey) : XOnlyPubKey(Span{pubkey}.subspan(1, 32)) {}
/** Verify a Schnorr signature against this public key.
*
diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h
index 211f3f506d..364962ee9a 100644
--- a/src/qt/guiutil.h
+++ b/src/qt/guiutil.h
@@ -428,6 +428,15 @@ namespace GUIUtil
*/
void ShowModalDialogAndDeleteOnClose(QDialog* dialog);
+ inline bool IsEscapeOrBack(int key)
+ {
+ if (key == Qt::Key_Escape) return true;
+#ifdef Q_OS_ANDROID
+ if (key == Qt::Key_Back) return true;
+#endif // Q_OS_ANDROID
+ return false;
+ }
+
} // namespace GUIUtil
#endif // BITCOIN_QT_GUIUTIL_H
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 6bcdcc4c29..1c19fb4b27 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -14,6 +14,7 @@
#include <netbase.h>
#include <qt/bantablemodel.h>
#include <qt/clientmodel.h>
+#include <qt/guiutil.h>
#include <qt/peertablesortproxy.h>
#include <qt/platformstyle.h>
#include <qt/walletmodel.h>
@@ -910,8 +911,7 @@ void RPCConsole::clear(bool keep_prompt)
void RPCConsole::keyPressEvent(QKeyEvent *event)
{
- if(windowType() != Qt::Widget && event->key() == Qt::Key_Escape)
- {
+ if (windowType() != Qt::Widget && GUIUtil::IsEscapeOrBack(event->key())) {
close();
}
}
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index 6a3e160d8c..2c05fc39fd 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -36,32 +36,33 @@
static RPCHelpMan validateaddress()
{
- return RPCHelpMan{"validateaddress",
- "\nReturn information about the given bitcoin address.\n",
- {
- {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address to validate"},
- },
- RPCResult{
- RPCResult::Type::OBJ, "", "",
+ return RPCHelpMan{
+ "validateaddress",
+ "\nReturn information about the given bitcoin address.\n",
+ {
+ {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address to validate"},
+ },
+ RPCResult{
+ RPCResult::Type::OBJ, "", "",
+ {
+ {RPCResult::Type::BOOL, "isvalid", "If the address is valid or not"},
+ {RPCResult::Type::STR, "address", /* optional */ true, "The bitcoin address validated"},
+ {RPCResult::Type::STR_HEX, "scriptPubKey", /* optional */ true, "The hex-encoded scriptPubKey generated by the address"},
+ {RPCResult::Type::BOOL, "isscript", /* optional */ true, "If the key is a script"},
+ {RPCResult::Type::BOOL, "iswitness", /* optional */ true, "If the address is a witness address"},
+ {RPCResult::Type::NUM, "witness_version", /* optional */ true, "The version number of the witness program"},
+ {RPCResult::Type::STR_HEX, "witness_program", /* optional */ true, "The hex value of the witness program"},
+ {RPCResult::Type::STR, "error", /* optional */ true, "Error message, if any"},
+ {RPCResult::Type::ARR, "error_locations", /*optional=*/true, "Indices of likely error locations in address, if known (e.g. Bech32 errors)",
{
- {RPCResult::Type::BOOL, "isvalid", "If the address is valid or not"},
- {RPCResult::Type::STR, "address", /* optional */ true, "The bitcoin address validated"},
- {RPCResult::Type::STR_HEX, "scriptPubKey", /* optional */ true, "The hex-encoded scriptPubKey generated by the address"},
- {RPCResult::Type::BOOL, "isscript", /* optional */ true, "If the key is a script"},
- {RPCResult::Type::BOOL, "iswitness", /* optional */ true, "If the address is a witness address"},
- {RPCResult::Type::NUM, "witness_version", /* optional */ true, "The version number of the witness program"},
- {RPCResult::Type::STR_HEX, "witness_program", /* optional */ true, "The hex value of the witness program"},
- {RPCResult::Type::STR, "error", /* optional */ true, "Error message, if any"},
- {RPCResult::Type::ARR, "error_locations", "Indices of likely error locations in address, if known (e.g. Bech32 errors)",
- {
- {RPCResult::Type::NUM, "index", "index of a potential error"},
- }},
- }
- },
- RPCExamples{
- HelpExampleCli("validateaddress", "\"" + EXAMPLE_ADDRESS[0] + "\"") +
- HelpExampleRpc("validateaddress", "\"" + EXAMPLE_ADDRESS[0] + "\"")
- },
+ {RPCResult::Type::NUM, "index", "index of a potential error"},
+ }},
+ }
+ },
+ RPCExamples{
+ HelpExampleCli("validateaddress", "\"" + EXAMPLE_ADDRESS[0] + "\"") +
+ HelpExampleRpc("validateaddress", "\"" + EXAMPLE_ADDRESS[0] + "\"")
+ },
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::string error_msg;
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index f4456bebc5..021e6ae320 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -106,82 +106,83 @@ static RPCHelpMan ping()
static RPCHelpMan getpeerinfo()
{
- return RPCHelpMan{"getpeerinfo",
- "\nReturns data about each connected network node as a json array of objects.\n",
- {},
- RPCResult{
- RPCResult::Type::ARR, "", "",
+ return RPCHelpMan{
+ "getpeerinfo",
+ "\nReturns data about each connected network node as a json array of objects.\n",
+ {},
+ RPCResult{
+ RPCResult::Type::ARR, "", "",
+ {
+ {RPCResult::Type::OBJ, "", "",
+ {
{
- {RPCResult::Type::OBJ, "", "",
- {
- {
- {RPCResult::Type::NUM, "id", "Peer index"},
- {RPCResult::Type::STR, "addr", "(host:port) The IP address and port of the peer"},
- {RPCResult::Type::STR, "addrbind", /* optional */ true, "(ip:port) Bind address of the connection to the peer"},
- {RPCResult::Type::STR, "addrlocal", /* optional */ true, "(ip:port) Local address as reported by the peer"},
- {RPCResult::Type::STR, "network", "Network (" + Join(GetNetworkNames(/* append_unroutable */ true), ", ") + ")"},
- {RPCResult::Type::NUM, "mapped_as", /* optional */ true, "The AS in the BGP route to the peer used for diversifying\n"
- "peer selection (only available if the asmap config flag is set)"},
- {RPCResult::Type::STR_HEX, "services", "The services offered"},
- {RPCResult::Type::ARR, "servicesnames", "the services offered, in human-readable form",
- {
- {RPCResult::Type::STR, "SERVICE_NAME", "the service name if it is recognised"}
- }},
- {RPCResult::Type::BOOL, "relaytxes", "Whether peer has asked us to relay transactions to it"},
- {RPCResult::Type::NUM_TIME, "lastsend", "The " + UNIX_EPOCH_TIME + " of the last send"},
- {RPCResult::Type::NUM_TIME, "lastrecv", "The " + UNIX_EPOCH_TIME + " of the last receive"},
- {RPCResult::Type::NUM_TIME, "last_transaction", "The " + UNIX_EPOCH_TIME + " of the last valid transaction received from this peer"},
- {RPCResult::Type::NUM_TIME, "last_block", "The " + UNIX_EPOCH_TIME + " of the last block received from this peer"},
- {RPCResult::Type::NUM, "bytessent", "The total bytes sent"},
- {RPCResult::Type::NUM, "bytesrecv", "The total bytes received"},
- {RPCResult::Type::NUM_TIME, "conntime", "The " + UNIX_EPOCH_TIME + " of the connection"},
- {RPCResult::Type::NUM, "timeoffset", "The time offset in seconds"},
- {RPCResult::Type::NUM, "pingtime", /* optional */ true, "ping time (if available)"},
- {RPCResult::Type::NUM, "minping", /* optional */ true, "minimum observed ping time (if any at all)"},
- {RPCResult::Type::NUM, "pingwait", /* optional */ true, "ping wait (if non-zero)"},
- {RPCResult::Type::NUM, "version", "The peer version, such as 70001"},
- {RPCResult::Type::STR, "subver", "The string version"},
- {RPCResult::Type::BOOL, "inbound", "Inbound (true) or Outbound (false)"},
- {RPCResult::Type::BOOL, "bip152_hb_to", "Whether we selected peer as (compact blocks) high-bandwidth peer"},
- {RPCResult::Type::BOOL, "bip152_hb_from", "Whether peer selected us as (compact blocks) high-bandwidth peer"},
- {RPCResult::Type::NUM, "startingheight", "The starting height (block) of the peer"},
- {RPCResult::Type::NUM, "synced_headers", "The last header we have in common with this peer"},
- {RPCResult::Type::NUM, "synced_blocks", "The last block we have in common with this peer"},
- {RPCResult::Type::ARR, "inflight", "",
- {
- {RPCResult::Type::NUM, "n", "The heights of blocks we're currently asking from this peer"},
- }},
- {RPCResult::Type::BOOL, "addr_relay_enabled", "Whether we participate in address relay with this peer"},
- {RPCResult::Type::NUM, "addr_processed", "The total number of addresses processed, excluding those dropped due to rate limiting"},
- {RPCResult::Type::NUM, "addr_rate_limited", "The total number of addresses dropped due to rate limiting"},
- {RPCResult::Type::ARR, "permissions", "Any special permissions that have been granted to this peer",
- {
- {RPCResult::Type::STR, "permission_type", Join(NET_PERMISSIONS_DOC, ",\n") + ".\n"},
- }},
- {RPCResult::Type::NUM, "minfeefilter", "The minimum fee rate for transactions this peer accepts"},
- {RPCResult::Type::OBJ_DYN, "bytessent_per_msg", "",
- {
- {RPCResult::Type::NUM, "msg", "The total bytes sent aggregated by message type\n"
- "When a message type is not listed in this json object, the bytes sent are 0.\n"
- "Only known message types can appear as keys in the object."}
- }},
- {RPCResult::Type::OBJ_DYN, "bytesrecv_per_msg", "",
- {
- {RPCResult::Type::NUM, "msg", "The total bytes received aggregated by message type\n"
- "When a message type is not listed in this json object, the bytes received are 0.\n"
- "Only known message types can appear as keys in the object and all bytes received\n"
- "of unknown message types are listed under '"+NET_MESSAGE_COMMAND_OTHER+"'."}
- }},
- {RPCResult::Type::STR, "connection_type", "Type of connection: \n" + Join(CONNECTION_TYPE_DOC, ",\n") + ".\n"
- "Please note this output is unlikely to be stable in upcoming releases as we iterate to\n"
- "best capture connection behaviors."},
- }},
+ {RPCResult::Type::NUM, "id", "Peer index"},
+ {RPCResult::Type::STR, "addr", "(host:port) The IP address and port of the peer"},
+ {RPCResult::Type::STR, "addrbind", /* optional */ true, "(ip:port) Bind address of the connection to the peer"},
+ {RPCResult::Type::STR, "addrlocal", /* optional */ true, "(ip:port) Local address as reported by the peer"},
+ {RPCResult::Type::STR, "network", "Network (" + Join(GetNetworkNames(/* append_unroutable */ true), ", ") + ")"},
+ {RPCResult::Type::NUM, "mapped_as", /* optional */ true, "The AS in the BGP route to the peer used for diversifying\n"
+ "peer selection (only available if the asmap config flag is set)"},
+ {RPCResult::Type::STR_HEX, "services", "The services offered"},
+ {RPCResult::Type::ARR, "servicesnames", "the services offered, in human-readable form",
+ {
+ {RPCResult::Type::STR, "SERVICE_NAME", "the service name if it is recognised"}
}},
- },
- RPCExamples{
- HelpExampleCli("getpeerinfo", "")
+ {RPCResult::Type::BOOL, "relaytxes", "Whether peer has asked us to relay transactions to it"},
+ {RPCResult::Type::NUM_TIME, "lastsend", "The " + UNIX_EPOCH_TIME + " of the last send"},
+ {RPCResult::Type::NUM_TIME, "lastrecv", "The " + UNIX_EPOCH_TIME + " of the last receive"},
+ {RPCResult::Type::NUM_TIME, "last_transaction", "The " + UNIX_EPOCH_TIME + " of the last valid transaction received from this peer"},
+ {RPCResult::Type::NUM_TIME, "last_block", "The " + UNIX_EPOCH_TIME + " of the last block received from this peer"},
+ {RPCResult::Type::NUM, "bytessent", "The total bytes sent"},
+ {RPCResult::Type::NUM, "bytesrecv", "The total bytes received"},
+ {RPCResult::Type::NUM_TIME, "conntime", "The " + UNIX_EPOCH_TIME + " of the connection"},
+ {RPCResult::Type::NUM, "timeoffset", "The time offset in seconds"},
+ {RPCResult::Type::NUM, "pingtime", /* optional */ true, "ping time (if available)"},
+ {RPCResult::Type::NUM, "minping", /* optional */ true, "minimum observed ping time (if any at all)"},
+ {RPCResult::Type::NUM, "pingwait", /* optional */ true, "ping wait (if non-zero)"},
+ {RPCResult::Type::NUM, "version", "The peer version, such as 70001"},
+ {RPCResult::Type::STR, "subver", "The string version"},
+ {RPCResult::Type::BOOL, "inbound", "Inbound (true) or Outbound (false)"},
+ {RPCResult::Type::BOOL, "bip152_hb_to", "Whether we selected peer as (compact blocks) high-bandwidth peer"},
+ {RPCResult::Type::BOOL, "bip152_hb_from", "Whether peer selected us as (compact blocks) high-bandwidth peer"},
+ {RPCResult::Type::NUM, "startingheight", /*optional=*/true, "The starting height (block) of the peer"},
+ {RPCResult::Type::NUM, "synced_headers", /*optional=*/true, "The last header we have in common with this peer"},
+ {RPCResult::Type::NUM, "synced_blocks", /*optional=*/true, "The last block we have in common with this peer"},
+ {RPCResult::Type::ARR, "inflight", /*optional=*/true, "",
+ {
+ {RPCResult::Type::NUM, "n", "The heights of blocks we're currently asking from this peer"},
+ }},
+ {RPCResult::Type::BOOL, "addr_relay_enabled", /*optional=*/true, "Whether we participate in address relay with this peer"},
+ {RPCResult::Type::NUM, "addr_processed", /*optional=*/true, "The total number of addresses processed, excluding those dropped due to rate limiting"},
+ {RPCResult::Type::NUM, "addr_rate_limited", /*optional=*/true, "The total number of addresses dropped due to rate limiting"},
+ {RPCResult::Type::ARR, "permissions", "Any special permissions that have been granted to this peer",
+ {
+ {RPCResult::Type::STR, "permission_type", Join(NET_PERMISSIONS_DOC, ",\n") + ".\n"},
+ }},
+ {RPCResult::Type::NUM, "minfeefilter", "The minimum fee rate for transactions this peer accepts"},
+ {RPCResult::Type::OBJ_DYN, "bytessent_per_msg", "",
+ {
+ {RPCResult::Type::NUM, "msg", "The total bytes sent aggregated by message type\n"
+ "When a message type is not listed in this json object, the bytes sent are 0.\n"
+ "Only known message types can appear as keys in the object."}
+ }},
+ {RPCResult::Type::OBJ_DYN, "bytesrecv_per_msg", "",
+ {
+ {RPCResult::Type::NUM, "msg", "The total bytes received aggregated by message type\n"
+ "When a message type is not listed in this json object, the bytes received are 0.\n"
+ "Only known message types can appear as keys in the object and all bytes received\n"
+ "of unknown message types are listed under '"+NET_MESSAGE_COMMAND_OTHER+"'."}
+ }},
+ {RPCResult::Type::STR, "connection_type", "Type of connection: \n" + Join(CONNECTION_TYPE_DOC, ",\n") + ".\n"
+ "Please note this output is unlikely to be stable in upcoming releases as we iterate to\n"
+ "best capture connection behaviors."},
+ }},
+ }},
+ },
+ RPCExamples{
+ HelpExampleCli("getpeerinfo", "")
+ HelpExampleRpc("getpeerinfo", "")
- },
+ },
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
NodeContext& node = EnsureAnyNodeContext(request.context);
diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp
index 2d7f5f2894..683cf88af8 100644
--- a/src/rpc/util.cpp
+++ b/src/rpc/util.cpp
@@ -317,7 +317,7 @@ public:
UniValue obj(UniValue::VOBJ);
obj.pushKV("iswitness", true);
obj.pushKV("witness_version", (int)id.version);
- obj.pushKV("witness_program", HexStr(Span<const unsigned char>(id.program, id.length)));
+ obj.pushKV("witness_program", HexStr({id.program, id.length}));
return obj;
}
};
diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp
index c3b4d1ddaa..30f929664f 100644
--- a/src/script/descriptor.cpp
+++ b/src/script/descriptor.cpp
@@ -631,7 +631,7 @@ public:
out.origins.emplace(entry.first.GetID(), std::make_pair<CPubKey, KeyOriginInfo>(CPubKey(entry.first), std::move(entry.second)));
}
- output_scripts = MakeScripts(pubkeys, MakeSpan(subscripts), out);
+ output_scripts = MakeScripts(pubkeys, Span{subscripts}, out);
return true;
}
@@ -974,10 +974,10 @@ std::unique_ptr<PubkeyProvider> ParsePubkeyInner(uint32_t key_exp_index, const S
}
KeyPath path;
DeriveType type = DeriveType::NO;
- if (split.back() == MakeSpan("*").first(1)) {
+ if (split.back() == Span{"*"}.first(1)) {
split.pop_back();
type = DeriveType::UNHARDENED;
- } else if (split.back() == MakeSpan("*'").first(2) || split.back() == MakeSpan("*h").first(2)) {
+ } else if (split.back() == Span{"*'"}.first(2) || split.back() == Span{"*h"}.first(2)) {
split.pop_back();
type = DeriveType::HARDENED;
}
@@ -1252,7 +1252,7 @@ std::unique_ptr<PubkeyProvider> InferXOnlyPubkey(const XOnlyPubKey& xkey, ParseS
std::unique_ptr<DescriptorImpl> InferScript(const CScript& script, ParseScriptContext ctx, const SigningProvider& provider)
{
if (ctx == ParseScriptContext::P2TR && script.size() == 34 && script[0] == 32 && script[33] == OP_CHECKSIG) {
- XOnlyPubKey key{Span<const unsigned char>{script.data() + 1, script.data() + 33}};
+ XOnlyPubKey key{Span{script}.subspan(1, 32)};
return std::make_unique<PKDescriptor>(InferXOnlyPubkey(key, ctx, provider));
}
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
index d83ec7192b..6433ba1b58 100644
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -1858,7 +1858,7 @@ uint256 ComputeTaprootMerkleRoot(Span<const unsigned char> control, const uint25
uint256 k = tapleaf_hash;
for (int i = 0; i < path_len; ++i) {
CHashWriter ss_branch{HASHER_TAPBRANCH};
- Span<const unsigned char> node(control.data() + TAPROOT_CONTROL_BASE_SIZE + TAPROOT_CONTROL_NODE_SIZE * i, TAPROOT_CONTROL_NODE_SIZE);
+ Span node{Span{control}.subspan(TAPROOT_CONTROL_BASE_SIZE + TAPROOT_CONTROL_NODE_SIZE * i, TAPROOT_CONTROL_NODE_SIZE)};
if (std::lexicographical_compare(k.begin(), k.end(), node.begin(), node.end())) {
ss_branch << k << node;
} else {
@@ -1874,7 +1874,7 @@ static bool VerifyTaprootCommitment(const std::vector<unsigned char>& control, c
assert(control.size() >= TAPROOT_CONTROL_BASE_SIZE);
assert(program.size() >= uint256::size());
//! The internal pubkey (x-only, so no Y coordinate parity).
- const XOnlyPubKey p{Span<const unsigned char>{control.data() + 1, control.data() + TAPROOT_CONTROL_BASE_SIZE}};
+ const XOnlyPubKey p{Span{control}.subspan(1, TAPROOT_CONTROL_BASE_SIZE - 1)};
//! The output pubkey (taken from the scriptPubKey).
const XOnlyPubKey q{program};
// Compute the Merkle root from the leaf and the provided path.
@@ -1886,7 +1886,7 @@ static bool VerifyTaprootCommitment(const std::vector<unsigned char>& control, c
static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, const std::vector<unsigned char>& program, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror, bool is_p2sh)
{
CScript exec_script; //!< Actually executed script (last stack item in P2WSH; implied P2PKH script in P2WPKH; leaf script in P2TR)
- Span<const valtype> stack{witness.stack};
+ Span stack{witness.stack};
ScriptExecutionData execdata;
if (witversion == 0) {
diff --git a/src/script/sign.cpp b/src/script/sign.cpp
index 8e044b1e00..3f7060879c 100644
--- a/src/script/sign.cpp
+++ b/src/script/sign.cpp
@@ -167,7 +167,7 @@ static bool SignTaprootScript(const SigningProvider& provider, const BaseSignatu
// <xonly pubkey> OP_CHECKSIG
if (script.size() == 34 && script[33] == OP_CHECKSIG && script[0] == 0x20) {
- XOnlyPubKey pubkey(MakeSpan(script).subspan(1, 32));
+ XOnlyPubKey pubkey{Span{script}.subspan(1, 32)};
std::vector<unsigned char> sig;
if (CreateTaprootScriptSig(creator, sigdata, provider, sig, pubkey, leaf_hash, sigversion)) {
result = Vector(std::move(sig));
diff --git a/src/script/sign.h b/src/script/sign.h
index 62335b644a..50525af332 100644
--- a/src/script/sign.h
+++ b/src/script/sign.h
@@ -149,7 +149,7 @@ void SerializeHDKeypaths(Stream& s, const std::map<CPubKey, KeyOriginInfo>& hd_k
if (!keypath_pair.first.IsValid()) {
throw std::ios_base::failure("Invalid CPubKey being serialized");
}
- SerializeToVector(s, type, MakeSpan(keypath_pair.first));
+ SerializeToVector(s, type, Span{keypath_pair.first});
WriteCompactSize(s, (keypath_pair.second.path.size() + 1) * sizeof(uint32_t));
s << keypath_pair.second.fingerprint;
for (const auto& path : keypath_pair.second.path) {
diff --git a/src/signet.cpp b/src/signet.cpp
index aafd1999ee..5cecb8decc 100644
--- a/src/signet.cpp
+++ b/src/signet.cpp
@@ -38,7 +38,7 @@ static bool FetchAndClearCommitmentSection(const Span<const uint8_t> header, CSc
std::vector<uint8_t> pushdata;
while (witness_commitment.GetOp(pc, opcode, pushdata)) {
if (pushdata.size() > 0) {
- if (!found_header && pushdata.size() > (size_t) header.size() && Span<const uint8_t>(pushdata.data(), header.size()) == header) {
+ if (!found_header && pushdata.size() > (size_t)header.size() && Span{pushdata}.first(header.size()) == header) {
// pushdata only counts if it has the header _and_ some data
result.insert(result.end(), pushdata.begin() + header.size(), pushdata.end());
pushdata.erase(pushdata.begin() + header.size(), pushdata.end());
@@ -98,7 +98,7 @@ std::optional<SignetTxs> SignetTxs::Create(const CBlock& block, const CScript& c
// no signet solution -- allow this to support OP_TRUE as trivial block challenge
} else {
try {
- VectorReader v(SER_NETWORK, INIT_PROTO_VERSION, signet_solution, 0);
+ SpanReader v{SER_NETWORK, INIT_PROTO_VERSION, signet_solution, 0};
v >> tx_spending.vin[0].scriptSig;
v >> tx_spending.vin[0].scriptWitness.stack;
if (!v.empty()) return std::nullopt; // extraneous data encountered
diff --git a/src/span.h b/src/span.h
index 746e41f2f4..6703e889c5 100644
--- a/src/span.h
+++ b/src/span.h
@@ -222,13 +222,15 @@ public:
template <typename O> friend class Span;
};
-// MakeSpan helps constructing a Span of the right type automatically.
-/** MakeSpan for arrays: */
-template <typename A, int N> Span<A> constexpr MakeSpan(A (&a)[N]) { return Span<A>(a, N); }
-/** MakeSpan for temporaries / rvalue references, only supporting const output. */
-template <typename V> constexpr auto MakeSpan(V&& v SPAN_ATTR_LIFETIMEBOUND) -> typename std::enable_if<!std::is_lvalue_reference<V>::value, Span<const typename std::remove_pointer<decltype(v.data())>::type>>::type { return std::forward<V>(v); }
-/** MakeSpan for (lvalue) references, supporting mutable output. */
-template <typename V> constexpr auto MakeSpan(V& v SPAN_ATTR_LIFETIMEBOUND) -> Span<typename std::remove_pointer<decltype(v.data())>::type> { return v; }
+// Deduction guides for Span
+// For the pointer/size based and iterator based constructor:
+template <typename T, typename EndOrSize> Span(T*, EndOrSize) -> Span<T>;
+// For the array constructor:
+template <typename T, std::size_t N> Span(T (&)[N]) -> Span<T>;
+// For the temporaries/rvalue references constructor, only supporting const output.
+template <typename T> Span(T&&) -> Span<std::enable_if_t<!std::is_lvalue_reference_v<T>, const std::remove_pointer_t<decltype(std::declval<T&&>().data())>>>;
+// For (lvalue) references, supporting mutable output.
+template <typename T> Span(T&) -> Span<std::remove_pointer_t<decltype(std::declval<T&>().data())>>;
/** Pop the last element off a span, and return a reference to that element. */
template <typename T>
@@ -256,12 +258,12 @@ Span<std::byte> AsWritableBytes(Span<T> s) noexcept
template <typename V>
Span<const std::byte> MakeByteSpan(V&& v) noexcept
{
- return AsBytes(MakeSpan(std::forward<V>(v)));
+ return AsBytes(Span{std::forward<V>(v)});
}
template <typename V>
Span<std::byte> MakeWritableByteSpan(V&& v) noexcept
{
- return AsWritableBytes(MakeSpan(std::forward<V>(v)));
+ return AsWritableBytes(Span{std::forward<V>(v)});
}
// Helper functions to safely cast to unsigned char pointers.
@@ -274,7 +276,7 @@ inline const unsigned char* UCharCast(const std::byte* c) { return reinterpret_c
// Helper function to safely convert a Span to a Span<[const] unsigned char>.
template <typename T> constexpr auto UCharSpanCast(Span<T> s) -> Span<typename std::remove_pointer<decltype(UCharCast(s.data()))>::type> { return {UCharCast(s.data()), s.size()}; }
-/** Like MakeSpan, but for (const) unsigned char member types only. Only works for (un)signed char containers. */
-template <typename V> constexpr auto MakeUCharSpan(V&& v) -> decltype(UCharSpanCast(MakeSpan(std::forward<V>(v)))) { return UCharSpanCast(MakeSpan(std::forward<V>(v))); }
+/** Like the Span constructor, but for (const) unsigned char member types only. Only works for (un)signed char containers. */
+template <typename V> constexpr auto MakeUCharSpan(V&& v) -> decltype(UCharSpanCast(Span{std::forward<V>(v)})) { return UCharSpanCast(Span{std::forward<V>(v)}); }
#endif // BITCOIN_SPAN_H
diff --git a/src/streams.h b/src/streams.h
index 9e8f379cd2..dbb942f306 100644
--- a/src/streams.h
+++ b/src/streams.h
@@ -128,15 +128,14 @@ private:
size_t nPos;
};
-/** Minimal stream for reading from an existing vector by reference
+/** Minimal stream for reading from an existing byte array by Span.
*/
-class VectorReader
+class SpanReader
{
private:
const int m_type;
const int m_version;
- const std::vector<unsigned char>& m_data;
- size_t m_pos = 0;
+ Span<const unsigned char> m_data;
public:
@@ -146,12 +145,13 @@ public:
* @param[in] data Referenced byte vector to overwrite/append
* @param[in] pos Starting position. Vector index where reads should start.
*/
- VectorReader(int type, int version, const std::vector<unsigned char>& data, size_t pos)
- : m_type(type), m_version(version), m_data(data), m_pos(pos)
+ SpanReader(int type, int version, Span<const unsigned char> data, size_t pos)
+ : m_type(type), m_version(version), m_data(data)
{
- if (m_pos > m_data.size()) {
- throw std::ios_base::failure("VectorReader(...): end of data (m_pos > m_data.size())");
+ if (pos > m_data.size()) {
+ throw std::ios_base::failure("SpanReader(...): end of data (pos > m_data.size())");
}
+ data = data.subspan(pos);
}
/**
@@ -159,15 +159,15 @@ public:
* @param[in] args A list of items to deserialize starting at pos.
*/
template <typename... Args>
- VectorReader(int type, int version, const std::vector<unsigned char>& data, size_t pos,
+ SpanReader(int type, int version, Span<const unsigned char> data, size_t pos,
Args&&... args)
- : VectorReader(type, version, data, pos)
+ : SpanReader(type, version, data, pos)
{
::UnserializeMany(*this, std::forward<Args>(args)...);
}
template<typename T>
- VectorReader& operator>>(T&& obj)
+ SpanReader& operator>>(T&& obj)
{
// Unserialize from this stream
::Unserialize(*this, obj);
@@ -177,8 +177,8 @@ public:
int GetVersion() const { return m_version; }
int GetType() const { return m_type; }
- size_t size() const { return m_data.size() - m_pos; }
- bool empty() const { return m_data.size() == m_pos; }
+ size_t size() const { return m_data.size(); }
+ bool empty() const { return m_data.empty(); }
void read(char* dst, size_t n)
{
@@ -187,12 +187,11 @@ public:
}
// Read from the beginning of the buffer
- size_t pos_next = m_pos + n;
- if (pos_next > m_data.size()) {
- throw std::ios_base::failure("VectorReader::read(): end of data");
+ if (n > m_data.size()) {
+ throw std::ios_base::failure("SpanReader::read(): end of data");
}
- memcpy(dst, m_data.data() + m_pos, n);
- m_pos = pos_next;
+ memcpy(dst, m_data.data(), n);
+ m_data = m_data.subspan(n);
}
};
diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp
index cbdedd1b85..bedef5de37 100644
--- a/src/test/crypto_tests.cpp
+++ b/src/test/crypto_tests.cpp
@@ -770,8 +770,8 @@ static void TestSHA3_256(const std::string& input, const std::string& output)
int s1 = InsecureRandRange(in_bytes.size() + 1);
int s2 = InsecureRandRange(in_bytes.size() + 1 - s1);
int s3 = in_bytes.size() - s1 - s2;
- sha.Write(MakeSpan(in_bytes).first(s1)).Write(MakeSpan(in_bytes).subspan(s1, s2));
- sha.Write(MakeSpan(in_bytes).last(s3)).Finalize(out);
+ sha.Write(Span{in_bytes}.first(s1)).Write(Span{in_bytes}.subspan(s1, s2));
+ sha.Write(Span{in_bytes}.last(s3)).Finalize(out);
BOOST_CHECK(std::equal(std::begin(out_bytes), std::end(out_bytes), out));
}
diff --git a/src/test/fuzz/asmap.cpp b/src/test/fuzz/asmap.cpp
index d402f8632c..c5e9c56049 100644
--- a/src/test/fuzz/asmap.cpp
+++ b/src/test/fuzz/asmap.cpp
@@ -49,7 +49,7 @@ FUZZ_TARGET(asmap)
CNetAddr net_addr;
if (ipv6) {
assert(addr_size == ADDR_IPV6_SIZE);
- net_addr.SetLegacyIPv6(Span<const uint8_t>(addr_data, addr_size));
+ net_addr.SetLegacyIPv6({addr_data, addr_size});
} else {
assert(addr_size == ADDR_IPV4_SIZE);
in_addr ipv4;
diff --git a/src/test/fuzz/golomb_rice.cpp b/src/test/fuzz/golomb_rice.cpp
index c99bf940c7..7b4634c67b 100644
--- a/src/test/fuzz/golomb_rice.cpp
+++ b/src/test/fuzz/golomb_rice.cpp
@@ -82,8 +82,8 @@ FUZZ_TARGET(golomb_rice)
std::vector<uint64_t> decoded_deltas;
{
- VectorReader stream{SER_NETWORK, 0, golomb_rice_data, 0};
- BitStreamReader<VectorReader> bitreader(stream);
+ SpanReader stream{SER_NETWORK, 0, golomb_rice_data, 0};
+ BitStreamReader<SpanReader> bitreader{stream};
const uint32_t n = static_cast<uint32_t>(ReadCompactSize(stream));
for (uint32_t i = 0; i < n; ++i) {
decoded_deltas.push_back(GolombRiceDecode(bitreader, BASIC_FILTER_P));
@@ -94,14 +94,14 @@ FUZZ_TARGET(golomb_rice)
{
const std::vector<uint8_t> random_bytes = ConsumeRandomLengthByteVector(fuzzed_data_provider, 1024);
- VectorReader stream{SER_NETWORK, 0, random_bytes, 0};
+ SpanReader stream{SER_NETWORK, 0, random_bytes, 0};
uint32_t n;
try {
n = static_cast<uint32_t>(ReadCompactSize(stream));
} catch (const std::ios_base::failure&) {
return;
}
- BitStreamReader<VectorReader> bitreader(stream);
+ BitStreamReader<SpanReader> bitreader{stream};
for (uint32_t i = 0; i < std::min<uint32_t>(n, 1024); ++i) {
try {
(void)GolombRiceDecode(bitreader, BASIC_FILTER_P);
diff --git a/src/test/fuzz/rpc.cpp b/src/test/fuzz/rpc.cpp
index 251687104e..790421d60c 100644
--- a/src/test/fuzz/rpc.cpp
+++ b/src/test/fuzz/rpc.cpp
@@ -41,13 +41,17 @@ struct RPCFuzzTestingSetup : public TestingSetup {
{
}
- UniValue CallRPC(const std::string& rpc_method, const std::vector<std::string>& arguments)
+ void CallRPC(const std::string& rpc_method, const std::vector<std::string>& arguments)
{
JSONRPCRequest request;
request.context = &m_node;
request.strMethod = rpc_method;
- request.params = RPCConvertValues(rpc_method, arguments);
- return tableRPC.execute(request);
+ try {
+ request.params = RPCConvertValues(rpc_method, arguments);
+ } catch (const std::runtime_error&) {
+ return;
+ }
+ tableRPC.execute(request);
}
std::vector<std::string> GetRPCCommands() const
@@ -353,7 +357,11 @@ FUZZ_TARGET_INIT(rpc, initialize_rpc)
}
try {
rpc_testing_setup->CallRPC(rpc_command, arguments);
- } catch (const UniValue&) {
- } catch (const std::runtime_error&) {
+ } catch (const UniValue& json_rpc_error) {
+ const std::string error_msg{find_value(json_rpc_error, "message").get_str()};
+ if (error_msg.find("Internal bug detected") != std::string::npos) {
+ // Only allow the intentional internal bug
+ assert(error_msg.find("trigger_internal_bug") != std::string::npos);
+ }
}
}
diff --git a/src/test/fuzz/script_assets_test_minimizer.cpp b/src/test/fuzz/script_assets_test_minimizer.cpp
index 4669f783aa..d661d79e84 100644
--- a/src/test/fuzz/script_assets_test_minimizer.cpp
+++ b/src/test/fuzz/script_assets_test_minimizer.cpp
@@ -54,7 +54,7 @@ CMutableTransaction TxFromHex(const std::string& str)
{
CMutableTransaction tx;
try {
- VectorReader(SER_DISK, SERIALIZE_TRANSACTION_NO_WITNESS, CheckedParseHex(str), 0) >> tx;
+ SpanReader{SER_DISK, SERIALIZE_TRANSACTION_NO_WITNESS, CheckedParseHex(str), 0} >> tx;
} catch (const std::ios_base::failure&) {
throw std::runtime_error("Tx deserialization failure");
}
@@ -68,7 +68,7 @@ std::vector<CTxOut> TxOutsFromJSON(const UniValue& univalue)
for (size_t i = 0; i < univalue.size(); ++i) {
CTxOut txout;
try {
- VectorReader(SER_DISK, 0, CheckedParseHex(univalue[i].get_str()), 0) >> txout;
+ SpanReader{SER_DISK, 0, CheckedParseHex(univalue[i].get_str()), 0} >> txout;
} catch (const std::ios_base::failure&) {
throw std::runtime_error("Prevout invalid format");
}
diff --git a/src/test/fuzz/utxo_snapshot.cpp b/src/test/fuzz/utxo_snapshot.cpp
index 02039cba81..1b9f0c8a02 100644
--- a/src/test/fuzz/utxo_snapshot.cpp
+++ b/src/test/fuzz/utxo_snapshot.cpp
@@ -38,7 +38,7 @@ FUZZ_TARGET_INIT(utxo_snapshot, initialize_chain)
{
CAutoFile outfile{fsbridge::fopen(snapshot_path, "wb"), SER_DISK, CLIENT_VERSION};
const auto file_data{ConsumeRandomLengthByteVector(fuzzed_data_provider)};
- outfile << Span<const uint8_t>{file_data};
+ outfile << Span{file_data};
}
const auto ActivateFuzzedSnapshot{[&] {
diff --git a/src/test/key_io_tests.cpp b/src/test/key_io_tests.cpp
index 0361618c82..02268dbcf5 100644
--- a/src/test/key_io_tests.cpp
+++ b/src/test/key_io_tests.cpp
@@ -46,7 +46,7 @@ BOOST_AUTO_TEST_CASE(key_io_valid_parse)
privkey = DecodeSecret(exp_base58string);
BOOST_CHECK_MESSAGE(privkey.IsValid(), "!IsValid:" + strTest);
BOOST_CHECK_MESSAGE(privkey.IsCompressed() == isCompressed, "compressed mismatch:" + strTest);
- BOOST_CHECK_MESSAGE(Span<const uint8_t>{privkey} == Span<const uint8_t>{exp_payload}, "key mismatch:" + strTest);
+ BOOST_CHECK_MESSAGE(Span{privkey} == Span{exp_payload}, "key mismatch:" + strTest);
// Private key must be invalid public key
destination = DecodeDestination(exp_base58string);
diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp
index c5bd9c73fd..d0f0e7d50f 100644
--- a/src/test/net_tests.cpp
+++ b/src/test/net_tests.cpp
@@ -386,9 +386,9 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2)
s.SetVersion(s.GetVersion() | ADDRV2_FORMAT);
// Valid IPv4.
- s << MakeSpan(ParseHex("01" // network type (IPv4)
- "04" // address length
- "01020304")); // address
+ s << Span{ParseHex("01" // network type (IPv4)
+ "04" // address length
+ "01020304")}; // address
s >> addr;
BOOST_CHECK(addr.IsValid());
BOOST_CHECK(addr.IsIPv4());
@@ -397,35 +397,35 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2)
BOOST_REQUIRE(s.empty());
// Invalid IPv4, valid length but address itself is shorter.
- s << MakeSpan(ParseHex("01" // network type (IPv4)
- "04" // address length
- "0102")); // address
+ s << Span{ParseHex("01" // network type (IPv4)
+ "04" // address length
+ "0102")}; // address
BOOST_CHECK_EXCEPTION(s >> addr, std::ios_base::failure, HasReason("end of data"));
BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input.
s.clear();
// Invalid IPv4, with bogus length.
- s << MakeSpan(ParseHex("01" // network type (IPv4)
- "05" // address length
- "01020304")); // address
+ s << Span{ParseHex("01" // network type (IPv4)
+ "05" // address length
+ "01020304")}; // address
BOOST_CHECK_EXCEPTION(s >> addr, std::ios_base::failure,
HasReason("BIP155 IPv4 address with length 5 (should be 4)"));
BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input.
s.clear();
// Invalid IPv4, with extreme length.
- s << MakeSpan(ParseHex("01" // network type (IPv4)
- "fd0102" // address length (513 as CompactSize)
- "01020304")); // address
+ s << Span{ParseHex("01" // network type (IPv4)
+ "fd0102" // address length (513 as CompactSize)
+ "01020304")}; // address
BOOST_CHECK_EXCEPTION(s >> addr, std::ios_base::failure,
HasReason("Address too long: 513 > 512"));
BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input.
s.clear();
// Valid IPv6.
- s << MakeSpan(ParseHex("02" // network type (IPv6)
- "10" // address length
- "0102030405060708090a0b0c0d0e0f10")); // address
+ s << Span{ParseHex("02" // network type (IPv6)
+ "10" // address length
+ "0102030405060708090a0b0c0d0e0f10")}; // address
s >> addr;
BOOST_CHECK(addr.IsValid());
BOOST_CHECK(addr.IsIPv6());
@@ -434,10 +434,10 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2)
BOOST_REQUIRE(s.empty());
// Valid IPv6, contains embedded "internal".
- s << MakeSpan(ParseHex(
+ s << Span{ParseHex(
"02" // network type (IPv6)
"10" // address length
- "fd6b88c08724ca978112ca1bbdcafac2")); // address: 0xfd + sha256("bitcoin")[0:5] +
+ "fd6b88c08724ca978112ca1bbdcafac2")}; // address: 0xfd + sha256("bitcoin")[0:5] +
// sha256(name)[0:10]
s >> addr;
BOOST_CHECK(addr.IsInternal());
@@ -446,44 +446,44 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2)
BOOST_REQUIRE(s.empty());
// Invalid IPv6, with bogus length.
- s << MakeSpan(ParseHex("02" // network type (IPv6)
- "04" // address length
- "00")); // address
+ s << Span{ParseHex("02" // network type (IPv6)
+ "04" // address length
+ "00")}; // address
BOOST_CHECK_EXCEPTION(s >> addr, std::ios_base::failure,
HasReason("BIP155 IPv6 address with length 4 (should be 16)"));
BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input.
s.clear();
// Invalid IPv6, contains embedded IPv4.
- s << MakeSpan(ParseHex("02" // network type (IPv6)
- "10" // address length
- "00000000000000000000ffff01020304")); // address
+ s << Span{ParseHex("02" // network type (IPv6)
+ "10" // address length
+ "00000000000000000000ffff01020304")}; // address
s >> addr;
BOOST_CHECK(!addr.IsValid());
BOOST_REQUIRE(s.empty());
// Invalid IPv6, contains embedded TORv2.
- s << MakeSpan(ParseHex("02" // network type (IPv6)
- "10" // address length
- "fd87d87eeb430102030405060708090a")); // address
+ s << Span{ParseHex("02" // network type (IPv6)
+ "10" // address length
+ "fd87d87eeb430102030405060708090a")}; // address
s >> addr;
BOOST_CHECK(!addr.IsValid());
BOOST_REQUIRE(s.empty());
// TORv2, no longer supported.
- s << MakeSpan(ParseHex("03" // network type (TORv2)
- "0a" // address length
- "f1f2f3f4f5f6f7f8f9fa")); // address
+ s << Span{ParseHex("03" // network type (TORv2)
+ "0a" // address length
+ "f1f2f3f4f5f6f7f8f9fa")}; // address
s >> addr;
BOOST_CHECK(!addr.IsValid());
BOOST_REQUIRE(s.empty());
// Valid TORv3.
- s << MakeSpan(ParseHex("04" // network type (TORv3)
- "20" // address length
- "79bcc625184b05194975c28b66b66b04" // address
- "69f7f6556fb1ac3189a79b40dda32f1f"
- ));
+ s << Span{ParseHex("04" // network type (TORv3)
+ "20" // address length
+ "79bcc625184b05194975c28b66b66b04" // address
+ "69f7f6556fb1ac3189a79b40dda32f1f"
+ )};
s >> addr;
BOOST_CHECK(addr.IsValid());
BOOST_CHECK(addr.IsTor());
@@ -493,20 +493,20 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2)
BOOST_REQUIRE(s.empty());
// Invalid TORv3, with bogus length.
- s << MakeSpan(ParseHex("04" // network type (TORv3)
- "00" // address length
- "00" // address
- ));
+ s << Span{ParseHex("04" // network type (TORv3)
+ "00" // address length
+ "00" // address
+ )};
BOOST_CHECK_EXCEPTION(s >> addr, std::ios_base::failure,
HasReason("BIP155 TORv3 address with length 0 (should be 32)"));
BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input.
s.clear();
// Valid I2P.
- s << MakeSpan(ParseHex("05" // network type (I2P)
- "20" // address length
- "a2894dabaec08c0051a481a6dac88b64" // address
- "f98232ae42d4b6fd2fa81952dfe36a87"));
+ s << Span{ParseHex("05" // network type (I2P)
+ "20" // address length
+ "a2894dabaec08c0051a481a6dac88b64" // address
+ "f98232ae42d4b6fd2fa81952dfe36a87")};
s >> addr;
BOOST_CHECK(addr.IsValid());
BOOST_CHECK(addr.IsI2P());
@@ -516,20 +516,20 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2)
BOOST_REQUIRE(s.empty());
// Invalid I2P, with bogus length.
- s << MakeSpan(ParseHex("05" // network type (I2P)
- "03" // address length
- "00" // address
- ));
+ s << Span{ParseHex("05" // network type (I2P)
+ "03" // address length
+ "00" // address
+ )};
BOOST_CHECK_EXCEPTION(s >> addr, std::ios_base::failure,
HasReason("BIP155 I2P address with length 3 (should be 32)"));
BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input.
s.clear();
// Valid CJDNS.
- s << MakeSpan(ParseHex("06" // network type (CJDNS)
- "10" // address length
- "fc000001000200030004000500060007" // address
- ));
+ s << Span{ParseHex("06" // network type (CJDNS)
+ "10" // address length
+ "fc000001000200030004000500060007" // address
+ )};
s >> addr;
BOOST_CHECK(addr.IsValid());
BOOST_CHECK(addr.IsCJDNS());
@@ -538,49 +538,49 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2)
BOOST_REQUIRE(s.empty());
// Invalid CJDNS, wrong prefix.
- s << MakeSpan(ParseHex("06" // network type (CJDNS)
- "10" // address length
- "aa000001000200030004000500060007" // address
- ));
+ s << Span{ParseHex("06" // network type (CJDNS)
+ "10" // address length
+ "aa000001000200030004000500060007" // address
+ )};
s >> addr;
BOOST_CHECK(addr.IsCJDNS());
BOOST_CHECK(!addr.IsValid());
BOOST_REQUIRE(s.empty());
// Invalid CJDNS, with bogus length.
- s << MakeSpan(ParseHex("06" // network type (CJDNS)
- "01" // address length
- "00" // address
- ));
+ s << Span{ParseHex("06" // network type (CJDNS)
+ "01" // address length
+ "00" // address
+ )};
BOOST_CHECK_EXCEPTION(s >> addr, std::ios_base::failure,
HasReason("BIP155 CJDNS address with length 1 (should be 16)"));
BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input.
s.clear();
// Unknown, with extreme length.
- s << MakeSpan(ParseHex("aa" // network type (unknown)
- "fe00000002" // address length (CompactSize's MAX_SIZE)
- "01020304050607" // address
- ));
+ s << Span{ParseHex("aa" // network type (unknown)
+ "fe00000002" // address length (CompactSize's MAX_SIZE)
+ "01020304050607" // address
+ )};
BOOST_CHECK_EXCEPTION(s >> addr, std::ios_base::failure,
HasReason("Address too long: 33554432 > 512"));
BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input.
s.clear();
// Unknown, with reasonable length.
- s << MakeSpan(ParseHex("aa" // network type (unknown)
- "04" // address length
- "01020304" // address
- ));
+ s << Span{ParseHex("aa" // network type (unknown)
+ "04" // address length
+ "01020304" // address
+ )};
s >> addr;
BOOST_CHECK(!addr.IsValid());
BOOST_REQUIRE(s.empty());
// Unknown, with zero length.
- s << MakeSpan(ParseHex("aa" // network type (unknown)
- "00" // address length
- "" // address
- ));
+ s << Span{ParseHex("aa" // network type (unknown)
+ "00" // address length
+ "" // address
+ )};
s >> addr;
BOOST_CHECK(!addr.IsValid());
BOOST_REQUIRE(s.empty());
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index a89eab68e9..12432828ac 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -284,7 +284,7 @@ public:
CScript scriptPubKey = script;
if (wm == WitnessMode::PKH) {
uint160 hash;
- CHash160().Write(MakeSpan(script).subspan(1)).Finalize(hash);
+ CHash160().Write(Span{script}.subspan(1)).Finalize(hash);
script = CScript() << OP_DUP << OP_HASH160 << ToByteVector(hash) << OP_EQUALVERIFY << OP_CHECKSIG;
scriptPubKey = CScript() << witnessversion << ToByteVector(hash);
} else if (wm == WitnessMode::SH) {
@@ -1473,7 +1473,7 @@ BOOST_AUTO_TEST_CASE(script_HasValidOps)
static CMutableTransaction TxFromHex(const std::string& str)
{
CMutableTransaction tx;
- VectorReader(SER_DISK, SERIALIZE_TRANSACTION_NO_WITNESS, ParseHex(str), 0) >> tx;
+ SpanReader{SER_DISK, SERIALIZE_TRANSACTION_NO_WITNESS, ParseHex(str), 0} >> tx;
return tx;
}
@@ -1483,7 +1483,7 @@ static std::vector<CTxOut> TxOutsFromJSON(const UniValue& univalue)
std::vector<CTxOut> prevouts;
for (size_t i = 0; i < univalue.size(); ++i) {
CTxOut txout;
- VectorReader(SER_DISK, 0, ParseHex(univalue[i].get_str()), 0) >> txout;
+ SpanReader{SER_DISK, 0, ParseHex(univalue[i].get_str()), 0} >> txout;
prevouts.push_back(std::move(txout));
}
return prevouts;
@@ -1754,7 +1754,7 @@ BOOST_AUTO_TEST_CASE(bip341_keypath_test_vectors)
for (const auto& vec : vectors.getValues()) {
auto txhex = ParseHex(vec["given"]["rawUnsignedTx"].get_str());
CMutableTransaction tx;
- VectorReader(SER_NETWORK, PROTOCOL_VERSION, txhex, 0) >> tx;
+ SpanReader{SER_NETWORK, PROTOCOL_VERSION, txhex, 0} >> tx;
std::vector<CTxOut> utxos;
for (const auto& utxo_spent : vec["given"]["utxosSpent"].getValues()) {
auto script_bytes = ParseHex(utxo_spent["scriptPubKey"].get_str());
@@ -1812,7 +1812,7 @@ BOOST_AUTO_TEST_CASE(bip341_keypath_test_vectors)
BOOST_CHECK_EQUAL(HexStr(sighash), input["intermediary"]["sigHash"].get_str());
// To verify the sigmsg, hash the expected sigmsg, and compare it with the (expected) sighash.
- BOOST_CHECK_EQUAL(HexStr((CHashWriter(HASHER_TAPSIGHASH) << MakeSpan(ParseHex(input["intermediary"]["sigMsg"].get_str()))).GetSHA256()), input["intermediary"]["sigHash"].get_str());
+ BOOST_CHECK_EQUAL(HexStr((CHashWriter(HASHER_TAPSIGHASH) << Span{ParseHex(input["intermediary"]["sigMsg"].get_str())}).GetSHA256()), input["intermediary"]["sigHash"].get_str());
}
}
diff --git a/src/test/streams_tests.cpp b/src/test/streams_tests.cpp
index b8d76c9608..f551663789 100644
--- a/src/test/streams_tests.cpp
+++ b/src/test/streams_tests.cpp
@@ -71,7 +71,7 @@ BOOST_AUTO_TEST_CASE(streams_vector_reader)
{
std::vector<unsigned char> vch = {1, 255, 3, 4, 5, 6};
- VectorReader reader(SER_NETWORK, INIT_PROTO_VERSION, vch, 0);
+ SpanReader reader{SER_NETWORK, INIT_PROTO_VERSION, vch, 0};
BOOST_CHECK_EQUAL(reader.size(), 6U);
BOOST_CHECK(!reader.empty());
@@ -101,7 +101,7 @@ BOOST_AUTO_TEST_CASE(streams_vector_reader)
BOOST_CHECK_THROW(reader >> d, std::ios_base::failure);
// Read a 4 bytes as a signed int from the beginning of the buffer.
- VectorReader new_reader(SER_NETWORK, INIT_PROTO_VERSION, vch, 0);
+ SpanReader new_reader{SER_NETWORK, INIT_PROTO_VERSION, vch, 0};
new_reader >> d;
BOOST_CHECK_EQUAL(d, 67370753); // 1,255,3,4 in little-endian base-256
BOOST_CHECK_EQUAL(new_reader.size(), 2U);
@@ -115,7 +115,7 @@ BOOST_AUTO_TEST_CASE(streams_vector_reader)
BOOST_AUTO_TEST_CASE(streams_vector_reader_rvalue)
{
std::vector<uint8_t> data{0x82, 0xa7, 0x31};
- VectorReader reader(SER_NETWORK, INIT_PROTO_VERSION, data, /* pos= */ 0);
+ SpanReader reader{SER_NETWORK, INIT_PROTO_VERSION, data, /* pos= */ 0};
uint32_t varint = 0;
// Deserialize into r-value
reader >> VARINT(varint);
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index 76a690fd28..9540cead24 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -142,13 +142,11 @@ BOOST_AUTO_TEST_CASE(util_HexStr)
"04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f");
BOOST_CHECK_EQUAL(
- HexStr(Span<const unsigned char>(
- ParseHex_expected + sizeof(ParseHex_expected),
- ParseHex_expected + sizeof(ParseHex_expected))),
+ HexStr(Span{ParseHex_expected}.last(0)),
"");
BOOST_CHECK_EQUAL(
- HexStr(Span<const unsigned char>(ParseHex_expected, ParseHex_expected)),
+ HexStr(Span{ParseHex_expected}.first(0)),
"");
{
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index 27fbb8acac..fcfc27d38e 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -5,6 +5,7 @@
#include <txmempool.h>
+#include <chain.h>
#include <coins.h>
#include <consensus/consensus.h>
#include <consensus/tx_verify.h>
@@ -73,16 +74,15 @@ private:
const LockPoints& lp;
};
-bool TestLockPointValidity(CChain& active_chain, const LockPoints* lp)
+bool TestLockPointValidity(CChain& active_chain, const LockPoints& lp)
{
AssertLockHeld(cs_main);
- assert(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) {
+ if (lp.maxInputBlock) {
// 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)) {
+ if (!active_chain.Contains(lp.maxInputBlock)) {
return false;
}
}
@@ -649,8 +649,8 @@ void CTxMemPool::removeForReorg(CChain& chain, std::function<bool(txiter)> check
}
RemoveStaged(setAllRemoves, false, MemPoolRemovalReason::REORG);
for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) {
- LockPoints lp = it->GetLockPoints();
- if (!TestLockPointValidity(chain, &lp)) {
+ const LockPoints lp{it->GetLockPoints()};
+ if (!TestLockPointValidity(chain, lp)) {
mapTx.modify(it, update_lock_points(lp));
}
}
diff --git a/src/txmempool.h b/src/txmempool.h
index c6e08a3ca5..f87ecc9cd0 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -14,7 +14,6 @@
#include <utility>
#include <vector>
-#include <chain.h>
#include <coins.h>
#include <consensus/amount.h>
#include <indirectmap.h>
@@ -26,12 +25,13 @@
#include <util/epochguard.h>
#include <util/hasher.h>
-#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/sequenced_index.hpp>
+#include <boost/multi_index_container.hpp>
class CBlockIndex;
+class CChain;
class CChainState;
extern RecursiveMutex cs_main;
@@ -53,7 +53,7 @@ struct LockPoints {
/**
* Test whether the LockPoints height and time are still valid on the current chain
*/
-bool TestLockPointValidity(CChain& active_chain, const LockPoints* lp) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+bool TestLockPointValidity(CChain& active_chain, const LockPoints& lp) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
struct CompareIteratorByHash {
// SFINAE for T where T is either a pointer type (e.g., a txiter) or a reference_wrapper<T>
diff --git a/src/validation.cpp b/src/validation.cpp
index 6ed5e7a548..203bd57676 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -357,7 +357,7 @@ void CChainState::MaybeUpdateMempoolForReorg(
AssertLockHeld(::cs_main);
const CTransaction& tx = it->GetTx();
LockPoints lp = it->GetLockPoints();
- bool validLP = TestLockPointValidity(m_chain, &lp);
+ const bool validLP{TestLockPointValidity(m_chain, lp)};
CCoinsViewMemPool view_mempool(&CoinsTip(), *m_mempool);
if (!CheckFinalTx(m_chain.Tip(), tx, flags)
|| !CheckSequenceLocks(m_chain.Tip(), view_mempool, tx, flags, &lp, validLP)) {
@@ -371,8 +371,8 @@ void CChainState::MaybeUpdateMempoolForReorg(
continue;
const Coin &coin = CoinsTip().AccessCoin(txin.prevout);
assert(!coin.IsSpent());
- unsigned int nMemPoolHeight = m_chain.Tip()->nHeight + 1;
- if (coin.IsSpent() || (coin.IsCoinBase() && ((signed long)nMemPoolHeight) - coin.nHeight < COINBASE_MATURITY)) {
+ const auto mempool_spend_height{m_chain.Tip()->nHeight + 1};
+ if (coin.IsSpent() || (coin.IsCoinBase() && mempool_spend_height - coin.nHeight < COINBASE_MATURITY)) {
should_remove = true;
break;
}
@@ -723,6 +723,8 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
// to coins_to_uncache)
m_view.SetBackend(m_dummy);
+ assert(m_active_chainstate.m_blockman.LookupBlockIndex(m_view.GetBestBlock()) == m_active_chainstate.m_chain.Tip());
+
// Only accept BIP68 sequence locked transactions that can be mined in the next
// block; we don't want our mempool filled up with transactions that can't
// be mined yet.
@@ -731,7 +733,8 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
if (!CheckSequenceLocks(m_active_chainstate.m_chain.Tip(), m_view, tx, STANDARD_LOCKTIME_VERIFY_FLAGS, &lp))
return state.Invalid(TxValidationResult::TX_PREMATURE_SPEND, "non-BIP68-final");
- if (!Consensus::CheckTxInputs(tx, state, m_view, m_active_chainstate.m_blockman.GetSpendHeight(m_view), ws.m_base_fees)) {
+ // The mempool holds txs for the next block, so pass height+1 to CheckTxInputs
+ if (!Consensus::CheckTxInputs(tx, state, m_view, m_active_chainstate.m_chain.Height() + 1, ws.m_base_fees)) {
return false; // state filled in by CheckTxInputs
}
@@ -1311,14 +1314,6 @@ bool CScriptCheck::operator()() {
return VerifyScript(scriptSig, m_tx_out.scriptPubKey, witness, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, m_tx_out.nValue, cacheStore, *txdata), &error);
}
-int BlockManager::GetSpendHeight(const CCoinsViewCache& inputs)
-{
- AssertLockHeld(cs_main);
- CBlockIndex* pindexPrev = LookupBlockIndex(inputs.GetBestBlock());
- return pindexPrev->nHeight + 1;
-}
-
-
static CuckooCache::cache<uint256, SignatureCacheHasher> g_scriptExecutionCache;
static CSHA256 g_scriptExecutionCacheHasher;
diff --git a/src/validation.h b/src/validation.h
index 881438f37a..9385dfdab4 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -478,13 +478,6 @@ public:
//! Returns last CBlockIndex* that is a checkpoint
CBlockIndex* GetLastCheckpoint(const CCheckpointData& data) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
- /**
- * Return the spend height, which is one more than the inputs.GetBestBlock().
- * While checking, GetBestBlock() refers to the parent block. (protected by cs_main)
- * This is also true for mempool checks.
- */
- int GetSpendHeight(const CCoinsViewCache& inputs) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
-
~BlockManager() {
Unload();
}
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpc/backup.cpp
index db22a19a63..a61ebb26b3 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpc/backup.cpp
@@ -35,7 +35,7 @@ std::string static EncodeDumpString(const std::string &str) {
std::stringstream ret;
for (const unsigned char c : str) {
if (c <= 32 || c >= 128 || c == '%') {
- ret << '%' << HexStr(Span<const unsigned char>(&c, 1));
+ ret << '%' << HexStr({&c, 1});
} else {
ret << c;
}
@@ -1808,11 +1808,10 @@ RPCHelpMan listdescriptors()
}
spk.pushKV("desc", descriptor);
spk.pushKV("timestamp", wallet_descriptor.creation_time);
- const bool active = active_spk_mans.count(desc_spk_man) != 0;
- spk.pushKV("active", active);
- const auto& type = wallet_descriptor.descriptor->GetOutputType();
- if (active && type) {
- spk.pushKV("internal", wallet->GetScriptPubKeyMan(*type, true) == desc_spk_man);
+ spk.pushKV("active", active_spk_mans.count(desc_spk_man) != 0);
+ const auto internal = wallet->IsInternalScriptPubKeyMan(desc_spk_man);
+ if (internal.has_value()) {
+ spk.pushKV("internal", *internal);
}
if (wallet_descriptor.descriptor->IsRange()) {
UniValue range(UniValue::VARR);
@@ -1832,3 +1831,99 @@ RPCHelpMan listdescriptors()
},
};
}
+
+RPCHelpMan backupwallet()
+{
+ return RPCHelpMan{"backupwallet",
+ "\nSafely copies current wallet file to destination, which can be a directory or a path with filename.\n",
+ {
+ {"destination", RPCArg::Type::STR, RPCArg::Optional::NO, "The destination directory or file"},
+ },
+ RPCResult{RPCResult::Type::NONE, "", ""},
+ RPCExamples{
+ HelpExampleCli("backupwallet", "\"backup.dat\"")
+ + HelpExampleRpc("backupwallet", "\"backup.dat\"")
+ },
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
+ const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
+ if (!pwallet) return NullUniValue;
+
+ // Make sure the results are valid at least up to the most recent block
+ // the user could have gotten from another RPC command prior to now
+ pwallet->BlockUntilSyncedToCurrentChain();
+
+ LOCK(pwallet->cs_wallet);
+
+ std::string strDest = request.params[0].get_str();
+ if (!pwallet->BackupWallet(strDest)) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
+ }
+
+ return NullUniValue;
+},
+ };
+}
+
+
+RPCHelpMan restorewallet()
+{
+ return RPCHelpMan{
+ "restorewallet",
+ "\nRestore and loads a wallet from backup.\n",
+ {
+ {"wallet_name", RPCArg::Type::STR, RPCArg::Optional::NO, "The name that will be applied to the restored wallet"},
+ {"backup_file", RPCArg::Type::STR, RPCArg::Optional::NO, "The backup file that will be used to restore the wallet."},
+ {"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."},
+ },
+ RPCResult{
+ RPCResult::Type::OBJ, "", "",
+ {
+ {RPCResult::Type::STR, "name", "The wallet name if restored successfully."},
+ {RPCResult::Type::STR, "warning", "Warning message if wallet was not loaded cleanly."},
+ }
+ },
+ RPCExamples{
+ HelpExampleCli("restorewallet", "\"testwallet\" \"home\\backups\\backup-file.bak\"")
+ + HelpExampleRpc("restorewallet", "\"testwallet\" \"home\\backups\\backup-file.bak\"")
+ + HelpExampleCliNamed("restorewallet", {{"wallet_name", "testwallet"}, {"backup_file", "home\\backups\\backup-file.bak\""}, {"load_on_startup", true}})
+ + HelpExampleRpcNamed("restorewallet", {{"wallet_name", "testwallet"}, {"backup_file", "home\\backups\\backup-file.bak\""}, {"load_on_startup", true}})
+ },
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
+
+ WalletContext& context = EnsureWalletContext(request.context);
+
+ 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");
+ }
+
+ std::string wallet_name = request.params[0].get_str();
+
+ 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.u8string()));
+ }
+
+ auto wallet_file = wallet_path / "wallet.dat";
+
+ fs::copy_file(backup_file, wallet_file, fs::copy_option::fail_if_exists);
+
+ auto [wallet, warnings] = LoadWalletHelper(context, request.params[2], wallet_name);
+
+ UniValue obj(UniValue::VOBJ);
+ obj.pushKV("name", wallet->GetName());
+ obj.pushKV("warning", Join(warnings, Untranslated("\n")).original);
+
+ return obj;
+
+},
+ };
+}
diff --git a/src/wallet/rpc/encrypt.cpp b/src/wallet/rpc/encrypt.cpp
new file mode 100644
index 0000000000..e659f434a3
--- /dev/null
+++ b/src/wallet/rpc/encrypt.cpp
@@ -0,0 +1,248 @@
+// Copyright (c) 2011-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.
+
+#include <rpc/util.h>
+#include <wallet/rpc/util.h>
+#include <wallet/wallet.h>
+
+
+RPCHelpMan walletpassphrase()
+{
+ return RPCHelpMan{"walletpassphrase",
+ "\nStores the wallet decryption key in memory for 'timeout' seconds.\n"
+ "This is needed prior to performing transactions related to private keys such as sending bitcoins\n"
+ "\nNote:\n"
+ "Issuing the walletpassphrase command while the wallet is already unlocked will set a new unlock\n"
+ "time that overrides the old one.\n",
+ {
+ {"passphrase", RPCArg::Type::STR, RPCArg::Optional::NO, "The wallet passphrase"},
+ {"timeout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The time to keep the decryption key in seconds; capped at 100000000 (~3 years)."},
+ },
+ RPCResult{RPCResult::Type::NONE, "", ""},
+ RPCExamples{
+ "\nUnlock the wallet for 60 seconds\n"
+ + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 60") +
+ "\nLock the wallet again (before 60 seconds)\n"
+ + HelpExampleCli("walletlock", "") +
+ "\nAs a JSON-RPC call\n"
+ + HelpExampleRpc("walletpassphrase", "\"my pass phrase\", 60")
+ },
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ if (!wallet) return NullUniValue;
+ CWallet* const pwallet = wallet.get();
+
+ int64_t nSleepTime;
+ int64_t relock_time;
+ // Prevent concurrent calls to walletpassphrase with the same wallet.
+ LOCK(pwallet->m_unlock_mutex);
+ {
+ LOCK(pwallet->cs_wallet);
+
+ if (!pwallet->IsCrypted()) {
+ throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
+ }
+
+ // Note that the walletpassphrase is stored in request.params[0] which is not mlock()ed
+ SecureString strWalletPass;
+ strWalletPass.reserve(100);
+ // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
+ // Alternately, find a way to make request.params[0] mlock()'d to begin with.
+ strWalletPass = request.params[0].get_str().c_str();
+
+ // Get the timeout
+ nSleepTime = request.params[1].get_int64();
+ // Timeout cannot be negative, otherwise it will relock immediately
+ if (nSleepTime < 0) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Timeout cannot be negative.");
+ }
+ // Clamp timeout
+ constexpr int64_t MAX_SLEEP_TIME = 100000000; // larger values trigger a macos/libevent bug?
+ if (nSleepTime > MAX_SLEEP_TIME) {
+ nSleepTime = MAX_SLEEP_TIME;
+ }
+
+ if (strWalletPass.empty()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "passphrase can not be empty");
+ }
+
+ if (!pwallet->Unlock(strWalletPass)) {
+ throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
+ }
+
+ pwallet->TopUpKeyPool();
+
+ pwallet->nRelockTime = GetTime() + nSleepTime;
+ relock_time = pwallet->nRelockTime;
+ }
+
+ // rpcRunLater must be called without cs_wallet held otherwise a deadlock
+ // can occur. The deadlock would happen when RPCRunLater removes the
+ // previous timer (and waits for the callback to finish if already running)
+ // and the callback locks cs_wallet.
+ AssertLockNotHeld(wallet->cs_wallet);
+ // Keep a weak pointer to the wallet so that it is possible to unload the
+ // wallet before the following callback is called. If a valid shared pointer
+ // is acquired in the callback then the wallet is still loaded.
+ std::weak_ptr<CWallet> weak_wallet = wallet;
+ pwallet->chain().rpcRunLater(strprintf("lockwallet(%s)", pwallet->GetName()), [weak_wallet, relock_time] {
+ if (auto shared_wallet = weak_wallet.lock()) {
+ LOCK(shared_wallet->cs_wallet);
+ // Skip if this is not the most recent rpcRunLater callback.
+ if (shared_wallet->nRelockTime != relock_time) return;
+ shared_wallet->Lock();
+ shared_wallet->nRelockTime = 0;
+ }
+ }, nSleepTime);
+
+ return NullUniValue;
+},
+ };
+}
+
+
+RPCHelpMan walletpassphrasechange()
+{
+ return RPCHelpMan{"walletpassphrasechange",
+ "\nChanges the wallet passphrase from 'oldpassphrase' to 'newpassphrase'.\n",
+ {
+ {"oldpassphrase", RPCArg::Type::STR, RPCArg::Optional::NO, "The current passphrase"},
+ {"newpassphrase", RPCArg::Type::STR, RPCArg::Optional::NO, "The new passphrase"},
+ },
+ RPCResult{RPCResult::Type::NONE, "", ""},
+ RPCExamples{
+ HelpExampleCli("walletpassphrasechange", "\"old one\" \"new one\"")
+ + HelpExampleRpc("walletpassphrasechange", "\"old one\", \"new one\"")
+ },
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
+ std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!pwallet) return NullUniValue;
+
+ LOCK(pwallet->cs_wallet);
+
+ if (!pwallet->IsCrypted()) {
+ throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
+ }
+
+ // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
+ // Alternately, find a way to make request.params[0] mlock()'d to begin with.
+ SecureString strOldWalletPass;
+ strOldWalletPass.reserve(100);
+ strOldWalletPass = request.params[0].get_str().c_str();
+
+ SecureString strNewWalletPass;
+ strNewWalletPass.reserve(100);
+ strNewWalletPass = request.params[1].get_str().c_str();
+
+ if (strOldWalletPass.empty() || strNewWalletPass.empty()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "passphrase can not be empty");
+ }
+
+ if (!pwallet->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass)) {
+ throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
+ }
+
+ return NullUniValue;
+},
+ };
+}
+
+
+RPCHelpMan walletlock()
+{
+ return RPCHelpMan{"walletlock",
+ "\nRemoves the wallet encryption key from memory, locking the wallet.\n"
+ "After calling this method, you will need to call walletpassphrase again\n"
+ "before being able to call any methods which require the wallet to be unlocked.\n",
+ {},
+ RPCResult{RPCResult::Type::NONE, "", ""},
+ RPCExamples{
+ "\nSet the passphrase for 2 minutes to perform a transaction\n"
+ + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 120") +
+ "\nPerform a send (requires passphrase set)\n"
+ + HelpExampleCli("sendtoaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 1.0") +
+ "\nClear the passphrase since we are done before 2 minutes is up\n"
+ + HelpExampleCli("walletlock", "") +
+ "\nAs a JSON-RPC call\n"
+ + HelpExampleRpc("walletlock", "")
+ },
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
+ std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!pwallet) return NullUniValue;
+
+ LOCK(pwallet->cs_wallet);
+
+ if (!pwallet->IsCrypted()) {
+ throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
+ }
+
+ pwallet->Lock();
+ pwallet->nRelockTime = 0;
+
+ return NullUniValue;
+},
+ };
+}
+
+
+RPCHelpMan encryptwallet()
+{
+ return RPCHelpMan{"encryptwallet",
+ "\nEncrypts the wallet with 'passphrase'. This is for first time encryption.\n"
+ "After this, any calls that interact with private keys such as sending or signing \n"
+ "will require the passphrase to be set prior the making these calls.\n"
+ "Use the walletpassphrase call for this, and then walletlock call.\n"
+ "If the wallet is already encrypted, use the walletpassphrasechange call.\n",
+ {
+ {"passphrase", RPCArg::Type::STR, RPCArg::Optional::NO, "The pass phrase to encrypt the wallet with. It must be at least 1 character, but should be long."},
+ },
+ RPCResult{RPCResult::Type::STR, "", "A string with further instructions"},
+ RPCExamples{
+ "\nEncrypt your wallet\n"
+ + HelpExampleCli("encryptwallet", "\"my pass phrase\"") +
+ "\nNow set the passphrase to use the wallet, such as for signing or sending bitcoin\n"
+ + HelpExampleCli("walletpassphrase", "\"my pass phrase\"") +
+ "\nNow we can do something like sign\n"
+ + HelpExampleCli("signmessage", "\"address\" \"test message\"") +
+ "\nNow lock the wallet again by removing the passphrase\n"
+ + HelpExampleCli("walletlock", "") +
+ "\nAs a JSON-RPC call\n"
+ + HelpExampleRpc("encryptwallet", "\"my pass phrase\"")
+ },
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
+ std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!pwallet) return NullUniValue;
+
+ LOCK(pwallet->cs_wallet);
+
+ if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
+ throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: wallet does not contain private keys, nothing to encrypt.");
+ }
+
+ if (pwallet->IsCrypted()) {
+ throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
+ }
+
+ // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
+ // Alternately, find a way to make request.params[0] mlock()'d to begin with.
+ SecureString strWalletPass;
+ strWalletPass.reserve(100);
+ strWalletPass = request.params[0].get_str().c_str();
+
+ if (strWalletPass.empty()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "passphrase can not be empty");
+ }
+
+ if (!pwallet->EncryptWallet(strWalletPass)) {
+ throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet.");
+ }
+
+ return "wallet encrypted; The keypool has been flushed and a new HD seed was generated (if you are using HD). You need to make a new backup.";
+},
+ };
+}
diff --git a/src/wallet/rpc/util.cpp b/src/wallet/rpc/util.cpp
index b926bfc75f..e2126b7236 100644
--- a/src/wallet/rpc/util.cpp
+++ b/src/wallet/rpc/util.cpp
@@ -5,6 +5,7 @@
#include <wallet/rpc/util.h>
#include <rpc/util.h>
+#include <util/translation.h>
#include <util/url.h>
#include <wallet/context.h>
#include <wallet/wallet.h>
@@ -120,3 +121,34 @@ std::string LabelFromValue(const UniValue& value)
throw JSONRPCError(RPC_WALLET_INVALID_LABEL_NAME, "Invalid label name");
return label;
}
+
+std::tuple<std::shared_ptr<CWallet>, std::vector<bilingual_str>> LoadWalletHelper(WalletContext& context, UniValue load_on_start_param, const std::string wallet_name)
+{
+ DatabaseOptions options;
+ DatabaseStatus status;
+ options.require_existing = true;
+ bilingual_str error;
+ std::vector<bilingual_str> warnings;
+ std::optional<bool> load_on_start = load_on_start_param.isNull() ? std::nullopt : std::optional<bool>(load_on_start_param.get_bool());
+ std::shared_ptr<CWallet> const wallet = LoadWallet(context, wallet_name, load_on_start, options, status, error, warnings);
+
+ if (!wallet) {
+ // Map bad format to not found, since bad format is returned when the
+ // wallet directory exists, but doesn't contain a data file.
+ RPCErrorCode code = RPC_WALLET_ERROR;
+ switch (status) {
+ case DatabaseStatus::FAILED_NOT_FOUND:
+ case DatabaseStatus::FAILED_BAD_FORMAT:
+ code = RPC_WALLET_NOT_FOUND;
+ break;
+ case DatabaseStatus::FAILED_ALREADY_LOADED:
+ code = RPC_WALLET_ALREADY_LOADED;
+ break;
+ default: // RPC_WALLET_ERROR is returned for all other cases.
+ break;
+ }
+ throw JSONRPCError(code, error.original);
+ }
+
+ return { wallet, warnings };
+}
diff --git a/src/wallet/rpc/util.h b/src/wallet/rpc/util.h
index a493a80a74..a1fa4d49b1 100644
--- a/src/wallet/rpc/util.h
+++ b/src/wallet/rpc/util.h
@@ -8,7 +8,9 @@
#include <any>
#include <memory>
#include <string>
+#include <vector>
+struct bilingual_str;
class CWallet;
class JSONRPCRequest;
class LegacyScriptPubKeyMan;
@@ -35,4 +37,6 @@ bool GetAvoidReuseFlag(const CWallet& wallet, const UniValue& param);
bool ParseIncludeWatchonly(const UniValue& include_watchonly, const CWallet& wallet);
std::string LabelFromValue(const UniValue& value);
+std::tuple<std::shared_ptr<CWallet>, std::vector<bilingual_str>> LoadWalletHelper(WalletContext& context, UniValue load_on_start_param, const std::string wallet_name);
+
#endif // BITCOIN_WALLET_RPC_UTIL_H
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 8cb2c46b63..181dd1bd54 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -1656,41 +1656,6 @@ static RPCHelpMan abandontransaction()
};
}
-
-static RPCHelpMan backupwallet()
-{
- return RPCHelpMan{"backupwallet",
- "\nSafely copies current wallet file to destination, which can be a directory or a path with filename.\n",
- {
- {"destination", RPCArg::Type::STR, RPCArg::Optional::NO, "The destination directory or file"},
- },
- RPCResult{RPCResult::Type::NONE, "", ""},
- RPCExamples{
- HelpExampleCli("backupwallet", "\"backup.dat\"")
- + HelpExampleRpc("backupwallet", "\"backup.dat\"")
- },
- [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
-{
- const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
-
- // Make sure the results are valid at least up to the most recent block
- // the user could have gotten from another RPC command prior to now
- pwallet->BlockUntilSyncedToCurrentChain();
-
- LOCK(pwallet->cs_wallet);
-
- std::string strDest = request.params[0].get_str();
- if (!pwallet->BackupWallet(strDest)) {
- throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
- }
-
- return NullUniValue;
-},
- };
-}
-
-
static RPCHelpMan keypoolrefill()
{
return RPCHelpMan{"keypoolrefill",
@@ -1762,247 +1727,6 @@ static RPCHelpMan newkeypool()
};
}
-
-static RPCHelpMan walletpassphrase()
-{
- return RPCHelpMan{"walletpassphrase",
- "\nStores the wallet decryption key in memory for 'timeout' seconds.\n"
- "This is needed prior to performing transactions related to private keys such as sending bitcoins\n"
- "\nNote:\n"
- "Issuing the walletpassphrase command while the wallet is already unlocked will set a new unlock\n"
- "time that overrides the old one.\n",
- {
- {"passphrase", RPCArg::Type::STR, RPCArg::Optional::NO, "The wallet passphrase"},
- {"timeout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The time to keep the decryption key in seconds; capped at 100000000 (~3 years)."},
- },
- RPCResult{RPCResult::Type::NONE, "", ""},
- RPCExamples{
- "\nUnlock the wallet for 60 seconds\n"
- + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 60") +
- "\nLock the wallet again (before 60 seconds)\n"
- + HelpExampleCli("walletlock", "") +
- "\nAs a JSON-RPC call\n"
- + HelpExampleRpc("walletpassphrase", "\"my pass phrase\", 60")
- },
- [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
-{
- std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
- if (!wallet) return NullUniValue;
- CWallet* const pwallet = wallet.get();
-
- int64_t nSleepTime;
- int64_t relock_time;
- // Prevent concurrent calls to walletpassphrase with the same wallet.
- LOCK(pwallet->m_unlock_mutex);
- {
- LOCK(pwallet->cs_wallet);
-
- if (!pwallet->IsCrypted()) {
- throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
- }
-
- // Note that the walletpassphrase is stored in request.params[0] which is not mlock()ed
- SecureString strWalletPass;
- strWalletPass.reserve(100);
- // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
- // Alternately, find a way to make request.params[0] mlock()'d to begin with.
- strWalletPass = request.params[0].get_str().c_str();
-
- // Get the timeout
- nSleepTime = request.params[1].get_int64();
- // Timeout cannot be negative, otherwise it will relock immediately
- if (nSleepTime < 0) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Timeout cannot be negative.");
- }
- // Clamp timeout
- constexpr int64_t MAX_SLEEP_TIME = 100000000; // larger values trigger a macos/libevent bug?
- if (nSleepTime > MAX_SLEEP_TIME) {
- nSleepTime = MAX_SLEEP_TIME;
- }
-
- if (strWalletPass.empty()) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "passphrase can not be empty");
- }
-
- if (!pwallet->Unlock(strWalletPass)) {
- throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
- }
-
- pwallet->TopUpKeyPool();
-
- pwallet->nRelockTime = GetTime() + nSleepTime;
- relock_time = pwallet->nRelockTime;
- }
-
- // rpcRunLater must be called without cs_wallet held otherwise a deadlock
- // can occur. The deadlock would happen when RPCRunLater removes the
- // previous timer (and waits for the callback to finish if already running)
- // and the callback locks cs_wallet.
- AssertLockNotHeld(wallet->cs_wallet);
- // Keep a weak pointer to the wallet so that it is possible to unload the
- // wallet before the following callback is called. If a valid shared pointer
- // is acquired in the callback then the wallet is still loaded.
- std::weak_ptr<CWallet> weak_wallet = wallet;
- pwallet->chain().rpcRunLater(strprintf("lockwallet(%s)", pwallet->GetName()), [weak_wallet, relock_time] {
- if (auto shared_wallet = weak_wallet.lock()) {
- LOCK(shared_wallet->cs_wallet);
- // Skip if this is not the most recent rpcRunLater callback.
- if (shared_wallet->nRelockTime != relock_time) return;
- shared_wallet->Lock();
- shared_wallet->nRelockTime = 0;
- }
- }, nSleepTime);
-
- return NullUniValue;
-},
- };
-}
-
-
-static RPCHelpMan walletpassphrasechange()
-{
- return RPCHelpMan{"walletpassphrasechange",
- "\nChanges the wallet passphrase from 'oldpassphrase' to 'newpassphrase'.\n",
- {
- {"oldpassphrase", RPCArg::Type::STR, RPCArg::Optional::NO, "The current passphrase"},
- {"newpassphrase", RPCArg::Type::STR, RPCArg::Optional::NO, "The new passphrase"},
- },
- RPCResult{RPCResult::Type::NONE, "", ""},
- RPCExamples{
- HelpExampleCli("walletpassphrasechange", "\"old one\" \"new one\"")
- + HelpExampleRpc("walletpassphrasechange", "\"old one\", \"new one\"")
- },
- [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
-{
- std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
-
- LOCK(pwallet->cs_wallet);
-
- if (!pwallet->IsCrypted()) {
- throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
- }
-
- // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
- // Alternately, find a way to make request.params[0] mlock()'d to begin with.
- SecureString strOldWalletPass;
- strOldWalletPass.reserve(100);
- strOldWalletPass = request.params[0].get_str().c_str();
-
- SecureString strNewWalletPass;
- strNewWalletPass.reserve(100);
- strNewWalletPass = request.params[1].get_str().c_str();
-
- if (strOldWalletPass.empty() || strNewWalletPass.empty()) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "passphrase can not be empty");
- }
-
- if (!pwallet->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass)) {
- throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
- }
-
- return NullUniValue;
-},
- };
-}
-
-
-static RPCHelpMan walletlock()
-{
- return RPCHelpMan{"walletlock",
- "\nRemoves the wallet encryption key from memory, locking the wallet.\n"
- "After calling this method, you will need to call walletpassphrase again\n"
- "before being able to call any methods which require the wallet to be unlocked.\n",
- {},
- RPCResult{RPCResult::Type::NONE, "", ""},
- RPCExamples{
- "\nSet the passphrase for 2 minutes to perform a transaction\n"
- + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 120") +
- "\nPerform a send (requires passphrase set)\n"
- + HelpExampleCli("sendtoaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 1.0") +
- "\nClear the passphrase since we are done before 2 minutes is up\n"
- + HelpExampleCli("walletlock", "") +
- "\nAs a JSON-RPC call\n"
- + HelpExampleRpc("walletlock", "")
- },
- [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
-{
- std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
-
- LOCK(pwallet->cs_wallet);
-
- if (!pwallet->IsCrypted()) {
- throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
- }
-
- pwallet->Lock();
- pwallet->nRelockTime = 0;
-
- return NullUniValue;
-},
- };
-}
-
-
-static RPCHelpMan encryptwallet()
-{
- return RPCHelpMan{"encryptwallet",
- "\nEncrypts the wallet with 'passphrase'. This is for first time encryption.\n"
- "After this, any calls that interact with private keys such as sending or signing \n"
- "will require the passphrase to be set prior the making these calls.\n"
- "Use the walletpassphrase call for this, and then walletlock call.\n"
- "If the wallet is already encrypted, use the walletpassphrasechange call.\n",
- {
- {"passphrase", RPCArg::Type::STR, RPCArg::Optional::NO, "The pass phrase to encrypt the wallet with. It must be at least 1 character, but should be long."},
- },
- RPCResult{RPCResult::Type::STR, "", "A string with further instructions"},
- RPCExamples{
- "\nEncrypt your wallet\n"
- + HelpExampleCli("encryptwallet", "\"my pass phrase\"") +
- "\nNow set the passphrase to use the wallet, such as for signing or sending bitcoin\n"
- + HelpExampleCli("walletpassphrase", "\"my pass phrase\"") +
- "\nNow we can do something like sign\n"
- + HelpExampleCli("signmessage", "\"address\" \"test message\"") +
- "\nNow lock the wallet again by removing the passphrase\n"
- + HelpExampleCli("walletlock", "") +
- "\nAs a JSON-RPC call\n"
- + HelpExampleRpc("encryptwallet", "\"my pass phrase\"")
- },
- [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
-{
- std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
-
- LOCK(pwallet->cs_wallet);
-
- if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
- throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: wallet does not contain private keys, nothing to encrypt.");
- }
-
- if (pwallet->IsCrypted()) {
- throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
- }
-
- // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
- // Alternately, find a way to make request.params[0] mlock()'d to begin with.
- SecureString strWalletPass;
- strWalletPass.reserve(100);
- strWalletPass = request.params[0].get_str().c_str();
-
- if (strWalletPass.empty()) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "passphrase can not be empty");
- }
-
- if (!pwallet->EncryptWallet(strWalletPass)) {
- throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet.");
- }
-
- return "wallet encrypted; The keypool has been flushed and a new HD seed was generated (if you are using HD). You need to make a new backup.";
-},
- };
-}
-
static RPCHelpMan lockunspent()
{
return RPCHelpMan{"lockunspent",
@@ -2467,37 +2191,6 @@ static RPCHelpMan listwallets()
};
}
-static std::tuple<std::shared_ptr<CWallet>, std::vector<bilingual_str>> LoadWalletHelper(WalletContext& context, UniValue load_on_start_param, const std::string wallet_name)
-{
- DatabaseOptions options;
- DatabaseStatus status;
- options.require_existing = true;
- bilingual_str error;
- std::vector<bilingual_str> warnings;
- std::optional<bool> load_on_start = load_on_start_param.isNull() ? std::nullopt : std::optional<bool>(load_on_start_param.get_bool());
- std::shared_ptr<CWallet> const wallet = LoadWallet(context, wallet_name, load_on_start, options, status, error, warnings);
-
- if (!wallet) {
- // Map bad format to not found, since bad format is returned when the
- // wallet directory exists, but doesn't contain a data file.
- RPCErrorCode code = RPC_WALLET_ERROR;
- switch (status) {
- case DatabaseStatus::FAILED_NOT_FOUND:
- case DatabaseStatus::FAILED_BAD_FORMAT:
- code = RPC_WALLET_NOT_FOUND;
- break;
- case DatabaseStatus::FAILED_ALREADY_LOADED:
- code = RPC_WALLET_ALREADY_LOADED;
- break;
- default: // RPC_WALLET_ERROR is returned for all other cases.
- break;
- }
- throw JSONRPCError(code, error.original);
- }
-
- return { wallet, warnings };
-}
-
static RPCHelpMan loadwallet()
{
return RPCHelpMan{"loadwallet",
@@ -2697,68 +2390,6 @@ static RPCHelpMan createwallet()
};
}
-static RPCHelpMan restorewallet()
-{
- return RPCHelpMan{
- "restorewallet",
- "\nRestore and loads a wallet from backup.\n",
- {
- {"wallet_name", RPCArg::Type::STR, RPCArg::Optional::NO, "The name that will be applied to the restored wallet"},
- {"backup_file", RPCArg::Type::STR, RPCArg::Optional::NO, "The backup file that will be used to restore the wallet."},
- {"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."},
- },
- RPCResult{
- RPCResult::Type::OBJ, "", "",
- {
- {RPCResult::Type::STR, "name", "The wallet name if restored successfully."},
- {RPCResult::Type::STR, "warning", "Warning message if wallet was not loaded cleanly."},
- }
- },
- RPCExamples{
- HelpExampleCli("restorewallet", "\"testwallet\" \"home\\backups\\backup-file.bak\"")
- + HelpExampleRpc("restorewallet", "\"testwallet\" \"home\\backups\\backup-file.bak\"")
- + HelpExampleCliNamed("restorewallet", {{"wallet_name", "testwallet"}, {"backup_file", "home\\backups\\backup-file.bak\""}, {"load_on_startup", true}})
- + HelpExampleRpcNamed("restorewallet", {{"wallet_name", "testwallet"}, {"backup_file", "home\\backups\\backup-file.bak\""}, {"load_on_startup", true}})
- },
- [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
-{
-
- WalletContext& context = EnsureWalletContext(request.context);
-
- 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");
- }
-
- std::string wallet_name = request.params[0].get_str();
-
- 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.u8string()));
- }
-
- auto wallet_file = wallet_path / "wallet.dat";
-
- fs::copy_file(backup_file, wallet_file, fs::copy_option::fail_if_exists);
-
- auto [wallet, warnings] = LoadWalletHelper(context, request.params[2], wallet_name);
-
- UniValue obj(UniValue::VOBJ);
- obj.pushKV("name", wallet->GetName());
- obj.pushKV("warning", Join(warnings, Untranslated("\n")).original);
-
- return obj;
-
-},
- };
-}
-
static RPCHelpMan unloadwallet()
{
return RPCHelpMan{"unloadwallet",
@@ -3940,8 +3571,12 @@ RPCHelpMan getaddressinfo()
ret.pushKV("solvable", false);
}
+ const auto& spk_mans = pwallet->GetScriptPubKeyMans(scriptPubKey);
+ // In most cases there is only one matching ScriptPubKey manager and we can't resolve ambiguity in a better way
+ ScriptPubKeyMan* spk_man{nullptr};
+ if (spk_mans.size()) spk_man = *spk_mans.begin();
- DescriptorScriptPubKeyMan* desc_spk_man = dynamic_cast<DescriptorScriptPubKeyMan*>(pwallet->GetScriptPubKeyMan(scriptPubKey));
+ DescriptorScriptPubKeyMan* desc_spk_man = dynamic_cast<DescriptorScriptPubKeyMan*>(spk_man);
if (desc_spk_man) {
std::string desc_str;
if (desc_spk_man->GetDescriptorString(desc_str, /* priv */ false)) {
@@ -3956,7 +3591,6 @@ RPCHelpMan getaddressinfo()
ret.pushKV("ischange", ScriptIsChange(*pwallet, scriptPubKey));
- ScriptPubKeyMan* spk_man = pwallet->GetScriptPubKeyMan(scriptPubKey);
if (spk_man) {
if (const std::unique_ptr<CKeyMetadata> meta = spk_man->GetMetadata(dest)) {
ret.pushKV("timestamp", meta->nCreateTime);
@@ -4696,6 +4330,14 @@ RPCHelpMan importmulti();
RPCHelpMan importdescriptors();
RPCHelpMan listdescriptors();
RPCHelpMan signmessage();
+RPCHelpMan backupwallet();
+RPCHelpMan restorewallet();
+
+// encryption
+RPCHelpMan walletpassphrase();
+RPCHelpMan walletpassphrasechange();
+RPCHelpMan walletlock();
+RPCHelpMan encryptwallet();
Span<const CRPCCommand> GetWalletRPCCommands()
{
@@ -4771,5 +4413,5 @@ static const CRPCCommand commands[] =
{ "wallet", &walletprocesspsbt, },
};
// clang-format on
- return MakeSpan(commands);
+ return commands;
}
diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp
index a82eaa4879..1769429efe 100644
--- a/src/wallet/scriptpubkeyman.cpp
+++ b/src/wallet/scriptpubkeyman.cpp
@@ -354,15 +354,22 @@ bool LegacyScriptPubKeyMan::TopUpInactiveHDChain(const CKeyID seed_id, int64_t i
return true;
}
-void LegacyScriptPubKeyMan::MarkUnusedAddresses(const CScript& script)
+std::vector<WalletDestination> LegacyScriptPubKeyMan::MarkUnusedAddresses(const CScript& script)
{
LOCK(cs_KeyStore);
+ std::vector<WalletDestination> result;
// extract addresses and check if they match with an unused keypool key
for (const auto& keyid : GetAffectedKeys(script, *this)) {
std::map<CKeyID, int64_t>::const_iterator mi = m_pool_key_to_index.find(keyid);
if (mi != m_pool_key_to_index.end()) {
WalletLogPrintf("%s: Detected a used keypool key, mark all keypool keys up to this key as used\n", __func__);
- MarkReserveKeysAsUsed(mi->second);
+ for (const auto& keypool : MarkReserveKeysAsUsed(mi->second)) {
+ // derive all possible destinations as any of them could have been used
+ for (const auto& type : LEGACY_OUTPUT_TYPES) {
+ const auto& dest = GetDestinationForKey(keypool.vchPubKey, type);
+ result.push_back({dest, keypool.fInternal});
+ }
+ }
if (!TopUp()) {
WalletLogPrintf("%s: Topping up keypool failed (locked wallet)\n", __func__);
@@ -384,6 +391,8 @@ void LegacyScriptPubKeyMan::MarkUnusedAddresses(const CScript& script)
}
}
}
+
+ return result;
}
void LegacyScriptPubKeyMan::UpgradeKeyMetadata()
@@ -1427,7 +1436,7 @@ void LegacyScriptPubKeyMan::LearnAllRelatedScripts(const CPubKey& key)
LearnRelatedScripts(key, OutputType::P2SH_SEGWIT);
}
-void LegacyScriptPubKeyMan::MarkReserveKeysAsUsed(int64_t keypool_id)
+std::vector<CKeyPool> LegacyScriptPubKeyMan::MarkReserveKeysAsUsed(int64_t keypool_id)
{
AssertLockHeld(cs_KeyStore);
bool internal = setInternalKeyPool.count(keypool_id);
@@ -1435,6 +1444,7 @@ void LegacyScriptPubKeyMan::MarkReserveKeysAsUsed(int64_t keypool_id)
std::set<int64_t> *setKeyPool = internal ? &setInternalKeyPool : (set_pre_split_keypool.empty() ? &setExternalKeyPool : &set_pre_split_keypool);
auto it = setKeyPool->begin();
+ std::vector<CKeyPool> result;
WalletBatch batch(m_storage.GetDatabase());
while (it != std::end(*setKeyPool)) {
const int64_t& index = *(it);
@@ -1448,7 +1458,10 @@ void LegacyScriptPubKeyMan::MarkReserveKeysAsUsed(int64_t keypool_id)
batch.ErasePool(index);
WalletLogPrintf("keypool index %d removed\n", index);
it = setKeyPool->erase(it);
+ result.push_back(std::move(keypool));
}
+
+ return result;
}
std::vector<CKeyID> GetAffectedKeys(const CScript& spk, const SigningProvider& provider)
@@ -1820,19 +1833,32 @@ bool DescriptorScriptPubKeyMan::TopUp(unsigned int size)
return true;
}
-void DescriptorScriptPubKeyMan::MarkUnusedAddresses(const CScript& script)
+std::vector<WalletDestination> DescriptorScriptPubKeyMan::MarkUnusedAddresses(const CScript& script)
{
LOCK(cs_desc_man);
+ std::vector<WalletDestination> result;
if (IsMine(script)) {
int32_t index = m_map_script_pub_keys[script];
if (index >= m_wallet_descriptor.next_index) {
WalletLogPrintf("%s: Detected a used keypool item at index %d, mark all keypool items up to this item as used\n", __func__, index);
- m_wallet_descriptor.next_index = index + 1;
+ auto out_keys = std::make_unique<FlatSigningProvider>();
+ std::vector<CScript> scripts_temp;
+ while (index >= m_wallet_descriptor.next_index) {
+ if (!m_wallet_descriptor.descriptor->ExpandFromCache(m_wallet_descriptor.next_index, m_wallet_descriptor.cache, scripts_temp, *out_keys)) {
+ throw std::runtime_error(std::string(__func__) + ": Unable to expand descriptor from cache");
+ }
+ CTxDestination dest;
+ ExtractDestination(scripts_temp[0], dest);
+ result.push_back({dest, std::nullopt});
+ m_wallet_descriptor.next_index++;
+ }
}
if (!TopUp()) {
WalletLogPrintf("%s: Topping up keypool failed (locked wallet)\n", __func__);
}
}
+
+ return result;
}
void DescriptorScriptPubKeyMan::AddDescriptorKey(const CKey& key, const CPubKey &pubkey)
diff --git a/src/wallet/scriptpubkeyman.h b/src/wallet/scriptpubkeyman.h
index 9d2304a542..ebe064fa0a 100644
--- a/src/wallet/scriptpubkeyman.h
+++ b/src/wallet/scriptpubkeyman.h
@@ -149,6 +149,12 @@ public:
}
};
+struct WalletDestination
+{
+ CTxDestination dest;
+ std::optional<bool> internal;
+};
+
/*
* A class implementing ScriptPubKeyMan manages some (or all) scriptPubKeys used in a wallet.
* It contains the scripts and keys related to the scriptPubKeys it manages.
@@ -181,8 +187,14 @@ public:
*/
virtual bool TopUp(unsigned int size = 0) { return false; }
- //! Mark unused addresses as being used
- virtual void MarkUnusedAddresses(const CScript& script) {}
+ /** Mark unused addresses as being used
+ * Affects all keys up to and including the one determined by provided script.
+ *
+ * @param script determines the last key to mark as used
+ *
+ * @return All of the addresses affected
+ */
+ virtual std::vector<WalletDestination> MarkUnusedAddresses(const CScript& script) { return {}; }
/** Sets up the key generation stuff, i.e. generates new HD seeds and sets them as active.
* Returns false if already setup or setup fails, true if setup is successful
@@ -357,7 +369,7 @@ public:
bool TopUp(unsigned int size = 0) override;
- void MarkUnusedAddresses(const CScript& script) override;
+ std::vector<WalletDestination> MarkUnusedAddresses(const CScript& script) override;
//! Upgrade stored CKeyMetadata objects to store key origin info as KeyOriginInfo
void UpgradeKeyMetadata();
@@ -482,9 +494,13 @@ public:
void LearnAllRelatedScripts(const CPubKey& key);
/**
- * Marks all keys in the keypool up to and including reserve_key as used.
+ * Marks all keys in the keypool up to and including the provided key as used.
+ *
+ * @param keypool_id determines the last key to mark as used
+ *
+ * @return All affected keys
*/
- void MarkReserveKeysAsUsed(int64_t keypool_id) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore);
+ std::vector<CKeyPool> MarkReserveKeysAsUsed(int64_t keypool_id) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore);
const std::map<CKeyID, int64_t>& GetAllReserveKeys() const { return m_pool_key_to_index; }
std::set<CKeyID> GetKeys() const override;
@@ -564,7 +580,7 @@ public:
// (with or without private keys), the "keypool" is a single xpub.
bool TopUp(unsigned int size = 0) override;
- void MarkUnusedAddresses(const CScript& script) override;
+ std::vector<WalletDestination> MarkUnusedAddresses(const CScript& script) override;
bool IsHDEnabled() const override;
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index 9842089cf8..b4141d1f9e 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -682,7 +682,7 @@ BOOST_FIXTURE_TEST_CASE(wallet_descriptor_test, BasicTestingSetup)
vw << (int32_t)0;
vw << (int32_t)1;
- VectorReader vr(0, 0, malformed_record, 0);
+ SpanReader vr{0, 0, malformed_record, 0};
WalletDescriptor w_desc;
BOOST_CHECK_EXCEPTION(vr >> w_desc, std::ios_base::failure, malformed_descriptor);
}
@@ -816,30 +816,35 @@ BOOST_FIXTURE_TEST_CASE(ZapSelectTx, TestChain100Setup)
context.args = &gArgs;
context.chain = m_node.chain.get();
auto wallet = TestLoadWallet(context);
- CKey key;
- key.MakeNewKey(true);
- AddKey(*wallet, key);
+ AddKey(*wallet, coinbaseKey);
- std::string error;
+ // rescan to ensure coinbase transactions from test fixture are picked up by the wallet
+ {
+ WalletRescanReserver reserver(*wallet);
+ reserver.reserve();
+ wallet->ScanForWalletTransactions(m_node.chain->getBlockHash(0), 0, /* max height= */ {}, reserver, /* update= */ true);
+ }
+ // create one more block to get the first block coinbase to maturity
m_coinbase_txns.push_back(CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]);
- auto block_tx = TestSimpleSpend(*m_coinbase_txns[0], 0, coinbaseKey, GetScriptForRawPubKey(key.GetPubKey()));
- CreateAndProcessBlock({block_tx}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
+ // spend first coinbase tx
+ auto spend_tx = TestSimpleSpend(*m_coinbase_txns[0], 0, coinbaseKey, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
+ CreateAndProcessBlock({spend_tx}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
SyncWithValidationInterfaceQueue();
{
- auto block_hash = block_tx.GetHash();
+ auto spend_tx_hash = spend_tx.GetHash();
auto prev_hash = m_coinbase_txns[0]->GetHash();
LOCK(wallet->cs_wallet);
BOOST_CHECK(wallet->HasWalletSpend(prev_hash));
- BOOST_CHECK_EQUAL(wallet->mapWallet.count(block_hash), 1u);
+ BOOST_CHECK_EQUAL(wallet->mapWallet.count(spend_tx_hash), 1u);
- std::vector<uint256> vHashIn{ block_hash }, vHashOut;
+ std::vector<uint256> vHashIn{spend_tx_hash}, vHashOut;
BOOST_CHECK_EQUAL(wallet->ZapSelectTx(vHashIn, vHashOut), DBErrors::LOAD_OK);
BOOST_CHECK(!wallet->HasWalletSpend(prev_hash));
- BOOST_CHECK_EQUAL(wallet->mapWallet.count(block_hash), 0u);
+ BOOST_CHECK_EQUAL(wallet->mapWallet.count(spend_tx_hash), 0u);
}
TestUnloadWallet(std::move(wallet));
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index e4c3822305..2e4b6a6eb0 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -919,7 +919,9 @@ CWalletTx* CWallet::AddToWallet(CTransactionRef tx, const TxState& state, const
wtx.nOrderPos = IncOrderPosNext(&batch);
wtx.m_it_wtxOrdered = wtxOrdered.insert(std::make_pair(wtx.nOrderPos, &wtx));
wtx.nTimeSmart = ComputeTimeSmart(wtx, rescanning_old_block);
- AddToSpends(hash, &batch);
+ if (IsFromMe(*tx.get())) {
+ AddToSpends(hash);
+ }
}
if (!fInsertedNew)
@@ -1061,8 +1063,23 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, const SyncTxS
// loop though all outputs
for (const CTxOut& txout: tx.vout) {
- for (const auto& spk_man_pair : m_spk_managers) {
- spk_man_pair.second->MarkUnusedAddresses(txout.scriptPubKey);
+ for (const auto& spk_man : GetScriptPubKeyMans(txout.scriptPubKey)) {
+ for (auto &dest : spk_man->MarkUnusedAddresses(txout.scriptPubKey)) {
+ // If internal flag is not defined try to infer it from the ScriptPubKeyMan
+ if (!dest.internal.has_value()) {
+ dest.internal = IsInternalScriptPubKeyMan(spk_man);
+ }
+
+ // skip if can't determine whether it's a receiving address or not
+ if (!dest.internal.has_value()) continue;
+
+ // If this is a receiving address and it's not in the address book yet
+ // (e.g. it wasn't generated on this node or we're restoring from backup)
+ // add it to the address book for proper transaction accounting
+ if (!*dest.internal && !FindAddressBookEntry(dest.dest, /* allow_change= */ false)) {
+ SetAddressBook(dest.dest, "", "receive");
+ }
+ }
}
}
@@ -2253,16 +2270,15 @@ void ReserveDestination::ReturnDestination()
bool CWallet::DisplayAddress(const CTxDestination& dest)
{
CScript scriptPubKey = GetScriptForDestination(dest);
- const auto spk_man = GetScriptPubKeyMan(scriptPubKey);
- if (spk_man == nullptr) {
- return false;
- }
- auto signer_spk_man = dynamic_cast<ExternalSignerScriptPubKeyMan*>(spk_man);
- if (signer_spk_man == nullptr) {
- return false;
+ for (const auto& spk_man : GetScriptPubKeyMans(scriptPubKey)) {
+ auto signer_spk_man = dynamic_cast<ExternalSignerScriptPubKeyMan *>(spk_man);
+ if (signer_spk_man == nullptr) {
+ continue;
+ }
+ ExternalSigner signer = ExternalSignerScriptPubKeyMan::GetExternalSigner();
+ return signer_spk_man->DisplayAddress(scriptPubKey, signer);
}
- ExternalSigner signer = ExternalSignerScriptPubKeyMan::GetExternalSigner();
- return signer_spk_man->DisplayAddress(scriptPubKey, signer);
+ return false;
}
bool CWallet::LockCoin(const COutPoint& output, WalletBatch* batch)
@@ -3050,9 +3066,10 @@ ScriptPubKeyMan* CWallet::GetScriptPubKeyMan(const OutputType& type, bool intern
return it->second;
}
-std::set<ScriptPubKeyMan*> CWallet::GetScriptPubKeyMans(const CScript& script, SignatureData& sigdata) const
+std::set<ScriptPubKeyMan*> CWallet::GetScriptPubKeyMans(const CScript& script) const
{
std::set<ScriptPubKeyMan*> spk_mans;
+ SignatureData sigdata;
for (const auto& spk_man_pair : m_spk_managers) {
if (spk_man_pair.second->CanProvide(script, sigdata)) {
spk_mans.insert(spk_man_pair.second.get());
@@ -3061,17 +3078,6 @@ std::set<ScriptPubKeyMan*> CWallet::GetScriptPubKeyMans(const CScript& script, S
return spk_mans;
}
-ScriptPubKeyMan* CWallet::GetScriptPubKeyMan(const CScript& script) const
-{
- SignatureData sigdata;
- for (const auto& spk_man_pair : m_spk_managers) {
- if (spk_man_pair.second->CanProvide(script, sigdata)) {
- return spk_man_pair.second.get();
- }
- }
- return nullptr;
-}
-
ScriptPubKeyMan* CWallet::GetScriptPubKeyMan(const uint256& id) const
{
if (m_spk_managers.count(id) > 0) {
@@ -3287,6 +3293,30 @@ DescriptorScriptPubKeyMan* CWallet::GetDescriptorScriptPubKeyMan(const WalletDes
return nullptr;
}
+std::optional<bool> CWallet::IsInternalScriptPubKeyMan(ScriptPubKeyMan* spk_man) const
+{
+ // Legacy script pubkey man can't be either external or internal
+ if (IsLegacy()) {
+ return std::nullopt;
+ }
+
+ // only active ScriptPubKeyMan can be internal
+ if (!GetActiveScriptPubKeyMans().count(spk_man)) {
+ return std::nullopt;
+ }
+
+ const auto desc_spk_man = dynamic_cast<DescriptorScriptPubKeyMan*>(spk_man);
+ if (!desc_spk_man) {
+ throw std::runtime_error(std::string(__func__) + ": unexpected ScriptPubKeyMan type.");
+ }
+
+ LOCK(desc_spk_man->cs_desc_man);
+ const auto& type = desc_spk_man->GetWalletDescriptor().descriptor->GetOutputType();
+ assert(type.has_value());
+
+ return GetScriptPubKeyMan(*type, /* internal= */ true) == desc_spk_man;
+}
+
ScriptPubKeyMan* CWallet::AddWalletDescriptor(WalletDescriptor& desc, const FlatSigningProvider& signing_provider, const std::string& label, bool internal)
{
AssertLockHeld(cs_wallet);
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index e294358609..dbf0f6375d 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -809,14 +809,11 @@ public:
//! Get the ScriptPubKeyMan for the given OutputType and internal/external chain.
ScriptPubKeyMan* GetScriptPubKeyMan(const OutputType& type, bool internal) const;
- //! Get the ScriptPubKeyMan for a script
- ScriptPubKeyMan* GetScriptPubKeyMan(const CScript& script) const;
+ //! Get all the ScriptPubKeyMans for a script
+ std::set<ScriptPubKeyMan*> GetScriptPubKeyMans(const CScript& script) const;
//! Get the ScriptPubKeyMan by id
ScriptPubKeyMan* GetScriptPubKeyMan(const uint256& id) const;
- //! Get all of the ScriptPubKeyMans for a script given additional information in sigdata (populated by e.g. a psbt)
- std::set<ScriptPubKeyMan*> GetScriptPubKeyMans(const CScript& script, SignatureData& sigdata) const;
-
//! Get the SigningProvider for a script
std::unique_ptr<SigningProvider> GetSolvingProvider(const CScript& script) const;
std::unique_ptr<SigningProvider> GetSolvingProvider(const CScript& script, SignatureData& sigdata) const;
@@ -882,6 +879,11 @@ public:
//! Return the DescriptorScriptPubKeyMan for a WalletDescriptor if it is already in the wallet
DescriptorScriptPubKeyMan* GetDescriptorScriptPubKeyMan(const WalletDescriptor& desc) const;
+ //! Returns whether the provided ScriptPubKeyMan is internal
+ //! @param[in] spk_man The ScriptPubKeyMan to test
+ //! @return contains value only for active DescriptorScriptPubKeyMan, otherwise undefined
+ std::optional<bool> IsInternalScriptPubKeyMan(ScriptPubKeyMan* spk_man) const;
+
//! Add a descriptor to the wallet, return a ScriptPubKeyMan & associated output type
ScriptPubKeyMan* AddWalletDescriptor(WalletDescriptor& desc, const FlatSigningProvider& signing_provider, const std::string& label, bool internal) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
};
diff --git a/test/functional/feature_coinstatsindex.py b/test/functional/feature_coinstatsindex.py
index 19bb908b64..8afd0ff74a 100755
--- a/test/functional/feature_coinstatsindex.py
+++ b/test/functional/feature_coinstatsindex.py
@@ -276,14 +276,6 @@ class CoinStatsIndexTest(BitcoinTestFramework):
res3 = index_node.gettxoutsetinfo(hash_type='muhash', hash_or_height=112)
assert_equal(res2, res3)
- self.log.info("Test that a node aware of stale blocks syncs them as well")
- node = self.nodes[0]
- # Ensure the node is aware of a stale block prior to restart
- node.getblock(reorg_block)
-
- self.restart_node(0, ["-coinstatsindex"])
- assert_raises_rpc_error(-32603, "Unable to get data because coinstatsindex is still syncing.", node.gettxoutsetinfo, 'muhash', reorg_block)
-
def _test_index_rejects_hash_serialized(self):
self.log.info("Test that the rpc raises if the legacy hash is passed with the index")
diff --git a/test/functional/wallet_listtransactions.py b/test/functional/wallet_listtransactions.py
index 8fd15a164c..fc263f17ce 100755
--- a/test/functional/wallet_listtransactions.py
+++ b/test/functional/wallet_listtransactions.py
@@ -3,6 +3,10 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the listtransactions API."""
+
+import shutil
+import os
+
from decimal import Decimal
from test_framework.messages import (
@@ -17,7 +21,7 @@ from test_framework.util import (
class ListTransactionsTest(BitcoinTestFramework):
def set_test_params(self):
- self.num_nodes = 2
+ self.num_nodes = 3
# This test isn't testing txn relay/timing, so set whitelist on the
# peers for instant txn relay. This speeds up the test run time 2-3x.
self.extra_args = [["-whitelist=noban@127.0.0.1"]] * self.num_nodes
@@ -102,7 +106,7 @@ class ListTransactionsTest(BitcoinTestFramework):
{"txid": txid, "label": "watchonly"})
self.run_rbf_opt_in_test()
-
+ self.run_externally_generated_address_test()
def run_rbf_opt_in_test(self):
"""Test the opt-in-rbf flag for sent and received transactions."""
@@ -217,5 +221,63 @@ class ListTransactionsTest(BitcoinTestFramework):
assert_equal(self.nodes[0].gettransaction(txid_3b)["bip125-replaceable"], "no")
assert_equal(self.nodes[0].gettransaction(txid_4)["bip125-replaceable"], "unknown")
+ def run_externally_generated_address_test(self):
+ """Test behavior when receiving address is not in the address book."""
+
+ self.log.info("Setup the same wallet on two nodes")
+ # refill keypool otherwise the second node wouldn't recognize addresses generated on the first nodes
+ self.nodes[0].keypoolrefill(1000)
+ self.stop_nodes()
+ wallet0 = os.path.join(self.nodes[0].datadir, self.chain, self.default_wallet_name, "wallet.dat")
+ wallet2 = os.path.join(self.nodes[2].datadir, self.chain, self.default_wallet_name, "wallet.dat")
+ shutil.copyfile(wallet0, wallet2)
+ self.start_nodes()
+ # reconnect nodes
+ self.connect_nodes(0, 1)
+ self.connect_nodes(1, 2)
+ self.connect_nodes(2, 0)
+
+ addr1 = self.nodes[0].getnewaddress("pizza1", 'legacy')
+ addr2 = self.nodes[0].getnewaddress("pizza2", 'p2sh-segwit')
+ addr3 = self.nodes[0].getnewaddress("pizza3", 'bech32')
+
+ self.log.info("Send to externally generated addresses")
+ # send to an address beyond the next to be generated to test the keypool gap
+ self.nodes[1].sendtoaddress(addr3, "0.001")
+ self.generate(self.nodes[1], 1)
+ self.sync_all()
+
+ # send to an address that is already marked as used due to the keypool gap mechanics
+ self.nodes[1].sendtoaddress(addr2, "0.001")
+ self.generate(self.nodes[1], 1)
+ self.sync_all()
+
+ # send to self transaction
+ self.nodes[0].sendtoaddress(addr1, "0.001")
+ self.generate(self.nodes[0], 1)
+ self.sync_all()
+
+ self.log.info("Verify listtransactions is the same regardless of where the address was generated")
+ transactions0 = self.nodes[0].listtransactions()
+ transactions2 = self.nodes[2].listtransactions()
+
+ # normalize results: remove fields that normally could differ and sort
+ def normalize_list(txs):
+ for tx in txs:
+ tx.pop('label', None)
+ tx.pop('time', None)
+ tx.pop('timereceived', None)
+ txs.sort(key=lambda x: x['txid'])
+
+ normalize_list(transactions0)
+ normalize_list(transactions2)
+ assert_equal(transactions0, transactions2)
+
+ self.log.info("Verify labels are persistent on the node generated the addresses")
+ assert_equal(['pizza1'], self.nodes[0].getaddressinfo(addr1)['labels'])
+ assert_equal(['pizza2'], self.nodes[0].getaddressinfo(addr2)['labels'])
+ assert_equal(['pizza3'], self.nodes[0].getaddressinfo(addr3)['labels'])
+
+
if __name__ == '__main__':
ListTransactionsTest().main()