diff options
130 files changed, 8898 insertions, 2227 deletions
diff --git a/.appveyor.yml b/.appveyor.yml index 097874b17a..fb95876c36 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -7,9 +7,9 @@ clone_depth: 5 environment: PATH: 'C:\Python37-x64;C:\Python37-x64\Scripts;%PATH%' PYTHONUTF8: 1 - QT_DOWNLOAD_URL: 'https://github.com/sipsorcery/qt_win_binary/releases/download/qt598x64_vs2019_v1681/qt598_x64_vs2019_1681.zip' - QT_DOWNLOAD_HASH: '00cf7327818c07d74e0b1a4464ffe987c2728b00d49d4bf333065892af0515c3' - QT_LOCAL_PATH: 'C:\Qt5.9.8_x64_static_vs2019' + QT_DOWNLOAD_URL: 'https://github.com/sipsorcery/qt_win_binary/releases/download/qt51210x64_vs2019_1694/Qt5.12.10_x64_static_vs2019_1694.zip' + QT_DOWNLOAD_HASH: '3035a1307e8302bb3a76eba9bb3102979f945ab4022cc3bc2e1583edd44bdc99' + QT_LOCAL_PATH: 'C:\Qt5.12.10_x64_static_vs2019_1694' VCPKG_TAG: '75522bb1f2e7d863078bcd06322348f053a9e33f' install: # Disable zmq test for now since python zmq library on Windows would cause Access violation sometimes. diff --git a/.cirrus.yml b/.cirrus.yml index 3999e2dfd7..6dc029ee51 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -41,11 +41,13 @@ global_task_template: &GLOBAL_TASK_TEMPLATE folder: "/tmp/ccache_dir" depends_built_cache: folder: "depends/built" - depends_sdk_cache: - folder: "depends/sdk-sources" ci_script: - ./ci/test_run_all.sh +depends_sdk_cache_template: &DEPENDS_SDK_CACHE_TEMPLATE + depends_sdk_cache: + folder: "depends/sdk-sources" + compute_credits_template: &CREDITS_TEMPLATE # https://cirrus-ci.org/pricing/#compute-credits # Only use credits for pull requests to the main repo @@ -111,19 +113,19 @@ task: task: name: '[previous releases, uses qt5 dev package and some depends packages] [unsigned char] [bionic]' - << : *GLOBAL_TASK_TEMPLATE - depends_releases_cache: + previous_releases_cache: folder: "releases" + << : *GLOBAL_TASK_TEMPLATE << : *PERSISTENT_WORKER_TEMPLATE env: << : *PERSISTENT_WORKER_TEMPLATE_ENV FILE_ENV: "./ci/test/00_setup_env_native_qt5.sh" task: - name: '[depends, sanitizers: thread (TSan), no gui] [focal]' + name: '[depends, sanitizers: thread (TSan), no gui] [hirsute]' << : *GLOBAL_TASK_TEMPLATE container: - image: ubuntu:focal + image: ubuntu:hirsute cpu: 6 # Increase CPU and Memory to avoid timeout memory: 24G env: @@ -178,6 +180,7 @@ task: task: name: 'macOS 10.14 [gui, no tests] [focal]' + << : *DEPENDS_SDK_CACHE_TEMPLATE << : *GLOBAL_TASK_TEMPLATE container: image: ubuntu:focal @@ -202,6 +205,7 @@ task: task: name: 'ARM64 Android APK [focal]' + << : *DEPENDS_SDK_CACHE_TEMPLATE depends_sources_cache: folder: "depends/sources" << : *GLOBAL_TASK_TEMPLATE diff --git a/.tx/config b/.tx/config index 86b517a612..232d481e18 100644 --- a/.tx/config +++ b/.tx/config @@ -1,7 +1,7 @@ [main] host = https://www.transifex.com -[bitcoin.qt-translation-021x] -file_filter = src/qt/locale/bitcoin_<lang>.ts -source_file = src/qt/locale/bitcoin_en.ts +[bitcoin.qt-translation-022x] +file_filter = src/qt/locale/bitcoin_<lang>.xlf +source_file = src/qt/locale/bitcoin_en.xlf source_lang = en diff --git a/build-aux/m4/bitcoin_qt.m4 b/build-aux/m4/bitcoin_qt.m4 index 57b4c10d77..0995ef1406 100644 --- a/build-aux/m4/bitcoin_qt.m4 +++ b/build-aux/m4/bitcoin_qt.m4 @@ -225,6 +225,7 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[ BITCOIN_QT_PATH_PROGS([RCC], [rcc-qt5 rcc5 rcc], $qt_bin_path) BITCOIN_QT_PATH_PROGS([LRELEASE], [lrelease-qt5 lrelease5 lrelease], $qt_bin_path) BITCOIN_QT_PATH_PROGS([LUPDATE], [lupdate-qt5 lupdate5 lupdate],$qt_bin_path, yes) + BITCOIN_QT_PATH_PROGS([LCONVERT], [lconvert-qt5 lconvert5 lconvert], $qt_bin_path, yes) MOC_DEFS='-DHAVE_CONFIG_H -I$(srcdir)' case $host in @@ -258,7 +259,10 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[ AC_MSG_ERROR([libQtDBus not found. Install libQtDBus or remove --with-qtdbus.]) fi if test "x$LUPDATE" = x; then - AC_MSG_WARN([lupdate is required to update qt translations]) + AC_MSG_WARN([lupdate tool is required to update Qt translations.]) + fi + if test "x$LCONVERT" = x; then + AC_MSG_WARN([lconvert tool is required to update Qt translations.]) fi ],[ bitcoin_enable_qt=no diff --git a/build_msvc/README.md b/build_msvc/README.md index 87ea556a23..5ce0f6cde4 100644 --- a/build_msvc/README.md +++ b/build_msvc/README.md @@ -27,7 +27,11 @@ Options for installing the dependencies in a Visual Studio compatible manner are - Download the source code, build each dependency, add the required include paths, link libraries and binary tools to the Visual Studio project files. - Use [nuget](https://www.nuget.org/) packages with the understanding that any binary files have been compiled by an untrusted third party. -The [external dependencies](https://github.com/bitcoin/bitcoin/blob/master/doc/dependencies.md) required for building are listed in the `build_msvc/vcpkg.json` file. The `msbuild` project files are configured to automatically install the `vcpkg` dependencies. +The [external dependencies](https://github.com/bitcoin/bitcoin/blob/master/doc/dependencies.md) required for building are listed in the `build_msvc/vcpkg.json` file. To ensure `msbuild` project files automatically install the `vcpkg` dependencies use: + +``` +vcpkg integrate install +``` Qt --------------------- diff --git a/build_msvc/common.qt.init.vcxproj b/build_msvc/common.qt.init.vcxproj index 42150a2310..837c088451 100644 --- a/build_msvc/common.qt.init.vcxproj +++ b/build_msvc/common.qt.init.vcxproj @@ -2,15 +2,15 @@ <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup Label="QtGlobals"> - <QtBaseDir>C:\Qt5.9.8_x64_static_vs2019</QtBaseDir> + <QtBaseDir>C:\Qt5.12.10_x64_static_vs2019_1694</QtBaseDir> <QtPluginsLibraryDir>$(QtBaseDir)\plugins</QtPluginsLibraryDir> <QtLibraryDir>$(QtBaseDir)\lib</QtLibraryDir> <QtIncludeDir>$(QtBaseDir)\include</QtIncludeDir> <QtIncludes>$(QtIncludeDir);$(QtIncludeDir)\QtNetwork;$(QtIncludeDir)\QtCore;$(QtIncludeDir)\QtWidgets;$(QtIncludeDir)\QtGui;</QtIncludes> <GeneratedFilesOutDir>.\QtGeneratedFiles\qt</GeneratedFilesOutDir> <QtToolsDir>$(QtBaseDir)\bin</QtToolsDir> - <QtReleaseLibraries>$(QtPluginsLibraryDir)\platforms\qminimal.lib;$(QtPluginsLibraryDir)\platforms\qwindows.lib;$(QtLibraryDir)\qtfreetype.lib;$(QtLibraryDir)\qtharfbuzz.lib;$(QtLibraryDir)\qtlibpng.lib;$(QtLibraryDir)\qtpcre2.lib;$(QtLibraryDir)\Qt5AccessibilitySupport.lib;$(QtLibraryDir)\Qt5Core.lib;$(QtLibraryDir)\Qt5Concurrent.lib;$(QtLibraryDir)\Qt5EventDispatcherSupport.lib;$(QtLibraryDir)\Qt5FontDatabaseSupport.lib;$(QtLibraryDir)\Qt5Gui.lib;$(QtLibraryDir)\Qt5Network.lib;$(QtLibraryDir)\Qt5PlatformCompositorSupport.lib;$(QtLibraryDir)\Qt5ThemeSupport.lib;$(QtLibraryDir)\Qt5Widgets.lib;$(QtLibraryDir)\Qt5WinExtras.lib;$(QtLibraryDir)\qtmain.lib;userenv.lib;netapi32.lib;imm32.lib;Dwmapi.lib;version.lib;winmm.lib;UxTheme.lib</QtReleaseLibraries> - <QtDebugLibraries>$(QtPluginsLibraryDir)\platforms\qwindowsd.lib;$(QtPluginsLibraryDir)\platforms\qminimald.lib;$(QtLibraryDir)\*d.lib;crypt32.lib;userenv.lib;netapi32.lib;imm32.lib;Dwmapi.lib;version.lib;winmm.lib;UxTheme.lib</QtDebugLibraries> + <QtReleaseLibraries>$(QtPluginsLibraryDir)\platforms\qminimal.lib;$(QtPluginsLibraryDir)\platforms\qwindows.lib;$(QtLibraryDir)\Qt5WindowsUIAutomationSupport.lib;$(QtLibraryDir)\qtfreetype.lib;$(QtLibraryDir)\qtharfbuzz.lib;$(QtLibraryDir)\qtlibpng.lib;$(QtLibraryDir)\qtpcre2.lib;$(QtLibraryDir)\Qt5AccessibilitySupport.lib;$(QtLibraryDir)\Qt5Core.lib;$(QtLibraryDir)\Qt5Concurrent.lib;$(QtLibraryDir)\Qt5EventDispatcherSupport.lib;$(QtLibraryDir)\Qt5FontDatabaseSupport.lib;$(QtLibraryDir)\Qt5Gui.lib;$(QtLibraryDir)\Qt5Network.lib;$(QtLibraryDir)\Qt5PlatformCompositorSupport.lib;$(QtLibraryDir)\Qt5ThemeSupport.lib;$(QtLibraryDir)\Qt5Widgets.lib;$(QtLibraryDir)\Qt5WinExtras.lib;$(QtLibraryDir)\qtmain.lib;Wtsapi32.lib;userenv.lib;netapi32.lib;imm32.lib;Dwmapi.lib;version.lib;winmm.lib;UxTheme.lib</QtReleaseLibraries> + <QtDebugLibraries>$(QtPluginsLibraryDir)\platforms\qwindowsd.lib;$(QtPluginsLibraryDir)\platforms\qminimald.lib;$(QtLibraryDir)\*d.lib;Wtsapi32.lib;crypt32.lib;userenv.lib;netapi32.lib;imm32.lib;Dwmapi.lib;version.lib;winmm.lib;UxTheme.lib</QtDebugLibraries> </PropertyGroup> </Project> diff --git a/ci/test/00_setup_env_native_tsan.sh b/ci/test/00_setup_env_native_tsan.sh index d3875fc045..33f63fa9ba 100644 --- a/ci/test/00_setup_env_native_tsan.sh +++ b/ci/test/00_setup_env_native_tsan.sh @@ -7,7 +7,7 @@ export LC_ALL=C.UTF-8 export CONTAINER_NAME=ci_native_tsan -export DOCKER_NAME_TAG=ubuntu:20.04 +export DOCKER_NAME_TAG=ubuntu:hirsute export PACKAGES="clang llvm libc++abi-dev libc++-dev python3-zmq" export DEP_OPTS="CC=clang CXX='clang++ -stdlib=libc++'" export GOAL="install" diff --git a/configure.ac b/configure.ac index cce97e9259..d1707dfd64 100644 --- a/configure.ac +++ b/configure.ac @@ -1640,6 +1640,10 @@ if test "x$use_ccache" != "xno"; then CXX="$ac_cv_path_CCACHE $CXX" fi AC_MSG_RESULT($use_ccache) + if test "x$use_ccache" = "xyes"; then + AX_CHECK_COMPILE_FLAG([-fdebug-prefix-map=A=B],[DEBUG_CXXFLAGS="$DEBUG_CXXFLAGS -fdebug-prefix-map=\$(abs_srcdir)=."],,[[$CXXFLAG_WERROR]]) + AX_CHECK_PREPROC_FLAG([-fmacro-prefix-map=A=B],[DEBUG_CPPFLAGS="$DEBUG_CPPFLAGS -fmacro-prefix-map=\$(abs_srcdir)=."],,[[$CXXFLAG_WERROR]]) + fi fi dnl enable wallet diff --git a/contrib/bitcoin-qt.pro b/contrib/bitcoin-qt.pro deleted file mode 100644 index 0e4eeee0a7..0000000000 --- a/contrib/bitcoin-qt.pro +++ /dev/null @@ -1,22 +0,0 @@ -FORMS += \ - ../src/qt/forms/aboutdialog.ui \ - ../src/qt/forms/addressbookpage.ui \ - ../src/qt/forms/askpassphrasedialog.ui \ - ../src/qt/forms/coincontroldialog.ui \ - ../src/qt/forms/editaddressdialog.ui \ - ../src/qt/forms/helpmessagedialog.ui \ - ../src/qt/forms/intro.ui \ - ../src/qt/forms/openuridialog.ui \ - ../src/qt/forms/optionsdialog.ui \ - ../src/qt/forms/overviewpage.ui \ - ../src/qt/forms/receivecoinsdialog.ui \ - ../src/qt/forms/receiverequestdialog.ui \ - ../src/qt/forms/debugwindow.ui \ - ../src/qt/forms/sendcoinsdialog.ui \ - ../src/qt/forms/sendcoinsentry.ui \ - ../src/qt/forms/signverifymessagedialog.ui \ - ../src/qt/forms/transactiondescdialog.ui \ - ../src/qt/forms/createwalletdialog.ui - -RESOURCES += \ - ../src/qt/bitcoin.qrc diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml index 52e2a0514a..9b5f5d7e07 100644 --- a/contrib/gitian-descriptors/gitian-linux.yml +++ b/contrib/gitian-descriptors/gitian-linux.yml @@ -55,7 +55,6 @@ script: | HOST_CXXFLAGS="-O2 -g" HOST_LDFLAGS_BASE="-static-libstdc++ -Wl,-O2" - export QT_RCC_TEST=1 export QT_RCC_SOURCE_DATE_OVERRIDE=1 export TZ="UTC" export BUILD_DIR="$PWD" diff --git a/contrib/gitian-descriptors/gitian-osx.yml b/contrib/gitian-descriptors/gitian-osx.yml index c37ad5b842..c1bd545501 100644 --- a/contrib/gitian-descriptors/gitian-osx.yml +++ b/contrib/gitian-descriptors/gitian-osx.yml @@ -41,7 +41,6 @@ script: | FAKETIME_HOST_PROGS="" FAKETIME_PROGS="ar ranlib date dmg xorrisofs" - export QT_RCC_TEST=1 export QT_RCC_SOURCE_DATE_OVERRIDE=1 export TZ="UTC" export BUILD_DIR="$PWD" diff --git a/contrib/gitian-descriptors/gitian-win.yml b/contrib/gitian-descriptors/gitian-win.yml index 95cf0185e2..dbf1e8cc67 100644 --- a/contrib/gitian-descriptors/gitian-win.yml +++ b/contrib/gitian-descriptors/gitian-win.yml @@ -37,7 +37,6 @@ script: | HOST_CFLAGS="-O2 -g -fno-ident" HOST_CXXFLAGS="-O2 -g -fno-ident" - export QT_RCC_TEST=1 export QT_RCC_SOURCE_DATE_OVERRIDE=1 export TZ="UTC" export BUILD_DIR="$PWD" diff --git a/contrib/guix/README.md b/contrib/guix/README.md index 8c7d6e90ca..dad7de32c4 100644 --- a/contrib/guix/README.md +++ b/contrib/guix/README.md @@ -205,10 +205,7 @@ find output/ -type f -print0 | sort -z | xargs -r0 sha256sum * _**ADDITIONAL_GUIX_COMMON_FLAGS**_ - Additional flags to be passed to all `guix` commands. For a fully-bootstrapped - build, set this to `--bootstrap --no-substitutes` (refer to the [security - model section](#choosing-your-security-model) for more details). Note that a - fully-bootstrapped build will take quite a long time on the first run. + Additional flags to be passed to all `guix` commands. * _**ADDITIONAL_GUIX_TIMEMACHINE_FLAGS**_ diff --git a/contrib/guix/libexec/build.sh b/contrib/guix/libexec/build.sh index 4239c3d475..6ea32329ba 100644 --- a/contrib/guix/libexec/build.sh +++ b/contrib/guix/libexec/build.sh @@ -175,7 +175,6 @@ case "$HOST" in esac # Environment variables for determinism -export QT_RCC_TEST=1 export QT_RCC_SOURCE_DATE_OVERRIDE=1 export TAR_OPTIONS="--owner=0 --group=0 --numeric-owner --mtime='@${SOURCE_DATE_EPOCH}' --sort=name" export TZ="UTC" diff --git a/contrib/verify-commits/trusted-keys b/contrib/verify-commits/trusted-keys index 27fede6277..c14f90b04b 100644 --- a/contrib/verify-commits/trusted-keys +++ b/contrib/verify-commits/trusted-keys @@ -4,3 +4,4 @@ B8B3F1C0E58C15DB6A81D30C3648A882F4316B9B CA03882CB1FC067B5D3ACFE4D300116E1C875A3D E777299FC265DD04793070EB944D35F9AC3DB76A +D1DBF2C4B96F2DEBF4C16654410108112E7EA81F diff --git a/depends/README.md b/depends/README.md index a1d4a99084..6b20791281 100644 --- a/depends/README.md +++ b/depends/README.md @@ -12,15 +12,18 @@ For example: make HOST=x86_64-w64-mingw32 -j4 -**Bitcoin Core's configure script by default will ignore the depends output.** In +**Bitcoin Core's `configure` script by default will ignore the depends output.** In order for it to pick up libraries, tools, and settings from the depends build, -you must point it at the appropriate `--prefix` directory generated by the -build. In the above example, a prefix dir named x86_64-w64-mingw32 will be -created. To use it for Bitcoin: +you must set the `CONFIG_SITE` environment variable to point to a `config.site` settings file. +In the above example, a file named `depends/x86_64-w64-mingw32/share/config.site` will be +created. To use it during compilation: - ./configure --prefix=$PWD/depends/x86_64-w64-mingw32 + CONFIG_SITE=$PWD/depends/x86_64-w64-mingw32/share/config.site ./configure -Common `host-platform-triplets` for cross compilation are: +The default install prefix when using `config.site` is `--prefix=depends/<host-platform-triplet>`, +so depends build outputs will be installed in that location. + +Common `host-platform-triplet`s for cross compilation are: - `i686-pc-linux-gnu` for Linux 32 bit - `x86_64-pc-linux-gnu` for x86 Linux @@ -133,4 +136,3 @@ This is an example command for a default build with no disabled dependencies: - [description.md](description.md): General description of the depends system - [packages.md](packages.md): Steps for adding packages - diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk index ae83eae911..0133eee920 100644 --- a/depends/packages/qt.mk +++ b/depends/packages/qt.mk @@ -173,7 +173,6 @@ $(package)_config_opts_armv7a_android += -android-arch armeabi-v7a $(package)_config_opts_x86_64_android += -android-arch x86_64 $(package)_config_opts_i686_android += -android-arch i686 -$(package)_build_env = QT_RCC_TEST=1 $(package)_build_env += QT_RCC_SOURCE_DATE_OVERRIDE=1 endef @@ -261,13 +260,15 @@ define $(package)_config_cmds qtbase/bin/qmake -o qttranslations/Makefile qttranslations/qttranslations.pro && \ qtbase/bin/qmake -o qttranslations/translations/Makefile qttranslations/translations/translations.pro && \ qtbase/bin/qmake -o qttools/src/linguist/lrelease/Makefile qttools/src/linguist/lrelease/lrelease.pro && \ - qtbase/bin/qmake -o qttools/src/linguist/lupdate/Makefile qttools/src/linguist/lupdate/lupdate.pro + qtbase/bin/qmake -o qttools/src/linguist/lupdate/Makefile qttools/src/linguist/lupdate/lupdate.pro && \ + qtbase/bin/qmake -o qttools/src/linguist/lconvert/Makefile qttools/src/linguist/lconvert/lconvert.pro endef define $(package)_build_cmds $(MAKE) -C qtbase/src $(addprefix sub-,$($(package)_qt_libs)) && \ $(MAKE) -C qttools/src/linguist/lrelease && \ $(MAKE) -C qttools/src/linguist/lupdate && \ + $(MAKE) -C qttools/src/linguist/lconvert && \ $(MAKE) -C qttranslations endef @@ -275,6 +276,7 @@ define $(package)_stage_cmds $(MAKE) -C qtbase/src INSTALL_ROOT=$($(package)_staging_dir) $(addsuffix -install_subtargets,$(addprefix sub-,$($(package)_qt_libs))) && \ $(MAKE) -C qttools/src/linguist/lrelease INSTALL_ROOT=$($(package)_staging_dir) install_target && \ $(MAKE) -C qttools/src/linguist/lupdate INSTALL_ROOT=$($(package)_staging_dir) install_target && \ + $(MAKE) -C qttools/src/linguist/lconvert INSTALL_ROOT=$($(package)_staging_dir) install_target && \ $(MAKE) -C qttranslations INSTALL_ROOT=$($(package)_staging_dir) install_subtargets endef diff --git a/doc/build-unix.md b/doc/build-unix.md index d7e0ff705d..0c438db29a 100644 --- a/doc/build-unix.md +++ b/doc/build-unix.md @@ -331,7 +331,7 @@ To build executables for ARM: make HOST=arm-linux-gnueabihf NO_QT=1 cd .. ./autogen.sh - ./configure --prefix=$PWD/depends/arm-linux-gnueabihf --enable-glibc-back-compat --enable-reduce-exports LDFLAGS=-static-libstdc++ + CONFIG_SITE=$PWD/depends/arm-linux-gnueabihf/share/config.site ./configure --enable-glibc-back-compat --enable-reduce-exports LDFLAGS=-static-libstdc++ make diff --git a/doc/multiprocess.md b/doc/multiprocess.md index 471d8561f7..7a42fdd734 100644 --- a/doc/multiprocess.md +++ b/doc/multiprocess.md @@ -24,7 +24,7 @@ The multiprocess feature requires [Cap'n Proto](https://capnproto.org/) and [lib ``` cd <BITCOIN_SOURCE_DIRECTORY> make -C depends NO_QT=1 MULTIPROCESS=1 -./configure --prefix=$PWD/depends/x86_64-pc-linux-gnu +CONFIG_SITE=$PWD/depends/x86_64-pc-linux-gnu/share/config.site ./configure make src/bitcoin-node -regtest -printtoconsole -debug=ipc BITCOIND=bitcoin-node test/functional/test_runner.py diff --git a/doc/release-notes.md b/doc/release-notes.md index fced86254a..874b919f08 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -136,6 +136,12 @@ Changes to Wallet or GUI related settings can be found in the GUI or Wallet sect Tools and Utilities ------------------- +- A new CLI `-addrinfo` command returns the number of addresses known to the + node per network type (including Tor v2 versus v3) and total. This can be + useful to see if the node knows enough addresses in a network to use options + like `-onlynet=<network>` or to upgrade to current and future Tor releases + that support Tor v3 addresses only. (#21595) + Wallet ------ diff --git a/doc/translation_process.md b/doc/translation_process.md index 39f878cea3..785bb0047b 100644 --- a/doc/translation_process.md +++ b/doc/translation_process.md @@ -22,8 +22,6 @@ cd src/ make translate ``` -`contrib/bitcoin-qt.pro` takes care of generating `.qm` (binary compiled) files from `.ts` (source files) files. It’s mostly automated, and you shouldn’t need to worry about it. - **Example Qt translation** ```cpp QToolBar *toolbar = addToolBar(tr("Tabs toolbar")); diff --git a/src/Makefile.am b/src/Makefile.am index 6f948e7a1f..d5190206c0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -156,6 +156,7 @@ BITCOIN_CORE_H = \ index/txindex.h \ indirectmap.h \ init.h \ + init/common.h \ interfaces/chain.h \ interfaces/handler.h \ interfaces/node.h \ @@ -175,6 +176,7 @@ BITCOIN_CORE_H = \ netaddress.h \ netbase.h \ netmessagemaker.h \ + node/blockstorage.h \ node/coin.h \ node/coinstats.h \ node/context.h \ @@ -198,6 +200,7 @@ BITCOIN_CORE_H = \ rpc/blockchain.h \ rpc/client.h \ rpc/mining.h \ + rpc/net.h \ rpc/protocol.h \ rpc/rawtransaction_util.h \ rpc/register.h \ @@ -323,6 +326,7 @@ libbitcoin_server_a_SOURCES = \ miner.cpp \ net.cpp \ net_processing.cpp \ + node/blockstorage.cpp \ node/coin.cpp \ node/coinstats.cpp \ node/context.cpp \ @@ -518,6 +522,7 @@ libbitcoin_common_a_SOURCES = \ core_read.cpp \ core_write.cpp \ external_signer.cpp \ + init/common.cpp \ key.cpp \ key_io.cpp \ merkleblock.cpp \ diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 399a8430ef..a573247afa 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -356,6 +356,8 @@ $(srcdir)/qt/bitcoinstrings.cpp: FORCE translate: $(srcdir)/qt/bitcoinstrings.cpp $(QT_FORMS_UI) $(QT_FORMS_UI) $(BITCOIN_QT_BASE_CPP) qt/bitcoin.cpp $(BITCOIN_QT_WINDOWS_CPP) $(BITCOIN_QT_WALLET_CPP) $(BITCOIN_QT_H) $(BITCOIN_MM) @test -n $(LUPDATE) || echo "lupdate is required for updating translations" $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(LUPDATE) $^ -locations relative -no-obsolete -ts $(srcdir)/qt/locale/bitcoin_en.ts + @test -n $(LCONVERT) || echo "lconvert is required for updating translations" + $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(LCONVERT) -o $(srcdir)/qt/locale/bitcoin_en.xlf -i $(srcdir)/qt/locale/bitcoin_en.ts $(QT_QRC_LOCALE_CPP): $(QT_QRC_LOCALE) $(QT_QM) @test -f $(RCC) diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index 4f3d7a4ffe..4a4710ea3a 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -42,6 +42,7 @@ static const char DEFAULT_RPCCONNECT[] = "127.0.0.1"; static const int DEFAULT_HTTP_CLIENT_TIMEOUT=900; static const bool DEFAULT_NAMED=false; static const int CONTINUE_EXECUTION=-1; +static constexpr int8_t UNKNOWN_NETWORK{-1}; /** Default number of blocks to generate for RPC generatetoaddress. */ static const std::string DEFAULT_NBLOCKS = "1"; @@ -59,6 +60,7 @@ static void SetupCliArgs(ArgsManager& argsman) argsman.AddArg("-conf=<file>", strprintf("Specify configuration file. Relative paths will be prefixed by datadir location. (default: %s)", BITCOIN_CONF_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-datadir=<dir>", "Specify data directory", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-generate", strprintf("Generate blocks immediately, equivalent to RPC getnewaddress followed by RPC generatetoaddress. Optional positional integer arguments are number of blocks to generate (default: %s) and maximum iterations to try (default: %s), equivalent to RPC generatetoaddress nblocks and maxtries arguments. Example: bitcoin-cli -generate 4 1000", DEFAULT_NBLOCKS, DEFAULT_MAX_TRIES), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); + argsman.AddArg("-addrinfo", "Get the number of addresses known to the node, per network and total.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-getinfo", "Get general information from the remote server. Note that unlike server-side RPC calls, the results of -getinfo is the result of multiple non-atomic requests. Some entries in the result may represent results from different states (e.g. wallet balance may be as of a different block from the chain state reported)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-netinfo", "Get network peer connection information from the remote server. An optional integer argument from 0 to 4 can be passed for different peers listings (default: 0). Pass \"help\" for detailed help documentation.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); @@ -228,6 +230,60 @@ public: virtual UniValue ProcessReply(const UniValue &batch_in) = 0; }; +/** Process addrinfo requests */ +class AddrinfoRequestHandler : public BaseRequestHandler +{ +private: + static constexpr std::array m_networks{"ipv4", "ipv6", "torv2", "torv3", "i2p"}; + int8_t NetworkStringToId(const std::string& str) const + { + for (size_t i = 0; i < m_networks.size(); ++i) { + if (str == m_networks.at(i)) return i; + } + return UNKNOWN_NETWORK; + } + +public: + UniValue PrepareRequest(const std::string& method, const std::vector<std::string>& args) override + { + if (!args.empty()) { + throw std::runtime_error("-addrinfo takes no arguments"); + } + UniValue params{RPCConvertValues("getnodeaddresses", std::vector<std::string>{{"0"}})}; + return JSONRPCRequestObj("getnodeaddresses", params, 1); + } + + UniValue ProcessReply(const UniValue& reply) override + { + if (!reply["error"].isNull()) return reply; + const std::vector<UniValue>& nodes{reply["result"].getValues()}; + if (!nodes.empty() && nodes.at(0)["network"].isNull()) { + throw std::runtime_error("-addrinfo requires bitcoind server to be running v22.0 and up"); + } + // Count the number of peers we know by network, including torv2 versus torv3. + std::array<uint64_t, m_networks.size()> counts{{}}; + for (const UniValue& node : nodes) { + std::string network_name{node["network"].get_str()}; + if (network_name == "onion") { + network_name = node["address"].get_str().size() > 22 ? "torv3" : "torv2"; + } + const int8_t network_id{NetworkStringToId(network_name)}; + if (network_id == UNKNOWN_NETWORK) continue; + ++counts.at(network_id); + } + // Prepare result to return to user. + UniValue result{UniValue::VOBJ}, addresses{UniValue::VOBJ}; + uint64_t total{0}; // Total address count + for (size_t i = 0; i < m_networks.size(); ++i) { + addresses.pushKV(m_networks.at(i), counts.at(i)); + total += counts.at(i); + } + addresses.pushKV("total", total); + result.pushKV("addresses_known", addresses); + return JSONRPCReplyObj(result, NullUniValue, 1); + } +}; + /** Process getinfo requests */ class GetinfoRequestHandler: public BaseRequestHandler { @@ -299,16 +355,14 @@ public: class NetinfoRequestHandler : public BaseRequestHandler { private: - static constexpr int8_t UNKNOWN_NETWORK{-1}; - static constexpr uint8_t m_networks_size{4}; static constexpr uint8_t MAX_DETAIL_LEVEL{4}; - const std::array<std::string, m_networks_size> m_networks{{"ipv4", "ipv6", "onion", "i2p"}}; - std::array<std::array<uint16_t, m_networks_size + 1>, 3> m_counts{{{}}}; //!< Peer counts by (in/out/total, networks/total) + static constexpr std::array m_networks{"ipv4", "ipv6", "onion", "i2p"}; + std::array<std::array<uint16_t, m_networks.size() + 1>, 3> m_counts{{{}}}; //!< Peer counts by (in/out/total, networks/total) uint8_t m_block_relay_peers_count{0}; uint8_t m_manual_peers_count{0}; int8_t NetworkStringToId(const std::string& str) const { - for (uint8_t i = 0; i < m_networks_size; ++i) { + for (size_t i = 0; i < m_networks.size(); ++i) { if (str == m_networks.at(i)) return i; } return UNKNOWN_NETWORK; @@ -405,10 +459,10 @@ public: const bool is_outbound{!peer["inbound"].get_bool()}; const bool is_block_relay{!peer["relaytxes"].get_bool()}; const std::string conn_type{peer["connection_type"].get_str()}; - ++m_counts.at(is_outbound).at(network_id); // in/out by network - ++m_counts.at(is_outbound).at(m_networks_size); // in/out overall - ++m_counts.at(2).at(network_id); // total by network - ++m_counts.at(2).at(m_networks_size); // total overall + ++m_counts.at(is_outbound).at(network_id); // in/out by network + ++m_counts.at(is_outbound).at(m_networks.size()); // in/out overall + ++m_counts.at(2).at(network_id); // total by network + ++m_counts.at(2).at(m_networks.size()); // total overall if (conn_type == "block-relay-only") ++m_block_relay_peers_count; if (conn_type == "manual") ++m_manual_peers_count; if (DetailsRequested()) { @@ -478,11 +532,11 @@ public: if (any_i2p_peers) result += " i2p"; result += " total block"; if (m_manual_peers_count) result += " manual"; - const std::array<std::string, 3> rows{{"in", "out", "total"}}; + const std::array rows{"in", "out", "total"}; for (uint8_t i = 0; i < 3; ++i) { result += strprintf("\n%-5s %5i %5i %5i", rows.at(i), m_counts.at(i).at(0), m_counts.at(i).at(1), m_counts.at(i).at(2)); // ipv4/ipv6/onion peers counts if (any_i2p_peers) result += strprintf(" %5i", m_counts.at(i).at(3)); // i2p peers count - result += strprintf(" %5i", m_counts.at(i).at(m_networks_size)); // total peers count + result += strprintf(" %5i", m_counts.at(i).at(m_networks.size())); // total peers count if (i == 1) { // the outbound row has two extra columns for block relay and manual peer counts result += strprintf(" %5i", m_block_relay_peers_count); if (m_manual_peers_count) result += strprintf(" %5i", m_manual_peers_count); @@ -914,6 +968,8 @@ static int CommandLineRPC(int argc, char *argv[]) } else { ParseError(error, strPrint, nRet); } + } else if (gArgs.GetBoolArg("-addrinfo", false)) { + rh.reset(new AddrinfoRequestHandler()); } else { rh.reset(new DefaultRequestHandler()); if (args.size() < 1) { diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 3e77883856..45d93ca014 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -78,16 +78,18 @@ public: consensus.nPowTargetSpacing = 10 * 60; consensus.fPowAllowMinDifficultyBlocks = false; consensus.fPowNoRetargeting = false; - consensus.nRuleChangeActivationThreshold = 1916; // 95% of 2016 + consensus.nRuleChangeActivationThreshold = 1815; // 90% of 2016 consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28; - consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008 - consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008 + consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = Consensus::BIP9Deployment::NEVER_ACTIVE; + consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; + consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].min_activation_height = 0; // No activation delay // Deployment of Taproot (BIPs 340-342) consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].bit = 2; - consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nStartTime = 1199145601; // January 1, 2008 - consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = 1230767999; // December 31, 2008 + consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nStartTime = 1619222400; // April 24th, 2021 + consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = 1628640000; // August 11th, 2021 + consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].min_activation_height = 709632; // Approximately November 12th, 2021 consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000001533efd8d716a517fe2c5008"); consensus.defaultAssumeValid = uint256S("0x0000000000000000000b9d2ec5a352ecba0592946514a92f14319dc2b367fc72"); // 654683 @@ -198,13 +200,15 @@ public: consensus.nRuleChangeActivationThreshold = 1512; // 75% for testchains consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28; - consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008 - consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008 + consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = Consensus::BIP9Deployment::NEVER_ACTIVE; + consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; + consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].min_activation_height = 0; // No activation delay // Deployment of Taproot (BIPs 340-342) consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].bit = 2; - consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nStartTime = 1199145601; // January 1, 2008 - consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = 1230767999; // December 31, 2008 + consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nStartTime = 1619222400; // April 24th, 2021 + consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = 1628640000; // August 11th, 2021 + consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].min_activation_height = 0; // No activation delay consensus.nMinimumChainWork = uint256S("0x0000000000000000000000000000000000000000000001db6ec4ac88cf2272c6"); consensus.defaultAssumeValid = uint256S("0x000000000000006433d1efec504c53ca332b64963c425395515b01977bd7b3b0"); // 1864000 @@ -328,18 +332,20 @@ public: consensus.nPowTargetSpacing = 10 * 60; consensus.fPowAllowMinDifficultyBlocks = false; consensus.fPowNoRetargeting = false; - consensus.nRuleChangeActivationThreshold = 1916; // 95% of 2016 + consensus.nRuleChangeActivationThreshold = 1815; // 90% of 2016 consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing consensus.MinBIP9WarningHeight = 0; consensus.powLimit = uint256S("00000377ae000000000000000000000000000000000000000000000000000000"); consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28; - consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008 - consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008 + consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = Consensus::BIP9Deployment::NEVER_ACTIVE; + consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; + consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].min_activation_height = 0; // No activation delay // Activation of Taproot (BIPs 340-342) consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].bit = 2; consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nStartTime = Consensus::BIP9Deployment::ALWAYS_ACTIVE; consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; + consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].min_activation_height = 0; // No activation delay // message start is defined as the first 4 bytes of the sha256d of the block script CHashWriter h(SER_DISK, 0); @@ -398,12 +404,16 @@ public: consensus.fPowNoRetargeting = true; consensus.nRuleChangeActivationThreshold = 108; // 75% for testchains consensus.nMinerConfirmationWindow = 144; // Faster than normal for regtest (144 instead of 2016) + consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28; consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 0; consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; + consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].min_activation_height = 0; // No activation delay + consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].bit = 2; consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nStartTime = Consensus::BIP9Deployment::ALWAYS_ACTIVE; consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; + consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].min_activation_height = 0; // No activation delay consensus.nMinimumChainWork = uint256{}; consensus.defaultAssumeValid = uint256{}; @@ -467,10 +477,11 @@ public: /** * Allows modifying the Version Bits regtest parameters. */ - void UpdateVersionBitsParameters(Consensus::DeploymentPos d, int64_t nStartTime, int64_t nTimeout) + void UpdateVersionBitsParameters(Consensus::DeploymentPos d, int64_t nStartTime, int64_t nTimeout, int min_activation_height) { consensus.vDeployments[d].nStartTime = nStartTime; consensus.vDeployments[d].nTimeout = nTimeout; + consensus.vDeployments[d].min_activation_height = min_activation_height; } void UpdateActivationParametersFromArgs(const ArgsManager& args); }; @@ -493,22 +504,26 @@ void CRegTestParams::UpdateActivationParametersFromArgs(const ArgsManager& args) for (const std::string& strDeployment : args.GetArgs("-vbparams")) { std::vector<std::string> vDeploymentParams; boost::split(vDeploymentParams, strDeployment, boost::is_any_of(":")); - if (vDeploymentParams.size() != 3) { - throw std::runtime_error("Version bits parameters malformed, expecting deployment:start:end"); + if (vDeploymentParams.size() < 3 || 4 < vDeploymentParams.size()) { + throw std::runtime_error("Version bits parameters malformed, expecting deployment:start:end[:min_activation_height]"); } int64_t nStartTime, nTimeout; + int min_activation_height = 0; if (!ParseInt64(vDeploymentParams[1], &nStartTime)) { throw std::runtime_error(strprintf("Invalid nStartTime (%s)", vDeploymentParams[1])); } if (!ParseInt64(vDeploymentParams[2], &nTimeout)) { throw std::runtime_error(strprintf("Invalid nTimeout (%s)", vDeploymentParams[2])); } + if (vDeploymentParams.size() >= 4 && !ParseInt32(vDeploymentParams[3], &min_activation_height)) { + throw std::runtime_error(strprintf("Invalid min_activation_height (%s)", vDeploymentParams[3])); + } bool found = false; for (int j=0; j < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++j) { if (vDeploymentParams[0] == VersionBitsDeploymentInfo[j].name) { - UpdateVersionBitsParameters(Consensus::DeploymentPos(j), nStartTime, nTimeout); + UpdateVersionBitsParameters(Consensus::DeploymentPos(j), nStartTime, nTimeout, min_activation_height); found = true; - LogPrintf("Setting version bits activation parameters for %s to start=%ld, timeout=%ld\n", vDeploymentParams[0], nStartTime, nTimeout); + LogPrintf("Setting version bits activation parameters for %s to start=%ld, timeout=%ld, min_activation_height=%d\n", vDeploymentParams[0], nStartTime, nTimeout, min_activation_height); break; } } diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp index 1631176477..e71b4bc859 100644 --- a/src/chainparamsbase.cpp +++ b/src/chainparamsbase.cpp @@ -22,7 +22,7 @@ void SetupChainParamsBaseOptions(ArgsManager& argsman) "This is intended for regression testing tools and app development. Equivalent to -chain=regtest.", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS); argsman.AddArg("-segwitheight=<n>", "Set the activation height of segwit. -1 to disable. (regtest-only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-testnet", "Use the test chain. Equivalent to -chain=test.", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS); - argsman.AddArg("-vbparams=deployment:start:end", "Use given start/end times for specified version bits deployment (regtest-only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS); + argsman.AddArg("-vbparams=deployment:start:end[:min_activation_height]", "Use given start/end times and min_activation_height for specified version bits deployment (regtest-only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS); argsman.AddArg("-signet", "Use the signet chain. Equivalent to -chain=signet. Note that the network is defined by the -signetchallenge parameter", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS); argsman.AddArg("-signetchallenge", "Blocks must satisfy the given script to be considered valid (only for signet networks; defaults to the global default signet test network challenge)", ArgsManager::ALLOW_STRING, OptionsCategory::CHAINPARAMS); argsman.AddArg("-signetseednode", "Specify a seed node for the signet network, in the hostname[:port] format, e.g. sig.net:1234 (may be used multiple times to specify multiple seed nodes; defaults to the global default signet test network seed node(s))", ArgsManager::ALLOW_STRING, OptionsCategory::CHAINPARAMS); diff --git a/src/consensus/params.h b/src/consensus/params.h index 217cb019e1..28c95e0884 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -29,6 +29,11 @@ struct BIP9Deployment { int64_t nStartTime; /** Timeout/expiry MedianTime for the deployment attempt. */ int64_t nTimeout; + /** If lock in occurs, delay activation until at least this block + * height. Note that activation will only occur on a retarget + * boundary. + */ + int min_activation_height{0}; /** Constant for nTimeout very far in the future. */ static constexpr int64_t NO_TIMEOUT = std::numeric_limits<int64_t>::max(); @@ -38,6 +43,11 @@ struct BIP9Deployment { * process (which takes at least 3 BIP9 intervals). Only tests that specifically test the * behaviour during activation cannot use this. */ static constexpr int64_t ALWAYS_ACTIVE = -1; + + /** Special value for nStartTime indicating that the deployment is never active. + * This is useful for integrating the code changes for a new feature + * prior to deploying it on some or all networks. */ + static constexpr int64_t NEVER_ACTIVE = -2; }; /** diff --git a/src/dummywallet.cpp b/src/dummywallet.cpp index bb06c95e7d..95886d3138 100644 --- a/src/dummywallet.cpp +++ b/src/dummywallet.cpp @@ -50,6 +50,7 @@ void DummyWalletInit::AddWalletOptions(ArgsManager& argsman) const "-flushwallet", "-privdb", "-walletrejectlongchains", + "-unsafesqlitesync", }); } diff --git a/src/external_signer.cpp b/src/external_signer.cpp index b82dcc503d..f16d21fa60 100644 --- a/src/external_signer.cpp +++ b/src/external_signer.cpp @@ -9,43 +9,44 @@ #include <util/system.h> #include <external_signer.h> -ExternalSigner::ExternalSigner(const std::string& command, const std::string& fingerprint, std::string chain, std::string name): m_command(command), m_fingerprint(fingerprint), m_chain(chain), m_name(name) {} +#include <stdexcept> +#include <string> +#include <vector> + +#ifdef ENABLE_EXTERNAL_SIGNER + +ExternalSigner::ExternalSigner(const std::string& command, const std::string& fingerprint, const std::string chain, const std::string name): m_command(command), m_fingerprint(fingerprint), m_chain(chain), m_name(name) {} const std::string ExternalSigner::NetworkArg() const { return " --chain " + m_chain; } -#ifdef ENABLE_EXTERNAL_SIGNER - -bool ExternalSigner::Enumerate(const std::string& command, std::vector<ExternalSigner>& signers, std::string chain, bool ignore_errors) +bool ExternalSigner::Enumerate(const std::string& command, std::vector<ExternalSigner>& signers, const std::string chain) { // Call <command> enumerate const UniValue result = RunCommandParseJSON(command + " enumerate"); if (!result.isArray()) { - if (ignore_errors) return false; - throw ExternalSignerException(strprintf("'%s' received invalid response, expected array of signers", command)); + throw std::runtime_error(strprintf("'%s' received invalid response, expected array of signers", command)); } for (UniValue signer : result.getValues()) { // Check for error const UniValue& error = find_value(signer, "error"); if (!error.isNull()) { - if (ignore_errors) return false; if (!error.isStr()) { - throw ExternalSignerException(strprintf("'%s' error", command)); + throw std::runtime_error(strprintf("'%s' error", command)); } - throw ExternalSignerException(strprintf("'%s' error: %s", command, error.getValStr())); + throw std::runtime_error(strprintf("'%s' error: %s", command, error.getValStr())); } // Check if fingerprint is present const UniValue& fingerprint = find_value(signer, "fingerprint"); if (fingerprint.isNull()) { - if (ignore_errors) return false; - throw ExternalSignerException(strprintf("'%s' received invalid response, missing signer fingerprint", command)); + throw std::runtime_error(strprintf("'%s' received invalid response, missing signer fingerprint", command)); } - std::string fingerprintStr = fingerprint.get_str(); + const std::string fingerprintStr = fingerprint.get_str(); // Skip duplicate signer bool duplicate = false; - for (ExternalSigner signer : signers) { + for (const ExternalSigner& signer : signers) { if (signer.m_fingerprint.compare(fingerprintStr) == 0) duplicate = true; } if (duplicate) break; @@ -64,7 +65,7 @@ UniValue ExternalSigner::DisplayAddress(const std::string& descriptor) const return RunCommandParseJSON(m_command + " --fingerprint \"" + m_fingerprint + "\"" + NetworkArg() + " displayaddress --desc \"" + descriptor + "\""); } -UniValue ExternalSigner::GetDescriptors(int account) +UniValue ExternalSigner::GetDescriptors(const int account) { return RunCommandParseJSON(m_command + " --fingerprint \"" + m_fingerprint + "\"" + NetworkArg() + " getdescriptors --account " + strprintf("%d", account)); } @@ -79,7 +80,7 @@ bool ExternalSigner::SignTransaction(PartiallySignedTransaction& psbtx, std::str bool match = false; for (unsigned int i = 0; i < psbtx.inputs.size(); ++i) { const PSBTInput& input = psbtx.inputs[i]; - for (auto entry : input.hd_keypaths) { + for (const auto& entry : input.hd_keypaths) { if (m_fingerprint == strprintf("%08x", ReadBE32(entry.second.fingerprint))) match = true; } } @@ -89,8 +90,8 @@ bool ExternalSigner::SignTransaction(PartiallySignedTransaction& psbtx, std::str return false; } - std::string command = m_command + " --stdin --fingerprint \"" + m_fingerprint + "\"" + NetworkArg(); - std::string stdinStr = "signtx \"" + EncodeBase64(ssTx.str()) + "\""; + const std::string command = m_command + " --stdin --fingerprint \"" + m_fingerprint + "\"" + NetworkArg(); + const std::string stdinStr = "signtx \"" + EncodeBase64(ssTx.str()) + "\""; const UniValue signer_result = RunCommandParseJSON(command, stdinStr); @@ -116,4 +117,4 @@ bool ExternalSigner::SignTransaction(PartiallySignedTransaction& psbtx, std::str return true; } -#endif +#endif // ENABLE_EXTERNAL_SIGNER diff --git a/src/external_signer.h b/src/external_signer.h index 17428ba2f9..b3b202091a 100644 --- a/src/external_signer.h +++ b/src/external_signer.h @@ -5,17 +5,15 @@ #ifndef BITCOIN_EXTERNAL_SIGNER_H #define BITCOIN_EXTERNAL_SIGNER_H -#include <stdexcept> -#include <string> #include <univalue.h> #include <util/system.h> -struct PartiallySignedTransaction; +#include <string> +#include <vector> -class ExternalSignerException : public std::runtime_error { -public: - using std::runtime_error::runtime_error; -}; +#ifdef ENABLE_EXTERNAL_SIGNER + +struct PartiallySignedTransaction; //! Enables interaction with an external signing device or service, such as //! a hardware wallet. See doc/external-signer.md @@ -30,7 +28,7 @@ public: //! @param[in] fingerprint master key fingerprint of the signer //! @param[in] chain "main", "test", "regtest" or "signet" //! @param[in] name device name - ExternalSigner(const std::string& command, const std::string& fingerprint, std::string chain, std::string name); + ExternalSigner(const std::string& command, const std::string& fingerprint, const std::string chain, const std::string name); //! Master key fingerprint of the signer std::string m_fingerprint; @@ -43,13 +41,12 @@ public: const std::string NetworkArg() const; -#ifdef ENABLE_EXTERNAL_SIGNER //! Obtain a list of signers. Calls `<command> enumerate`. //! @param[in] command the command which handles interaction with the external signer //! @param[in,out] signers vector to which new signers (with a unique master key fingerprint) are added //! @param chain "main", "test", "regtest" or "signet" //! @returns success - static bool Enumerate(const std::string& command, std::vector<ExternalSigner>& signers, std::string chain, bool ignore_errors = false); + static bool Enumerate(const std::string& command, std::vector<ExternalSigner>& signers, const std::string chain); //! Display address on the device. Calls `<command> displayaddress --desc <descriptor>`. //! @param[in] descriptor Descriptor specifying which address to display. @@ -60,14 +57,14 @@ public: //! Calls `<command> getdescriptors --account <account>` //! @param[in] account which BIP32 account to use (e.g. `m/44'/0'/account'`) //! @returns see doc/external-signer.md - UniValue GetDescriptors(int account); + UniValue GetDescriptors(const int account); //! Sign PartiallySignedTransaction on the device. //! Calls `<command> signtransaction` and passes the PSBT via stdin. //! @param[in,out] psbt PartiallySignedTransaction to be signed bool SignTransaction(PartiallySignedTransaction& psbt, std::string& error); - -#endif }; +#endif // ENABLE_EXTERNAL_SIGNER + #endif // BITCOIN_EXTERNAL_SIGNER_H diff --git a/src/index/base.cpp b/src/index/base.cpp index 25644c3b41..9e637c9c6f 100644 --- a/src/index/base.cpp +++ b/src/index/base.cpp @@ -4,12 +4,13 @@ #include <chainparams.h> #include <index/base.h> +#include <node/blockstorage.h> #include <node/ui_interface.h> #include <shutdown.h> #include <tinyformat.h> #include <util/system.h> #include <util/translation.h> -#include <validation.h> +#include <validation.h> // For g_chainman #include <warnings.h> constexpr char DB_BEST_BLOCK = 'B'; diff --git a/src/index/blockfilterindex.cpp b/src/index/blockfilterindex.cpp index 32271fb7ab..154d7a7027 100644 --- a/src/index/blockfilterindex.cpp +++ b/src/index/blockfilterindex.cpp @@ -6,8 +6,8 @@ #include <dbwrapper.h> #include <index/blockfilterindex.h> +#include <node/blockstorage.h> #include <util/system.h> -#include <validation.h> /* The index database stores three items for each block: the disk location of the encoded filter, * its dSHA256 hash, and the header. Those belonging to blocks on the active chain are indexed by diff --git a/src/init.cpp b/src/init.cpp index 280a0cbda7..bb5b144802 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -16,22 +16,22 @@ #include <chain.h> #include <chainparams.h> #include <compat/sanity.h> -#include <consensus/validation.h> #include <fs.h> #include <hash.h> #include <httprpc.h> #include <httpserver.h> #include <index/blockfilterindex.h> #include <index/txindex.h> +#include <init/common.h> #include <interfaces/chain.h> #include <interfaces/node.h> -#include <key.h> #include <mapport.h> #include <miner.h> #include <net.h> #include <net_permissions.h> #include <net_processing.h> #include <netbase.h> +#include <node/blockstorage.h> #include <node/context.h> #include <node/ui_interface.h> #include <policy/feerate.h> @@ -61,7 +61,6 @@ #include <util/threadnames.h> #include <util/translation.h> #include <validation.h> - #include <validationinterface.h> #include <walletinitinterface.h> @@ -90,7 +89,6 @@ static const bool DEFAULT_PROXYRANDOMIZE = true; static const bool DEFAULT_REST_ENABLE = false; -static const bool DEFAULT_STOPAFTERBLOCKIMPORT = false; #ifdef WIN32 // Win32 LevelDB doesn't use filedescriptors, and the ones used for @@ -153,10 +151,6 @@ static fs::path GetPidFile(const ArgsManager& args) // shutdown thing. // -static std::unique_ptr<ECCVerifyHandle> globalVerifyHandle; - -static std::thread g_load_block; - void Interrupt(NodeContext& node) { InterruptHTTPServer(); @@ -207,7 +201,7 @@ void Shutdown(NodeContext& node) // After everything has been shut down, but before things get flushed, stop the // CScheduler/checkqueue, scheduler and load block thread. if (node.scheduler) node.scheduler->stop(); - if (g_load_block.joinable()) g_load_block.join(); + if (node.chainman && node.chainman->m_load_block.joinable()) node.chainman->m_load_block.join(); StopScriptCheckWorkerThreads(); // After the threads that potentially access these pointers have been stopped, @@ -277,8 +271,7 @@ void Shutdown(NodeContext& node) node.chain_clients.clear(); UnregisterAllValidationInterfaces(); GetMainSignals().UnregisterBackgroundSignalScheduler(); - globalVerifyHandle.reset(); - ECC_Stop(); + init::UnsetGlobals(); node.mempool.reset(); node.fee_estimator.reset(); node.chainman = nullptr; @@ -354,6 +347,8 @@ void SetupServerArgs(NodeContext& node) SetupHelpOptions(argsman); argsman.AddArg("-help-debug", "Print help message with debugging options and exit", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); // server-only for now + init::AddLoggingArgs(argsman); + const auto defaultBaseParams = CreateBaseChainParams(CBaseChainParams::MAIN); const auto testnetBaseParams = CreateBaseChainParams(CBaseChainParams::TESTNET); const auto signetBaseParams = CreateBaseChainParams(CBaseChainParams::SIGNET); @@ -385,7 +380,6 @@ void SetupServerArgs(NodeContext& node) argsman.AddArg("-datadir=<dir>", "Specify data directory", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-dbbatchsize", strprintf("Maximum database write batch size in bytes (default: %u)", nDefaultDbBatchSize), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::OPTIONS); argsman.AddArg("-dbcache=<n>", strprintf("Maximum database cache size <n> MiB (%d to %d, default: %d). In addition, unused mempool memory is shared for this cache (see -maxmempool).", nMinDbCache, nMaxDbCache, nDefaultDbCache), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-debuglogfile=<file>", strprintf("Specify location of debug log file. Relative paths will be prefixed by a net-specific datadir location. (-nodebuglogfile to disable; default: %s)", DEFAULT_DEBUGLOGFILE), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-feefilter", strprintf("Tell other nodes to filter invs to us by our mempool min fee (default: %u)", DEFAULT_FEEFILTER), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::OPTIONS); argsman.AddArg("-includeconf=<file>", "Specify additional configuration file, relative to the -datadir path (only useable from configuration file, not command line)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-loadblock=<file>", "Imports blocks from external file on startup", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); @@ -513,25 +507,10 @@ void SetupServerArgs(NodeContext& node) argsman.AddArg("-limitdescendantsize=<n>", strprintf("Do not accept transactions if any ancestor would have more than <n> kilobytes of in-mempool descendants (default: %u).", DEFAULT_DESCENDANT_SIZE_LIMIT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-addrmantest", "Allows to test address relay on localhost", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-capturemessages", "Capture all P2P messages to disk", ArgsManager::ALLOW_BOOL | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); - argsman.AddArg("-debug=<category>", "Output debugging information (default: -nodebug, supplying <category> is optional). " - "If <category> is not supplied or if <category> = 1, output all debugging information. <category> can be: " + LogInstance().LogCategoriesString() + ". This option can be specified multiple times to output multiple categories.", - ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); - argsman.AddArg("-debugexclude=<category>", strprintf("Exclude debugging information for a category. Can be used in conjunction with -debug=1 to output debug logs for all categories except the specified category. This option can be specified multiple times to exclude multiple categories."), ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); - argsman.AddArg("-logips", strprintf("Include IP addresses in debug output (default: %u)", DEFAULT_LOGIPS), ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); - argsman.AddArg("-logtimestamps", strprintf("Prepend debug output with timestamp (default: %u)", DEFAULT_LOGTIMESTAMPS), ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); -#ifdef HAVE_THREAD_LOCAL - argsman.AddArg("-logthreadnames", strprintf("Prepend debug output with name of the originating thread (only available on platforms supporting thread_local) (default: %u)", DEFAULT_LOGTHREADNAMES), ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); -#else - hidden_args.emplace_back("-logthreadnames"); -#endif - argsman.AddArg("-logsourcelocations", strprintf("Prepend debug output with name of the originating source location (source file, line number and function name) (default: %u)", DEFAULT_LOGSOURCELOCATIONS), ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); - argsman.AddArg("-logtimemicros", strprintf("Add microsecond precision to debug timestamps (default: %u)", DEFAULT_LOGTIMEMICROS), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-mocktime=<n>", "Replace actual time with " + UNIX_EPOCH_TIME + " (default: 0)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-maxsigcachesize=<n>", strprintf("Limit sum of signature cache and script execution cache sizes to <n> MiB (default: %u)", DEFAULT_MAX_SIG_CACHE_SIZE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-maxtipage=<n>", strprintf("Maximum tip age in seconds to consider node in initial block download (default: %u)", DEFAULT_MAX_TIP_AGE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-printpriority", strprintf("Log transaction fee per kB when mining blocks (default: %u)", DEFAULT_PRINTPRIORITY), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); - argsman.AddArg("-printtoconsole", "Send trace/debug info to console (default: 1 when no -daemon. To disable logging to file, set -nodebuglogfile)", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); - argsman.AddArg("-shrinkdebugfile", "Shrink debug.log file on client startup (default: 1 when no -debug)", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-uacomment=<cmt>", "Append comment to the user agent string", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); SetupChainParamsBaseOptions(argsman); @@ -614,20 +593,6 @@ static void BlockNotifyGenesisWait(const CBlockIndex* pBlockIndex) } } -struct CImportingNow -{ - CImportingNow() { - assert(fImporting == false); - fImporting = true; - } - - ~CImportingNow() { - assert(fImporting == true); - fImporting = false; - } -}; - - // If we're using -prune with -reindex, then delete block files that will be ignored by the // reindex. Since reindexing works by starting at block file 0 and looping until a blockfile // is missing, do the same here to delete any later block files after a gap. Also delete all @@ -642,7 +607,7 @@ static void CleanupBlockRevFiles() // Remove the rev files immediately and insert the blk file paths into an // ordered map keyed by block file index. LogPrintf("Removing unusable blk?????.dat and rev?????.dat files for -reindex with -prune\n"); - fs::path blocksdir = GetBlocksDir(); + fs::path blocksdir = gArgs.GetBlocksDirPath(); for (fs::directory_iterator it(blocksdir); it != fs::directory_iterator(); it++) { if (fs::is_regular_file(*it) && it->path().filename().string().length() == 12 && @@ -680,101 +645,6 @@ static void StartupNotify(const ArgsManager& args) } #endif -static void ThreadImport(ChainstateManager& chainman, std::vector<fs::path> vImportFiles, const ArgsManager& args) -{ - const CChainParams& chainparams = Params(); - ScheduleBatchPriority(); - - { - CImportingNow imp; - - // -reindex - if (fReindex) { - int nFile = 0; - while (true) { - FlatFilePos pos(nFile, 0); - if (!fs::exists(GetBlockPosFilename(pos))) - break; // No block files left to reindex - FILE *file = OpenBlockFile(pos, true); - if (!file) - break; // This error is logged in OpenBlockFile - LogPrintf("Reindexing block file blk%05u.dat...\n", (unsigned int)nFile); - ::ChainstateActive().LoadExternalBlockFile(chainparams, file, &pos); - if (ShutdownRequested()) { - LogPrintf("Shutdown requested. Exit %s\n", __func__); - return; - } - nFile++; - } - pblocktree->WriteReindexing(false); - fReindex = false; - LogPrintf("Reindexing finished\n"); - // To avoid ending up in a situation without genesis block, re-try initializing (no-op if reindexing worked): - ::ChainstateActive().LoadGenesisBlock(chainparams); - } - - // -loadblock= - for (const fs::path& path : vImportFiles) { - FILE *file = fsbridge::fopen(path, "rb"); - if (file) { - LogPrintf("Importing blocks file %s...\n", path.string()); - ::ChainstateActive().LoadExternalBlockFile(chainparams, file); - if (ShutdownRequested()) { - LogPrintf("Shutdown requested. Exit %s\n", __func__); - return; - } - } else { - LogPrintf("Warning: Could not open blocks file %s\n", path.string()); - } - } - - // scan for better chains in the block chain database, that are not yet connected in the active best chain - - // We can't hold cs_main during ActivateBestChain even though we're accessing - // the chainman unique_ptrs since ABC requires us not to be holding cs_main, so retrieve - // the relevant pointers before the ABC call. - for (CChainState* chainstate : WITH_LOCK(::cs_main, return chainman.GetAll())) { - BlockValidationState state; - if (!chainstate->ActivateBestChain(state, chainparams, nullptr)) { - LogPrintf("Failed to connect best block (%s)\n", state.ToString()); - StartShutdown(); - return; - } - } - - if (args.GetBoolArg("-stopafterblockimport", DEFAULT_STOPAFTERBLOCKIMPORT)) { - LogPrintf("Stopping after block import\n"); - StartShutdown(); - return; - } - } // End scope of CImportingNow - chainman.ActiveChainstate().LoadMempool(args); -} - -/** Sanity checks - * Ensure that Bitcoin is running in a usable environment with all - * necessary library support. - */ -static bool InitSanityCheck() -{ - if (!ECC_InitSanityCheck()) { - return InitError(Untranslated("Elliptic curve cryptography sanity check failure. Aborting.")); - } - - if (!glibcxx_sanity_test()) - return false; - - if (!Random_SanityCheck()) { - return InitError(Untranslated("OS cryptographic RNG sanity check failure. Aborting.")); - } - - if (!ChronoSanityCheck()) { - return InitError(Untranslated("Clock epoch mismatch. Aborting.")); - } - - return true; -} - static bool AppInitServers(NodeContext& node) { const ArgsManager& args = *Assert(node.args); @@ -872,25 +742,8 @@ void InitParameterInteraction(ArgsManager& args) */ void InitLogging(const ArgsManager& args) { - LogInstance().m_print_to_file = !args.IsArgNegated("-debuglogfile"); - LogInstance().m_file_path = AbsPathForConfigVal(args.GetArg("-debuglogfile", DEFAULT_DEBUGLOGFILE)); - LogInstance().m_print_to_console = args.GetBoolArg("-printtoconsole", !args.GetBoolArg("-daemon", false)); - LogInstance().m_log_timestamps = args.GetBoolArg("-logtimestamps", DEFAULT_LOGTIMESTAMPS); - LogInstance().m_log_time_micros = args.GetBoolArg("-logtimemicros", DEFAULT_LOGTIMEMICROS); -#ifdef HAVE_THREAD_LOCAL - LogInstance().m_log_threadnames = args.GetBoolArg("-logthreadnames", DEFAULT_LOGTHREADNAMES); -#endif - LogInstance().m_log_sourcelocations = args.GetBoolArg("-logsourcelocations", DEFAULT_LOGSOURCELOCATIONS); - - fLogIPs = args.GetBoolArg("-logips", DEFAULT_LOGIPS); - - std::string version_string = FormatFullVersion(); -#ifdef DEBUG - version_string += " (debug build)"; -#else - version_string += " (release build)"; -#endif - LogPrintf(PACKAGE_NAME " version %s\n", version_string); + init::SetLoggingOptions(args); + init::LogPackageVersion(); } namespace { // Variables internal to initialization process only @@ -995,7 +848,7 @@ bool AppInitParameterInteraction(const ArgsManager& args) InitWarning(warnings); } - if (!fs::is_directory(GetBlocksDir())) { + if (!fs::is_directory(gArgs.GetBlocksDirPath())) { return InitError(strprintf(_("Specified blocks directory \"%s\" does not exist."), args.GetArg("-blocksdir", ""))); } @@ -1058,26 +911,7 @@ bool AppInitParameterInteraction(const ArgsManager& args) InitWarning(strprintf(_("Reducing -maxconnections from %d to %d, because of system limitations."), nUserMaxConnections, nMaxConnections)); // ********************************************************* Step 3: parameter-to-internal-flags - if (args.IsArgSet("-debug")) { - // Special-case: if -debug=0/-nodebug is set, turn off debugging messages - const std::vector<std::string> categories = args.GetArgs("-debug"); - - if (std::none_of(categories.begin(), categories.end(), - [](std::string cat){return cat == "0" || cat == "none";})) { - for (const auto& cat : categories) { - if (!LogInstance().EnableCategory(cat)) { - InitWarning(strprintf(_("Unsupported logging category %s=%s."), "-debug", cat)); - } - } - } - } - - // Now remove the logging categories which were explicitly excluded - for (const std::string& cat : args.GetArgs("-debugexclude")) { - if (!LogInstance().DisableCategory(cat)) { - InitWarning(strprintf(_("Unsupported logging category %s=%s."), "-debugexclude", cat)); - } - } + init::SetLoggingCategories(args); fCheckBlockIndex = args.GetBoolArg("-checkblockindex", chainparams.DefaultConsistencyChecks()); fCheckpointsEnabled = args.GetBoolArg("-checkpoints", DEFAULT_CHECKPOINTS_ENABLED); @@ -1224,16 +1058,11 @@ bool AppInitSanityChecks() { // ********************************************************* Step 4: sanity checks - // Initialize elliptic curve code - std::string sha256_algo = SHA256AutoDetect(); - LogPrintf("Using the '%s' SHA256 implementation\n", sha256_algo); - RandomInit(); - ECC_Start(); - globalVerifyHandle.reset(new ECCVerifyHandle()); + init::SetGlobals(); - // Sanity check - if (!InitSanityCheck()) + if (!init::SanityChecks()) { return InitError(strprintf(_("Initialization sanity check failed. %s is shutting down."), PACKAGE_NAME)); + } // Probe the data directory lock to give an early error message, if possible // We cannot hold the data directory lock here, as the forking for daemon() hasn't yet happened, @@ -1273,38 +1102,11 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) // Detailed error printed inside CreatePidFile(). return false; } - if (LogInstance().m_print_to_file) { - if (args.GetBoolArg("-shrinkdebugfile", LogInstance().DefaultShrinkDebugFile())) { - // Do this first since it both loads a bunch of debug.log into memory, - // and because this needs to happen before any other debug.log printing - LogInstance().ShrinkDebugFile(); - } - } - if (!LogInstance().StartLogging()) { - return InitError(strprintf(Untranslated("Could not open debug log file %s"), - LogInstance().m_file_path.string())); - } - - if (!LogInstance().m_log_timestamps) - LogPrintf("Startup time: %s\n", FormatISO8601DateTime(GetTime())); - LogPrintf("Default data directory %s\n", GetDefaultDataDir().string()); - LogPrintf("Using data directory %s\n", GetDataDir().string()); - - // Only log conf file usage message if conf file actually exists. - fs::path config_file_path = GetConfigFile(args.GetArg("-conf", BITCOIN_CONF_FILENAME)); - if (fs::exists(config_file_path)) { - LogPrintf("Config file: %s\n", config_file_path.string()); - } else if (args.IsArgSet("-conf")) { - // Warn if no conf file exists at path provided by user - InitWarning(strprintf(_("The specified config file %s does not exist"), config_file_path.string())); - } else { - // Not categorizing as "Warning" because it's the default behavior - LogPrintf("Config file: %s (not found, skipping)\n", config_file_path.string()); + if (!init::StartLogging(args)) { + // Detailed error printed inside StartLogging(). + return false; } - // Log the config arguments to debug.log - args.LogArgs(); - LogPrintf("Using at most %i automatic connections (%i file descriptors available)\n", nMaxConnections, nFD); // Warn about relative -datadir path. @@ -1835,8 +1637,8 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) InitError(strprintf(_("Error: Disk space is low for %s"), GetDataDir())); return false; } - if (!CheckDiskSpace(GetBlocksDir())) { - InitError(strprintf(_("Error: Disk space is low for %s"), GetBlocksDir())); + if (!CheckDiskSpace(gArgs.GetBlocksDirPath())) { + InitError(strprintf(_("Error: Disk space is low for %s"), gArgs.GetBlocksDirPath())); return false; } @@ -1867,7 +1669,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) vImportFiles.push_back(strFile); } - g_load_block = std::thread(&TraceThread<std::function<void()>>, "loadblk", [=, &chainman, &args] { + chainman.m_load_block = std::thread(&TraceThread<std::function<void()>>, "loadblk", [=, &chainman, &args] { ThreadImport(chainman, vImportFiles, args); }); diff --git a/src/init/common.cpp b/src/init/common.cpp new file mode 100644 index 0000000000..79e0c9da78 --- /dev/null +++ b/src/init/common.cpp @@ -0,0 +1,167 @@ +// Copyright (c) 2021 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#if defined(HAVE_CONFIG_H) +#include <config/bitcoin-config.h> +#endif + +#include <clientversion.h> +#include <compat/sanity.h> +#include <crypto/sha256.h> +#include <key.h> +#include <logging.h> +#include <node/ui_interface.h> +#include <pubkey.h> +#include <random.h> +#include <util/system.h> +#include <util/time.h> +#include <util/translation.h> + +#include <memory> + +static std::unique_ptr<ECCVerifyHandle> globalVerifyHandle; + +namespace init { +void SetGlobals() +{ + std::string sha256_algo = SHA256AutoDetect(); + LogPrintf("Using the '%s' SHA256 implementation\n", sha256_algo); + RandomInit(); + ECC_Start(); + globalVerifyHandle.reset(new ECCVerifyHandle()); +} + +void UnsetGlobals() +{ + globalVerifyHandle.reset(); + ECC_Stop(); +} + +bool SanityChecks() +{ + if (!ECC_InitSanityCheck()) { + return InitError(Untranslated("Elliptic curve cryptography sanity check failure. Aborting.")); + } + + if (!glibcxx_sanity_test()) + return false; + + if (!Random_SanityCheck()) { + return InitError(Untranslated("OS cryptographic RNG sanity check failure. Aborting.")); + } + + if (!ChronoSanityCheck()) { + return InitError(Untranslated("Clock epoch mismatch. Aborting.")); + } + + return true; +} + +void AddLoggingArgs(ArgsManager& argsman) +{ + argsman.AddArg("-debuglogfile=<file>", strprintf("Specify location of debug log file. Relative paths will be prefixed by a net-specific datadir location. (-nodebuglogfile to disable; default: %s)", DEFAULT_DEBUGLOGFILE), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); + argsman.AddArg("-debug=<category>", "Output debugging information (default: -nodebug, supplying <category> is optional). " + "If <category> is not supplied or if <category> = 1, output all debugging information. <category> can be: " + LogInstance().LogCategoriesString() + ". This option can be specified multiple times to output multiple categories.", + ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); + argsman.AddArg("-debugexclude=<category>", strprintf("Exclude debugging information for a category. Can be used in conjunction with -debug=1 to output debug logs for all categories except the specified category. This option can be specified multiple times to exclude multiple categories."), ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); + argsman.AddArg("-logips", strprintf("Include IP addresses in debug output (default: %u)", DEFAULT_LOGIPS), ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); + argsman.AddArg("-logtimestamps", strprintf("Prepend debug output with timestamp (default: %u)", DEFAULT_LOGTIMESTAMPS), ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); +#ifdef HAVE_THREAD_LOCAL + argsman.AddArg("-logthreadnames", strprintf("Prepend debug output with name of the originating thread (only available on platforms supporting thread_local) (default: %u)", DEFAULT_LOGTHREADNAMES), ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); +#else + argsman.AddHiddenArgs({"-logthreadnames"}); +#endif + argsman.AddArg("-logsourcelocations", strprintf("Prepend debug output with name of the originating source location (source file, line number and function name) (default: %u)", DEFAULT_LOGSOURCELOCATIONS), ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); + argsman.AddArg("-logtimemicros", strprintf("Add microsecond precision to debug timestamps (default: %u)", DEFAULT_LOGTIMEMICROS), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); + argsman.AddArg("-printtoconsole", "Send trace/debug info to console (default: 1 when no -daemon. To disable logging to file, set -nodebuglogfile)", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); + argsman.AddArg("-shrinkdebugfile", "Shrink debug.log file on client startup (default: 1 when no -debug)", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); +} + +void SetLoggingOptions(const ArgsManager& args) +{ + LogInstance().m_print_to_file = !args.IsArgNegated("-debuglogfile"); + LogInstance().m_file_path = AbsPathForConfigVal(args.GetArg("-debuglogfile", DEFAULT_DEBUGLOGFILE)); + LogInstance().m_print_to_console = args.GetBoolArg("-printtoconsole", !args.GetBoolArg("-daemon", false)); + LogInstance().m_log_timestamps = args.GetBoolArg("-logtimestamps", DEFAULT_LOGTIMESTAMPS); + LogInstance().m_log_time_micros = args.GetBoolArg("-logtimemicros", DEFAULT_LOGTIMEMICROS); +#ifdef HAVE_THREAD_LOCAL + LogInstance().m_log_threadnames = args.GetBoolArg("-logthreadnames", DEFAULT_LOGTHREADNAMES); +#endif + LogInstance().m_log_sourcelocations = args.GetBoolArg("-logsourcelocations", DEFAULT_LOGSOURCELOCATIONS); + + fLogIPs = args.GetBoolArg("-logips", DEFAULT_LOGIPS); +} + +void SetLoggingCategories(const ArgsManager& args) +{ + if (args.IsArgSet("-debug")) { + // Special-case: if -debug=0/-nodebug is set, turn off debugging messages + const std::vector<std::string> categories = args.GetArgs("-debug"); + + if (std::none_of(categories.begin(), categories.end(), + [](std::string cat){return cat == "0" || cat == "none";})) { + for (const auto& cat : categories) { + if (!LogInstance().EnableCategory(cat)) { + InitWarning(strprintf(_("Unsupported logging category %s=%s."), "-debug", cat)); + } + } + } + } + + // Now remove the logging categories which were explicitly excluded + for (const std::string& cat : args.GetArgs("-debugexclude")) { + if (!LogInstance().DisableCategory(cat)) { + InitWarning(strprintf(_("Unsupported logging category %s=%s."), "-debugexclude", cat)); + } + } +} + +bool StartLogging(const ArgsManager& args) +{ + if (LogInstance().m_print_to_file) { + if (args.GetBoolArg("-shrinkdebugfile", LogInstance().DefaultShrinkDebugFile())) { + // Do this first since it both loads a bunch of debug.log into memory, + // and because this needs to happen before any other debug.log printing + LogInstance().ShrinkDebugFile(); + } + } + if (!LogInstance().StartLogging()) { + return InitError(strprintf(Untranslated("Could not open debug log file %s"), + LogInstance().m_file_path.string())); + } + + if (!LogInstance().m_log_timestamps) + LogPrintf("Startup time: %s\n", FormatISO8601DateTime(GetTime())); + LogPrintf("Default data directory %s\n", GetDefaultDataDir().string()); + LogPrintf("Using data directory %s\n", GetDataDir().string()); + + // Only log conf file usage message if conf file actually exists. + fs::path config_file_path = GetConfigFile(args.GetArg("-conf", BITCOIN_CONF_FILENAME)); + if (fs::exists(config_file_path)) { + LogPrintf("Config file: %s\n", config_file_path.string()); + } else if (args.IsArgSet("-conf")) { + // Warn if no conf file exists at path provided by user + InitWarning(strprintf(_("The specified config file %s does not exist"), config_file_path.string())); + } else { + // Not categorizing as "Warning" because it's the default behavior + LogPrintf("Config file: %s (not found, skipping)\n", config_file_path.string()); + } + + // Log the config arguments to debug.log + args.LogArgs(); + + return true; +} + +void LogPackageVersion() +{ + std::string version_string = FormatFullVersion(); +#ifdef DEBUG + version_string += " (debug build)"; +#else + version_string += " (release build)"; +#endif + LogPrintf(PACKAGE_NAME " version %s\n", version_string); +} +} // namespace init diff --git a/src/init/common.h b/src/init/common.h new file mode 100644 index 0000000000..fc4bc1b280 --- /dev/null +++ b/src/init/common.h @@ -0,0 +1,28 @@ +// Copyright (c) 2021 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +//! @file +//! @brief Common init functions shared by bitcoin-node, bitcoin-wallet, etc. + +#ifndef BITCOIN_INIT_COMMON_H +#define BITCOIN_INIT_COMMON_H + +class ArgsManager; + +namespace init { +void SetGlobals(); +void UnsetGlobals(); +/** + * Ensure a usable environment with all + * necessary library support. + */ +bool SanityChecks(); +void AddLoggingArgs(ArgsManager& args); +void SetLoggingOptions(const ArgsManager& args); +void SetLoggingCategories(const ArgsManager& args); +bool StartLogging(const ArgsManager& args); +void LogPackageVersion(); +} // namespace init + +#endif // BITCOIN_INIT_COMMON_H diff --git a/src/miner.cpp b/src/miner.cpp index 8a9406f810..3bc7fdd458 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -39,13 +39,14 @@ int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParam return nNewTime - nOldTime; } -void RegenerateCommitments(CBlock& block, BlockManager& blockman) +void RegenerateCommitments(CBlock& block, CBlockIndex* prev_block) { CMutableTransaction tx{*block.vtx.at(0)}; tx.vout.erase(tx.vout.begin() + GetWitnessCommitmentIndex(block)); block.vtx.at(0) = MakeTransactionRef(tx); - GenerateCoinbaseCommitment(block, WITH_LOCK(::cs_main, assert(std::addressof(g_chainman.m_blockman) == std::addressof(blockman)); return blockman.LookupBlockIndex(block.hashPrevBlock)), Params().GetConsensus()); + WITH_LOCK(::cs_main, assert(g_chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock) == prev_block)); + GenerateCoinbaseCommitment(block, prev_block, Params().GetConsensus()); block.hashMerkleRoot = BlockMerkleRoot(block); } diff --git a/src/miner.h b/src/miner.h index c400c90f6c..becf362b79 100644 --- a/src/miner.h +++ b/src/miner.h @@ -202,8 +202,7 @@ private: void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned int& nExtraNonce); int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev); -// TODO just accept a CBlockIndex* /** Update an old GenerateCoinbaseCommitment from CreateNewBlock after the block txs have changed */ -void RegenerateCommitments(CBlock& block, BlockManager& blockman); +void RegenerateCommitments(CBlock& block, CBlockIndex* prev_block); #endif // BITCOIN_MINER_H diff --git a/src/net.cpp b/src/net.cpp index a8e07a567d..fe1a0dfded 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1732,7 +1732,7 @@ void CConnman::ProcessAddrFetch() } } -bool CConnman::GetTryNewOutboundPeer() +bool CConnman::GetTryNewOutboundPeer() const { return m_try_another_outbound_peer; } @@ -1749,7 +1749,7 @@ void CConnman::SetTryNewOutboundPeer(bool flag) // Also exclude peers that haven't finished initial connection handshake yet // (so that we don't decide we're over our desired connection limit, and then // evict some peer that has finished the handshake) -int CConnman::GetExtraFullOutboundCount() +int CConnman::GetExtraFullOutboundCount() const { int full_outbound_peers = 0; { @@ -1763,7 +1763,7 @@ int CConnman::GetExtraFullOutboundCount() return std::max(full_outbound_peers - m_max_outbound_full_relay, 0); } -int CConnman::GetExtraBlockRelayCount() +int CConnman::GetExtraBlockRelayCount() const { int block_relay_peers = 0; { @@ -2061,7 +2061,7 @@ std::vector<CAddress> CConnman::GetCurrentBlockRelayOnlyConns() const return ret; } -std::vector<AddedNodeInfo> CConnman::GetAddedNodeInfo() +std::vector<AddedNodeInfo> CConnman::GetAddedNodeInfo() const { std::vector<AddedNodeInfo> ret; @@ -2674,7 +2674,7 @@ CConnman::~CConnman() Stop(); } -std::vector<CAddress> CConnman::GetAddresses(size_t max_addresses, size_t max_pct) +std::vector<CAddress> CConnman::GetAddresses(size_t max_addresses, size_t max_pct) const { std::vector<CAddress> addresses = addrman.GetAddr(max_addresses, max_pct); if (m_banman) { @@ -2749,7 +2749,7 @@ bool CConnman::RemoveAddedNode(const std::string& strNode) return false; } -size_t CConnman::GetNodeCount(ConnectionDirection flags) +size_t CConnman::GetNodeCount(ConnectionDirection flags) const { LOCK(cs_vNodes); if (flags == ConnectionDirection::Both) // Shortcut if we want total @@ -2765,7 +2765,7 @@ size_t CConnman::GetNodeCount(ConnectionDirection flags) return nNum; } -void CConnman::GetNodeStats(std::vector<CNodeStats>& vstats) +void CConnman::GetNodeStats(std::vector<CNodeStats>& vstats) const { vstats.clear(); LOCK(cs_vNodes); @@ -2842,18 +2842,18 @@ void CConnman::RecordBytesSent(uint64_t bytes) nMaxOutboundTotalBytesSentInCycle += bytes; } -uint64_t CConnman::GetMaxOutboundTarget() +uint64_t CConnman::GetMaxOutboundTarget() const { LOCK(cs_totalBytesSent); return nMaxOutboundLimit; } -std::chrono::seconds CConnman::GetMaxOutboundTimeframe() +std::chrono::seconds CConnman::GetMaxOutboundTimeframe() const { return MAX_UPLOAD_TIMEFRAME; } -std::chrono::seconds CConnman::GetMaxOutboundTimeLeftInCycle() +std::chrono::seconds CConnman::GetMaxOutboundTimeLeftInCycle() const { LOCK(cs_totalBytesSent); if (nMaxOutboundLimit == 0) @@ -2867,7 +2867,7 @@ std::chrono::seconds CConnman::GetMaxOutboundTimeLeftInCycle() return (cycleEndTime < now) ? 0s : cycleEndTime - now; } -bool CConnman::OutboundTargetReached(bool historicalBlockServingLimit) +bool CConnman::OutboundTargetReached(bool historicalBlockServingLimit) const { LOCK(cs_totalBytesSent); if (nMaxOutboundLimit == 0) @@ -2887,7 +2887,7 @@ bool CConnman::OutboundTargetReached(bool historicalBlockServingLimit) return false; } -uint64_t CConnman::GetOutboundTargetBytesLeft() +uint64_t CConnman::GetOutboundTargetBytesLeft() const { LOCK(cs_totalBytesSent); if (nMaxOutboundLimit == 0) @@ -2896,13 +2896,13 @@ uint64_t CConnman::GetOutboundTargetBytesLeft() return (nMaxOutboundTotalBytesSentInCycle >= nMaxOutboundLimit) ? 0 : nMaxOutboundLimit - nMaxOutboundTotalBytesSentInCycle; } -uint64_t CConnman::GetTotalBytesRecv() +uint64_t CConnman::GetTotalBytesRecv() const { LOCK(cs_totalBytesRecv); return nTotalBytesRecv; } -uint64_t CConnman::GetTotalBytesSent() +uint64_t CConnman::GetTotalBytesSent() const { LOCK(cs_totalBytesSent); return nTotalBytesSent; @@ -923,7 +923,7 @@ public: }; // Addrman functions - std::vector<CAddress> GetAddresses(size_t max_addresses, size_t max_pct); + std::vector<CAddress> GetAddresses(size_t max_addresses, size_t max_pct) const; /** * Cache is used to minimize topology leaks, so it should * be used for all non-trusted calls, for example, p2p. @@ -935,7 +935,7 @@ public: // This allows temporarily exceeding m_max_outbound_full_relay, with the goal of finding // a peer that is better than all our current peers. void SetTryNewOutboundPeer(bool flag); - bool GetTryNewOutboundPeer(); + bool GetTryNewOutboundPeer() const; void StartExtraBlockRelayPeers() { LogPrint(BCLog::NET, "net: enabling extra block-relay-only peers\n"); @@ -948,13 +948,13 @@ public: // return a value less than (num_outbound_connections - num_outbound_slots) // in cases where some outbound connections are not yet fully connected, or // not yet fully disconnected. - int GetExtraFullOutboundCount(); + int GetExtraFullOutboundCount() const; // Count the number of block-relay-only peers we have over our limit. - int GetExtraBlockRelayCount(); + int GetExtraBlockRelayCount() const; bool AddNode(const std::string& node); bool RemoveAddedNode(const std::string& node); - std::vector<AddedNodeInfo> GetAddedNodeInfo(); + std::vector<AddedNodeInfo> GetAddedNodeInfo() const; /** * Attempts to open a connection. Currently only used from tests. @@ -969,8 +969,8 @@ public: */ bool AddConnection(const std::string& address, ConnectionType conn_type); - size_t GetNodeCount(ConnectionDirection); - void GetNodeStats(std::vector<CNodeStats>& vstats); + size_t GetNodeCount(ConnectionDirection) const; + void GetNodeStats(std::vector<CNodeStats>& vstats) const; bool DisconnectNode(const std::string& node); bool DisconnectNode(const CSubNet& subnet); bool DisconnectNode(const CNetAddr& addr); @@ -984,24 +984,24 @@ public: //! that peer during `net_processing.cpp:PushNodeVersion()`. ServiceFlags GetLocalServices() const; - uint64_t GetMaxOutboundTarget(); - std::chrono::seconds GetMaxOutboundTimeframe(); + uint64_t GetMaxOutboundTarget() const; + std::chrono::seconds GetMaxOutboundTimeframe() const; //! check if the outbound target is reached //! if param historicalBlockServingLimit is set true, the function will //! response true if the limit for serving historical blocks has been reached - bool OutboundTargetReached(bool historicalBlockServingLimit); + bool OutboundTargetReached(bool historicalBlockServingLimit) const; //! response the bytes left in the current max outbound cycle //! in case of no limit, it will always response 0 - uint64_t GetOutboundTargetBytesLeft(); + uint64_t GetOutboundTargetBytesLeft() const; //! returns the time left in the current max outbound cycle //! in case of no limit, it will always return 0 - std::chrono::seconds GetMaxOutboundTimeLeftInCycle(); + std::chrono::seconds GetMaxOutboundTimeLeftInCycle() const; - uint64_t GetTotalBytesRecv(); - uint64_t GetTotalBytesSent(); + uint64_t GetTotalBytesRecv() const; + uint64_t GetTotalBytesSent() const; /** Get a unique deterministic randomizer. */ CSipHasher GetDeterministicRandomizer(uint64_t id) const; @@ -1106,8 +1106,8 @@ private: static bool NodeFullyConnected(const CNode* pnode); // Network usage totals - RecursiveMutex cs_totalBytesRecv; - RecursiveMutex cs_totalBytesSent; + mutable RecursiveMutex cs_totalBytesRecv; + mutable RecursiveMutex cs_totalBytesSent; uint64_t nTotalBytesRecv GUARDED_BY(cs_totalBytesRecv) {0}; uint64_t nTotalBytesSent GUARDED_BY(cs_totalBytesSent) {0}; @@ -1133,7 +1133,7 @@ private: std::deque<std::string> m_addr_fetches GUARDED_BY(m_addr_fetches_mutex); RecursiveMutex m_addr_fetches_mutex; std::vector<std::string> vAddedNodes GUARDED_BY(cs_vAddedNodes); - RecursiveMutex cs_vAddedNodes; + mutable RecursiveMutex cs_vAddedNodes; std::vector<CNode*> vNodes GUARDED_BY(cs_vNodes); std::list<CNode*> vNodesDisconnected; mutable RecursiveMutex cs_vNodes; diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 84c26c3df1..2201caf7d2 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -16,6 +16,7 @@ #include <merkleblock.h> #include <netbase.h> #include <netmessagemaker.h> +#include <node/blockstorage.h> #include <policy/fees.h> #include <policy/policy.h> #include <primitives/block.h> @@ -245,7 +246,7 @@ public: /** Implement PeerManager */ void CheckForStaleTipAndEvictPeers() override; - bool GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) override; + bool GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) const override; bool IgnoresIncomingTxs() override { return m_ignore_incoming_txs; } void SendPings() override; void RelayTransaction(const uint256& txid, const uint256& wtxid) override; @@ -450,6 +451,8 @@ private: void ProcessGetData(CNode& pfrom, Peer& peer, const std::atomic<bool>& interruptMsgProc) EXCLUSIVE_LOCKS_REQUIRED(peer.m_getdata_requests_mutex) LOCKS_EXCLUDED(::cs_main); + void ProcessBlock(CNode& pfrom, const std::shared_ptr<const CBlock>& pblock, bool fForceProcessing); + /** Relay map (txid or wtxid -> CTransactionRef) */ typedef std::map<uint256, CTransactionRef> MapRelay; MapRelay mapRelay GUARDED_BY(cs_main); @@ -1100,7 +1103,7 @@ PeerRef PeerManagerImpl::RemovePeer(NodeId id) return ret; } -bool PeerManagerImpl::GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) +bool PeerManagerImpl::GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) const { { LOCK(cs_main); @@ -2308,6 +2311,18 @@ void PeerManagerImpl::ProcessGetCFCheckPt(CNode& peer, CDataStream& vRecv) m_connman.PushMessage(&peer, std::move(msg)); } +void PeerManagerImpl::ProcessBlock(CNode& pfrom, const std::shared_ptr<const CBlock>& pblock, bool fForceProcessing) +{ + bool fNewBlock = false; + m_chainman.ProcessNewBlock(m_chainparams, pblock, fForceProcessing, &fNewBlock); + if (fNewBlock) { + pfrom.nLastBlockTime = GetTime(); + } else { + LOCK(cs_main); + mapBlockSource.erase(pblock->GetHash()); + } +} + void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv, const std::chrono::microseconds time_received, const std::atomic<bool>& interruptMsgProc) @@ -3389,7 +3404,6 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, LOCK(cs_main); mapBlockSource.emplace(pblock->GetHash(), std::make_pair(pfrom.GetId(), false)); } - bool fNewBlock = false; // Setting fForceProcessing to true means that we bypass some of // our anti-DoS protections in AcceptBlock, which filters // unrequested blocks that might be trying to waste our resources @@ -3399,13 +3413,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, // we have a chain with at least nMinimumChainWork), and we ignore // compact blocks with less work than our tip, it is safe to treat // reconstructed compact blocks as having been requested. - m_chainman.ProcessNewBlock(m_chainparams, pblock, /*fForceProcessing=*/true, &fNewBlock); - if (fNewBlock) { - pfrom.nLastBlockTime = GetTime(); - } else { - LOCK(cs_main); - mapBlockSource.erase(pblock->GetHash()); - } + ProcessBlock(pfrom, pblock, /*fForceProcessing=*/true); LOCK(cs_main); // hold cs_main for CBlockIndex::IsValid() if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS)) { // Clear download state for this block, which is in @@ -3482,20 +3490,13 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, } } // Don't hold cs_main when we call into ProcessNewBlock if (fBlockRead) { - bool fNewBlock = false; // Since we requested this block (it was in mapBlocksInFlight), force it to be processed, // even if it would not be a candidate for new tip (missing previous block, chain not long enough, etc) // This bypasses some anti-DoS logic in AcceptBlock (eg to prevent // disk-space attacks), but this should be safe due to the // protections in the compact block handler -- see related comment // in compact block optimistic reconstruction handling. - m_chainman.ProcessNewBlock(m_chainparams, pblock, /*fForceProcessing=*/true, &fNewBlock); - if (fNewBlock) { - pfrom.nLastBlockTime = GetTime(); - } else { - LOCK(cs_main); - mapBlockSource.erase(pblock->GetHash()); - } + ProcessBlock(pfrom, pblock, /*fForceProcessing=*/true); } return; } @@ -3550,14 +3551,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, // cs_main in ProcessNewBlock is fine. mapBlockSource.emplace(hash, std::make_pair(pfrom.GetId(), true)); } - bool fNewBlock = false; - m_chainman.ProcessNewBlock(m_chainparams, pblock, forceProcessing, &fNewBlock); - if (fNewBlock) { - pfrom.nLastBlockTime = GetTime(); - } else { - LOCK(cs_main); - mapBlockSource.erase(pblock->GetHash()); - } + ProcessBlock(pfrom, pblock, forceProcessing); return; } diff --git a/src/net_processing.h b/src/net_processing.h index 4556d32377..67252acbb6 100644 --- a/src/net_processing.h +++ b/src/net_processing.h @@ -43,7 +43,7 @@ public: virtual ~PeerManager() { } /** Get statistics from node state */ - virtual bool GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) = 0; + virtual bool GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) const = 0; /** Whether this node ignores txs received over p2p. */ virtual bool IgnoresIncomingTxs() = 0; diff --git a/src/netaddress.cpp b/src/netaddress.cpp index 69edc15c66..d56ae78e92 100644 --- a/src/netaddress.cpp +++ b/src/netaddress.cpp @@ -551,6 +551,11 @@ enum Network CNetAddr::GetNetwork() const return m_net; } +static std::string IPv4ToString(Span<const uint8_t> a) +{ + return strprintf("%u.%u.%u.%u", a[0], a[1], a[2], a[3]); +} + static std::string IPv6ToString(Span<const uint8_t> a) { assert(a.size() == ADDR_IPV6_SIZE); @@ -571,6 +576,7 @@ std::string CNetAddr::ToStringIP() const { switch (m_net) { case NET_IPV4: + return IPv4ToString(m_addr); case NET_IPV6: { CService serv(*this, 0); struct sockaddr_storage sockaddr; @@ -581,9 +587,6 @@ std::string CNetAddr::ToStringIP() const sizeof(name), nullptr, 0, NI_NUMERICHOST)) return std::string(name); } - if (m_net == NET_IPV4) { - return strprintf("%u.%u.%u.%u", m_addr[0], m_addr[1], m_addr[2], m_addr[3]); - } return IPv6ToString(m_addr); } case NET_ONION: diff --git a/src/node/README.md b/src/node/README.md index e99a717534..ab5979594d 100644 --- a/src/node/README.md +++ b/src/node/README.md @@ -15,8 +15,7 @@ As a rule of thumb, code in one of the [`src/node/`](./), calling code in the other directories directly, and only invoke it indirectly through the more limited [`src/interfaces/`](../interfaces/) classes. -The [`src/node/`](./) directory is a new directory introduced in -[#14978](https://github.com/bitcoin/bitcoin/pull/14978) and at the moment is +This directory is at the moment sparsely populated. Eventually more substantial files like [`src/validation.cpp`](../validation.cpp) and [`src/txmempool.cpp`](../txmempool.cpp) might be moved there. diff --git a/src/node/blockstorage.cpp b/src/node/blockstorage.cpp new file mode 100644 index 0000000000..daed6605e8 --- /dev/null +++ b/src/node/blockstorage.cpp @@ -0,0 +1,244 @@ +// 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 <node/blockstorage.h> + +#include <chain.h> +#include <chainparams.h> +#include <flatfile.h> +#include <fs.h> +#include <pow.h> +#include <shutdown.h> +#include <signet.h> +#include <streams.h> +#include <util/system.h> +#include <validation.h> + +// From validation. TODO move here +bool FindBlockPos(FlatFilePos& pos, unsigned int nAddSize, unsigned int nHeight, CChain& active_chain, uint64_t nTime, bool fKnown = false); + +static bool WriteBlockToDisk(const CBlock& block, FlatFilePos& pos, const CMessageHeader::MessageStartChars& messageStart) +{ + // Open history file to append + CAutoFile fileout(OpenBlockFile(pos), SER_DISK, CLIENT_VERSION); + if (fileout.IsNull()) { + return error("WriteBlockToDisk: OpenBlockFile failed"); + } + + // Write index header + unsigned int nSize = GetSerializeSize(block, fileout.GetVersion()); + fileout << messageStart << nSize; + + // Write block + long fileOutPos = ftell(fileout.Get()); + if (fileOutPos < 0) { + return error("WriteBlockToDisk: ftell failed"); + } + pos.nPos = (unsigned int)fileOutPos; + fileout << block; + + return true; +} + +bool ReadBlockFromDisk(CBlock& block, const FlatFilePos& pos, const Consensus::Params& consensusParams) +{ + block.SetNull(); + + // Open history file to read + CAutoFile filein(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION); + if (filein.IsNull()) { + return error("ReadBlockFromDisk: OpenBlockFile failed for %s", pos.ToString()); + } + + // Read block + try { + filein >> block; + } catch (const std::exception& e) { + return error("%s: Deserialize or I/O error - %s at %s", __func__, e.what(), pos.ToString()); + } + + // Check the header + if (!CheckProofOfWork(block.GetHash(), block.nBits, consensusParams)) { + return error("ReadBlockFromDisk: Errors in block header at %s", pos.ToString()); + } + + // Signet only: check block solution + if (consensusParams.signet_blocks && !CheckSignetBlockSolution(block, consensusParams)) { + return error("ReadBlockFromDisk: Errors in block solution at %s", pos.ToString()); + } + + return true; +} + +bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const Consensus::Params& consensusParams) +{ + FlatFilePos blockPos; + { + LOCK(cs_main); + blockPos = pindex->GetBlockPos(); + } + + if (!ReadBlockFromDisk(block, blockPos, consensusParams)) { + return false; + } + if (block.GetHash() != pindex->GetBlockHash()) { + return error("ReadBlockFromDisk(CBlock&, CBlockIndex*): GetHash() doesn't match index for %s at %s", + pindex->ToString(), pindex->GetBlockPos().ToString()); + } + return true; +} + +bool ReadRawBlockFromDisk(std::vector<uint8_t>& block, const FlatFilePos& pos, const CMessageHeader::MessageStartChars& message_start) +{ + FlatFilePos hpos = pos; + hpos.nPos -= 8; // Seek back 8 bytes for meta header + CAutoFile filein(OpenBlockFile(hpos, true), SER_DISK, CLIENT_VERSION); + if (filein.IsNull()) { + return error("%s: OpenBlockFile failed for %s", __func__, pos.ToString()); + } + + try { + CMessageHeader::MessageStartChars blk_start; + unsigned int blk_size; + + filein >> blk_start >> blk_size; + + if (memcmp(blk_start, message_start, CMessageHeader::MESSAGE_START_SIZE)) { + return error("%s: Block magic mismatch for %s: %s versus expected %s", __func__, pos.ToString(), + HexStr(blk_start), + HexStr(message_start)); + } + + if (blk_size > MAX_SIZE) { + return error("%s: Block data is larger than maximum deserialization size for %s: %s versus %s", __func__, pos.ToString(), + blk_size, MAX_SIZE); + } + + block.resize(blk_size); // Zeroing of memory is intentional here + filein.read((char*)block.data(), blk_size); + } catch (const std::exception& e) { + return error("%s: Read from block file failed: %s for %s", __func__, e.what(), pos.ToString()); + } + + return true; +} + +bool ReadRawBlockFromDisk(std::vector<uint8_t>& block, const CBlockIndex* pindex, const CMessageHeader::MessageStartChars& message_start) +{ + FlatFilePos block_pos; + { + LOCK(cs_main); + block_pos = pindex->GetBlockPos(); + } + + return ReadRawBlockFromDisk(block, block_pos, message_start); +} + +/** Store block on disk. If dbp is non-nullptr, the file is known to already reside on disk */ +FlatFilePos SaveBlockToDisk(const CBlock& block, int nHeight, CChain& active_chain, const CChainParams& chainparams, const FlatFilePos* dbp) +{ + unsigned int nBlockSize = ::GetSerializeSize(block, CLIENT_VERSION); + FlatFilePos blockPos; + if (dbp != nullptr) { + blockPos = *dbp; + } + if (!FindBlockPos(blockPos, nBlockSize + 8, nHeight, active_chain, block.GetBlockTime(), dbp != nullptr)) { + error("%s: FindBlockPos failed", __func__); + return FlatFilePos(); + } + if (dbp == nullptr) { + if (!WriteBlockToDisk(block, blockPos, chainparams.MessageStart())) { + AbortNode("Failed to write block"); + return FlatFilePos(); + } + } + return blockPos; +} + +struct CImportingNow { + CImportingNow() + { + assert(fImporting == false); + fImporting = true; + } + + ~CImportingNow() + { + assert(fImporting == true); + fImporting = false; + } +}; + +void ThreadImport(ChainstateManager& chainman, std::vector<fs::path> vImportFiles, const ArgsManager& args) +{ + const CChainParams& chainparams = Params(); + ScheduleBatchPriority(); + + { + CImportingNow imp; + + // -reindex + if (fReindex) { + int nFile = 0; + while (true) { + FlatFilePos pos(nFile, 0); + if (!fs::exists(GetBlockPosFilename(pos))) { + break; // No block files left to reindex + } + FILE* file = OpenBlockFile(pos, true); + if (!file) { + break; // This error is logged in OpenBlockFile + } + LogPrintf("Reindexing block file blk%05u.dat...\n", (unsigned int)nFile); + chainman.ActiveChainstate().LoadExternalBlockFile(chainparams, file, &pos); + if (ShutdownRequested()) { + LogPrintf("Shutdown requested. Exit %s\n", __func__); + return; + } + nFile++; + } + pblocktree->WriteReindexing(false); + fReindex = false; + LogPrintf("Reindexing finished\n"); + // To avoid ending up in a situation without genesis block, re-try initializing (no-op if reindexing worked): + chainman.ActiveChainstate().LoadGenesisBlock(chainparams); + } + + // -loadblock= + for (const fs::path& path : vImportFiles) { + FILE* file = fsbridge::fopen(path, "rb"); + if (file) { + LogPrintf("Importing blocks file %s...\n", path.string()); + chainman.ActiveChainstate().LoadExternalBlockFile(chainparams, file); + if (ShutdownRequested()) { + LogPrintf("Shutdown requested. Exit %s\n", __func__); + return; + } + } else { + LogPrintf("Warning: Could not open blocks file %s\n", path.string()); + } + } + + // scan for better chains in the block chain database, that are not yet connected in the active best chain + + // We can't hold cs_main during ActivateBestChain even though we're accessing + // the chainman unique_ptrs since ABC requires us not to be holding cs_main, so retrieve + // the relevant pointers before the ABC call. + for (CChainState* chainstate : WITH_LOCK(::cs_main, return chainman.GetAll())) { + BlockValidationState state; + if (!chainstate->ActivateBestChain(state, chainparams, nullptr)) { + LogPrintf("Failed to connect best block (%s)\n", state.ToString()); + StartShutdown(); + return; + } + } + + if (args.GetBoolArg("-stopafterblockimport", DEFAULT_STOPAFTERBLOCKIMPORT)) { + LogPrintf("Stopping after block import\n"); + StartShutdown(); + return; + } + } // End scope of CImportingNow + chainman.ActiveChainstate().LoadMempool(args); +} diff --git a/src/node/blockstorage.h b/src/node/blockstorage.h new file mode 100644 index 0000000000..3b546f0719 --- /dev/null +++ b/src/node/blockstorage.h @@ -0,0 +1,40 @@ +// 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. + +#ifndef BITCOIN_NODE_BLOCKSTORAGE_H +#define BITCOIN_NODE_BLOCKSTORAGE_H + +#include <cstdint> +#include <vector> + +#include <fs.h> +#include <protocol.h> // For CMessageHeader::MessageStartChars + +class ArgsManager; +class CBlock; +class CBlockIndex; +class CBlockUndo; +class CChain; +class CChainParams; +class ChainstateManager; +struct FlatFilePos; +namespace Consensus { +struct Params; +} + +static constexpr bool DEFAULT_STOPAFTERBLOCKIMPORT{false}; + +/** Functions for disk access for blocks */ +bool ReadBlockFromDisk(CBlock& block, const FlatFilePos& pos, const Consensus::Params& consensusParams); +bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const Consensus::Params& consensusParams); +bool ReadRawBlockFromDisk(std::vector<uint8_t>& block, const FlatFilePos& pos, const CMessageHeader::MessageStartChars& message_start); +bool ReadRawBlockFromDisk(std::vector<uint8_t>& block, const CBlockIndex* pindex, const CMessageHeader::MessageStartChars& message_start); + +bool UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex* pindex); + +FlatFilePos SaveBlockToDisk(const CBlock& block, int nHeight, CChain& active_chain, const CChainParams& chainparams, const FlatFilePos* dbp); + +void ThreadImport(ChainstateManager& chainman, std::vector<fs::path> vImportFiles, const ArgsManager& args); + +#endif // BITCOIN_NODE_BLOCKSTORAGE_H diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp index e10e89b8cf..8befbf5e30 100644 --- a/src/node/interfaces.cpp +++ b/src/node/interfaces.cpp @@ -4,7 +4,6 @@ #include <addrdb.h> #include <banman.h> -#include <boost/signals2/signal.hpp> #include <chain.h> #include <chainparams.h> #include <init.h> @@ -17,6 +16,7 @@ #include <net_processing.h> #include <netaddress.h> #include <netbase.h> +#include <node/blockstorage.h> #include <node/coin.h> #include <node/context.h> #include <node/transaction.h> @@ -53,6 +53,8 @@ #include <optional> #include <utility> +#include <boost/signals2/signal.hpp> + using interfaces::BlockTip; using interfaces::Chain; using interfaces::FoundBlock; diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp index 9927e925ac..a816a0764c 100644 --- a/src/qt/addressbookpage.cpp +++ b/src/qt/addressbookpage.cpp @@ -112,29 +112,17 @@ AddressBookPage::AddressBookPage(const PlatformStyle *platformStyle, Mode _mode, break; } - // Context menu actions - QAction *copyAddressAction = new QAction(tr("&Copy Address"), this); - QAction *copyLabelAction = new QAction(tr("Copy &Label"), this); - QAction *editAction = new QAction(tr("&Edit"), this); - deleteAction = new QAction(ui->deleteAddress->text(), this); - // Build context menu contextMenu = new QMenu(this); - contextMenu->addAction(copyAddressAction); - contextMenu->addAction(copyLabelAction); - contextMenu->addAction(editAction); - if(tab == SendingTab) - contextMenu->addAction(deleteAction); - contextMenu->addSeparator(); - - // Connect signals for context menu actions - connect(copyAddressAction, &QAction::triggered, this, &AddressBookPage::on_copyAddress_clicked); - connect(copyLabelAction, &QAction::triggered, this, &AddressBookPage::onCopyLabelAction); - connect(editAction, &QAction::triggered, this, &AddressBookPage::onEditAction); - connect(deleteAction, &QAction::triggered, this, &AddressBookPage::on_deleteAddress_clicked); + contextMenu->addAction(tr("Copy Address"), this, &AddressBookPage::on_copyAddress_clicked); + contextMenu->addAction(tr("Copy Label"), this, &AddressBookPage::onCopyLabelAction); + contextMenu->addAction(tr("Edit"), this, &AddressBookPage::onEditAction); - connect(ui->tableView, &QWidget::customContextMenuRequested, this, &AddressBookPage::contextualMenu); + if (tab == SendingTab) { + contextMenu->addAction(tr("Delete"), this, &AddressBookPage::on_deleteAddress_clicked); + } + connect(ui->tableView, &QWidget::customContextMenuRequested, this, &AddressBookPage::contextualMenu); connect(ui->closeButton, &QPushButton::clicked, this, &QDialog::accept); GUIUtil::handleCloseWindowShortcut(this); @@ -249,13 +237,11 @@ void AddressBookPage::selectionChanged() // In sending tab, allow deletion of selection ui->deleteAddress->setEnabled(true); ui->deleteAddress->setVisible(true); - deleteAction->setEnabled(true); break; case ReceivingTab: // Deleting receiving addresses, however, is not allowed ui->deleteAddress->setEnabled(false); ui->deleteAddress->setVisible(false); - deleteAction->setEnabled(false); break; } ui->copyAddress->setEnabled(true); @@ -309,7 +295,8 @@ void AddressBookPage::on_exportButton_clicked() if(!writer.write()) { QMessageBox::critical(this, tr("Exporting Failed"), - tr("There was an error trying to save the address list to %1. Please try again.").arg(filename)); + //: %1 is a name of the file (e.g., "addrbook.csv") that the bitcoin addresses were exported to. + tr("There was an error trying to save the address list to %1. Please try again.", "An error message.").arg(filename)); } } diff --git a/src/qt/addressbookpage.h b/src/qt/addressbookpage.h index c6a364ccbd..93feac9e23 100644 --- a/src/qt/addressbookpage.h +++ b/src/qt/addressbookpage.h @@ -55,7 +55,6 @@ private: QString returnValue; AddressBookSortFilterProxyModel *proxyModel; QMenu *contextMenu; - QAction *deleteAction; // to be able to explicitly disable it QString newAddressToSelect; private Q_SLOTS: diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index fc6d0febc2..de71b7dea7 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -45,10 +45,12 @@ #include <QApplication> #include <QDebug> #include <QFontDatabase> +#include <QLatin1String> #include <QLibraryInfo> #include <QLocale> #include <QMessageBox> #include <QSettings> +#include <QStringBuilder> #include <QThread> #include <QTimer> #include <QTranslator> @@ -417,10 +419,23 @@ void BitcoinApplication::shutdownResult() void BitcoinApplication::handleRunawayException(const QString &message) { - QMessageBox::critical(nullptr, "Runaway exception", BitcoinGUI::tr("A fatal error occurred. %1 can no longer continue safely and will quit.").arg(PACKAGE_NAME) + QString("<br><br>") + message); + QMessageBox::critical( + nullptr, tr("Runaway exception"), + tr("A fatal error occurred. %1 can no longer continue safely and will quit.").arg(PACKAGE_NAME) % + QLatin1String("<br><br>") % GUIUtil::MakeHtmlLink(message, PACKAGE_BUGREPORT)); ::exit(EXIT_FAILURE); } +void BitcoinApplication::handleNonFatalException(const QString& message) +{ + assert(QThread::currentThread() == thread()); + QMessageBox::warning( + nullptr, tr("Internal error"), + tr("An internal error occurred. %1 will attempt to continue safely. This is " + "an unexpected bug which can be reported as described below.").arg(PACKAGE_NAME) % + QLatin1String("<br><br>") % GUIUtil::MakeHtmlLink(message, PACKAGE_BUGREPORT)); +} + WId BitcoinApplication::getMainWinId() const { if (!window) diff --git a/src/qt/bitcoin.h b/src/qt/bitcoin.h index 69e0a5921e..5fd6bd607f 100644 --- a/src/qt/bitcoin.h +++ b/src/qt/bitcoin.h @@ -99,6 +99,12 @@ public Q_SLOTS: /// Handle runaway exceptions. Shows a message box with the problem and quits the program. void handleRunawayException(const QString &message); + /** + * A helper function that shows a message box + * with details about a non-fatal exception. + */ + void handleNonFatalException(const QString& message); + Q_SIGNALS: void requestedInitialize(); void requestedShutdown(); diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 6677c9e3b5..3e29d8e132 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -654,7 +654,7 @@ void BitcoinGUI::setWalletController(WalletController* wallet_controller) m_open_wallet_action->setEnabled(true); m_open_wallet_action->setMenu(m_open_wallet_menu); - connect(wallet_controller, &WalletController::walletAdded, this, &BitcoinGUI::addWallet); + GUIUtil::ExceptionSafeConnect(wallet_controller, &WalletController::walletAdded, this, &BitcoinGUI::addWallet); connect(wallet_controller, &WalletController::walletRemoved, this, &BitcoinGUI::removeWallet); for (WalletModel* wallet_model : m_wallet_controller->getOpenWallets()) { @@ -1468,11 +1468,8 @@ void UnitDisplayStatusBarControl::mousePressEvent(QMouseEvent *event) void UnitDisplayStatusBarControl::createContextMenu() { menu = new QMenu(this); - for (const BitcoinUnits::Unit u : BitcoinUnits::availableUnits()) - { - QAction *menuAction = new QAction(QString(BitcoinUnits::longName(u)), this); - menuAction->setData(QVariant(u)); - menu->addAction(menuAction); + for (const BitcoinUnits::Unit u : BitcoinUnits::availableUnits()) { + menu->addAction(BitcoinUnits::longName(u))->setData(QVariant(u)); } connect(menu, &QMenu::triggered, this, &UnitDisplayStatusBarControl::onMenuSelection); } diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp index 27e512d075..ab631459fb 100644 --- a/src/qt/bitcoinstrings.cpp +++ b/src/qt/bitcoinstrings.cpp @@ -17,13 +17,17 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" "-maxtxfee is set very high! Fees this large could be paid on a single " "transaction."), QT_TRANSLATE_NOOP("bitcoin-core", "" +"Cannot downgrade wallet from version %i to version %i. Wallet version " +"unchanged."), +QT_TRANSLATE_NOOP("bitcoin-core", "" "Cannot obtain a lock on data directory %s. %s is probably already running."), QT_TRANSLATE_NOOP("bitcoin-core", "" "Cannot provide specific connections and have addrman find outgoing " "connections at the same."), QT_TRANSLATE_NOOP("bitcoin-core", "" -"Cannot upgrade a non HD split wallet without upgrading to support pre split " -"keypool. Please use version 169900 or no version specified."), +"Cannot upgrade a non HD split wallet from version %i to version %i without " +"upgrading to support pre-split keypool. Please use version %i or no version " +"specified."), QT_TRANSLATE_NOOP("bitcoin-core", "" "Distributed under the MIT software license, see the accompanying file %s or " "%s"), @@ -31,17 +35,35 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" "Error reading %s! All keys read correctly, but transaction data or address " "book entries might be missing or incorrect."), QT_TRANSLATE_NOOP("bitcoin-core", "" +"Error: Dumpfile format record is incorrect. Got \"%s\", expected \"format\"."), +QT_TRANSLATE_NOOP("bitcoin-core", "" +"Error: Dumpfile identifier record is incorrect. Got \"%s\", expected \"%s\"."), +QT_TRANSLATE_NOOP("bitcoin-core", "" +"Error: Dumpfile version is not supported. This version of bitcoin-wallet " +"only supports version 1 dumpfiles. Got dumpfile with version %s"), +QT_TRANSLATE_NOOP("bitcoin-core", "" "Error: Listening for incoming connections failed (listen returned error %s)"), QT_TRANSLATE_NOOP("bitcoin-core", "" "Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -" "fallbackfee."), QT_TRANSLATE_NOOP("bitcoin-core", "" +"File %s already exists. If you are sure this is what you want, move it out " +"of the way first."), +QT_TRANSLATE_NOOP("bitcoin-core", "" "Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay " "fee of %s to prevent stuck transactions)"), QT_TRANSLATE_NOOP("bitcoin-core", "" "More than one onion bind address is provided. Using %s for the automatically " "created Tor onion service."), QT_TRANSLATE_NOOP("bitcoin-core", "" +"No dump file provided. To use createfromdump, -dumpfile=<filename> must be " +"provided."), +QT_TRANSLATE_NOOP("bitcoin-core", "" +"No dump file provided. To use dump, -dumpfile=<filename> must be provided."), +QT_TRANSLATE_NOOP("bitcoin-core", "" +"No wallet file format provided. To use createfromdump, -format=<format> must " +"be provided."), +QT_TRANSLATE_NOOP("bitcoin-core", "" "Please check that your computer's date and time are correct! If your clock " "is wrong, %s will not work properly."), QT_TRANSLATE_NOOP("bitcoin-core", "" @@ -96,10 +118,13 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" "Unable to rewind the database to a pre-fork state. You will need to " "redownload the blockchain"), QT_TRANSLATE_NOOP("bitcoin-core", "" -"Warning: Private keys detected in wallet {%s} with disabled private keys"), +"Unknown wallet file format \"%s\" provided. Please provide one of \"bdb\" or " +"\"sqlite\"."), QT_TRANSLATE_NOOP("bitcoin-core", "" -"Warning: The network does not appear to fully agree! Some miners appear to " -"be experiencing issues."), +"Warning: Dumpfile wallet format \"%s\" does not match command line specified " +"format \"%s\"."), +QT_TRANSLATE_NOOP("bitcoin-core", "" +"Warning: Private keys detected in wallet {%s} with disabled private keys"), QT_TRANSLATE_NOOP("bitcoin-core", "" "Warning: We do not appear to fully agree with our peers! You may need to " "upgrade, or other nodes may need to upgrade."), @@ -109,7 +134,6 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" QT_TRANSLATE_NOOP("bitcoin-core", "%s is set very high!"), QT_TRANSLATE_NOOP("bitcoin-core", "-maxmempool must be at least %d MB"), QT_TRANSLATE_NOOP("bitcoin-core", "A fatal internal error occurred, see debug.log for details"), -QT_TRANSLATE_NOOP("bitcoin-core", "Cannot downgrade wallet"), QT_TRANSLATE_NOOP("bitcoin-core", "Cannot resolve -%s address: '%s'"), QT_TRANSLATE_NOOP("bitcoin-core", "Cannot set -peerblockfilters without -blockfilterindex."), QT_TRANSLATE_NOOP("bitcoin-core", "Cannot write to data directory '%s'; check permissions."), @@ -122,6 +146,8 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Could not parse asmap file %s"), QT_TRANSLATE_NOOP("bitcoin-core", "Disk space is too low!"), QT_TRANSLATE_NOOP("bitcoin-core", "Do you want to rebuild the block database now?"), QT_TRANSLATE_NOOP("bitcoin-core", "Done loading"), +QT_TRANSLATE_NOOP("bitcoin-core", "Dump file %s does not exist."), +QT_TRANSLATE_NOOP("bitcoin-core", "Error creating %s"), QT_TRANSLATE_NOOP("bitcoin-core", "Error initializing block database"), QT_TRANSLATE_NOOP("bitcoin-core", "Error initializing wallet database environment %s!"), QT_TRANSLATE_NOOP("bitcoin-core", "Error loading %s"), @@ -131,9 +157,17 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Error loading %s: Wallet requires newer versi QT_TRANSLATE_NOOP("bitcoin-core", "Error loading block database"), QT_TRANSLATE_NOOP("bitcoin-core", "Error opening block database"), QT_TRANSLATE_NOOP("bitcoin-core", "Error reading from database, shutting down."), +QT_TRANSLATE_NOOP("bitcoin-core", "Error reading next record from wallet database"), QT_TRANSLATE_NOOP("bitcoin-core", "Error upgrading chainstate database"), +QT_TRANSLATE_NOOP("bitcoin-core", "Error: Couldn't create cursor into database"), QT_TRANSLATE_NOOP("bitcoin-core", "Error: Disk space is low for %s"), +QT_TRANSLATE_NOOP("bitcoin-core", "Error: Dumpfile checksum does not match. Computed %s, expected %s"), +QT_TRANSLATE_NOOP("bitcoin-core", "Error: Got key that was not hex: %s"), +QT_TRANSLATE_NOOP("bitcoin-core", "Error: Got value that was not hex: %s"), QT_TRANSLATE_NOOP("bitcoin-core", "Error: Keypool ran out, please call keypoolrefill first"), +QT_TRANSLATE_NOOP("bitcoin-core", "Error: Missing checksum"), +QT_TRANSLATE_NOOP("bitcoin-core", "Error: Unable to parse version %u as a uint32_t"), +QT_TRANSLATE_NOOP("bitcoin-core", "Error: Unable to write record to new wallet"), QT_TRANSLATE_NOOP("bitcoin-core", "Failed to listen on any port. Use -listen=0 if you want this."), QT_TRANSLATE_NOOP("bitcoin-core", "Failed to rescan the wallet during initialization"), QT_TRANSLATE_NOOP("bitcoin-core", "Failed to verify database"), @@ -143,6 +177,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Importing..."), QT_TRANSLATE_NOOP("bitcoin-core", "Incorrect or no genesis block found. Wrong datadir for network?"), QT_TRANSLATE_NOOP("bitcoin-core", "Initialization sanity check failed. %s is shutting down."), QT_TRANSLATE_NOOP("bitcoin-core", "Insufficient funds"), +QT_TRANSLATE_NOOP("bitcoin-core", "Invalid -i2psam address or hostname: '%s'"), QT_TRANSLATE_NOOP("bitcoin-core", "Invalid -onion address or hostname: '%s'"), QT_TRANSLATE_NOOP("bitcoin-core", "Invalid -proxy address or hostname: '%s'"), QT_TRANSLATE_NOOP("bitcoin-core", "Invalid P2P permission: '%s'"), @@ -159,7 +194,6 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Need to specify a port with -whitebind: '%s'" QT_TRANSLATE_NOOP("bitcoin-core", "No proxy server specified. Use -proxy=<ip> or -proxy=<ip:port>."), QT_TRANSLATE_NOOP("bitcoin-core", "Not enough file descriptors available."), QT_TRANSLATE_NOOP("bitcoin-core", "Prune cannot be configured with a negative value."), -QT_TRANSLATE_NOOP("bitcoin-core", "Prune mode is incompatible with -blockfilterindex."), QT_TRANSLATE_NOOP("bitcoin-core", "Prune mode is incompatible with -txindex."), QT_TRANSLATE_NOOP("bitcoin-core", "Pruning blockstore..."), QT_TRANSLATE_NOOP("bitcoin-core", "Reducing -maxconnections from %d to %d, because of system limitations."), @@ -180,7 +214,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Specified -walletdir \"%s\" is not a director QT_TRANSLATE_NOOP("bitcoin-core", "Specified blocks directory \"%s\" does not exist."), QT_TRANSLATE_NOOP("bitcoin-core", "Starting network threads..."), QT_TRANSLATE_NOOP("bitcoin-core", "The source code is available from %s."), -QT_TRANSLATE_NOOP("bitcoin-core", "The specified config file %s does not exist\n"), +QT_TRANSLATE_NOOP("bitcoin-core", "The specified config file %s does not exist"), QT_TRANSLATE_NOOP("bitcoin-core", "The transaction amount is too small to pay the fee"), QT_TRANSLATE_NOOP("bitcoin-core", "The wallet will avoid paying less than the minimum relay fee."), QT_TRANSLATE_NOOP("bitcoin-core", "This is experimental software."), @@ -197,6 +231,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Unable to bind to %s on this computer. %s is QT_TRANSLATE_NOOP("bitcoin-core", "Unable to create the PID file '%s': %s"), QT_TRANSLATE_NOOP("bitcoin-core", "Unable to generate initial keys"), QT_TRANSLATE_NOOP("bitcoin-core", "Unable to generate keys"), +QT_TRANSLATE_NOOP("bitcoin-core", "Unable to open %s for writing"), QT_TRANSLATE_NOOP("bitcoin-core", "Unable to start HTTP server. See debug log for details."), QT_TRANSLATE_NOOP("bitcoin-core", "Unknown -blockfilterindex value %s."), QT_TRANSLATE_NOOP("bitcoin-core", "Unknown address type '%s'"), diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index b244bc94f2..f2c555de52 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -216,7 +216,7 @@ QString ClientModel::dataDir() const QString ClientModel::blocksDir() const { - return GUIUtil::boostPathToQString(GetBlocksDir()); + return GUIUtil::boostPathToQString(gArgs.GetBlocksDirPath()); } void ClientModel::updateBanlist() diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index ca78c96d70..daea2f9cab 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -50,32 +50,16 @@ CoinControlDialog::CoinControlDialog(CCoinControl& coin_control, WalletModel* _m { ui->setupUi(this); - // context menu actions - QAction *copyAddressAction = new QAction(tr("Copy address"), this); - QAction *copyLabelAction = new QAction(tr("Copy label"), this); - QAction *copyAmountAction = new QAction(tr("Copy amount"), this); - copyTransactionHashAction = new QAction(tr("Copy transaction ID"), this); // we need to enable/disable this - lockAction = new QAction(tr("Lock unspent"), this); // we need to enable/disable this - unlockAction = new QAction(tr("Unlock unspent"), this); // we need to enable/disable this - // context menu contextMenu = new QMenu(this); - contextMenu->addAction(copyAddressAction); - contextMenu->addAction(copyLabelAction); - contextMenu->addAction(copyAmountAction); - contextMenu->addAction(copyTransactionHashAction); + contextMenu->addAction(tr("Copy address"), this, &CoinControlDialog::copyAddress); + contextMenu->addAction(tr("Copy label"), this, &CoinControlDialog::copyLabel); + contextMenu->addAction(tr("Copy amount"), this, &CoinControlDialog::copyAmount); + copyTransactionHashAction = contextMenu->addAction(tr("Copy transaction ID"), this, &CoinControlDialog::copyTransactionHash); contextMenu->addSeparator(); - contextMenu->addAction(lockAction); - contextMenu->addAction(unlockAction); - - // context menu signals + lockAction = contextMenu->addAction(tr("Lock unspent"), this, &CoinControlDialog::lockCoin); + unlockAction = contextMenu->addAction(tr("Unlock unspent"), this, &CoinControlDialog::unlockCoin); connect(ui->treeWidget, &QWidget::customContextMenuRequested, this, &CoinControlDialog::showMenu); - connect(copyAddressAction, &QAction::triggered, this, &CoinControlDialog::copyAddress); - connect(copyLabelAction, &QAction::triggered, this, &CoinControlDialog::copyLabel); - connect(copyAmountAction, &QAction::triggered, this, &CoinControlDialog::copyAmount); - connect(copyTransactionHashAction, &QAction::triggered, this, &CoinControlDialog::copyTransactionHash); - connect(lockAction, &QAction::triggered, this, &CoinControlDialog::lockCoin); - connect(unlockAction, &QAction::triggered, this, &CoinControlDialog::unlockCoin); // clipboard actions QAction *clipboardQuantityAction = new QAction(tr("Copy quantity"), this); diff --git a/src/qt/forms/debugwindow.ui b/src/qt/forms/debugwindow.ui index e45cafe48a..13687a6510 100644 --- a/src/qt/forms/debugwindow.ui +++ b/src/qt/forms/debugwindow.ui @@ -923,9 +923,15 @@ <property name="tabKeyNavigation"> <bool>false</bool> </property> + <property name="textElideMode"> + <enum>Qt::ElideMiddle</enum> + </property> <property name="sortingEnabled"> <bool>true</bool> </property> + <property name="wordWrap"> + <bool>false</bool> + </property> <attribute name="horizontalHeaderHighlightSections"> <bool>false</bool> </attribute> diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index b4afdbcc22..d10bf9f9ae 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -42,6 +42,7 @@ #include <QGuiApplication> #include <QJsonObject> #include <QKeyEvent> +#include <QLatin1String> #include <QLineEdit> #include <QList> #include <QLocale> @@ -54,6 +55,7 @@ #include <QShortcut> #include <QSize> #include <QString> +#include <QStringBuilder> #include <QTextDocument> // for Qt::mightBeRichText #include <QThread> #include <QUrlQuery> @@ -628,8 +630,11 @@ bool SetStartOnSystemStartup(bool fAutoStart) { return false; } void setClipboard(const QString& str) { - QApplication::clipboard()->setText(str, QClipboard::Clipboard); - QApplication::clipboard()->setText(str, QClipboard::Selection); + QClipboard* clipboard = QApplication::clipboard(); + clipboard->setText(str, QClipboard::Clipboard); + if (clipboard->supportsSelection()) { + clipboard->setText(str, QClipboard::Selection); + } } fs::path qstringToBoostPath(const QString &path) @@ -893,4 +898,22 @@ QImage GetImage(const QLabel* label) #endif } +QString MakeHtmlLink(const QString& source, const QString& link) +{ + return QString(source).replace( + link, + QLatin1String("<a href=\"") % link % QLatin1String("\">") % link % QLatin1String("</a>")); +} + +void PrintSlotException( + const std::exception* exception, + const QObject* sender, + const QObject* receiver) +{ + std::string description = sender->metaObject()->className(); + description += "->"; + description += receiver->metaObject()->className(); + PrintExceptionContinue(exception, description.c_str()); +} + } // namespace GUIUtil diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index 6395ec6abd..a1cf274354 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -9,18 +9,23 @@ #include <fs.h> #include <net.h> #include <netaddress.h> +#include <util/check.h> +#include <QApplication> #include <QEvent> #include <QHeaderView> #include <QItemDelegate> #include <QLabel> #include <QMessageBox> +#include <QMetaObject> #include <QObject> #include <QProgressBar> #include <QString> #include <QTableView> +#include <cassert> #include <chrono> +#include <utility> class QValidatedLineEdit; class SendCoinsRecipient; @@ -327,6 +332,58 @@ namespace GUIUtil QObject::connect(&source, &QObject::destroyed, object, std::forward<Fn>(function), connection); } + /** + * Replaces a plain text link with an HTML tagged one. + */ + QString MakeHtmlLink(const QString& source, const QString& link); + + void PrintSlotException( + const std::exception* exception, + const QObject* sender, + const QObject* receiver); + + /** + * A drop-in replacement of QObject::connect function + * (see: https://doc.qt.io/qt-5/qobject.html#connect-3), that + * guaranties that all exceptions are handled within the slot. + * + * NOTE: This function is incompatible with Qt private signals. + */ + template <typename Sender, typename Signal, typename Receiver, typename Slot> + auto ExceptionSafeConnect( + Sender sender, Signal signal, Receiver receiver, Slot method, + Qt::ConnectionType type = Qt::AutoConnection) + { + return QObject::connect( + sender, signal, receiver, + [sender, receiver, method](auto&&... args) { + bool ok{true}; + try { + (receiver->*method)(std::forward<decltype(args)>(args)...); + } catch (const NonFatalCheckError& e) { + PrintSlotException(&e, sender, receiver); + ok = QMetaObject::invokeMethod( + qApp, "handleNonFatalException", + blockingGUIThreadConnection(), + Q_ARG(QString, QString::fromStdString(e.what()))); + } catch (const std::exception& e) { + PrintSlotException(&e, sender, receiver); + ok = QMetaObject::invokeMethod( + qApp, "handleRunawayException", + blockingGUIThreadConnection(), + Q_ARG(QString, QString::fromStdString(e.what()))); + } catch (...) { + PrintSlotException(nullptr, sender, receiver); + ok = QMetaObject::invokeMethod( + qApp, "handleRunawayException", + blockingGUIThreadConnection(), + Q_ARG(QString, "Unknown failure occurred.")); + } + assert(ok); + }, + type); + } + } // namespace GUIUtil #endif // BITCOIN_QT_GUIUTIL_H diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts index c55cc65b63..e2640c8884 100644 --- a/src/qt/locale/bitcoin_en.ts +++ b/src/qt/locale/bitcoin_en.ts @@ -116,17 +116,20 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <location line="+1"/> - <source>Comma separated file (*.csv)</source> + <source>Comma separated file</source> + <comment>Name of CSV file format</comment> <translation type="unfinished"></translation> </message> <message> - <location line="+13"/> - <source>Exporting Failed</source> + <location line="+15"/> + <source>There was an error trying to save the address list to %1. Please try again.</source> + <comment>An error message.</comment> + <extracomment>%1 is a name of the file (e.g., "addrbook.csv") that the bitcoin addresses were exported to.</extracomment> <translation type="unfinished"></translation> </message> <message> - <location line="+1"/> - <source>There was an error trying to save the address list to %1. Please try again.</source> + <location line="-2"/> + <source>Exporting Failed</source> <translation type="unfinished"></translation> </message> </context> @@ -143,7 +146,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+36"/> + <location line="+38"/> <source>(no label)</source> <translation type="unfinished"></translation> </message> @@ -192,16 +195,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <location line="+3"/> - <source>This operation needs your wallet passphrase to decrypt the wallet.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+5"/> - <source>Decrypt wallet</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+3"/> <source>Change passphrase</source> <translation type="unfinished"></translation> </message> @@ -221,18 +214,18 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+19"/> - <location line="+57"/> + <location line="+18"/> + <location line="+44"/> <source>Wallet encrypted</source> <translation type="unfinished"></translation> </message> <message> - <location line="-147"/> + <location line="-125"/> <source>Enter the new passphrase for the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+23"/> + <location line="+15"/> <source>Enter the old passphrase and new passphrase for the wallet.</source> <translation type="unfinished"></translation> </message> @@ -252,7 +245,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+8"/> + <location line="+7"/> <source>Your wallet is now encrypted. </source> <translation type="unfinished"></translation> </message> @@ -262,49 +255,43 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> + <location line="+6"/> <location line="+8"/> - <location line="+8"/> - <location line="+43"/> + <location line="+32"/> <location line="+6"/> <source>Wallet encryption failed</source> <translation type="unfinished"></translation> </message> <message> - <location line="-56"/> + <location line="-45"/> <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source> <translation type="unfinished"></translation> </message> <message> <location line="+8"/> - <location line="+49"/> + <location line="+38"/> <source>The supplied passphrases do not match.</source> <translation type="unfinished"></translation> </message> <message> - <location line="-38"/> + <location line="-27"/> <location line="+6"/> <source>Wallet unlock failed</source> <translation type="unfinished"></translation> </message> <message> <location line="-5"/> - <location line="+12"/> - <location line="+19"/> + <location line="+20"/> <source>The passphrase entered for the wallet decryption was incorrect.</source> <translation type="unfinished"></translation> </message> <message> - <location line="-20"/> - <source>Wallet decryption failed</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+14"/> + <location line="-6"/> <source>Wallet passphrase was successfully changed.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+47"/> + <location line="+46"/> <location line="+33"/> <source>Warning: The Caps Lock key is on!</source> <translation type="unfinished"></translation> @@ -313,7 +300,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <context> <name>BanTableModel</name> <message> - <location filename="../bantablemodel.cpp" line="+86"/> + <location filename="../bantablemodel.cpp" line="+85"/> <source>IP/Netmask</source> <translation type="unfinished"></translation> </message> @@ -324,19 +311,42 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> </context> <context> + <name>BitcoinApplication</name> + <message> + <location filename="../bitcoin.cpp" line="+423"/> + <source>Runaway exception</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>A fatal error occurred. %1 can no longer continue safely and will quit.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+9"/> + <source>Internal error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>An internal error occurred. %1 will attempt to continue safely. This is an unexpected bug which can be reported as described below.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> <name>BitcoinGUI</name> <message> - <location filename="../bitcoingui.cpp" line="+322"/> + <location filename="../bitcoingui.cpp" line="+325"/> <source>Sign &message...</source> <translation>Sign &message...</translation> </message> <message> - <location line="+669"/> + <location line="+668"/> <source>Synchronizing with network...</source> <translation>Synchronizing with network...</translation> </message> <message> - <location line="-747"/> + <location line="-746"/> <source>&Overview</source> <translation>&Overview</translation> </message> @@ -426,7 +436,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+210"/> + <location line="+209"/> <source>Wallet:</source> <translation type="unfinished"></translation> </message> @@ -461,7 +471,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="-1065"/> + <location line="-1064"/> <source>Send coins to a Bitcoin address</source> <translation>Send coins to a Bitcoin address</translation> </message> @@ -556,7 +566,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message numerus="yes"> - <location line="+556"/> + <location line="+555"/> <source>%n active connection(s) to Bitcoin network</source> <translation> <numerusform>%n active connection to Bitcoin network</numerusform> @@ -617,7 +627,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation>Up to date</translation> </message> <message> - <location line="-695"/> + <location line="-694"/> <source>&Load PSBT from file...</source> <translation type="unfinished"></translation> </message> @@ -737,7 +747,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+246"/> + <location line="+245"/> <source>%1 client</source> <translation type="unfinished"></translation> </message> @@ -833,15 +843,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation>Wallet is <b>encrypted</b> and currently <b>locked</b></translation> </message> <message> - <location line="+129"/> + <location line="+121"/> <source>Original message:</source> <translation type="unfinished"></translation> </message> - <message> - <location filename="../bitcoin.cpp" line="+418"/> - <source>A fatal error occurred. %1 can no longer continue safely and will quit.</source> - <translation type="unfinished"></translation> - </message> </context> <context> <name>CoinControlDialog</name> @@ -1036,7 +1041,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <context> <name>CreateWalletActivity</name> <message> - <location filename="../walletcontroller.cpp" line="+241"/> + <location filename="../walletcontroller.cpp" line="+250"/> <source>Creating Wallet <b>%1</b>...</source> <translation type="unfinished"></translation> </message> @@ -1059,12 +1064,17 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+38"/> + <location line="+11"/> <source>Wallet Name</source> <translation type="unfinished"></translation> </message> <message> <location line="+13"/> + <source>Wallet</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+9"/> <source>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source> <translation type="unfinished"></translation> </message> @@ -1074,7 +1084,12 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+19"/> + <location line="+26"/> + <source>Advanced Options</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+9"/> <source>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</source> <translation type="unfinished"></translation> </message> @@ -1084,7 +1099,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+13"/> + <location line="+7"/> <source>Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</source> <translation type="unfinished"></translation> </message> @@ -1094,7 +1109,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+13"/> + <location line="+7"/> <source>Use descriptors for scriptPubKey management</source> <translation type="unfinished"></translation> </message> @@ -1104,12 +1119,12 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../createwalletdialog.cpp" line="+19"/> + <location filename="../createwalletdialog.cpp" line="+21"/> <source>Create</source> <translation type="unfinished"></translation> </message> <message> - <location line="+20"/> + <location line="+42"/> <source>Compiled without sqlite support (required for descriptor wallets)</source> <translation type="unfinished"></translation> </message> @@ -1475,7 +1490,12 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+72"/> + <location line="+22"/> + <source>Enabling pruning significantly reduces the disk space required to store transactions. All blocks are still fully validated. Reverting this setting requires re-downloading the entire blockchain.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+50"/> <source>Size of &database cache</source> <translation type="unfinished"></translation> </message> @@ -1485,7 +1505,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+161"/> + <location line="+171"/> <location line="+187"/> <source>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source> <translation type="unfinished"></translation> @@ -1498,17 +1518,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+146"/> - <source>Hide the icon from the system tray.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+3"/> - <source>&Hide tray icon</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+17"/> + <location line="+169"/> <source>Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Exit in the menu.</source> <translation type="unfinished"></translation> </message> @@ -1519,7 +1529,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+79"/> + <location line="+179"/> <source>Open the %1 configuration file from the working directory.</source> <translation type="unfinished"></translation> </message> @@ -1539,17 +1549,12 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation>&Reset Options</translation> </message> <message> - <location line="-532"/> + <location line="-645"/> <source>&Network</source> <translation>&Network</translation> </message> <message> - <location line="-191"/> - <source>Disables some advanced features but all blocks will still be fully validated. Reverting this setting requires re-downloading the entire blockchain. Actual disk usage may be somewhat higher.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+3"/> + <location line="-188"/> <source>Prune &block storage to</source> <translation type="unfinished"></translation> </message> @@ -1610,6 +1615,16 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <location line="+7"/> + <source>Automatically open the Bitcoin client port on the router. This only works when your router supports NAT-PMP and it is enabled. The external port could be random.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Map port using NA&T-PMP</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+7"/> <source>Accept connections from outside.</source> <translation type="unfinished"></translation> </message> @@ -1672,7 +1687,17 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation>&Window</translation> </message> <message> - <location line="+16"/> + <location line="+6"/> + <source>Show the icon in the system tray.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>&Show tray icon</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+10"/> <source>Show only a tray icon after minimizing the window.</source> <translation>Show only a tray icon after minimizing the window.</translation> </message> @@ -1712,12 +1737,12 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation>Choose the default subdivision unit to show in the interface and when sending coins.</translation> </message> <message> - <location line="-450"/> + <location line="-463"/> <source>Whether to show coin control features or not.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+250"/> + <location line="+260"/> <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor onion services.</source> <translation type="unfinished"></translation> </message> @@ -1727,12 +1752,39 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+211"/> + <location line="+214"/> <source>&Third party transaction URLs</source> <translation type="unfinished"></translation> </message> <message> - <location line="+44"/> + <location line="+22"/> + <source>Monospaced font in the Overview tab:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+8"/> + <source>embedded "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+22"/> + <location line="+49"/> + <source>111.11111111 BTC</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="-42"/> + <location line="+49"/> + <source>909.09090909 BTC</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="-29"/> + <source>closest matching "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+65"/> <source>Options set in this dialog are overridden by the command line or in the configuration file:</source> <translation type="unfinished"></translation> </message> @@ -1747,28 +1799,28 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation>&Cancel</translation> </message> <message> - <location filename="../optionsdialog.cpp" line="+96"/> + <location filename="../optionsdialog.cpp" line="+104"/> <source>default</source> <translation>default</translation> </message> <message> - <location line="+67"/> + <location line="+81"/> <source>none</source> <translation type="unfinished"></translation> </message> <message> - <location line="+89"/> + <location line="+91"/> <source>Confirm options reset</source> <translation>Confirm options reset</translation> </message> <message> <location line="+1"/> - <location line="+60"/> + <location line="+57"/> <source>Client restart required to activate changes.</source> <translation type="unfinished"></translation> </message> <message> - <location line="-60"/> + <location line="-57"/> <source>Client will be shut down. Do you want to proceed?</source> <translation type="unfinished"></translation> </message> @@ -1793,7 +1845,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+43"/> + <location line="+40"/> <source>This change would require a client restart.</source> <translation type="unfinished"></translation> </message> @@ -1812,12 +1864,12 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <location line="+62"/> - <location line="+394"/> + <location line="+335"/> <source>The displayed information may be out of date. Your wallet automatically synchronizes with the Bitcoin network after a connection is established, but this process has not completed yet.</source> <translation>The displayed information may be out of date. Your wallet automatically synchronizes with the Bitcoin network after a connection is established, but this process has not completed yet.</translation> </message> <message> - <location line="-141"/> + <location line="-127"/> <source>Watch-only:</source> <translation type="unfinished"></translation> </message> @@ -1827,22 +1879,22 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+17"/> + <location line="+10"/> <source>Your current spendable balance</source> <translation>Your current spendable balance</translation> </message> <message> - <location line="+42"/> + <location line="+35"/> <source>Pending:</source> <translation type="unfinished"></translation> </message> <message> - <location line="-242"/> + <location line="-200"/> <source>Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</source> <translation>Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</translation> </message> <message> - <location line="+114"/> + <location line="+100"/> <source>Immature:</source> <translation>Immature:</translation> </message> @@ -1852,22 +1904,22 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation>Mined balance that has not yet matured</translation> </message> <message> - <location line="-181"/> + <location line="-150"/> <source>Balances</source> <translation type="unfinished"></translation> </message> <message> - <location line="+164"/> + <location line="+140"/> <source>Total:</source> <translation>Total:</translation> </message> <message> - <location line="+63"/> + <location line="+49"/> <source>Your current total balance</source> <translation>Your current total balance</translation> </message> <message> - <location line="+95"/> + <location line="+74"/> <source>Your current balance in watch-only addresses</source> <translation type="unfinished"></translation> </message> @@ -1882,22 +1934,22 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="-324"/> + <location line="-275"/> <source>Unconfirmed transactions to watch-only addresses</source> <translation type="unfinished"></translation> </message> <message> - <location line="+52"/> + <location line="+38"/> <source>Mined balance in watch-only addresses that has not yet matured</source> <translation type="unfinished"></translation> </message> <message> - <location line="+131"/> + <location line="+110"/> <source>Current total balance in watch-only addresses</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../overviewpage.cpp" line="+166"/> + <location filename="../overviewpage.cpp" line="+191"/> <source>Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings->Mask values.</source> <translation type="unfinished"></translation> </message> @@ -1986,7 +2038,8 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <location line="+1"/> - <source>Partially Signed Transaction (Binary) (*.psbt)</source> + <source>Partially Signed Transaction (Binary)</source> + <comment>Name of binary PSBT file format</comment> <translation type="unfinished"></translation> </message> <message> @@ -2058,7 +2111,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <context> <name>PaymentServer</name> <message> - <location filename="../paymentserver.cpp" line="+174"/> + <location filename="../paymentserver.cpp" line="+173"/> <source>Payment request error</source> <translation type="unfinished"></translation> </message> @@ -2083,23 +2136,13 @@ Signing is only possible with addresses of the type 'legacy'.</source> <message> <location line="+14"/> <location line="+23"/> - <source>Cannot process payment request because BIP70 is not supported.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="-22"/> - <location line="+23"/> - <source>Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored.</source> + <source>Cannot process payment request because BIP70 is not supported. +Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored. +If you are receiving this error you should request the merchant provide a BIP21 compatible URI.</source> <translation type="unfinished"></translation> </message> <message> - <location line="-22"/> - <location line="+23"/> - <source>If you are receiving this error you should request the merchant provide a BIP21 compatible URI.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="-20"/> + <location line="-18"/> <source>Invalid payment address %1</source> <translation type="unfinished"></translation> </message> @@ -2117,50 +2160,105 @@ Signing is only possible with addresses of the type 'legacy'.</source> <context> <name>PeerTableModel</name> <message> - <location filename="../peertablemodel.cpp" line="+107"/> + <location filename="../peertablemodel.h" line="+91"/> <source>User Agent</source> <translation type="unfinished"></translation> </message> <message> <location line="+0"/> - <source>Node/Service</source> + <source>Ping</source> <translation type="unfinished"></translation> </message> <message> <location line="+0"/> - <source>NodeId</source> + <source>Sent</source> <translation type="unfinished"></translation> </message> <message> <location line="+0"/> - <source>Ping</source> + <source>Received</source> <translation type="unfinished"></translation> </message> <message> <location line="+0"/> - <source>Sent</source> + <source>Peer Id</source> <translation type="unfinished"></translation> </message> <message> <location line="+0"/> - <source>Received</source> + <source>Address</source> <translation type="unfinished"></translation> </message> + <message> + <location line="+0"/> + <source>Type</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+0"/> + <source>Network</source> + <translation type="unfinished">Network</translation> + </message> </context> <context> <name>QObject</name> <message> - <location filename="../bitcoinunits.cpp" line="+209"/> + <location filename="../bitcoinunits.cpp" line="+213"/> <source>Amount</source> <translation type="unfinished">Amount</translation> </message> <message> - <location filename="../guiutil.cpp" line="+108"/> + <location filename="../guiutil.cpp" line="+118"/> <source>Enter a Bitcoin address (e.g. %1)</source> <translation type="unfinished"></translation> </message> <message> - <location line="+652"/> + <location line="+532"/> + <source>Unroutable</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+6"/> + <source>Internal</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+10"/> + <source>Inbound</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+0"/> + <source>Outbound</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> + <source>Full Relay</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Block Relay</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Manual</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Feeler</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Address Fetch</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+14"/> <source>%1 d</source> <translation type="unfinished"></translation> </message> @@ -2176,22 +2274,22 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <location line="+2"/> - <location line="+26"/> + <location line="+28"/> <source>%1 s</source> <translation type="unfinished"></translation> </message> <message> - <location line="-10"/> + <location line="-12"/> <source>None</source> <translation type="unfinished"></translation> </message> <message> - <location line="+5"/> + <location line="+6"/> <source>N/A</source> <translation type="unfinished">N/A</translation> </message> <message> - <location line="+0"/> + <location line="+1"/> <source>%1 ms</source> <translation type="unfinished"></translation> </message> @@ -2256,7 +2354,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <location line="+2"/> - <source>%1 KB</source> + <source>%1 kB</source> <translation type="unfinished"></translation> </message> <message> @@ -2270,7 +2368,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../bitcoin.cpp" line="+105"/> + <location filename="../bitcoin.cpp" line="+111"/> <source>Error: Specified data directory "%1" does not exist.</source> <translation type="unfinished"></translation> </message> @@ -2328,13 +2426,14 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+32"/> + <location line="+30"/> <source>Save QR Code</source> <translation type="unfinished"></translation> </message> <message> - <location line="+0"/> - <source>PNG Image (*.png)</source> + <location line="+1"/> + <source>PNG Image</source> + <comment>Name of PNG file format</comment> <translation type="unfinished"></translation> </message> </context> @@ -2344,7 +2443,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <location filename="../forms/debugwindow.ui" line="+75"/> <location line="+26"/> <location line="+26"/> - <location line="+26"/> <location line="+29"/> <location line="+26"/> <location line="+36"/> @@ -2354,14 +2452,19 @@ Signing is only possible with addresses of the type 'legacy'.</source> <location line="+36"/> <location line="+23"/> <location line="+710"/> + <location line="+26"/> + <location line="+26"/> <location line="+23"/> <location line="+23"/> <location line="+23"/> + <location line="+26"/> + <location line="+26"/> <location line="+23"/> <location line="+23"/> <location line="+23"/> <location line="+23"/> - <location line="+23"/> + <location line="+26"/> + <location line="+26"/> <location line="+23"/> <location line="+23"/> <location line="+23"/> @@ -2371,13 +2474,12 @@ Signing is only possible with addresses of the type 'legacy'.</source> <location line="+23"/> <location line="+23"/> <location line="+26"/> - <location filename="../rpcconsole.cpp" line="+1127"/> - <location line="+8"/> + <location filename="../rpcconsole.h" line="+141"/> <source>N/A</source> <translation>N/A</translation> </message> <message> - <location line="-1427"/> + <location line="-1534"/> <source>Client version</source> <translation>Client version</translation> </message> @@ -2393,11 +2495,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <location line="+56"/> - <source>Using BerkeleyDB version</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+26"/> <source>Datadir</source> <translation type="unfinished"></translation> </message> @@ -2423,11 +2520,12 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <location line="+29"/> + <location line="+910"/> <source>Network</source> <translation>Network</translation> </message> <message> - <location line="+7"/> + <location line="-903"/> <source>Name</source> <translation type="unfinished"></translation> </message> @@ -2473,18 +2571,18 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <location line="+80"/> - <location line="+560"/> + <location line="+693"/> <source>Received</source> <translation type="unfinished"></translation> </message> <message> - <location line="-480"/> - <location line="+457"/> + <location line="-613"/> + <location line="+590"/> <source>Sent</source> <translation type="unfinished"></translation> </message> <message> - <location line="-416"/> + <location line="-549"/> <source>&Peers</source> <translation type="unfinished"></translation> </message> @@ -2495,23 +2593,17 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <location line="+65"/> - <location filename="../rpcconsole.cpp" line="-637"/> - <location line="+766"/> + <location filename="../rpcconsole.cpp" line="+1104"/> <source>Select a peer to view detailed information.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+54"/> - <source>Direction</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+23"/> + <location line="+106"/> <source>Version</source> <translation type="unfinished"></translation> </message> <message> - <location line="+69"/> + <location line="+121"/> <source>Starting Block</source> <translation type="unfinished"></translation> </message> @@ -2526,7 +2618,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+233"/> + <location line="+285"/> <source>The mapped Autonomous System used for diversifying peer selection.</source> <translation type="unfinished"></translation> </message> @@ -2536,18 +2628,18 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="-1394"/> - <location line="+1066"/> + <location line="-1501"/> + <location line="+1069"/> <source>User Agent</source> <translation type="unfinished"></translation> </message> <message> - <location line="-1140"/> + <location line="-1143"/> <source>Node window</source> <translation type="unfinished"></translation> </message> <message> - <location line="+279"/> + <location line="+253"/> <source>Current block height</source> <translation type="unfinished"></translation> </message> @@ -2572,17 +2664,72 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+92"/> + <location line="+23"/> + <source>The direction and type of peer connection: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Direction/Type</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+23"/> + <source>The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+72"/> <source>Services</source> <translation type="unfinished"></translation> </message> <message> + <location line="+23"/> + <source>Whether the peer requested us to relay transactions.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Wants Tx Relay</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+23"/> + <source>High bandwidth BIP152 compact block relay: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>High Bandwidth</source> + <translation type="unfinished"></translation> + </message> + <message> <location line="+92"/> <source>Connection Time</source> <translation type="unfinished"></translation> </message> <message> <location line="+23"/> + <source>Elapsed time since a novel block passing initial validity checks was received from this peer.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Last Block</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+23"/> + <source>Elapsed time since a novel transaction accepted into our mempool was received from this peer.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Last Tx</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+23"/> <source>Last Send</source> <translation type="unfinished"></translation> </message> @@ -2617,7 +2764,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="-1140"/> + <location line="-1273"/> <source>Last block time</source> <translation>Last block time</translation> </message> @@ -2642,7 +2789,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../rpcconsole.cpp" line="-416"/> + <location filename="../rpcconsole.cpp" line="-242"/> <source>In:</source> <translation type="unfinished"></translation> </message> @@ -2662,7 +2809,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation>Clear console</translation> </message> <message> - <location filename="../rpcconsole.cpp" line="-243"/> + <location filename="../rpcconsole.cpp" line="-242"/> <source>1 &hour</source> <translation type="unfinished"></translation> </message> @@ -2687,15 +2834,82 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> + <location filename="../rpcconsole.h" line="-1"/> + <source>Yes</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+0"/> + <source>No</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+0"/> + <source>To</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+0"/> + <source>From</source> + <translation type="unfinished"></translation> + </message> + <message> <location line="+1"/> + <source>Ban for</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+37"/> + <source>Never</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../rpcconsole.cpp" line="-155"/> + <source>Inbound: initiated by peer</source> + <translation type="unfinished"></translation> + </message> + <message> <location line="+1"/> + <source>Outbound Full Relay: default</source> + <translation type="unfinished"></translation> + </message> + <message> <location line="+1"/> + <source>Outbound Block Relay: does not relay transactions or addresses</source> + <translation type="unfinished"></translation> + </message> + <message> <location line="+1"/> - <source>Ban for</source> + <source>Outbound Manual: added using RPC %1 or %2/%3 configuration options</source> <translation type="unfinished"></translation> </message> <message> - <location line="+38"/> + <location line="+4"/> + <source>Outbound Feeler: short-lived, for testing addresses</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Outbound Address Fetch: short-lived, for soliciting addresses</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> + <source>we selected the peer for high bandwidth relay</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>the peer selected us for high bandwidth relay</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>no high bandwidth relay selected</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+182"/> <source>&Unban</source> <translation type="unfinished"></translation> </message> @@ -2735,39 +2949,22 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="-2"/> - <source>Executing command using "%1" wallet</source> + <location line="+178"/> + <source>(peer id: %1)</source> <translation type="unfinished"></translation> </message> <message> - <location line="+192"/> - <source>(node id: %1)</source> + <location line="-180"/> + <source>Executing command using "%1" wallet</source> <translation type="unfinished"></translation> </message> <message> - <location line="+2"/> + <location line="+182"/> <source>via %1</source> <translation type="unfinished"></translation> </message> <message> - <location line="+3"/> - <location line="+1"/> - <source>never</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+10"/> - <source>Inbound</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+0"/> - <source>Outbound</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+20"/> - <location line="+6"/> + <location filename="../rpcconsole.h" line="-37"/> <source>Unknown</source> <translation type="unfinished"></translation> </message> @@ -2871,12 +3068,17 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../receivecoinsdialog.cpp" line="+45"/> + <location filename="../receivecoinsdialog.cpp" line="+46"/> <source>Copy URI</source> <translation type="unfinished"></translation> </message> <message> <location line="+1"/> + <source>Copy address</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> <source>Copy label</source> <translation type="unfinished"></translation> </message> @@ -2891,7 +3093,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+131"/> + <location line="+140"/> <source>Could not unlock wallet.</source> <translation type="unfinished"></translation> </message> @@ -2977,7 +3179,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+39"/> + <location line="+41"/> <source>(no label)</source> <translation type="unfinished"></translation> </message> @@ -3001,7 +3203,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <name>SendCoinsDialog</name> <message> <location filename="../forms/sendcoinsdialog.ui" line="+14"/> - <location filename="../sendcoinsdialog.cpp" line="+664"/> + <location filename="../sendcoinsdialog.cpp" line="+673"/> <source>Send Coins</source> <translation>Send Coins</translation> </message> @@ -3188,7 +3390,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation>S&end</translation> </message> <message> - <location filename="../sendcoinsdialog.cpp" line="-572"/> + <location filename="../sendcoinsdialog.cpp" line="-581"/> <source>Copy quantity</source> <translation type="unfinished"></translation> </message> @@ -3223,12 +3425,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message> - <location line="+74"/> + <location line="+76"/> <source>%1 (%2 blocks)</source> <translation type="unfinished"></translation> </message> <message> - <location line="+22"/> + <location line="+29"/> <source>Cr&eate Unsigned</source> <translation type="unfinished"></translation> </message> @@ -3273,12 +3475,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message> - <location line="+1"/> - <source>Partially Signed Transaction (Binary) (*.psbt)</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+7"/> + <location line="+8"/> <source>PSBT saved</source> <translation type="unfinished"></translation> </message> @@ -3338,7 +3535,13 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message> - <location line="+228"/> + <location line="+45"/> + <source>Partially Signed Transaction (Binary)</source> + <comment>Name of binary PSBT file format</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+183"/> <source>Watch-only balance:</source> <translation type="unfinished"></translation> </message> @@ -3743,7 +3946,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <name>TrafficGraphWidget</name> <message> <location filename="../trafficgraphwidget.cpp" line="+82"/> - <source>KB/s</source> + <source>kB/s</source> <translation type="unfinished"></translation> </message> </context> @@ -3996,7 +4199,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <context> <name>TransactionTableModel</name> <message> - <location filename="../transactiontablemodel.cpp" line="+251"/> + <location filename="../transactiontablemodel.cpp" line="+252"/> <source>Date</source> <translation type="unfinished">Date</translation> </message> @@ -4011,7 +4214,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message numerus="yes"> - <location line="+58"/> + <location line="+62"/> <source>Open for %n more block(s)</source> <translation> <numerusform>Open for %n more block</numerusform> @@ -4094,7 +4297,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message> - <location line="+208"/> + <location line="+210"/> <source>(no label)</source> <translation type="unfinished"></translation> </message> @@ -4132,7 +4335,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <context> <name>TransactionView</name> <message> - <location filename="../transactionview.cpp" line="+69"/> + <location filename="../transactionview.cpp" line="+70"/> <location line="+16"/> <source>All</source> <translation type="unfinished"></translation> @@ -4203,7 +4406,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message> - <location line="+51"/> + <location line="+63"/> <source>Abandon transaction</source> <translation type="unfinished"></translation> </message> @@ -4244,26 +4447,27 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos </message> <message> <location line="+1"/> - <source>Edit label</source> + <source>Edit address label</source> <translation type="unfinished"></translation> </message> <message> - <location line="+1"/> - <source>Show transaction details</source> + <location line="+186"/> + <source>Comma separated file</source> + <comment>Name of CSV file format</comment> <translation type="unfinished"></translation> </message> <message> - <location line="+194"/> - <source>Export Transaction History</source> + <location line="-185"/> + <source>Show transaction details</source> <translation type="unfinished"></translation> </message> <message> - <location line="+1"/> - <source>Comma separated file (*.csv)</source> + <location line="+184"/> + <source>Export Transaction History</source> <translation type="unfinished"></translation> </message> <message> - <location line="+9"/> + <location line="+10"/> <source>Confirmed</source> <translation type="unfinished">Confirmed</translation> </message> @@ -4339,7 +4543,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <context> <name>WalletController</name> <message> - <location filename="../walletcontroller.cpp" line="-238"/> + <location filename="../walletcontroller.cpp" line="-247"/> <source>Close wallet</source> <translation type="unfinished"></translation> </message> @@ -4382,20 +4586,20 @@ Go to File > Open Wallet to load a wallet. <context> <name>WalletModel</name> <message> - <location filename="../walletmodel.cpp" line="+214"/> + <location filename="../walletmodel.cpp" line="+218"/> <source>Send Coins</source> <translation type="unfinished">Send Coins</translation> </message> <message> - <location line="+282"/> - <location line="+45"/> + <location line="+279"/> + <location line="+52"/> <location line="+13"/> <location line="+5"/> <source>Fee bump error</source> <translation type="unfinished"></translation> </message> <message> - <location line="-63"/> + <location line="-70"/> <source>Increasing transaction fee failed</source> <translation type="unfinished"></translation> </message> @@ -4425,7 +4629,12 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished"></translation> </message> <message> - <location line="+4"/> + <location line="+8"/> + <source>Warning: This may pay the additional fee by reducing change outputs or adding inputs, when necessary. It may add a new change output if one does not already exist. These changes may potentially leak privacy.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> <source>Confirm fee bump</source> <translation type="unfinished"></translation> </message> @@ -4506,7 +4715,8 @@ Go to File > Open Wallet to load a wallet. </message> <message> <location line="+1"/> - <source>Wallet Data (*.dat)</source> + <source>Wallet Data</source> + <comment>Name of wallet data file format</comment> <translation type="unfinished"></translation> </message> <message> @@ -4538,12 +4748,12 @@ Go to File > Open Wallet to load a wallet. <context> <name>bitcoin-core</name> <message> - <location filename="../bitcoinstrings.cpp" line="+27"/> + <location filename="../bitcoinstrings.cpp" line="+31"/> <source>Distributed under the MIT software license, see the accompanying file %s or %s</source> <translation type="unfinished"></translation> </message> <message> - <location line="+23"/> + <location line="+41"/> <source>Prune configured below the minimum of %d MiB. Please use a higher number.</source> <translation type="unfinished"></translation> </message> @@ -4553,22 +4763,22 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished"></translation> </message> <message> - <location line="+112"/> + <location line="+124"/> <source>Pruning blockstore...</source> <translation type="unfinished"></translation> </message> <message> - <location line="+36"/> + <location line="+37"/> <source>Unable to start HTTP server. See debug log for details.</source> <translation type="unfinished"></translation> </message> <message> - <location line="-188"/> + <location line="-223"/> <source>The %s developers</source> <translation type="unfinished"></translation> </message> <message> - <location line="+7"/> + <location line="+10"/> <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> <translation type="unfinished"></translation> </message> @@ -4578,17 +4788,17 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished"></translation> </message> <message> - <location line="+9"/> + <location line="+10"/> <source>Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+11"/> + <location line="+21"/> <source>More than one onion bind address is provided. Using %s for the automatically created Tor onion service.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+3"/> + <location line="+11"/> <source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source> <translation type="unfinished"></translation> </message> @@ -4638,12 +4848,7 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished"></translation> </message> <message> - <location line="+5"/> - <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+3"/> + <location line="+11"/> <source>Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.</source> <translation type="unfinished"></translation> </message> @@ -4653,7 +4858,7 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished"></translation> </message> <message> - <location line="+3"/> + <location line="+2"/> <source>Cannot resolve -%s address: '%s'</source> <translation type="unfinished"></translation> </message> @@ -4694,6 +4899,16 @@ Go to File > Open Wallet to load a wallet. </message> <message> <location line="+2"/> + <source>Dump file %s does not exist.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Error creating %s</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> <source>Error initializing block database</source> <translation>Error initializing block database</translation> </message> @@ -4733,7 +4948,47 @@ Go to File > Open Wallet to load a wallet. <translation>Error opening block database</translation> </message> <message> - <location line="+5"/> + <location line="+2"/> + <source>Error reading next record from wallet database</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Error: Couldn't create cursor into database</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Error: Dumpfile checksum does not match. Computed %s, expected %s</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Error: Got key that was not hex: %s</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Error: Got value that was not hex: %s</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Error: Missing checksum</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Error: Unable to parse version %u as a uint32_t</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Error: Unable to write record to new wallet</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> <source>Failed to listen on any port. Use -listen=0 if you want this.</source> <translation>Failed to listen on any port. Use -listen=0 if you want this.</translation> </message> @@ -4768,7 +5023,12 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished"></translation> </message> <message> - <location line="+4"/> + <location line="+2"/> + <source>Invalid -i2psam address or hostname: '%s'</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> <source>Invalid P2P permission: '%s'</source> <translation type="unfinished"></translation> </message> @@ -4788,7 +5048,7 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished"></translation> </message> <message> - <location line="+18"/> + <location line="+17"/> <source>SQLiteDatabase: Failed to execute statement to verify database: %s</source> <translation type="unfinished"></translation> </message> @@ -4823,7 +5083,17 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished"></translation> </message> <message> - <location line="+22"/> + <location line="+3"/> + <source>The specified config file %s does not exist</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+17"/> + <source>Unable to open %s for writing</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> <source>Unknown address type '%s'</source> <translation type="unfinished"></translation> </message> @@ -4843,7 +5113,62 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished"></translation> </message> <message> - <location line="+1"/> + <location line="-170"/> + <source>Cannot downgrade wallet from version %i to version %i. Wallet version unchanged.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+8"/> + <source>Cannot upgrade a non HD split wallet from version %i to version %i without upgrading to support pre-split keypool. Please use version %i or no version specified.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+10"/> + <source>Error: Dumpfile format record is incorrect. Got "%s", expected "format".</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Error: Dumpfile identifier record is incorrect. Got "%s", expected "%s".</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Error: Dumpfile version is not supported. This version of bitcoin-wallet only supports version 1 dumpfiles. Got dumpfile with version %s</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+8"/> + <source>File %s already exists. If you are sure this is what you want, move it out of the way first.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+9"/> + <source>No dump file provided. To use createfromdump, -dumpfile=<filename> must be provided.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>No dump file provided. To use dump, -dumpfile=<filename> must be provided.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>No wallet file format provided. To use createfromdump, -format=<format> must be provided.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+57"/> + <source>Unknown wallet file format "%s" provided. Please provide one of "bdb" or "sqlite".</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Warning: Dumpfile wallet format "%s" does not match command line specified format "%s".</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+67"/> <source>Loading banlist...</source> <translation type="unfinished"></translation> </message> @@ -4858,7 +5183,7 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished"></translation> </message> <message> - <location line="+2"/> + <location line="+1"/> <source>Prune mode is incompatible with -txindex.</source> <translation type="unfinished"></translation> </message> @@ -4893,7 +5218,7 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished"></translation> </message> <message> - <location line="+6"/> + <location line="+7"/> <source>Unsupported logging category %s=%s.</source> <translation type="unfinished"></translation> </message> @@ -4918,27 +5243,22 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished"></translation> </message> <message> - <location line="-178"/> + <location line="-202"/> <source>Error: Listening for incoming connections failed (listen returned error %s)</source> <translation type="unfinished"></translation> </message> <message> - <location line="-20"/> + <location line="-31"/> <source>%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring a backup.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+11"/> - <source>Cannot upgrade a non HD split wallet without upgrading to support pre split keypool. Please use version 169900 or no version specified.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+14"/> + <location line="+39"/> <source>Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)</source> <translation type="unfinished"></translation> </message> <message> - <location line="+31"/> + <location line="+39"/> <source>The transaction amount is too small to send after the fee has been deducted</source> <translation type="unfinished"></translation> </message> @@ -4958,7 +5278,7 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished"></translation> </message> <message> - <location line="+17"/> + <location line="+20"/> <source>You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain</source> <translation type="unfinished"></translation> </message> @@ -4968,7 +5288,7 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished"></translation> </message> <message> - <location line="+3"/> + <location line="+2"/> <source>Cannot set -peerblockfilters without -blockfilterindex.</source> <translation type="unfinished"></translation> </message> @@ -4978,32 +5298,32 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished"></translation> </message> <message> - <location line="+11"/> + <location line="+13"/> <source>Error reading from database, shutting down.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+1"/> + <location line="+2"/> <source>Error upgrading chainstate database</source> <translation type="unfinished"></translation> </message> <message> - <location line="+1"/> + <location line="+2"/> <source>Error: Disk space is low for %s</source> <translation type="unfinished"></translation> </message> <message> - <location line="+1"/> + <location line="+4"/> <source>Error: Keypool ran out, please call keypoolrefill first</source> <translation type="unfinished"></translation> </message> <message> - <location line="+4"/> + <location line="+7"/> <source>Fee rate (%s) is lower than the minimum fee rate setting (%s)</source> <translation type="unfinished"></translation> </message> <message> - <location line="+6"/> + <location line="+7"/> <source>Invalid -onion address or hostname: '%s'</source> <translation type="unfinished"></translation> </message> @@ -5033,12 +5353,7 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished"></translation> </message> <message> - <location line="+3"/> - <source>Prune mode is incompatible with -blockfilterindex.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+3"/> + <location line="+5"/> <source>Reducing -maxconnections from %d to %d, because of system limitations.</source> <translation type="unfinished"></translation> </message> @@ -5068,13 +5383,7 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished"></translation> </message> <message> - <location line="+4"/> - <source>The specified config file %s does not exist -</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+1"/> + <location line="+5"/> <source>The transaction amount is too small to pay the fee</source> <translation type="unfinished"></translation> </message> @@ -5109,7 +5418,7 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished"></translation> </message> <message> - <location line="+3"/> + <location line="+4"/> <source>Unknown -blockfilterindex value %s.</source> <translation type="unfinished"></translation> </message> @@ -5124,12 +5433,12 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished"></translation> </message> <message> - <location line="-196"/> + <location line="-231"/> <source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+68"/> + <location line="+90"/> <source>This is the transaction fee you may pay when fee estimates are not available.</source> <translation type="unfinished"></translation> </message> @@ -5139,12 +5448,12 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished"></translation> </message> <message> - <location line="+23"/> + <location line="+26"/> <source>%s is set very high!</source> <translation type="unfinished"></translation> </message> <message> - <location line="+72"/> + <location line="+81"/> <source>Starting network threads...</source> <translation type="unfinished"></translation> </message> @@ -5179,32 +5488,32 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished"></translation> </message> <message> - <location line="+11"/> + <location line="+12"/> <source>Unknown network specified in -onlynet: '%s'</source> <translation>Unknown network specified in -onlynet: '%s'</translation> </message> <message> - <location line="-59"/> + <location line="-60"/> <source>Insufficient funds</source> <translation>Insufficient funds</translation> </message> <message> - <location line="-110"/> + <location line="-133"/> <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+63"/> + <location line="+80"/> <source>Warning: Private keys detected in wallet {%s} with disabled private keys</source> <translation type="unfinished"></translation> </message> <message> - <location line="+17"/> + <location line="+13"/> <source>Cannot write to data directory '%s'; check permissions.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+41"/> + <location line="+52"/> <source>Loading block index...</source> <translation>Loading block index...</translation> </message> @@ -5214,17 +5523,12 @@ Go to File > Open Wallet to load a wallet. <translation>Loading wallet...</translation> </message> <message> - <location line="-45"/> - <source>Cannot downgrade wallet</source> - <translation>Cannot downgrade wallet</translation> - </message> - <message> - <location line="+55"/> + <location line="+9"/> <source>Rescanning...</source> <translation>Rescanning...</translation> </message> <message> - <location line="-43"/> + <location line="-53"/> <source>Done loading</source> <translation>Done loading</translation> </message> diff --git a/src/qt/locale/bitcoin_en.xlf b/src/qt/locale/bitcoin_en.xlf new file mode 100644 index 0000000000..a8a5f57f15 --- /dev/null +++ b/src/qt/locale/bitcoin_en.xlf @@ -0,0 +1,5688 @@ +<?xml version="1.0" encoding="utf-8"?> +<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:trolltech="urn:trolltech:names:ts:document:1.0"> + <file original="../forms/addressbookpage.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="AddressBookPage"> + <trans-unit id="_msg1"> + <source xml:space="preserve">Right-click to edit address or label</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">37</context></context-group> + </trans-unit> + <trans-unit id="_msg2" approved="yes"> + <source xml:space="preserve">Create a new address</source> + <target xml:space="preserve">Create a new address</target> + <context-group purpose="location"><context context-type="linenumber">64</context></context-group> + </trans-unit> + <trans-unit id="_msg3"> + <source xml:space="preserve">&New</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">67</context></context-group> + </trans-unit> + <trans-unit id="_msg4" approved="yes"> + <source xml:space="preserve">Copy the currently selected address to the system clipboard</source> + <target xml:space="preserve">Copy the currently selected address to the system clipboard</target> + <context-group purpose="location"><context context-type="linenumber">81</context></context-group> + </trans-unit> + <trans-unit id="_msg5"> + <source xml:space="preserve">&Copy</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">84</context></context-group> + </trans-unit> + <trans-unit id="_msg6"> + <source xml:space="preserve">C&lose</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">151</context></context-group> + </trans-unit> + <trans-unit id="_msg7" approved="yes"> + <source xml:space="preserve">Delete the currently selected address from the list</source> + <target xml:space="preserve">Delete the currently selected address from the list</target> + <context-group purpose="location"><context context-type="linenumber">98</context></context-group> + </trans-unit> + <trans-unit id="_msg8"> + <source xml:space="preserve">Enter address or label to search</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">27</context></context-group> + </trans-unit> + <trans-unit id="_msg9" approved="yes"> + <source xml:space="preserve">Export the data in the current tab to a file</source> + <target xml:space="preserve">Export the data in the current tab to a file</target> + <context-group purpose="location"><context context-type="linenumber">128</context></context-group> + </trans-unit> + <trans-unit id="_msg10" approved="yes"> + <source xml:space="preserve">&Export</source> + <target xml:space="preserve">&Export</target> + <context-group purpose="location"><context context-type="linenumber">131</context></context-group> + </trans-unit> + <trans-unit id="_msg11" approved="yes"> + <source xml:space="preserve">&Delete</source> + <target xml:space="preserve">&Delete</target> + <context-group purpose="location"><context context-type="linenumber">101</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../addressbookpage.cpp" datatype="cpp" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="AddressBookPage"> + <trans-unit id="_msg12"> + <source xml:space="preserve">Choose the address to send coins to</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">84</context></context-group> + </trans-unit> + <trans-unit id="_msg13"> + <source xml:space="preserve">Choose the address to receive coins with</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">85</context></context-group> + </trans-unit> + <trans-unit id="_msg14"> + <source xml:space="preserve">C&hoose</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">90</context></context-group> + </trans-unit> + <trans-unit id="_msg15"> + <source xml:space="preserve">Sending addresses</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">96</context></context-group> + </trans-unit> + <trans-unit id="_msg16"> + <source xml:space="preserve">Receiving addresses</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">97</context></context-group> + </trans-unit> + <trans-unit id="_msg17"> + <source xml:space="preserve">These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">104</context></context-group> + </trans-unit> + <trans-unit id="_msg18"> + <source xml:space="preserve">These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses. +Signing is only possible with addresses of the type 'legacy'.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">109</context></context-group> + </trans-unit> + <trans-unit id="_msg19"> + <source xml:space="preserve">&Copy Address</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">116</context></context-group> + </trans-unit> + <trans-unit id="_msg20"> + <source xml:space="preserve">Copy &Label</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">117</context></context-group> + </trans-unit> + <trans-unit id="_msg21"> + <source xml:space="preserve">&Edit</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">118</context></context-group> + </trans-unit> + <trans-unit id="_msg22"> + <source xml:space="preserve">Export Address List</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">297</context></context-group> + </trans-unit> + <trans-unit id="_msg23"> + <source xml:space="preserve">Comma separated file</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">298</context></context-group> + <context-group><context context-type="x-gettext-msgctxt">Name of CSV file format</context></context-group> + </trans-unit> + <trans-unit id="_msg24"> + <source xml:space="preserve">There was an error trying to save the address list to %1. Please try again.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">313</context></context-group> + <context-group><context context-type="x-gettext-msgctxt">An error message.</context></context-group> + <note annotates="source" from="developer">%1 is a name of the file (e.g., "addrbook.csv") that the bitcoin addresses were exported to.</note> + </trans-unit> + <trans-unit id="_msg25"> + <source xml:space="preserve">Exporting Failed</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">311</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../addresstablemodel.cpp" datatype="cpp" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="AddressTableModel"> + <trans-unit id="_msg26"> + <source xml:space="preserve">Label</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">168</context></context-group> + </trans-unit> + <trans-unit id="_msg27"> + <source xml:space="preserve">Address</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">168</context></context-group> + </trans-unit> + <trans-unit id="_msg28"> + <source xml:space="preserve">(no label)</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">206</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../forms/askpassphrasedialog.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="AskPassphraseDialog"> + <trans-unit id="_msg29" approved="yes"> + <source xml:space="preserve">Passphrase Dialog</source> + <target xml:space="preserve">Passphrase Dialog</target> + <context-group purpose="location"><context context-type="linenumber">26</context></context-group> + </trans-unit> + <trans-unit id="_msg30" approved="yes"> + <source xml:space="preserve">Enter passphrase</source> + <target xml:space="preserve">Enter passphrase</target> + <context-group purpose="location"><context context-type="linenumber">56</context></context-group> + </trans-unit> + <trans-unit id="_msg31" approved="yes"> + <source xml:space="preserve">New passphrase</source> + <target xml:space="preserve">New passphrase</target> + <context-group purpose="location"><context context-type="linenumber">70</context></context-group> + </trans-unit> + <trans-unit id="_msg32" approved="yes"> + <source xml:space="preserve">Repeat new passphrase</source> + <target xml:space="preserve">Repeat new passphrase</target> + <context-group purpose="location"><context context-type="linenumber">84</context></context-group> + </trans-unit> + <trans-unit id="_msg33"> + <source xml:space="preserve">Show passphrase</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">98</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../askpassphrasedialog.cpp" datatype="cpp" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="AskPassphraseDialog"> + <trans-unit id="_msg34"> + <source xml:space="preserve">Encrypt wallet</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">51</context></context-group> + </trans-unit> + <trans-unit id="_msg35"> + <source xml:space="preserve">This operation needs your wallet passphrase to unlock the wallet.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">54</context></context-group> + </trans-unit> + <trans-unit id="_msg36"> + <source xml:space="preserve">Unlock wallet</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">59</context></context-group> + </trans-unit> + <trans-unit id="_msg37"> + <source xml:space="preserve">Change passphrase</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">62</context></context-group> + </trans-unit> + <trans-unit id="_msg38"> + <source xml:space="preserve">Confirm wallet encryption</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">110</context></context-group> + </trans-unit> + <trans-unit id="_msg39"> + <source xml:space="preserve">Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>!</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">111</context></context-group> + </trans-unit> + <trans-unit id="_msg40"> + <source xml:space="preserve">Are you sure you wish to encrypt your wallet?</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">111</context></context-group> + </trans-unit> + <trans-unit id="_msg41"> + <source xml:space="preserve">Wallet encrypted</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">129</context></context-group> + <context-group purpose="location"><context context-type="linenumber">173</context></context-group> + </trans-unit> + <trans-unit id="_msg42"> + <source xml:space="preserve">Enter the new passphrase for the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">48</context></context-group> + </trans-unit> + <trans-unit id="_msg43"> + <source xml:space="preserve">Enter the old passphrase and new passphrase for the wallet.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">63</context></context-group> + </trans-unit> + <trans-unit id="_msg44"> + <source xml:space="preserve">Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">118</context></context-group> + </trans-unit> + <trans-unit id="_msg45"> + <source xml:space="preserve">Wallet to be encrypted</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">122</context></context-group> + </trans-unit> + <trans-unit id="_msg46"> + <source xml:space="preserve">Your wallet is about to be encrypted. </source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">124</context></context-group> + </trans-unit> + <trans-unit id="_msg47"> + <source xml:space="preserve">Your wallet is now encrypted. </source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">131</context></context-group> + </trans-unit> + <trans-unit id="_msg48"> + <source xml:space="preserve">IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">133</context></context-group> + </trans-unit> + <trans-unit id="_msg49"> + <source xml:space="preserve">Wallet encryption failed</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">139</context></context-group> + <context-group purpose="location"><context context-type="linenumber">147</context></context-group> + <context-group purpose="location"><context context-type="linenumber">179</context></context-group> + <context-group purpose="location"><context context-type="linenumber">185</context></context-group> + </trans-unit> + <trans-unit id="_msg50"> + <source xml:space="preserve">Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">140</context></context-group> + </trans-unit> + <trans-unit id="_msg51"> + <source xml:space="preserve">The supplied passphrases do not match.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">148</context></context-group> + <context-group purpose="location"><context context-type="linenumber">186</context></context-group> + </trans-unit> + <trans-unit id="_msg52"> + <source xml:space="preserve">Wallet unlock failed</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">159</context></context-group> + <context-group purpose="location"><context context-type="linenumber">165</context></context-group> + </trans-unit> + <trans-unit id="_msg53"> + <source xml:space="preserve">The passphrase entered for the wallet decryption was incorrect.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">160</context></context-group> + <context-group purpose="location"><context context-type="linenumber">180</context></context-group> + </trans-unit> + <trans-unit id="_msg54"> + <source xml:space="preserve">Wallet passphrase was successfully changed.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">174</context></context-group> + </trans-unit> + <trans-unit id="_msg55"> + <source xml:space="preserve">Warning: The Caps Lock key is on!</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">220</context></context-group> + <context-group purpose="location"><context context-type="linenumber">253</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../bantablemodel.cpp" datatype="cpp" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="BanTableModel"> + <trans-unit id="_msg56"> + <source xml:space="preserve">IP/Netmask</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">85</context></context-group> + </trans-unit> + <trans-unit id="_msg57"> + <source xml:space="preserve">Banned Until</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">85</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../bitcoin.cpp" datatype="cpp" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="BitcoinApplication"> + <trans-unit id="_msg58"> + <source xml:space="preserve">Runaway exception</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">423</context></context-group> + </trans-unit> + <trans-unit id="_msg59"> + <source xml:space="preserve">A fatal error occurred. %1 can no longer continue safely and will quit.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">424</context></context-group> + </trans-unit> + <trans-unit id="_msg60"> + <source xml:space="preserve">Internal error</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">433</context></context-group> + </trans-unit> + <trans-unit id="_msg61"> + <source xml:space="preserve">An internal error occurred. %1 will attempt to continue safely. This is an unexpected bug which can be reported as described below.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">434</context></context-group> + </trans-unit> + </group> + <group restype="x-trolltech-linguist-context" resname="QObject"> + <trans-unit id="_msg62"> + <source xml:space="preserve">Error: Specified data directory "%1" does not exist.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">545</context></context-group> + </trans-unit> + <trans-unit id="_msg63"> + <source xml:space="preserve">Error: Cannot parse configuration file: %1.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">551</context></context-group> + </trans-unit> + <trans-unit id="_msg64"> + <source xml:space="preserve">Error: %1</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">566</context></context-group> + </trans-unit> + <trans-unit id="_msg65"> + <source xml:space="preserve">Error initializing settings: %1</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">575</context></context-group> + </trans-unit> + <trans-unit id="_msg66"> + <source xml:space="preserve">%1 didn't yet exit safely...</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">638</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../bitcoingui.cpp" datatype="cpp" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="BitcoinGUI"> + <trans-unit id="_msg67" approved="yes"> + <source xml:space="preserve">Sign &message...</source> + <target xml:space="preserve">Sign &message...</target> + <context-group purpose="location"><context context-type="linenumber">325</context></context-group> + </trans-unit> + <trans-unit id="_msg68" approved="yes"> + <source xml:space="preserve">Synchronizing with network...</source> + <target xml:space="preserve">Synchronizing with network...</target> + <context-group purpose="location"><context context-type="linenumber">993</context></context-group> + </trans-unit> + <trans-unit id="_msg69" approved="yes"> + <source xml:space="preserve">&Overview</source> + <target xml:space="preserve">&Overview</target> + <context-group purpose="location"><context context-type="linenumber">247</context></context-group> + </trans-unit> + <trans-unit id="_msg70" approved="yes"> + <source xml:space="preserve">Show general overview of wallet</source> + <target xml:space="preserve">Show general overview of wallet</target> + <context-group purpose="location"><context context-type="linenumber">248</context></context-group> + </trans-unit> + <trans-unit id="_msg71" approved="yes"> + <source xml:space="preserve">&Transactions</source> + <target xml:space="preserve">&Transactions</target> + <context-group purpose="location"><context context-type="linenumber">276</context></context-group> + </trans-unit> + <trans-unit id="_msg72" approved="yes"> + <source xml:space="preserve">Browse transaction history</source> + <target xml:space="preserve">Browse transaction history</target> + <context-group purpose="location"><context context-type="linenumber">277</context></context-group> + </trans-unit> + <trans-unit id="_msg73" approved="yes"> + <source xml:space="preserve">E&xit</source> + <target xml:space="preserve">E&xit</target> + <context-group purpose="location"><context context-type="linenumber">300</context></context-group> + </trans-unit> + <trans-unit id="_msg74" approved="yes"> + <source xml:space="preserve">Quit application</source> + <target xml:space="preserve">Quit application</target> + <context-group purpose="location"><context context-type="linenumber">301</context></context-group> + </trans-unit> + <trans-unit id="_msg75"> + <source xml:space="preserve">&About %1</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">304</context></context-group> + </trans-unit> + <trans-unit id="_msg76"> + <source xml:space="preserve">Show information about %1</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">305</context></context-group> + </trans-unit> + <trans-unit id="_msg77" approved="yes"> + <source xml:space="preserve">About &Qt</source> + <target xml:space="preserve">About &Qt</target> + <context-group purpose="location"><context context-type="linenumber">308</context></context-group> + </trans-unit> + <trans-unit id="_msg78" approved="yes"> + <source xml:space="preserve">Show information about Qt</source> + <target xml:space="preserve">Show information about Qt</target> + <context-group purpose="location"><context context-type="linenumber">309</context></context-group> + </trans-unit> + <trans-unit id="_msg79" approved="yes"> + <source xml:space="preserve">&Options...</source> + <target xml:space="preserve">&Options...</target> + <context-group purpose="location"><context context-type="linenumber">311</context></context-group> + </trans-unit> + <trans-unit id="_msg80"> + <source xml:space="preserve">Modify configuration options for %1</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">312</context></context-group> + </trans-unit> + <trans-unit id="_msg81" approved="yes"> + <source xml:space="preserve">&Encrypt Wallet...</source> + <target xml:space="preserve">&Encrypt Wallet...</target> + <context-group purpose="location"><context context-type="linenumber">318</context></context-group> + </trans-unit> + <trans-unit id="_msg82" approved="yes"> + <source xml:space="preserve">&Backup Wallet...</source> + <target xml:space="preserve">&Backup Wallet...</target> + <context-group purpose="location"><context context-type="linenumber">321</context></context-group> + </trans-unit> + <trans-unit id="_msg83" approved="yes"> + <source xml:space="preserve">&Change Passphrase...</source> + <target xml:space="preserve">&Change Passphrase...</target> + <context-group purpose="location"><context context-type="linenumber">323</context></context-group> + </trans-unit> + <trans-unit id="_msg84"> + <source xml:space="preserve">Open &URI...</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">345</context></context-group> + </trans-unit> + <trans-unit id="_msg85"> + <source xml:space="preserve">Create Wallet...</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">356</context></context-group> + </trans-unit> + <trans-unit id="_msg86"> + <source xml:space="preserve">Create a new wallet</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">358</context></context-group> + </trans-unit> + <trans-unit id="_msg87"> + <source xml:space="preserve">Wallet:</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">567</context></context-group> + </trans-unit> + <trans-unit id="_msg88"> + <source xml:space="preserve">Click to disable network activity.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">918</context></context-group> + </trans-unit> + <trans-unit id="_msg89"> + <source xml:space="preserve">Network activity disabled.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">920</context></context-group> + </trans-unit> + <trans-unit id="_msg90"> + <source xml:space="preserve">Click to enable network activity again.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">920</context></context-group> + </trans-unit> + <trans-unit id="_msg91"> + <source xml:space="preserve">Syncing Headers (%1%)...</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">947</context></context-group> + </trans-unit> + <trans-unit id="_msg92" approved="yes"> + <source xml:space="preserve">Reindexing blocks on disk...</source> + <target xml:space="preserve">Reindexing blocks on disk...</target> + <context-group purpose="location"><context context-type="linenumber">1004</context></context-group> + </trans-unit> + <trans-unit id="_msg93"> + <source xml:space="preserve">Proxy is <b>enabled</b>: %1</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1319</context></context-group> + </trans-unit> + <trans-unit id="_msg94" approved="yes"> + <source xml:space="preserve">Send coins to a Bitcoin address</source> + <target xml:space="preserve">Send coins to a Bitcoin address</target> + <context-group purpose="location"><context context-type="linenumber">255</context></context-group> + </trans-unit> + <trans-unit id="_msg95" approved="yes"> + <source xml:space="preserve">Backup wallet to another location</source> + <target xml:space="preserve">Backup wallet to another location</target> + <context-group purpose="location"><context context-type="linenumber">322</context></context-group> + </trans-unit> + <trans-unit id="_msg96" approved="yes"> + <source xml:space="preserve">Change the passphrase used for wallet encryption</source> + <target xml:space="preserve">Change the passphrase used for wallet encryption</target> + <context-group purpose="location"><context context-type="linenumber">324</context></context-group> + </trans-unit> + <trans-unit id="_msg97" approved="yes"> + <source xml:space="preserve">&Verify message...</source> + <target xml:space="preserve">&Verify message...</target> + <context-group purpose="location"><context context-type="linenumber">327</context></context-group> + </trans-unit> + <trans-unit id="_msg98" approved="yes"> + <source xml:space="preserve">&Send</source> + <target xml:space="preserve">&Send</target> + <context-group purpose="location"><context context-type="linenumber">254</context></context-group> + </trans-unit> + <trans-unit id="_msg99" approved="yes"> + <source xml:space="preserve">&Receive</source> + <target xml:space="preserve">&Receive</target> + <context-group purpose="location"><context context-type="linenumber">265</context></context-group> + </trans-unit> + <trans-unit id="_msg100" approved="yes"> + <source xml:space="preserve">&Show / Hide</source> + <target xml:space="preserve">&Show / Hide</target> + <context-group purpose="location"><context context-type="linenumber">315</context></context-group> + </trans-unit> + <trans-unit id="_msg101" approved="yes"> + <source xml:space="preserve">Show or hide the main Window</source> + <target xml:space="preserve">Show or hide the main Window</target> + <context-group purpose="location"><context context-type="linenumber">316</context></context-group> + </trans-unit> + <trans-unit id="_msg102" approved="yes"> + <source xml:space="preserve">Encrypt the private keys that belong to your wallet</source> + <target xml:space="preserve">Encrypt the private keys that belong to your wallet</target> + <context-group purpose="location"><context context-type="linenumber">319</context></context-group> + </trans-unit> + <trans-unit id="_msg103" approved="yes"> + <source xml:space="preserve">Sign messages with your Bitcoin addresses to prove you own them</source> + <target xml:space="preserve">Sign messages with your Bitcoin addresses to prove you own them</target> + <context-group purpose="location"><context context-type="linenumber">326</context></context-group> + </trans-unit> + <trans-unit id="_msg104" approved="yes"> + <source xml:space="preserve">Verify messages to ensure they were signed with specified Bitcoin addresses</source> + <target xml:space="preserve">Verify messages to ensure they were signed with specified Bitcoin addresses</target> + <context-group purpose="location"><context context-type="linenumber">328</context></context-group> + </trans-unit> + <trans-unit id="_msg105" approved="yes"> + <source xml:space="preserve">&File</source> + <target xml:space="preserve">&File</target> + <context-group purpose="location"><context context-type="linenumber">457</context></context-group> + </trans-unit> + <trans-unit id="_msg106" approved="yes"> + <source xml:space="preserve">&Settings</source> + <target xml:space="preserve">&Settings</target> + <context-group purpose="location"><context context-type="linenumber">475</context></context-group> + </trans-unit> + <trans-unit id="_msg107" approved="yes"> + <source xml:space="preserve">&Help</source> + <target xml:space="preserve">&Help</target> + <context-group purpose="location"><context context-type="linenumber">536</context></context-group> + </trans-unit> + <trans-unit id="_msg108" approved="yes"> + <source xml:space="preserve">Tabs toolbar</source> + <target xml:space="preserve">Tabs toolbar</target> + <context-group purpose="location"><context context-type="linenumber">547</context></context-group> + </trans-unit> + <trans-unit id="_msg109"> + <source xml:space="preserve">Request payments (generates QR codes and bitcoin: URIs)</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">266</context></context-group> + </trans-unit> + <trans-unit id="_msg110"> + <source xml:space="preserve">Show the list of used sending addresses and labels</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">341</context></context-group> + </trans-unit> + <trans-unit id="_msg111"> + <source xml:space="preserve">Show the list of used receiving addresses and labels</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">343</context></context-group> + </trans-unit> + <trans-unit id="_msg112"> + <source xml:space="preserve">&Command-line options</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">363</context></context-group> + </trans-unit> + <group restype="x-gettext-plurals"> + <context-group purpose="location"><context context-type="linenumber">918</context></context-group> + <trans-unit id="_msg113[0]" approved="yes"> + <source xml:space="preserve">%n active connection(s) to Bitcoin network</source> + <target xml:space="preserve">%n active connection to Bitcoin network</target> + </trans-unit> + <trans-unit id="_msg113[1]" approved="yes"> + <source xml:space="preserve">%n active connection(s) to Bitcoin network</source> + <target xml:space="preserve">%n active connections to Bitcoin network</target> + </trans-unit> + </group> + <trans-unit id="_msg114"> + <source xml:space="preserve">Indexing blocks on disk...</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">998</context></context-group> + </trans-unit> + <trans-unit id="_msg115"> + <source xml:space="preserve">Processing blocks on disk...</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1000</context></context-group> + </trans-unit> + <group restype="x-gettext-plurals"> + <context-group purpose="location"><context context-type="linenumber">1019</context></context-group> + <trans-unit id="_msg116[0]" approved="yes"> + <source xml:space="preserve">Processed %n block(s) of transaction history.</source> + <target xml:space="preserve">Processed %n block of transaction history.</target> + </trans-unit> + <trans-unit id="_msg116[1]" approved="yes"> + <source xml:space="preserve">Processed %n block(s) of transaction history.</source> + <target xml:space="preserve">Processed %n blocks of transaction history.</target> + </trans-unit> + </group> + <trans-unit id="_msg117" approved="yes"> + <source xml:space="preserve">%1 behind</source> + <target xml:space="preserve">%1 behind</target> + <context-group purpose="location"><context context-type="linenumber">1042</context></context-group> + </trans-unit> + <trans-unit id="_msg118" approved="yes"> + <source xml:space="preserve">Last received block was generated %1 ago.</source> + <target xml:space="preserve">Last received block was generated %1 ago.</target> + <context-group purpose="location"><context context-type="linenumber">1066</context></context-group> + </trans-unit> + <trans-unit id="_msg119" approved="yes"> + <source xml:space="preserve">Transactions after this will not yet be visible.</source> + <target xml:space="preserve">Transactions after this will not yet be visible.</target> + <context-group purpose="location"><context context-type="linenumber">1068</context></context-group> + </trans-unit> + <trans-unit id="_msg120" approved="yes"> + <source xml:space="preserve">Error</source> + <target xml:space="preserve">Error</target> + <context-group purpose="location"><context context-type="linenumber">1093</context></context-group> + </trans-unit> + <trans-unit id="_msg121" approved="yes"> + <source xml:space="preserve">Warning</source> + <target xml:space="preserve">Warning</target> + <context-group purpose="location"><context context-type="linenumber">1097</context></context-group> + </trans-unit> + <trans-unit id="_msg122" approved="yes"> + <source xml:space="preserve">Information</source> + <target xml:space="preserve">Information</target> + <context-group purpose="location"><context context-type="linenumber">1101</context></context-group> + </trans-unit> + <trans-unit id="_msg123" approved="yes"> + <source xml:space="preserve">Up to date</source> + <target xml:space="preserve">Up to date</target> + <context-group purpose="location"><context context-type="linenumber">1023</context></context-group> + </trans-unit> + <trans-unit id="_msg124"> + <source xml:space="preserve">&Load PSBT from file...</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">329</context></context-group> + </trans-unit> + <trans-unit id="_msg125"> + <source xml:space="preserve">Load Partially Signed Bitcoin Transaction</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">330</context></context-group> + </trans-unit> + <trans-unit id="_msg126"> + <source xml:space="preserve">Load PSBT from clipboard...</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">331</context></context-group> + </trans-unit> + <trans-unit id="_msg127"> + <source xml:space="preserve">Load Partially Signed Bitcoin Transaction from clipboard</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">332</context></context-group> + </trans-unit> + <trans-unit id="_msg128"> + <source xml:space="preserve">Node window</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">334</context></context-group> + </trans-unit> + <trans-unit id="_msg129"> + <source xml:space="preserve">Open node debugging and diagnostic console</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">335</context></context-group> + </trans-unit> + <trans-unit id="_msg130"> + <source xml:space="preserve">&Sending addresses</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">340</context></context-group> + </trans-unit> + <trans-unit id="_msg131"> + <source xml:space="preserve">&Receiving addresses</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">342</context></context-group> + </trans-unit> + <trans-unit id="_msg132"> + <source xml:space="preserve">Open a bitcoin: URI</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">346</context></context-group> + </trans-unit> + <trans-unit id="_msg133"> + <source xml:space="preserve">Open Wallet</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">348</context></context-group> + </trans-unit> + <trans-unit id="_msg134"> + <source xml:space="preserve">Open a wallet</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">350</context></context-group> + </trans-unit> + <trans-unit id="_msg135"> + <source xml:space="preserve">Close Wallet...</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">353</context></context-group> + </trans-unit> + <trans-unit id="_msg136"> + <source xml:space="preserve">Close wallet</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">354</context></context-group> + </trans-unit> + <trans-unit id="_msg137"> + <source xml:space="preserve">Close All Wallets...</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">360</context></context-group> + </trans-unit> + <trans-unit id="_msg138"> + <source xml:space="preserve">Close all wallets</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">361</context></context-group> + </trans-unit> + <trans-unit id="_msg139"> + <source xml:space="preserve">Show the %1 help message to get a list with possible Bitcoin command-line options</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">365</context></context-group> + </trans-unit> + <trans-unit id="_msg140"> + <source xml:space="preserve">&Mask values</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">367</context></context-group> + </trans-unit> + <trans-unit id="_msg141"> + <source xml:space="preserve">Mask the values in the Overview tab</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">369</context></context-group> + </trans-unit> + <trans-unit id="_msg142"> + <source xml:space="preserve">default wallet</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">401</context></context-group> + </trans-unit> + <trans-unit id="_msg143"> + <source xml:space="preserve">No wallets available</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">422</context></context-group> + </trans-unit> + <trans-unit id="_msg144"> + <source xml:space="preserve">&Window</source> + <target xml:space="preserve" state="needs-review-translation">&Window</target> + <context-group purpose="location"><context context-type="linenumber">486</context></context-group> + </trans-unit> + <trans-unit id="_msg145"> + <source xml:space="preserve">Minimize</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">488</context></context-group> + </trans-unit> + <trans-unit id="_msg146"> + <source xml:space="preserve">Zoom</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">498</context></context-group> + </trans-unit> + <trans-unit id="_msg147"> + <source xml:space="preserve">Main Window</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">516</context></context-group> + </trans-unit> + <trans-unit id="_msg148"> + <source xml:space="preserve">%1 client</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">761</context></context-group> + </trans-unit> + <trans-unit id="_msg149"> + <source xml:space="preserve">Connecting to peers...</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1010</context></context-group> + </trans-unit> + <trans-unit id="_msg150" approved="yes"> + <source xml:space="preserve">Catching up...</source> + <target xml:space="preserve">Catching up...</target> + <context-group purpose="location"><context context-type="linenumber">1047</context></context-group> + </trans-unit> + <trans-unit id="_msg151"> + <source xml:space="preserve">Error: %1</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1094</context></context-group> + </trans-unit> + <trans-unit id="_msg152"> + <source xml:space="preserve">Warning: %1</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1098</context></context-group> + </trans-unit> + <trans-unit id="_msg153"> + <source xml:space="preserve">Date: %1 +</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1198</context></context-group> + </trans-unit> + <trans-unit id="_msg154"> + <source xml:space="preserve">Amount: %1 +</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1199</context></context-group> + </trans-unit> + <trans-unit id="_msg155"> + <source xml:space="preserve">Wallet: %1 +</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1201</context></context-group> + </trans-unit> + <trans-unit id="_msg156"> + <source xml:space="preserve">Type: %1 +</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1203</context></context-group> + </trans-unit> + <trans-unit id="_msg157"> + <source xml:space="preserve">Label: %1 +</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1205</context></context-group> + </trans-unit> + <trans-unit id="_msg158"> + <source xml:space="preserve">Address: %1 +</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1207</context></context-group> + </trans-unit> + <trans-unit id="_msg159" approved="yes"> + <source xml:space="preserve">Sent transaction</source> + <target xml:space="preserve">Sent transaction</target> + <context-group purpose="location"><context context-type="linenumber">1208</context></context-group> + </trans-unit> + <trans-unit id="_msg160" approved="yes"> + <source xml:space="preserve">Incoming transaction</source> + <target xml:space="preserve">Incoming transaction</target> + <context-group purpose="location"><context context-type="linenumber">1208</context></context-group> + </trans-unit> + <trans-unit id="_msg161"> + <source xml:space="preserve">HD key generation is <b>enabled</b></source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1260</context></context-group> + </trans-unit> + <trans-unit id="_msg162"> + <source xml:space="preserve">HD key generation is <b>disabled</b></source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1260</context></context-group> + </trans-unit> + <trans-unit id="_msg163"> + <source xml:space="preserve">Private key <b>disabled</b></source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1260</context></context-group> + </trans-unit> + <trans-unit id="_msg164" approved="yes"> + <source xml:space="preserve">Wallet is <b>encrypted</b> and currently <b>unlocked</b></source> + <target xml:space="preserve">Wallet is <b>encrypted</b> and currently <b>unlocked</b></target> + <context-group purpose="location"><context context-type="linenumber">1279</context></context-group> + </trans-unit> + <trans-unit id="_msg165" approved="yes"> + <source xml:space="preserve">Wallet is <b>encrypted</b> and currently <b>locked</b></source> + <target xml:space="preserve">Wallet is <b>encrypted</b> and currently <b>locked</b></target> + <context-group purpose="location"><context context-type="linenumber">1287</context></context-group> + </trans-unit> + <trans-unit id="_msg166"> + <source xml:space="preserve">Original message:</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1408</context></context-group> + </trans-unit> + </group> + <group restype="x-trolltech-linguist-context" resname="UnitDisplayStatusBarControl"> + <trans-unit id="_msg167"> + <source xml:space="preserve">Unit to show amounts in. Click to select another unit.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1448</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../forms/coincontroldialog.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="CoinControlDialog"> + <trans-unit id="_msg168"> + <source xml:space="preserve">Coin Selection</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">14</context></context-group> + </trans-unit> + <trans-unit id="_msg169"> + <source xml:space="preserve">Quantity:</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">48</context></context-group> + </trans-unit> + <trans-unit id="_msg170"> + <source xml:space="preserve">Bytes:</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">77</context></context-group> + </trans-unit> + <trans-unit id="_msg171"> + <source xml:space="preserve">Amount:</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">122</context></context-group> + </trans-unit> + <trans-unit id="_msg172"> + <source xml:space="preserve">Fee:</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">202</context></context-group> + </trans-unit> + <trans-unit id="_msg173"> + <source xml:space="preserve">Dust:</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">154</context></context-group> + </trans-unit> + <trans-unit id="_msg174"> + <source xml:space="preserve">After Fee:</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">247</context></context-group> + </trans-unit> + <trans-unit id="_msg175"> + <source xml:space="preserve">Change:</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">279</context></context-group> + </trans-unit> + <trans-unit id="_msg176"> + <source xml:space="preserve">(un)select all</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">335</context></context-group> + </trans-unit> + <trans-unit id="_msg177"> + <source xml:space="preserve">Tree mode</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">351</context></context-group> + </trans-unit> + <trans-unit id="_msg178"> + <source xml:space="preserve">List mode</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">364</context></context-group> + </trans-unit> + <trans-unit id="_msg179"> + <source xml:space="preserve">Amount</source> + <target xml:space="preserve" state="needs-review-translation">Amount</target> + <context-group purpose="location"><context context-type="linenumber">420</context></context-group> + </trans-unit> + <trans-unit id="_msg180"> + <source xml:space="preserve">Received with label</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">425</context></context-group> + </trans-unit> + <trans-unit id="_msg181"> + <source xml:space="preserve">Received with address</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">430</context></context-group> + </trans-unit> + <trans-unit id="_msg182"> + <source xml:space="preserve">Date</source> + <target xml:space="preserve" state="needs-review-translation">Date</target> + <context-group purpose="location"><context context-type="linenumber">435</context></context-group> + </trans-unit> + <trans-unit id="_msg183"> + <source xml:space="preserve">Confirmations</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">440</context></context-group> + </trans-unit> + <trans-unit id="_msg184"> + <source xml:space="preserve">Confirmed</source> + <target xml:space="preserve" state="needs-review-translation">Confirmed</target> + <context-group purpose="location"><context context-type="linenumber">443</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../coincontroldialog.cpp" datatype="cpp" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="CoinControlDialog"> + <trans-unit id="_msg185"> + <source xml:space="preserve">Copy address</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">54</context></context-group> + </trans-unit> + <trans-unit id="_msg186"> + <source xml:space="preserve">Copy label</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">55</context></context-group> + </trans-unit> + <trans-unit id="_msg187"> + <source xml:space="preserve">Copy amount</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">56</context></context-group> + <context-group purpose="location"><context context-type="linenumber">82</context></context-group> + </trans-unit> + <trans-unit id="_msg188"> + <source xml:space="preserve">Copy transaction ID</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">57</context></context-group> + </trans-unit> + <trans-unit id="_msg189"> + <source xml:space="preserve">Lock unspent</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">58</context></context-group> + </trans-unit> + <trans-unit id="_msg190"> + <source xml:space="preserve">Unlock unspent</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">59</context></context-group> + </trans-unit> + <trans-unit id="_msg191"> + <source xml:space="preserve">Copy quantity</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">81</context></context-group> + </trans-unit> + <trans-unit id="_msg192"> + <source xml:space="preserve">Copy fee</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">83</context></context-group> + </trans-unit> + <trans-unit id="_msg193"> + <source xml:space="preserve">Copy after fee</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">84</context></context-group> + </trans-unit> + <trans-unit id="_msg194"> + <source xml:space="preserve">Copy bytes</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">85</context></context-group> + </trans-unit> + <trans-unit id="_msg195"> + <source xml:space="preserve">Copy dust</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">86</context></context-group> + </trans-unit> + <trans-unit id="_msg196"> + <source xml:space="preserve">Copy change</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">87</context></context-group> + </trans-unit> + <trans-unit id="_msg197"> + <source xml:space="preserve">(%1 locked)</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">389</context></context-group> + </trans-unit> + <trans-unit id="_msg198"> + <source xml:space="preserve">yes</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">544</context></context-group> + </trans-unit> + <trans-unit id="_msg199"> + <source xml:space="preserve">no</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">544</context></context-group> + </trans-unit> + <trans-unit id="_msg200"> + <source xml:space="preserve">This label turns red if any recipient receives an amount smaller than the current dust threshold.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">558</context></context-group> + </trans-unit> + <trans-unit id="_msg201"> + <source xml:space="preserve">Can vary +/- %1 satoshi(s) per input.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">563</context></context-group> + </trans-unit> + <trans-unit id="_msg202"> + <source xml:space="preserve">(no label)</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">601</context></context-group> + <context-group purpose="location"><context context-type="linenumber">655</context></context-group> + </trans-unit> + <trans-unit id="_msg203"> + <source xml:space="preserve">change from %1 (%2)</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">648</context></context-group> + </trans-unit> + <trans-unit id="_msg204"> + <source xml:space="preserve">(change)</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">649</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../walletcontroller.cpp" datatype="cpp" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="CreateWalletActivity"> + <trans-unit id="_msg205"> + <source xml:space="preserve">Creating Wallet <b>%1</b>...</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">250</context></context-group> + </trans-unit> + <trans-unit id="_msg206"> + <source xml:space="preserve">Create wallet failed</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">278</context></context-group> + </trans-unit> + <trans-unit id="_msg207"> + <source xml:space="preserve">Create wallet warning</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">280</context></context-group> + </trans-unit> + </group> + <group restype="x-trolltech-linguist-context" resname="OpenWalletActivity"> + <trans-unit id="_msg208"> + <source xml:space="preserve">Open wallet failed</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">319</context></context-group> + </trans-unit> + <trans-unit id="_msg209"> + <source xml:space="preserve">Open wallet warning</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">321</context></context-group> + </trans-unit> + <trans-unit id="_msg210"> + <source xml:space="preserve">default wallet</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">331</context></context-group> + </trans-unit> + <trans-unit id="_msg211"> + <source xml:space="preserve">Opening Wallet <b>%1</b>...</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">333</context></context-group> + </trans-unit> + </group> + <group restype="x-trolltech-linguist-context" resname="WalletController"> + <trans-unit id="_msg212"> + <source xml:space="preserve">Close wallet</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">86</context></context-group> + </trans-unit> + <trans-unit id="_msg213"> + <source xml:space="preserve">Are you sure you wish to close the wallet <i>%1</i>?</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">87</context></context-group> + </trans-unit> + <trans-unit id="_msg214"> + <source xml:space="preserve">Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">88</context></context-group> + </trans-unit> + <trans-unit id="_msg215"> + <source xml:space="preserve">Close all wallets</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">101</context></context-group> + </trans-unit> + <trans-unit id="_msg216"> + <source xml:space="preserve">Are you sure you wish to close all wallets?</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">102</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../forms/createwalletdialog.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="CreateWalletDialog"> + <trans-unit id="_msg217"> + <source xml:space="preserve">Create Wallet</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">14</context></context-group> + </trans-unit> + <trans-unit id="_msg218"> + <source xml:space="preserve">Wallet Name</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">25</context></context-group> + </trans-unit> + <trans-unit id="_msg219"> + <source xml:space="preserve">Wallet</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">38</context></context-group> + </trans-unit> + <trans-unit id="_msg220"> + <source xml:space="preserve">Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">47</context></context-group> + </trans-unit> + <trans-unit id="_msg221"> + <source xml:space="preserve">Encrypt Wallet</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">50</context></context-group> + </trans-unit> + <trans-unit id="_msg222"> + <source xml:space="preserve">Advanced Options</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">76</context></context-group> + </trans-unit> + <trans-unit id="_msg223"> + <source xml:space="preserve">Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">85</context></context-group> + </trans-unit> + <trans-unit id="_msg224"> + <source xml:space="preserve">Disable Private Keys</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">88</context></context-group> + </trans-unit> + <trans-unit id="_msg225"> + <source xml:space="preserve">Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">95</context></context-group> + </trans-unit> + <trans-unit id="_msg226"> + <source xml:space="preserve">Make Blank Wallet</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">98</context></context-group> + </trans-unit> + <trans-unit id="_msg227"> + <source xml:space="preserve">Use descriptors for scriptPubKey management</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">105</context></context-group> + </trans-unit> + <trans-unit id="_msg228"> + <source xml:space="preserve">Descriptor Wallet</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">108</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../createwalletdialog.cpp" datatype="cpp" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="CreateWalletDialog"> + <trans-unit id="_msg229"> + <source xml:space="preserve">Create</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">21</context></context-group> + </trans-unit> + <trans-unit id="_msg230"> + <source xml:space="preserve">Compiled without sqlite support (required for descriptor wallets)</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">63</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../forms/editaddressdialog.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="EditAddressDialog"> + <trans-unit id="_msg231" approved="yes"> + <source xml:space="preserve">Edit Address</source> + <target xml:space="preserve">Edit Address</target> + <context-group purpose="location"><context context-type="linenumber">14</context></context-group> + </trans-unit> + <trans-unit id="_msg232" approved="yes"> + <source xml:space="preserve">&Label</source> + <target xml:space="preserve">&Label</target> + <context-group purpose="location"><context context-type="linenumber">25</context></context-group> + </trans-unit> + <trans-unit id="_msg233"> + <source xml:space="preserve">The label associated with this address list entry</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">35</context></context-group> + </trans-unit> + <trans-unit id="_msg234"> + <source xml:space="preserve">The address associated with this address list entry. This can only be modified for sending addresses.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">52</context></context-group> + </trans-unit> + <trans-unit id="_msg235" approved="yes"> + <source xml:space="preserve">&Address</source> + <target xml:space="preserve">&Address</target> + <context-group purpose="location"><context context-type="linenumber">42</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../editaddressdialog.cpp" datatype="cpp" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="EditAddressDialog"> + <trans-unit id="_msg236"> + <source xml:space="preserve">New sending address</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">29</context></context-group> + </trans-unit> + <trans-unit id="_msg237"> + <source xml:space="preserve">Edit receiving address</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">32</context></context-group> + </trans-unit> + <trans-unit id="_msg238"> + <source xml:space="preserve">Edit sending address</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">36</context></context-group> + </trans-unit> + <trans-unit id="_msg239"> + <source xml:space="preserve">The entered address "%1" is not a valid Bitcoin address.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">113</context></context-group> + </trans-unit> + <trans-unit id="_msg240"> + <source xml:space="preserve">Address "%1" already exists as a receiving address with label "%2" and so cannot be added as a sending address.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">146</context></context-group> + </trans-unit> + <trans-unit id="_msg241"> + <source xml:space="preserve">The entered address "%1" is already in the address book with label "%2".</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">151</context></context-group> + </trans-unit> + <trans-unit id="_msg242"> + <source xml:space="preserve">Could not unlock wallet.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">123</context></context-group> + </trans-unit> + <trans-unit id="_msg243"> + <source xml:space="preserve">New key generation failed.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">128</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../intro.cpp" datatype="cpp" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="FreespaceChecker"> + <trans-unit id="_msg244" approved="yes"> + <source xml:space="preserve">A new data directory will be created.</source> + <target xml:space="preserve">A new data directory will be created.</target> + <context-group purpose="location"><context context-type="linenumber">72</context></context-group> + </trans-unit> + <trans-unit id="_msg245" approved="yes"> + <source xml:space="preserve">name</source> + <target xml:space="preserve">name</target> + <context-group purpose="location"><context context-type="linenumber">94</context></context-group> + </trans-unit> + <trans-unit id="_msg246" approved="yes"> + <source xml:space="preserve">Directory already exists. Add %1 if you intend to create a new directory here.</source> + <target xml:space="preserve">Directory already exists. Add %1 if you intend to create a new directory here.</target> + <context-group purpose="location"><context context-type="linenumber">96</context></context-group> + </trans-unit> + <trans-unit id="_msg247" approved="yes"> + <source xml:space="preserve">Path already exists, and is not a directory.</source> + <target xml:space="preserve">Path already exists, and is not a directory.</target> + <context-group purpose="location"><context context-type="linenumber">99</context></context-group> + </trans-unit> + <trans-unit id="_msg248" approved="yes"> + <source xml:space="preserve">Cannot create data directory here.</source> + <target xml:space="preserve">Cannot create data directory here.</target> + <context-group purpose="location"><context context-type="linenumber">106</context></context-group> + </trans-unit> + </group> + <group restype="x-trolltech-linguist-context" resname="Intro"> + <trans-unit id="_msg249"> + <source xml:space="preserve">Bitcoin</source> + <target xml:space="preserve" state="needs-review-translation">Bitcoin</target> + <context-group purpose="location"><context context-type="linenumber">138</context></context-group> + </trans-unit> + <trans-unit id="_msg250"> + <source xml:space="preserve">Discard blocks after verification, except most recent %1 GB (prune)</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">146</context></context-group> + </trans-unit> + <trans-unit id="_msg251"> + <source xml:space="preserve">At least %1 GB of data will be stored in this directory, and it will grow over time.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">358</context></context-group> + </trans-unit> + <trans-unit id="_msg252"> + <source xml:space="preserve">Approximately %1 GB of data will be stored in this directory.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">361</context></context-group> + </trans-unit> + <trans-unit id="_msg253"> + <source xml:space="preserve">%1 will download and store a copy of the Bitcoin block chain.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">365</context></context-group> + </trans-unit> + <trans-unit id="_msg254"> + <source xml:space="preserve">The wallet will also be stored in this directory.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">367</context></context-group> + </trans-unit> + <trans-unit id="_msg255"> + <source xml:space="preserve">Error: Specified data directory "%1" cannot be created.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">230</context></context-group> + </trans-unit> + <trans-unit id="_msg256" approved="yes"> + <source xml:space="preserve">Error</source> + <target xml:space="preserve">Error</target> + <context-group purpose="location"><context context-type="linenumber">260</context></context-group> + </trans-unit> + <group restype="x-gettext-plurals"> + <context-group purpose="location"><context context-type="linenumber">281</context></context-group> + <trans-unit id="_msg257[0]" approved="yes"> + <source xml:space="preserve">%n GB of free space available</source> + <target xml:space="preserve">%n GB of free space available</target> + </trans-unit> + <trans-unit id="_msg257[1]" approved="yes"> + <source xml:space="preserve">%n GB of free space available</source> + <target xml:space="preserve">%n GB of free space available</target> + </trans-unit> + </group> + <group restype="x-gettext-plurals"> + <context-group purpose="location"><context context-type="linenumber">283</context></context-group> + <trans-unit id="_msg258[0]" approved="yes"> + <source xml:space="preserve">(of %n GB needed)</source> + <target xml:space="preserve">(of %n GB needed)</target> + </trans-unit> + <trans-unit id="_msg258[1]" approved="yes"> + <source xml:space="preserve">(of %n GB needed)</source> + <target xml:space="preserve">(of %n GB needed)</target> + </trans-unit> + </group> + <group restype="x-gettext-plurals"> + <context-group purpose="location"><context context-type="linenumber">286</context></context-group> + <trans-unit id="_msg259[0]"> + <source xml:space="preserve">(%n GB needed for full chain)</source> + <target xml:space="preserve"></target> + </trans-unit> + <trans-unit id="_msg259[1]"> + <source xml:space="preserve">(%n GB needed for full chain)</source> + <target xml:space="preserve"></target> + </trans-unit> + </group> + </group> + </body></file> + <file original="../utilitydialog.cpp" datatype="cpp" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="HelpMessageDialog"> + <trans-unit id="_msg260"> + <source xml:space="preserve">version</source> + <target xml:space="preserve" state="needs-review-translation">version</target> + <context-group purpose="location"><context context-type="linenumber">37</context></context-group> + </trans-unit> + <trans-unit id="_msg261"> + <source xml:space="preserve">About %1</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">41</context></context-group> + </trans-unit> + <trans-unit id="_msg262"> + <source xml:space="preserve">Command-line options</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">60</context></context-group> + </trans-unit> + </group> + <group restype="x-trolltech-linguist-context" resname="ShutdownWindow"> + <trans-unit id="_msg263"> + <source xml:space="preserve">%1 is shutting down...</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">145</context></context-group> + </trans-unit> + <trans-unit id="_msg264"> + <source xml:space="preserve">Do not shut down the computer until this window disappears.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">146</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../forms/intro.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="Intro"> + <trans-unit id="_msg265" approved="yes"> + <source xml:space="preserve">Welcome</source> + <target xml:space="preserve">Welcome</target> + <context-group purpose="location"><context context-type="linenumber">14</context></context-group> + </trans-unit> + <trans-unit id="_msg266"> + <source xml:space="preserve">Welcome to %1.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">23</context></context-group> + </trans-unit> + <trans-unit id="_msg267"> + <source xml:space="preserve">As this is the first time the program is launched, you can choose where %1 will store its data.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">49</context></context-group> + </trans-unit> + <trans-unit id="_msg268"> + <source xml:space="preserve">When you click OK, %1 will begin to download and process the full %4 block chain (%2GB) starting with the earliest transactions in %3 when %4 initially launched.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">206</context></context-group> + </trans-unit> + <trans-unit id="_msg269"> + <source xml:space="preserve">Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">216</context></context-group> + </trans-unit> + <trans-unit id="_msg270"> + <source xml:space="preserve">This initial synchronisation is very demanding, and may expose hardware problems with your computer that had previously gone unnoticed. Each time you run %1, it will continue downloading where it left off.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">226</context></context-group> + </trans-unit> + <trans-unit id="_msg271"> + <source xml:space="preserve">If you have chosen to limit block chain storage (pruning), the historical data must still be downloaded and processed, but will be deleted afterward to keep your disk usage low.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">236</context></context-group> + </trans-unit> + <trans-unit id="_msg272" approved="yes"> + <source xml:space="preserve">Use the default data directory</source> + <target xml:space="preserve">Use the default data directory</target> + <context-group purpose="location"><context context-type="linenumber">66</context></context-group> + </trans-unit> + <trans-unit id="_msg273" approved="yes"> + <source xml:space="preserve">Use a custom data directory:</source> + <target xml:space="preserve">Use a custom data directory:</target> + <context-group purpose="location"><context context-type="linenumber">73</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../forms/modaloverlay.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="ModalOverlay"> + <trans-unit id="_msg274"> + <source xml:space="preserve">Form</source> + <target xml:space="preserve" state="needs-review-translation">Form</target> + <context-group purpose="location"><context context-type="linenumber">14</context></context-group> + </trans-unit> + <trans-unit id="_msg275"> + <source xml:space="preserve">Recent transactions may not yet be visible, and therefore your wallet's balance might be incorrect. This information will be correct once your wallet has finished synchronizing with the bitcoin network, as detailed below.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">133</context></context-group> + </trans-unit> + <trans-unit id="_msg276"> + <source xml:space="preserve">Attempting to spend bitcoins that are affected by not-yet-displayed transactions will not be accepted by the network.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">152</context></context-group> + </trans-unit> + <trans-unit id="_msg277"> + <source xml:space="preserve">Number of blocks left</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">215</context></context-group> + </trans-unit> + <trans-unit id="_msg278"> + <source xml:space="preserve">Unknown...</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">222</context></context-group> + <context-group purpose="location"><context context-type="linenumber">248</context></context-group> + <context-group purpose="location"><context context-type="sourcefile">../modaloverlay.cpp</context><context context-type="linenumber">153</context></context-group> + </trans-unit> + <trans-unit id="_msg279"> + <source xml:space="preserve">Last block time</source> + <target xml:space="preserve" state="needs-review-translation">Last block time</target> + <context-group purpose="location"><context context-type="linenumber">235</context></context-group> + </trans-unit> + <trans-unit id="_msg280"> + <source xml:space="preserve">Progress</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">261</context></context-group> + </trans-unit> + <trans-unit id="_msg281"> + <source xml:space="preserve">Progress increase per hour</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">295</context></context-group> + </trans-unit> + <trans-unit id="_msg282"> + <source xml:space="preserve">calculating...</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">302</context></context-group> + <context-group purpose="location"><context context-type="linenumber">322</context></context-group> + </trans-unit> + <trans-unit id="_msg283"> + <source xml:space="preserve">Estimated time left until synced</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">315</context></context-group> + </trans-unit> + <trans-unit id="_msg284"> + <source xml:space="preserve">Hide</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">352</context></context-group> + </trans-unit> + <trans-unit id="_msg285"> + <source xml:space="preserve">Esc</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">355</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../modaloverlay.cpp" datatype="cpp" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="ModalOverlay"> + <trans-unit id="_msg286"> + <source xml:space="preserve">%1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">34</context></context-group> + </trans-unit> + <trans-unit id="_msg287"> + <source xml:space="preserve">Unknown. Syncing Headers (%1, %2%)...</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">159</context></context-group> + </trans-unit> + </group> + <group restype="x-trolltech-linguist-context" resname="QObject"> + <trans-unit id="_msg288"> + <source xml:space="preserve">unknown</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">123</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../forms/openuridialog.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="OpenURIDialog"> + <trans-unit id="_msg289"> + <source xml:space="preserve">Open bitcoin URI</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">14</context></context-group> + </trans-unit> + <trans-unit id="_msg290"> + <source xml:space="preserve">URI:</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">22</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../forms/optionsdialog.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="OptionsDialog"> + <trans-unit id="_msg291" approved="yes"> + <source xml:space="preserve">Options</source> + <target xml:space="preserve">Options</target> + <context-group purpose="location"><context context-type="linenumber">14</context></context-group> + </trans-unit> + <trans-unit id="_msg292" approved="yes"> + <source xml:space="preserve">&Main</source> + <target xml:space="preserve">&Main</target> + <context-group purpose="location"><context context-type="linenumber">27</context></context-group> + </trans-unit> + <trans-unit id="_msg293"> + <source xml:space="preserve">Automatically start %1 after logging in to the system.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">33</context></context-group> + </trans-unit> + <trans-unit id="_msg294"> + <source xml:space="preserve">&Start %1 on system login</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">36</context></context-group> + </trans-unit> + <trans-unit id="_msg295"> + <source xml:space="preserve">Enabling pruning significantly reduces the disk space required to store transactions. All blocks are still fully validated. Reverting this setting requires re-downloading the entire blockchain.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">58</context></context-group> + </trans-unit> + <trans-unit id="_msg296"> + <source xml:space="preserve">Size of &database cache</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">108</context></context-group> + </trans-unit> + <trans-unit id="_msg297"> + <source xml:space="preserve">Number of script &verification threads</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">151</context></context-group> + </trans-unit> + <trans-unit id="_msg298"> + <source xml:space="preserve">IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">322</context></context-group> + <context-group purpose="location"><context context-type="linenumber">509</context></context-group> + </trans-unit> + <trans-unit id="_msg299"> + <source xml:space="preserve">Shows if the supplied default SOCKS5 proxy is used to reach peers via this network type.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">391</context></context-group> + <context-group purpose="location"><context context-type="linenumber">414</context></context-group> + <context-group purpose="location"><context context-type="linenumber">437</context></context-group> + </trans-unit> + <trans-unit id="_msg300"> + <source xml:space="preserve">Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Exit in the menu.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">606</context></context-group> + </trans-unit> + <trans-unit id="_msg301"> + <source xml:space="preserve">Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items. %s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">686</context></context-group> + <context-group purpose="location"><context context-type="linenumber">699</context></context-group> + </trans-unit> + <trans-unit id="_msg302"> + <source xml:space="preserve">Open the %1 configuration file from the working directory.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">878</context></context-group> + </trans-unit> + <trans-unit id="_msg303"> + <source xml:space="preserve">Open Configuration File</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">881</context></context-group> + </trans-unit> + <trans-unit id="_msg304" approved="yes"> + <source xml:space="preserve">Reset all client options to default.</source> + <target xml:space="preserve">Reset all client options to default.</target> + <context-group purpose="location"><context context-type="linenumber">891</context></context-group> + </trans-unit> + <trans-unit id="_msg305" approved="yes"> + <source xml:space="preserve">&Reset Options</source> + <target xml:space="preserve">&Reset Options</target> + <context-group purpose="location"><context context-type="linenumber">894</context></context-group> + </trans-unit> + <trans-unit id="_msg306" approved="yes"> + <source xml:space="preserve">&Network</source> + <target xml:space="preserve">&Network</target> + <context-group purpose="location"><context context-type="linenumber">249</context></context-group> + </trans-unit> + <trans-unit id="_msg307"> + <source xml:space="preserve">Prune &block storage to</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">61</context></context-group> + </trans-unit> + <trans-unit id="_msg308"> + <source xml:space="preserve">GB</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">71</context></context-group> + </trans-unit> + <trans-unit id="_msg309"> + <source xml:space="preserve">Reverting this setting requires re-downloading the entire blockchain.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">96</context></context-group> + </trans-unit> + <trans-unit id="_msg310"> + <source xml:space="preserve">MiB</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">124</context></context-group> + </trans-unit> + <trans-unit id="_msg311"> + <source xml:space="preserve">(0 = auto, <0 = leave that many cores free)</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">164</context></context-group> + </trans-unit> + <trans-unit id="_msg312"> + <source xml:space="preserve">W&allet</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">200</context></context-group> + </trans-unit> + <trans-unit id="_msg313"> + <source xml:space="preserve">Expert</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">206</context></context-group> + </trans-unit> + <trans-unit id="_msg314"> + <source xml:space="preserve">Enable coin &control features</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">215</context></context-group> + </trans-unit> + <trans-unit id="_msg315"> + <source xml:space="preserve">If you disable the spending of unconfirmed change, the change from a transaction cannot be used until that transaction has at least one confirmation. This also affects how your balance is computed.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">222</context></context-group> + </trans-unit> + <trans-unit id="_msg316"> + <source xml:space="preserve">&Spend unconfirmed change</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">225</context></context-group> + </trans-unit> + <trans-unit id="_msg317" approved="yes"> + <source xml:space="preserve">Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled.</source> + <target xml:space="preserve">Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled.</target> + <context-group purpose="location"><context context-type="linenumber">255</context></context-group> + </trans-unit> + <trans-unit id="_msg318" approved="yes"> + <source xml:space="preserve">Map port using &UPnP</source> + <target xml:space="preserve">Map port using &UPnP</target> + <context-group purpose="location"><context context-type="linenumber">258</context></context-group> + </trans-unit> + <trans-unit id="_msg319"> + <source xml:space="preserve">Automatically open the Bitcoin client port on the router. This only works when your router supports NAT-PMP and it is enabled. The external port could be random.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">265</context></context-group> + </trans-unit> + <trans-unit id="_msg320"> + <source xml:space="preserve">Map port using NA&T-PMP</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">268</context></context-group> + </trans-unit> + <trans-unit id="_msg321"> + <source xml:space="preserve">Accept connections from outside.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">275</context></context-group> + </trans-unit> + <trans-unit id="_msg322"> + <source xml:space="preserve">Allow incomin&g connections</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">278</context></context-group> + </trans-unit> + <trans-unit id="_msg323"> + <source xml:space="preserve">Connect to the Bitcoin network through a SOCKS5 proxy.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">285</context></context-group> + </trans-unit> + <trans-unit id="_msg324"> + <source xml:space="preserve">&Connect through SOCKS5 proxy (default proxy):</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">288</context></context-group> + </trans-unit> + <trans-unit id="_msg325" approved="yes"> + <source xml:space="preserve">Proxy &IP:</source> + <target xml:space="preserve">Proxy &IP:</target> + <context-group purpose="location"><context context-type="linenumber">297</context></context-group> + <context-group purpose="location"><context context-type="linenumber">484</context></context-group> + </trans-unit> + <trans-unit id="_msg326" approved="yes"> + <source xml:space="preserve">&Port:</source> + <target xml:space="preserve">&Port:</target> + <context-group purpose="location"><context context-type="linenumber">329</context></context-group> + <context-group purpose="location"><context context-type="linenumber">516</context></context-group> + </trans-unit> + <trans-unit id="_msg327" approved="yes"> + <source xml:space="preserve">Port of the proxy (e.g. 9050)</source> + <target xml:space="preserve">Port of the proxy (e.g. 9050)</target> + <context-group purpose="location"><context context-type="linenumber">354</context></context-group> + <context-group purpose="location"><context context-type="linenumber">541</context></context-group> + </trans-unit> + <trans-unit id="_msg328"> + <source xml:space="preserve">Used for reaching peers via:</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">378</context></context-group> + </trans-unit> + <trans-unit id="_msg329"> + <source xml:space="preserve">IPv4</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">401</context></context-group> + </trans-unit> + <trans-unit id="_msg330"> + <source xml:space="preserve">IPv6</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">424</context></context-group> + </trans-unit> + <trans-unit id="_msg331"> + <source xml:space="preserve">Tor</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">447</context></context-group> + </trans-unit> + <trans-unit id="_msg332" approved="yes"> + <source xml:space="preserve">&Window</source> + <target xml:space="preserve">&Window</target> + <context-group purpose="location"><context context-type="linenumber">577</context></context-group> + </trans-unit> + <trans-unit id="_msg333"> + <source xml:space="preserve">Show the icon in the system tray.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">583</context></context-group> + </trans-unit> + <trans-unit id="_msg334"> + <source xml:space="preserve">&Show tray icon</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">586</context></context-group> + </trans-unit> + <trans-unit id="_msg335" approved="yes"> + <source xml:space="preserve">Show only a tray icon after minimizing the window.</source> + <target xml:space="preserve">Show only a tray icon after minimizing the window.</target> + <context-group purpose="location"><context context-type="linenumber">596</context></context-group> + </trans-unit> + <trans-unit id="_msg336" approved="yes"> + <source xml:space="preserve">&Minimize to the tray instead of the taskbar</source> + <target xml:space="preserve">&Minimize to the tray instead of the taskbar</target> + <context-group purpose="location"><context context-type="linenumber">599</context></context-group> + </trans-unit> + <trans-unit id="_msg337" approved="yes"> + <source xml:space="preserve">M&inimize on close</source> + <target xml:space="preserve">M&inimize on close</target> + <context-group purpose="location"><context context-type="linenumber">609</context></context-group> + </trans-unit> + <trans-unit id="_msg338" approved="yes"> + <source xml:space="preserve">&Display</source> + <target xml:space="preserve">&Display</target> + <context-group purpose="location"><context context-type="linenumber">630</context></context-group> + </trans-unit> + <trans-unit id="_msg339" approved="yes"> + <source xml:space="preserve">User Interface &language:</source> + <target xml:space="preserve">User Interface &language:</target> + <context-group purpose="location"><context context-type="linenumber">638</context></context-group> + </trans-unit> + <trans-unit id="_msg340"> + <source xml:space="preserve">The user interface language can be set here. This setting will take effect after restarting %1.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">651</context></context-group> + </trans-unit> + <trans-unit id="_msg341" approved="yes"> + <source xml:space="preserve">&Unit to show amounts in:</source> + <target xml:space="preserve">&Unit to show amounts in:</target> + <context-group purpose="location"><context context-type="linenumber">662</context></context-group> + </trans-unit> + <trans-unit id="_msg342" approved="yes"> + <source xml:space="preserve">Choose the default subdivision unit to show in the interface and when sending coins.</source> + <target xml:space="preserve">Choose the default subdivision unit to show in the interface and when sending coins.</target> + <context-group purpose="location"><context context-type="linenumber">675</context></context-group> + </trans-unit> + <trans-unit id="_msg343"> + <source xml:space="preserve">Whether to show coin control features or not.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">212</context></context-group> + </trans-unit> + <trans-unit id="_msg344"> + <source xml:space="preserve">Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor onion services.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">472</context></context-group> + </trans-unit> + <trans-unit id="_msg345"> + <source xml:space="preserve">Use separate SOCKS&5 proxy to reach peers via Tor onion services:</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">475</context></context-group> + </trans-unit> + <trans-unit id="_msg346"> + <source xml:space="preserve">&Third party transaction URLs</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">689</context></context-group> + </trans-unit> + <trans-unit id="_msg347"> + <source xml:space="preserve">Monospaced font in the Overview tab:</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">711</context></context-group> + </trans-unit> + <trans-unit id="_msg348"> + <source xml:space="preserve">embedded "%1"</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">719</context></context-group> + </trans-unit> + <trans-unit id="_msg349"> + <source xml:space="preserve">111.11111111 BTC</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">741</context></context-group> + <context-group purpose="location"><context context-type="linenumber">790</context></context-group> + </trans-unit> + <trans-unit id="_msg350"> + <source xml:space="preserve">909.09090909 BTC</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">748</context></context-group> + <context-group purpose="location"><context context-type="linenumber">797</context></context-group> + </trans-unit> + <trans-unit id="_msg351"> + <source xml:space="preserve">closest matching "%1"</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">768</context></context-group> + </trans-unit> + <trans-unit id="_msg352"> + <source xml:space="preserve">Options set in this dialog are overridden by the command line or in the configuration file:</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">833</context></context-group> + </trans-unit> + <trans-unit id="_msg353" approved="yes"> + <source xml:space="preserve">&OK</source> + <target xml:space="preserve">&OK</target> + <context-group purpose="location"><context context-type="linenumber">974</context></context-group> + </trans-unit> + <trans-unit id="_msg354" approved="yes"> + <source xml:space="preserve">&Cancel</source> + <target xml:space="preserve">&Cancel</target> + <context-group purpose="location"><context context-type="linenumber">987</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../optionsdialog.cpp" datatype="cpp" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="OptionsDialog"> + <trans-unit id="_msg355" approved="yes"> + <source xml:space="preserve">default</source> + <target xml:space="preserve">default</target> + <context-group purpose="location"><context context-type="linenumber">104</context></context-group> + </trans-unit> + <trans-unit id="_msg356"> + <source xml:space="preserve">none</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">185</context></context-group> + </trans-unit> + <trans-unit id="_msg357" approved="yes"> + <source xml:space="preserve">Confirm options reset</source> + <target xml:space="preserve">Confirm options reset</target> + <context-group purpose="location"><context context-type="linenumber">276</context></context-group> + </trans-unit> + <trans-unit id="_msg358"> + <source xml:space="preserve">Client restart required to activate changes.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">277</context></context-group> + <context-group purpose="location"><context context-type="linenumber">334</context></context-group> + </trans-unit> + <trans-unit id="_msg359"> + <source xml:space="preserve">Client will be shut down. Do you want to proceed?</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">277</context></context-group> + </trans-unit> + <trans-unit id="_msg360"> + <source xml:space="preserve">Configuration options</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">292</context></context-group> + </trans-unit> + <trans-unit id="_msg361"> + <source xml:space="preserve">The configuration file is used to specify advanced user options which override GUI settings. Additionally, any command-line options will override this configuration file.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">293</context></context-group> + </trans-unit> + <trans-unit id="_msg362"> + <source xml:space="preserve">Error</source> + <target xml:space="preserve" state="needs-review-translation">Error</target> + <context-group purpose="location"><context context-type="linenumber">298</context></context-group> + </trans-unit> + <trans-unit id="_msg363"> + <source xml:space="preserve">The configuration file could not be opened.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">298</context></context-group> + </trans-unit> + <trans-unit id="_msg364"> + <source xml:space="preserve">This change would require a client restart.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">338</context></context-group> + </trans-unit> + <trans-unit id="_msg365" approved="yes"> + <source xml:space="preserve">The supplied proxy address is invalid.</source> + <target xml:space="preserve">The supplied proxy address is invalid.</target> + <context-group purpose="location"><context context-type="linenumber">366</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../forms/overviewpage.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="OverviewPage"> + <trans-unit id="_msg366" approved="yes"> + <source xml:space="preserve">Form</source> + <target xml:space="preserve">Form</target> + <context-group purpose="location"><context context-type="linenumber">14</context></context-group> + </trans-unit> + <trans-unit id="_msg367" approved="yes"> + <source xml:space="preserve">The displayed information may be out of date. Your wallet automatically synchronizes with the Bitcoin network after a connection is established, but this process has not completed yet.</source> + <target xml:space="preserve">The displayed information may be out of date. Your wallet automatically synchronizes with the Bitcoin network after a connection is established, but this process has not completed yet.</target> + <context-group purpose="location"><context context-type="linenumber">76</context></context-group> + <context-group purpose="location"><context context-type="linenumber">411</context></context-group> + </trans-unit> + <trans-unit id="_msg368"> + <source xml:space="preserve">Watch-only:</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">284</context></context-group> + </trans-unit> + <trans-unit id="_msg369"> + <source xml:space="preserve">Available:</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">294</context></context-group> + </trans-unit> + <trans-unit id="_msg370" approved="yes"> + <source xml:space="preserve">Your current spendable balance</source> + <target xml:space="preserve">Your current spendable balance</target> + <context-group purpose="location"><context context-type="linenumber">304</context></context-group> + </trans-unit> + <trans-unit id="_msg371"> + <source xml:space="preserve">Pending:</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">339</context></context-group> + </trans-unit> + <trans-unit id="_msg372" approved="yes"> + <source xml:space="preserve">Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</source> + <target xml:space="preserve">Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</target> + <context-group purpose="location"><context context-type="linenumber">139</context></context-group> + </trans-unit> + <trans-unit id="_msg373" approved="yes"> + <source xml:space="preserve">Immature:</source> + <target xml:space="preserve">Immature:</target> + <context-group purpose="location"><context context-type="linenumber">239</context></context-group> + </trans-unit> + <trans-unit id="_msg374" approved="yes"> + <source xml:space="preserve">Mined balance that has not yet matured</source> + <target xml:space="preserve">Mined balance that has not yet matured</target> + <context-group purpose="location"><context context-type="linenumber">210</context></context-group> + </trans-unit> + <trans-unit id="_msg375"> + <source xml:space="preserve">Balances</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">60</context></context-group> + </trans-unit> + <trans-unit id="_msg376" approved="yes"> + <source xml:space="preserve">Total:</source> + <target xml:space="preserve">Total:</target> + <context-group purpose="location"><context context-type="linenumber">200</context></context-group> + </trans-unit> + <trans-unit id="_msg377" approved="yes"> + <source xml:space="preserve">Your current total balance</source> + <target xml:space="preserve">Your current total balance</target> + <context-group purpose="location"><context context-type="linenumber">249</context></context-group> + </trans-unit> + <trans-unit id="_msg378"> + <source xml:space="preserve">Your current balance in watch-only addresses</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">323</context></context-group> + </trans-unit> + <trans-unit id="_msg379"> + <source xml:space="preserve">Spendable:</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">346</context></context-group> + </trans-unit> + <trans-unit id="_msg380"> + <source xml:space="preserve">Recent transactions</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">395</context></context-group> + </trans-unit> + <trans-unit id="_msg381"> + <source xml:space="preserve">Unconfirmed transactions to watch-only addresses</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">120</context></context-group> + </trans-unit> + <trans-unit id="_msg382"> + <source xml:space="preserve">Mined balance in watch-only addresses that has not yet matured</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">158</context></context-group> + </trans-unit> + <trans-unit id="_msg383"> + <source xml:space="preserve">Current total balance in watch-only addresses</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">268</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../overviewpage.cpp" datatype="cpp" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="OverviewPage"> + <trans-unit id="_msg384"> + <source xml:space="preserve">Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings->Mask values.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">191</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../forms/psbtoperationsdialog.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="PSBTOperationsDialog"> + <trans-unit id="_msg385"> + <source xml:space="preserve">Dialog</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">14</context></context-group> + </trans-unit> + <trans-unit id="_msg386"> + <source xml:space="preserve">Sign Tx</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">86</context></context-group> + </trans-unit> + <trans-unit id="_msg387"> + <source xml:space="preserve">Broadcast Tx</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">102</context></context-group> + </trans-unit> + <trans-unit id="_msg388"> + <source xml:space="preserve">Copy to Clipboard</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">122</context></context-group> + </trans-unit> + <trans-unit id="_msg389"> + <source xml:space="preserve">Save...</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">129</context></context-group> + </trans-unit> + <trans-unit id="_msg390"> + <source xml:space="preserve">Close</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">136</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../psbtoperationsdialog.cpp" datatype="cpp" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="PSBTOperationsDialog"> + <trans-unit id="_msg391"> + <source xml:space="preserve">Failed to load transaction: %1</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">55</context></context-group> + </trans-unit> + <trans-unit id="_msg392"> + <source xml:space="preserve">Failed to sign transaction: %1</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">73</context></context-group> + </trans-unit> + <trans-unit id="_msg393"> + <source xml:space="preserve">Could not sign any more inputs.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">81</context></context-group> + </trans-unit> + <trans-unit id="_msg394"> + <source xml:space="preserve">Signed %1 inputs, but more signatures are still required.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">83</context></context-group> + </trans-unit> + <trans-unit id="_msg395"> + <source xml:space="preserve">Signed transaction successfully. Transaction is ready to broadcast.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">86</context></context-group> + </trans-unit> + <trans-unit id="_msg396"> + <source xml:space="preserve">Unknown error processing transaction.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">98</context></context-group> + </trans-unit> + <trans-unit id="_msg397"> + <source xml:space="preserve">Transaction broadcast successfully! Transaction ID: %1</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">108</context></context-group> + </trans-unit> + <trans-unit id="_msg398"> + <source xml:space="preserve">Transaction broadcast failed: %1</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">111</context></context-group> + </trans-unit> + <trans-unit id="_msg399"> + <source xml:space="preserve">PSBT copied to clipboard.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">120</context></context-group> + </trans-unit> + <trans-unit id="_msg400"> + <source xml:space="preserve">Save Transaction Data</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">143</context></context-group> + </trans-unit> + <trans-unit id="_msg401"> + <source xml:space="preserve">Partially Signed Transaction (Binary)</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">144</context></context-group> + <context-group><context context-type="x-gettext-msgctxt">Name of binary PSBT file format</context></context-group> + </trans-unit> + <trans-unit id="_msg402"> + <source xml:space="preserve">PSBT saved to disk.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">151</context></context-group> + </trans-unit> + <trans-unit id="_msg403"> + <source xml:space="preserve"> * Sends %1 to %2</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">167</context></context-group> + </trans-unit> + <trans-unit id="_msg404"> + <source xml:space="preserve">Unable to calculate transaction fee or total transaction amount.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">177</context></context-group> + </trans-unit> + <trans-unit id="_msg405"> + <source xml:space="preserve">Pays transaction fee: </source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">179</context></context-group> + </trans-unit> + <trans-unit id="_msg406"> + <source xml:space="preserve">Total Amount</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">191</context></context-group> + </trans-unit> + <trans-unit id="_msg407"> + <source xml:space="preserve">or</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">194</context></context-group> + </trans-unit> + <trans-unit id="_msg408"> + <source xml:space="preserve">Transaction has %1 unsigned inputs.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">200</context></context-group> + </trans-unit> + <trans-unit id="_msg409"> + <source xml:space="preserve">Transaction is missing some information about inputs.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">242</context></context-group> + </trans-unit> + <trans-unit id="_msg410"> + <source xml:space="preserve">Transaction still needs signature(s).</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">246</context></context-group> + </trans-unit> + <trans-unit id="_msg411"> + <source xml:space="preserve">(But this wallet cannot sign transactions.)</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">249</context></context-group> + </trans-unit> + <trans-unit id="_msg412"> + <source xml:space="preserve">(But this wallet does not have the right keys.)</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">252</context></context-group> + </trans-unit> + <trans-unit id="_msg413"> + <source xml:space="preserve">Transaction is fully signed and ready for broadcast.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">260</context></context-group> + </trans-unit> + <trans-unit id="_msg414"> + <source xml:space="preserve">Transaction status is unknown.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">264</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../paymentserver.cpp" datatype="cpp" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="PaymentServer"> + <trans-unit id="_msg415"> + <source xml:space="preserve">Payment request error</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">173</context></context-group> + </trans-unit> + <trans-unit id="_msg416"> + <source xml:space="preserve">Cannot start bitcoin: click-to-pay handler</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">174</context></context-group> + </trans-unit> + <trans-unit id="_msg417"> + <source xml:space="preserve">URI handling</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">224</context></context-group> + <context-group purpose="location"><context context-type="linenumber">237</context></context-group> + <context-group purpose="location"><context context-type="linenumber">243</context></context-group> + <context-group purpose="location"><context context-type="linenumber">250</context></context-group> + </trans-unit> + <trans-unit id="_msg418"> + <source xml:space="preserve">'bitcoin://' is not a valid URI. Use 'bitcoin:' instead.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">224</context></context-group> + </trans-unit> + <trans-unit id="_msg419"> + <source xml:space="preserve">Cannot process payment request because BIP70 is not supported. +Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored. +If you are receiving this error you should request the merchant provide a BIP21 compatible URI.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">238</context></context-group> + <context-group purpose="location"><context context-type="linenumber">261</context></context-group> + </trans-unit> + <trans-unit id="_msg420"> + <source xml:space="preserve">Invalid payment address %1</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">243</context></context-group> + </trans-unit> + <trans-unit id="_msg421"> + <source xml:space="preserve">URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">251</context></context-group> + </trans-unit> + <trans-unit id="_msg422"> + <source xml:space="preserve">Payment request file handling</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">260</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../peertablemodel.h" datatype="c" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="PeerTableModel"> + <trans-unit id="_msg423"> + <source xml:space="preserve">User Agent</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">91</context></context-group> + </trans-unit> + <trans-unit id="_msg424"> + <source xml:space="preserve">Ping</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">91</context></context-group> + </trans-unit> + <trans-unit id="_msg425"> + <source xml:space="preserve">Sent</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">91</context></context-group> + </trans-unit> + <trans-unit id="_msg426"> + <source xml:space="preserve">Received</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">91</context></context-group> + </trans-unit> + <trans-unit id="_msg427"> + <source xml:space="preserve">Peer Id</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">91</context></context-group> + </trans-unit> + <trans-unit id="_msg428"> + <source xml:space="preserve">Address</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">91</context></context-group> + </trans-unit> + <trans-unit id="_msg429"> + <source xml:space="preserve">Type</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">91</context></context-group> + </trans-unit> + <trans-unit id="_msg430"> + <source xml:space="preserve">Network</source> + <target xml:space="preserve" state="needs-review-translation">Network</target> + <context-group purpose="location"><context context-type="linenumber">91</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../bitcoinunits.cpp" datatype="cpp" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="QObject"> + <trans-unit id="_msg431"> + <source xml:space="preserve">Amount</source> + <target xml:space="preserve" state="needs-review-translation">Amount</target> + <context-group purpose="location"><context context-type="linenumber">213</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../guiutil.cpp" datatype="cpp" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="QObject"> + <trans-unit id="_msg432"> + <source xml:space="preserve">Enter a Bitcoin address (e.g. %1)</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">118</context></context-group> + </trans-unit> + <trans-unit id="_msg433"> + <source xml:space="preserve">Unroutable</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">650</context></context-group> + </trans-unit> + <trans-unit id="_msg434"> + <source xml:space="preserve">Internal</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">656</context></context-group> + </trans-unit> + <trans-unit id="_msg435"> + <source xml:space="preserve">Inbound</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">666</context></context-group> + </trans-unit> + <trans-unit id="_msg436"> + <source xml:space="preserve">Outbound</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">666</context></context-group> + </trans-unit> + <trans-unit id="_msg437"> + <source xml:space="preserve">Full Relay</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">670</context></context-group> + </trans-unit> + <trans-unit id="_msg438"> + <source xml:space="preserve">Block Relay</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">671</context></context-group> + </trans-unit> + <trans-unit id="_msg439"> + <source xml:space="preserve">Manual</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">672</context></context-group> + </trans-unit> + <trans-unit id="_msg440"> + <source xml:space="preserve">Feeler</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">673</context></context-group> + </trans-unit> + <trans-unit id="_msg441"> + <source xml:space="preserve">Address Fetch</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">674</context></context-group> + </trans-unit> + <trans-unit id="_msg442"> + <source xml:space="preserve">%1 d</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">688</context></context-group> + </trans-unit> + <trans-unit id="_msg443"> + <source xml:space="preserve">%1 h</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">690</context></context-group> + </trans-unit> + <trans-unit id="_msg444"> + <source xml:space="preserve">%1 m</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">692</context></context-group> + </trans-unit> + <trans-unit id="_msg445"> + <source xml:space="preserve">%1 s</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">694</context></context-group> + <context-group purpose="location"><context context-type="linenumber">722</context></context-group> + </trans-unit> + <trans-unit id="_msg446"> + <source xml:space="preserve">None</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">710</context></context-group> + </trans-unit> + <trans-unit id="_msg447"> + <source xml:space="preserve">N/A</source> + <target xml:space="preserve" state="needs-review-translation">N/A</target> + <context-group purpose="location"><context context-type="linenumber">716</context></context-group> + </trans-unit> + <trans-unit id="_msg448"> + <source xml:space="preserve">%1 ms</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">717</context></context-group> + </trans-unit> + <group restype="x-gettext-plurals"> + <context-group purpose="location"><context context-type="linenumber">735</context></context-group> + <trans-unit id="_msg449[0]" approved="yes"> + <source xml:space="preserve">%n second(s)</source> + <target xml:space="preserve">%n second</target> + </trans-unit> + <trans-unit id="_msg449[1]" approved="yes"> + <source xml:space="preserve">%n second(s)</source> + <target xml:space="preserve">%n seconds</target> + </trans-unit> + </group> + <group restype="x-gettext-plurals"> + <context-group purpose="location"><context context-type="linenumber">739</context></context-group> + <trans-unit id="_msg450[0]" approved="yes"> + <source xml:space="preserve">%n minute(s)</source> + <target xml:space="preserve">%n minute</target> + </trans-unit> + <trans-unit id="_msg450[1]" approved="yes"> + <source xml:space="preserve">%n minute(s)</source> + <target xml:space="preserve">%n minutes</target> + </trans-unit> + </group> + <group restype="x-gettext-plurals"> + <context-group purpose="location"><context context-type="linenumber">743</context></context-group> + <trans-unit id="_msg451[0]"> + <source xml:space="preserve">%n hour(s)</source> + <target xml:space="preserve" state="needs-review-translation">%n hour</target> + </trans-unit> + <trans-unit id="_msg451[1]"> + <source xml:space="preserve">%n hour(s)</source> + <target xml:space="preserve" state="needs-review-translation">%n hours</target> + </trans-unit> + </group> + <group restype="x-gettext-plurals"> + <context-group purpose="location"><context context-type="linenumber">747</context></context-group> + <trans-unit id="_msg452[0]"> + <source xml:space="preserve">%n day(s)</source> + <target xml:space="preserve" state="needs-review-translation">%n day</target> + </trans-unit> + <trans-unit id="_msg452[1]"> + <source xml:space="preserve">%n day(s)</source> + <target xml:space="preserve" state="needs-review-translation">%n days</target> + </trans-unit> + </group> + <group restype="x-gettext-plurals"> + <context-group purpose="location"><context context-type="linenumber">751</context></context-group> + <context-group purpose="location"><context context-type="linenumber">757</context></context-group> + <trans-unit id="_msg453[0]"> + <source xml:space="preserve">%n week(s)</source> + <target xml:space="preserve" state="needs-review-translation">%n week</target> + </trans-unit> + <trans-unit id="_msg453[1]"> + <source xml:space="preserve">%n week(s)</source> + <target xml:space="preserve" state="needs-review-translation">%n weeks</target> + </trans-unit> + </group> + <trans-unit id="_msg454"> + <source xml:space="preserve">%1 and %2</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">757</context></context-group> + </trans-unit> + <group restype="x-gettext-plurals"> + <context-group purpose="location"><context context-type="linenumber">757</context></context-group> + <trans-unit id="_msg455[0]"> + <source xml:space="preserve">%n year(s)</source> + <target xml:space="preserve" state="needs-review-translation">%n year</target> + </trans-unit> + <trans-unit id="_msg455[1]"> + <source xml:space="preserve">%n year(s)</source> + <target xml:space="preserve" state="needs-review-translation">%n years</target> + </trans-unit> + </group> + <trans-unit id="_msg456"> + <source xml:space="preserve">%1 B</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">765</context></context-group> + </trans-unit> + <trans-unit id="_msg457"> + <source xml:space="preserve">%1 kB</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">767</context></context-group> + </trans-unit> + <trans-unit id="_msg458"> + <source xml:space="preserve">%1 MB</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">769</context></context-group> + </trans-unit> + <trans-unit id="_msg459"> + <source xml:space="preserve">%1 GB</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">771</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../qrimagewidget.cpp" datatype="cpp" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="QRImageWidget"> + <trans-unit id="_msg460"> + <source xml:space="preserve">&Save Image...</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">30</context></context-group> + </trans-unit> + <trans-unit id="_msg461"> + <source xml:space="preserve">&Copy Image</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">33</context></context-group> + </trans-unit> + <trans-unit id="_msg462"> + <source xml:space="preserve">Resulting URI too long, try to reduce the text for label / message.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">46</context></context-group> + </trans-unit> + <trans-unit id="_msg463"> + <source xml:space="preserve">Error encoding URI into QR Code.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">53</context></context-group> + </trans-unit> + <trans-unit id="_msg464"> + <source xml:space="preserve">QR code support not available.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">94</context></context-group> + </trans-unit> + <trans-unit id="_msg465"> + <source xml:space="preserve">Save QR Code</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">124</context></context-group> + </trans-unit> + <trans-unit id="_msg466"> + <source xml:space="preserve">PNG Image</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">125</context></context-group> + <context-group><context context-type="x-gettext-msgctxt">Name of PNG file format</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../forms/debugwindow.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="RPCConsole"> + <trans-unit id="_msg467" approved="yes"> + <source xml:space="preserve">N/A</source> + <target xml:space="preserve">N/A</target> + <context-group purpose="location"><context context-type="linenumber">75</context></context-group> + <context-group purpose="location"><context context-type="linenumber">101</context></context-group> + <context-group purpose="location"><context context-type="linenumber">127</context></context-group> + <context-group purpose="location"><context context-type="linenumber">156</context></context-group> + <context-group purpose="location"><context context-type="linenumber">182</context></context-group> + <context-group purpose="location"><context context-type="linenumber">218</context></context-group> + <context-group purpose="location"><context context-type="linenumber">241</context></context-group> + <context-group purpose="location"><context context-type="linenumber">277</context></context-group> + <context-group purpose="location"><context context-type="linenumber">300</context></context-group> + <context-group purpose="location"><context context-type="linenumber">336</context></context-group> + <context-group purpose="location"><context context-type="linenumber">359</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1069</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1095</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1121</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1144</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1167</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1190</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1216</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1242</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1265</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1288</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1311</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1334</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1360</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1386</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1409</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1432</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1455</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1478</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1501</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1527</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1550</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1573</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1599</context></context-group> + <context-group purpose="location"><context context-type="sourcefile">../rpcconsole.h</context><context context-type="linenumber">141</context></context-group> + </trans-unit> + <trans-unit id="_msg468" approved="yes"> + <source xml:space="preserve">Client version</source> + <target xml:space="preserve">Client version</target> + <context-group purpose="location"><context context-type="linenumber">65</context></context-group> + </trans-unit> + <trans-unit id="_msg469" approved="yes"> + <source xml:space="preserve">&Information</source> + <target xml:space="preserve">&Information</target> + <context-group purpose="location"><context context-type="linenumber">43</context></context-group> + </trans-unit> + <trans-unit id="_msg470"> + <source xml:space="preserve">General</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">58</context></context-group> + </trans-unit> + <trans-unit id="_msg471"> + <source xml:space="preserve">Datadir</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">114</context></context-group> + </trans-unit> + <trans-unit id="_msg472"> + <source xml:space="preserve">To specify a non-default location of the data directory use the '%1' option.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">124</context></context-group> + </trans-unit> + <trans-unit id="_msg473"> + <source xml:space="preserve">Blocksdir</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">143</context></context-group> + </trans-unit> + <trans-unit id="_msg474"> + <source xml:space="preserve">To specify a non-default location of the blocks directory use the '%1' option.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">153</context></context-group> + </trans-unit> + <trans-unit id="_msg475" approved="yes"> + <source xml:space="preserve">Startup time</source> + <target xml:space="preserve">Startup time</target> + <context-group purpose="location"><context context-type="linenumber">172</context></context-group> + </trans-unit> + <trans-unit id="_msg476" approved="yes"> + <source xml:space="preserve">Network</source> + <target xml:space="preserve">Network</target> + <context-group purpose="location"><context context-type="linenumber">201</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1111</context></context-group> + </trans-unit> + <trans-unit id="_msg477"> + <source xml:space="preserve">Name</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">208</context></context-group> + </trans-unit> + <trans-unit id="_msg478" approved="yes"> + <source xml:space="preserve">Number of connections</source> + <target xml:space="preserve">Number of connections</target> + <context-group purpose="location"><context context-type="linenumber">231</context></context-group> + </trans-unit> + <trans-unit id="_msg479" approved="yes"> + <source xml:space="preserve">Block chain</source> + <target xml:space="preserve">Block chain</target> + <context-group purpose="location"><context context-type="linenumber">260</context></context-group> + </trans-unit> + <trans-unit id="_msg480"> + <source xml:space="preserve">Memory Pool</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">319</context></context-group> + </trans-unit> + <trans-unit id="_msg481"> + <source xml:space="preserve">Current number of transactions</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">326</context></context-group> + </trans-unit> + <trans-unit id="_msg482"> + <source xml:space="preserve">Memory usage</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">349</context></context-group> + </trans-unit> + <trans-unit id="_msg483"> + <source xml:space="preserve">Wallet: </source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">443</context></context-group> + </trans-unit> + <trans-unit id="_msg484"> + <source xml:space="preserve">(none)</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">454</context></context-group> + </trans-unit> + <trans-unit id="_msg485"> + <source xml:space="preserve">&Reset</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">695</context></context-group> + </trans-unit> + <trans-unit id="_msg486"> + <source xml:space="preserve">Received</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">775</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1468</context></context-group> + </trans-unit> + <trans-unit id="_msg487"> + <source xml:space="preserve">Sent</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">855</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1445</context></context-group> + </trans-unit> + <trans-unit id="_msg488"> + <source xml:space="preserve">&Peers</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">896</context></context-group> + </trans-unit> + <trans-unit id="_msg489"> + <source xml:space="preserve">Banned peers</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">963</context></context-group> + </trans-unit> + <trans-unit id="_msg490"> + <source xml:space="preserve">Select a peer to view detailed information.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1028</context></context-group> + <context-group purpose="location"><context context-type="sourcefile">../rpcconsole.cpp</context><context context-type="linenumber">1104</context></context-group> + </trans-unit> + <trans-unit id="_msg491"> + <source xml:space="preserve">Version</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1134</context></context-group> + </trans-unit> + <trans-unit id="_msg492"> + <source xml:space="preserve">Starting Block</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1255</context></context-group> + </trans-unit> + <trans-unit id="_msg493"> + <source xml:space="preserve">Synced Headers</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1278</context></context-group> + </trans-unit> + <trans-unit id="_msg494"> + <source xml:space="preserve">Synced Blocks</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1301</context></context-group> + </trans-unit> + <trans-unit id="_msg495"> + <source xml:space="preserve">The mapped Autonomous System used for diversifying peer selection.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1586</context></context-group> + </trans-unit> + <trans-unit id="_msg496"> + <source xml:space="preserve">Mapped AS</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1589</context></context-group> + </trans-unit> + <trans-unit id="_msg497"> + <source xml:space="preserve">User Agent</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">88</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1157</context></context-group> + </trans-unit> + <trans-unit id="_msg498"> + <source xml:space="preserve">Node window</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">14</context></context-group> + </trans-unit> + <trans-unit id="_msg499"> + <source xml:space="preserve">Current block height</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">267</context></context-group> + </trans-unit> + <trans-unit id="_msg500"> + <source xml:space="preserve">Open the %1 debug log file from the current data directory. This can take a few seconds for large log files.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">397</context></context-group> + </trans-unit> + <trans-unit id="_msg501"> + <source xml:space="preserve">Decrease font size</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">481</context></context-group> + </trans-unit> + <trans-unit id="_msg502"> + <source xml:space="preserve">Increase font size</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">513</context></context-group> + </trans-unit> + <trans-unit id="_msg503"> + <source xml:space="preserve">Permissions</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1059</context></context-group> + </trans-unit> + <trans-unit id="_msg504"> + <source xml:space="preserve">The direction and type of peer connection: %1</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1082</context></context-group> + </trans-unit> + <trans-unit id="_msg505"> + <source xml:space="preserve">Direction/Type</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1085</context></context-group> + </trans-unit> + <trans-unit id="_msg506"> + <source xml:space="preserve">The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1108</context></context-group> + </trans-unit> + <trans-unit id="_msg507"> + <source xml:space="preserve">Services</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1180</context></context-group> + </trans-unit> + <trans-unit id="_msg508"> + <source xml:space="preserve">Whether the peer requested us to relay transactions.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1203</context></context-group> + </trans-unit> + <trans-unit id="_msg509"> + <source xml:space="preserve">Wants Tx Relay</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1206</context></context-group> + </trans-unit> + <trans-unit id="_msg510"> + <source xml:space="preserve">High bandwidth BIP152 compact block relay: %1</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1229</context></context-group> + </trans-unit> + <trans-unit id="_msg511"> + <source xml:space="preserve">High Bandwidth</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1232</context></context-group> + </trans-unit> + <trans-unit id="_msg512"> + <source xml:space="preserve">Connection Time</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1324</context></context-group> + </trans-unit> + <trans-unit id="_msg513"> + <source xml:space="preserve">Elapsed time since a novel block passing initial validity checks was received from this peer.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1347</context></context-group> + </trans-unit> + <trans-unit id="_msg514"> + <source xml:space="preserve">Last Block</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1350</context></context-group> + </trans-unit> + <trans-unit id="_msg515"> + <source xml:space="preserve">Elapsed time since a novel transaction accepted into our mempool was received from this peer.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1373</context></context-group> + </trans-unit> + <trans-unit id="_msg516"> + <source xml:space="preserve">Last Tx</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1376</context></context-group> + </trans-unit> + <trans-unit id="_msg517"> + <source xml:space="preserve">Last Send</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1399</context></context-group> + </trans-unit> + <trans-unit id="_msg518"> + <source xml:space="preserve">Last Receive</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1422</context></context-group> + </trans-unit> + <trans-unit id="_msg519"> + <source xml:space="preserve">Ping Time</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1491</context></context-group> + </trans-unit> + <trans-unit id="_msg520"> + <source xml:space="preserve">The duration of a currently outstanding ping.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1514</context></context-group> + </trans-unit> + <trans-unit id="_msg521"> + <source xml:space="preserve">Ping Wait</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1517</context></context-group> + </trans-unit> + <trans-unit id="_msg522"> + <source xml:space="preserve">Min Ping</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1540</context></context-group> + </trans-unit> + <trans-unit id="_msg523"> + <source xml:space="preserve">Time Offset</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1563</context></context-group> + </trans-unit> + <trans-unit id="_msg524" approved="yes"> + <source xml:space="preserve">Last block time</source> + <target xml:space="preserve">Last block time</target> + <context-group purpose="location"><context context-type="linenumber">290</context></context-group> + </trans-unit> + <trans-unit id="_msg525" approved="yes"> + <source xml:space="preserve">&Open</source> + <target xml:space="preserve">&Open</target> + <context-group purpose="location"><context context-type="linenumber">400</context></context-group> + </trans-unit> + <trans-unit id="_msg526" approved="yes"> + <source xml:space="preserve">&Console</source> + <target xml:space="preserve">&Console</target> + <context-group purpose="location"><context context-type="linenumber">426</context></context-group> + </trans-unit> + <trans-unit id="_msg527"> + <source xml:space="preserve">&Network Traffic</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">643</context></context-group> + </trans-unit> + <trans-unit id="_msg528"> + <source xml:space="preserve">Totals</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">711</context></context-group> + </trans-unit> + <trans-unit id="_msg529" approved="yes"> + <source xml:space="preserve">Debug log file</source> + <target xml:space="preserve">Debug log file</target> + <context-group purpose="location"><context context-type="linenumber">390</context></context-group> + </trans-unit> + <trans-unit id="_msg530" approved="yes"> + <source xml:space="preserve">Clear console</source> + <target xml:space="preserve">Clear console</target> + <context-group purpose="location"><context context-type="linenumber">545</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../rpcconsole.cpp" datatype="cpp" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="RPCConsole"> + <trans-unit id="_msg531"> + <source xml:space="preserve">In:</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">862</context></context-group> + </trans-unit> + <trans-unit id="_msg532"> + <source xml:space="preserve">Out:</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">863</context></context-group> + </trans-unit> + <trans-unit id="_msg533"> + <source xml:space="preserve">1 &hour</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">621</context></context-group> + </trans-unit> + <trans-unit id="_msg534"> + <source xml:space="preserve">1 &day</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">622</context></context-group> + </trans-unit> + <trans-unit id="_msg535"> + <source xml:space="preserve">1 &week</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">623</context></context-group> + </trans-unit> + <trans-unit id="_msg536"> + <source xml:space="preserve">1 &year</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">624</context></context-group> + </trans-unit> + <trans-unit id="_msg537"> + <source xml:space="preserve">&Disconnect</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">620</context></context-group> + </trans-unit> + <trans-unit id="_msg538"> + <source xml:space="preserve">Inbound: initiated by peer</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">465</context></context-group> + </trans-unit> + <trans-unit id="_msg539"> + <source xml:space="preserve">Outbound Full Relay: default</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">466</context></context-group> + </trans-unit> + <trans-unit id="_msg540"> + <source xml:space="preserve">Outbound Block Relay: does not relay transactions or addresses</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">467</context></context-group> + </trans-unit> + <trans-unit id="_msg541"> + <source xml:space="preserve">Outbound Manual: added using RPC %1 or %2/%3 configuration options</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">468</context></context-group> + </trans-unit> + <trans-unit id="_msg542"> + <source xml:space="preserve">Outbound Feeler: short-lived, for testing addresses</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">472</context></context-group> + </trans-unit> + <trans-unit id="_msg543"> + <source xml:space="preserve">Outbound Address Fetch: short-lived, for soliciting addresses</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">473</context></context-group> + </trans-unit> + <trans-unit id="_msg544"> + <source xml:space="preserve">we selected the peer for high bandwidth relay</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">477</context></context-group> + </trans-unit> + <trans-unit id="_msg545"> + <source xml:space="preserve">the peer selected us for high bandwidth relay</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">478</context></context-group> + </trans-unit> + <trans-unit id="_msg546"> + <source xml:space="preserve">no high bandwidth relay selected</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">479</context></context-group> + </trans-unit> + <trans-unit id="_msg547"> + <source xml:space="preserve">&Unban</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">661</context></context-group> + </trans-unit> + <trans-unit id="_msg548"> + <source xml:space="preserve">Welcome to the %1 RPC console.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">825</context></context-group> + </trans-unit> + <trans-unit id="_msg549"> + <source xml:space="preserve">Use up and down arrows to navigate history, and %1 to clear screen.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">826</context></context-group> + </trans-unit> + <trans-unit id="_msg550"> + <source xml:space="preserve">Type %1 for an overview of available commands.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">827</context></context-group> + </trans-unit> + <trans-unit id="_msg551"> + <source xml:space="preserve">For more information on using this console type %1.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">828</context></context-group> + </trans-unit> + <trans-unit id="_msg552"> + <source xml:space="preserve">WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramifications of a command.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">830</context></context-group> + </trans-unit> + <trans-unit id="_msg553"> + <source xml:space="preserve">Network activity disabled</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">866</context></context-group> + </trans-unit> + <trans-unit id="_msg554"> + <source xml:space="preserve">Executing command without any wallet</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">932</context></context-group> + </trans-unit> + <trans-unit id="_msg555"> + <source xml:space="preserve">(peer id: %1)</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1110</context></context-group> + </trans-unit> + <trans-unit id="_msg556"> + <source xml:space="preserve">Executing command using "%1" wallet</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">930</context></context-group> + </trans-unit> + <trans-unit id="_msg557"> + <source xml:space="preserve">via %1</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1112</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../rpcconsole.h" datatype="c" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="RPCConsole"> + <trans-unit id="_msg558"> + <source xml:space="preserve">Yes</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">140</context></context-group> + </trans-unit> + <trans-unit id="_msg559"> + <source xml:space="preserve">No</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">140</context></context-group> + </trans-unit> + <trans-unit id="_msg560"> + <source xml:space="preserve">To</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">140</context></context-group> + </trans-unit> + <trans-unit id="_msg561"> + <source xml:space="preserve">From</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">140</context></context-group> + </trans-unit> + <trans-unit id="_msg562"> + <source xml:space="preserve">Ban for</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">141</context></context-group> + </trans-unit> + <trans-unit id="_msg563"> + <source xml:space="preserve">Never</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">178</context></context-group> + </trans-unit> + <trans-unit id="_msg564"> + <source xml:space="preserve">Unknown</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">141</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../forms/receivecoinsdialog.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="ReceiveCoinsDialog"> + <trans-unit id="_msg565"> + <source xml:space="preserve">&Amount:</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">37</context></context-group> + </trans-unit> + <trans-unit id="_msg566"> + <source xml:space="preserve">&Label:</source> + <target xml:space="preserve" state="needs-review-translation">&Label:</target> + <context-group purpose="location"><context context-type="linenumber">83</context></context-group> + </trans-unit> + <trans-unit id="_msg567"> + <source xml:space="preserve">&Message:</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">53</context></context-group> + </trans-unit> + <trans-unit id="_msg568"> + <source xml:space="preserve">An optional message to attach to the payment request, which will be displayed when the request is opened. Note: The message will not be sent with the payment over the Bitcoin network.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">50</context></context-group> + </trans-unit> + <trans-unit id="_msg569"> + <source xml:space="preserve">An optional label to associate with the new receiving address.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">80</context></context-group> + </trans-unit> + <trans-unit id="_msg570"> + <source xml:space="preserve">Use this form to request payments. All fields are <b>optional</b>.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">73</context></context-group> + </trans-unit> + <trans-unit id="_msg571"> + <source xml:space="preserve">An optional amount to request. Leave this empty or zero to not request a specific amount.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">34</context></context-group> + <context-group purpose="location"><context context-type="linenumber">193</context></context-group> + </trans-unit> + <trans-unit id="_msg572"> + <source xml:space="preserve">An optional label to associate with the new receiving address (used by you to identify an invoice). It is also attached to the payment request.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">66</context></context-group> + </trans-unit> + <trans-unit id="_msg573"> + <source xml:space="preserve">An optional message that is attached to the payment request and may be displayed to the sender.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">96</context></context-group> + </trans-unit> + <trans-unit id="_msg574"> + <source xml:space="preserve">&Create new receiving address</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">111</context></context-group> + </trans-unit> + <trans-unit id="_msg575"> + <source xml:space="preserve">Clear all fields of the form.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">134</context></context-group> + </trans-unit> + <trans-unit id="_msg576"> + <source xml:space="preserve">Clear</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">137</context></context-group> + </trans-unit> + <trans-unit id="_msg577"> + <source xml:space="preserve">Native segwit addresses (aka Bech32 or BIP-173) reduce your transaction fees later on and offer better protection against typos, but old wallets don't support them. When unchecked, an address compatible with older wallets will be created instead.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">215</context></context-group> + </trans-unit> + <trans-unit id="_msg578"> + <source xml:space="preserve">Generate native segwit (Bech32) address</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">218</context></context-group> + </trans-unit> + <trans-unit id="_msg579"> + <source xml:space="preserve">Requested payments history</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">279</context></context-group> + </trans-unit> + <trans-unit id="_msg580"> + <source xml:space="preserve">Show the selected request (does the same as double clicking an entry)</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">304</context></context-group> + </trans-unit> + <trans-unit id="_msg581"> + <source xml:space="preserve">Show</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">307</context></context-group> + </trans-unit> + <trans-unit id="_msg582"> + <source xml:space="preserve">Remove the selected entries from the list</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">324</context></context-group> + </trans-unit> + <trans-unit id="_msg583"> + <source xml:space="preserve">Remove</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">327</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../receivecoinsdialog.cpp" datatype="cpp" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="ReceiveCoinsDialog"> + <trans-unit id="_msg584"> + <source xml:space="preserve">Copy URI</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">46</context></context-group> + </trans-unit> + <trans-unit id="_msg585"> + <source xml:space="preserve">Copy address</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">47</context></context-group> + </trans-unit> + <trans-unit id="_msg586"> + <source xml:space="preserve">Copy label</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">48</context></context-group> + </trans-unit> + <trans-unit id="_msg587"> + <source xml:space="preserve">Copy message</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">49</context></context-group> + </trans-unit> + <trans-unit id="_msg588"> + <source xml:space="preserve">Copy amount</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">50</context></context-group> + </trans-unit> + <trans-unit id="_msg589"> + <source xml:space="preserve">Could not unlock wallet.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">190</context></context-group> + </trans-unit> + <trans-unit id="_msg590"> + <source xml:space="preserve">Could not generate new %1 address</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">195</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../forms/receiverequestdialog.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="ReceiveRequestDialog"> + <trans-unit id="_msg591"> + <source xml:space="preserve">Request payment to ...</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">14</context></context-group> + </trans-unit> + <trans-unit id="_msg592"> + <source xml:space="preserve">Address:</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">90</context></context-group> + </trans-unit> + <trans-unit id="_msg593"> + <source xml:space="preserve">Amount:</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">119</context></context-group> + </trans-unit> + <trans-unit id="_msg594"> + <source xml:space="preserve">Label:</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">148</context></context-group> + </trans-unit> + <trans-unit id="_msg595"> + <source xml:space="preserve">Message:</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">180</context></context-group> + </trans-unit> + <trans-unit id="_msg596"> + <source xml:space="preserve">Wallet:</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">212</context></context-group> + </trans-unit> + <trans-unit id="_msg597"> + <source xml:space="preserve">Copy &URI</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">240</context></context-group> + </trans-unit> + <trans-unit id="_msg598"> + <source xml:space="preserve">Copy &Address</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">250</context></context-group> + </trans-unit> + <trans-unit id="_msg599"> + <source xml:space="preserve">&Save Image...</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">260</context></context-group> + </trans-unit> + <trans-unit id="_msg600"> + <source xml:space="preserve">Payment information</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">39</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../receiverequestdialog.cpp" datatype="cpp" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="ReceiveRequestDialog"> + <trans-unit id="_msg601"> + <source xml:space="preserve">Request payment to %1</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">49</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../recentrequeststablemodel.cpp" datatype="cpp" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="RecentRequestsTableModel"> + <trans-unit id="_msg602"> + <source xml:space="preserve">Date</source> + <target xml:space="preserve" state="needs-review-translation">Date</target> + <context-group purpose="location"><context context-type="linenumber">27</context></context-group> + </trans-unit> + <trans-unit id="_msg603"> + <source xml:space="preserve">Label</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">27</context></context-group> + </trans-unit> + <trans-unit id="_msg604"> + <source xml:space="preserve">Message</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">27</context></context-group> + </trans-unit> + <trans-unit id="_msg605"> + <source xml:space="preserve">(no label)</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">68</context></context-group> + </trans-unit> + <trans-unit id="_msg606"> + <source xml:space="preserve">(no message)</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">77</context></context-group> + </trans-unit> + <trans-unit id="_msg607"> + <source xml:space="preserve">(no amount requested)</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">85</context></context-group> + </trans-unit> + <trans-unit id="_msg608"> + <source xml:space="preserve">Requested</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">127</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../forms/sendcoinsdialog.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="SendCoinsDialog"> + <trans-unit id="_msg609" approved="yes"> + <source xml:space="preserve">Send Coins</source> + <target xml:space="preserve">Send Coins</target> + <context-group purpose="location"><context context-type="linenumber">14</context></context-group> + <context-group purpose="location"><context context-type="sourcefile">../sendcoinsdialog.cpp</context><context context-type="linenumber">673</context></context-group> + </trans-unit> + <trans-unit id="_msg610"> + <source xml:space="preserve">Coin Control Features</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">90</context></context-group> + </trans-unit> + <trans-unit id="_msg611"> + <source xml:space="preserve">Inputs...</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">110</context></context-group> + </trans-unit> + <trans-unit id="_msg612"> + <source xml:space="preserve">automatically selected</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">120</context></context-group> + </trans-unit> + <trans-unit id="_msg613"> + <source xml:space="preserve">Insufficient funds!</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">139</context></context-group> + </trans-unit> + <trans-unit id="_msg614"> + <source xml:space="preserve">Quantity:</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">228</context></context-group> + </trans-unit> + <trans-unit id="_msg615"> + <source xml:space="preserve">Bytes:</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">263</context></context-group> + </trans-unit> + <trans-unit id="_msg616"> + <source xml:space="preserve">Amount:</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">311</context></context-group> + </trans-unit> + <trans-unit id="_msg617"> + <source xml:space="preserve">Fee:</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">391</context></context-group> + </trans-unit> + <trans-unit id="_msg618"> + <source xml:space="preserve">After Fee:</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">442</context></context-group> + </trans-unit> + <trans-unit id="_msg619"> + <source xml:space="preserve">Change:</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">474</context></context-group> + </trans-unit> + <trans-unit id="_msg620"> + <source xml:space="preserve">If this is activated, but the change address is empty or invalid, change will be sent to a newly generated address.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">518</context></context-group> + </trans-unit> + <trans-unit id="_msg621"> + <source xml:space="preserve">Custom change address</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">521</context></context-group> + </trans-unit> + <trans-unit id="_msg622"> + <source xml:space="preserve">Transaction Fee:</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">727</context></context-group> + </trans-unit> + <trans-unit id="_msg623"> + <source xml:space="preserve">Choose...</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">741</context></context-group> + </trans-unit> + <trans-unit id="_msg624"> + <source xml:space="preserve">Using the fallbackfee can result in sending a transaction that will take several hours or days (or never) to confirm. Consider choosing your fee manually or wait until you have validated the complete chain.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">765</context></context-group> + </trans-unit> + <trans-unit id="_msg625"> + <source xml:space="preserve">Warning: Fee estimation is currently not possible.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">774</context></context-group> + </trans-unit> + <trans-unit id="_msg626"> + <source xml:space="preserve">Specify a custom fee per kB (1,000 bytes) of the transaction's virtual size. + +Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis per kB" for a transaction size of 500 bytes (half of 1 kB) would ultimately yield a fee of only 50 satoshis.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">851</context></context-group> + </trans-unit> + <trans-unit id="_msg627"> + <source xml:space="preserve">per kilobyte</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">856</context></context-group> + </trans-unit> + <trans-unit id="_msg628"> + <source xml:space="preserve">Hide</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">803</context></context-group> + </trans-unit> + <trans-unit id="_msg629"> + <source xml:space="preserve">Recommended:</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">915</context></context-group> + </trans-unit> + <trans-unit id="_msg630"> + <source xml:space="preserve">Custom:</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">945</context></context-group> + </trans-unit> + <trans-unit id="_msg631"> + <source xml:space="preserve">(Smart fee not initialized yet. This usually takes a few blocks...)</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">994</context></context-group> + </trans-unit> + <trans-unit id="_msg632" approved="yes"> + <source xml:space="preserve">Send to multiple recipients at once</source> + <target xml:space="preserve">Send to multiple recipients at once</target> + <context-group purpose="location"><context context-type="linenumber">1160</context></context-group> + </trans-unit> + <trans-unit id="_msg633" approved="yes"> + <source xml:space="preserve">Add &Recipient</source> + <target xml:space="preserve">Add &Recipient</target> + <context-group purpose="location"><context context-type="linenumber">1163</context></context-group> + </trans-unit> + <trans-unit id="_msg634"> + <source xml:space="preserve">Clear all fields of the form.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1143</context></context-group> + </trans-unit> + <trans-unit id="_msg635"> + <source xml:space="preserve">Dust:</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">343</context></context-group> + </trans-unit> + <trans-unit id="_msg636"> + <source xml:space="preserve">Hide transaction fee settings</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">800</context></context-group> + </trans-unit> + <trans-unit id="_msg637"> + <source xml:space="preserve">When there is less transaction volume than space in the blocks, miners as well as relaying nodes may enforce a minimum fee. Paying only this minimum fee is just fine, but be aware that this can result in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">886</context></context-group> + </trans-unit> + <trans-unit id="_msg638"> + <source xml:space="preserve">A too low fee might result in a never confirming transaction (read the tooltip)</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">889</context></context-group> + </trans-unit> + <trans-unit id="_msg639"> + <source xml:space="preserve">Confirmation time target:</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1020</context></context-group> + </trans-unit> + <trans-unit id="_msg640"> + <source xml:space="preserve">Enable Replace-By-Fee</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1078</context></context-group> + </trans-unit> + <trans-unit id="_msg641"> + <source xml:space="preserve">With Replace-By-Fee (BIP-125) you can increase a transaction's fee after it is sent. Without this, a higher fee may be recommended to compensate for increased transaction delay risk.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1081</context></context-group> + </trans-unit> + <trans-unit id="_msg642" approved="yes"> + <source xml:space="preserve">Clear &All</source> + <target xml:space="preserve">Clear &All</target> + <context-group purpose="location"><context context-type="linenumber">1146</context></context-group> + </trans-unit> + <trans-unit id="_msg643" approved="yes"> + <source xml:space="preserve">Balance:</source> + <target xml:space="preserve">Balance:</target> + <context-group purpose="location"><context context-type="linenumber">1201</context></context-group> + </trans-unit> + <trans-unit id="_msg644" approved="yes"> + <source xml:space="preserve">Confirm the send action</source> + <target xml:space="preserve">Confirm the send action</target> + <context-group purpose="location"><context context-type="linenumber">1117</context></context-group> + </trans-unit> + <trans-unit id="_msg645" approved="yes"> + <source xml:space="preserve">S&end</source> + <target xml:space="preserve">S&end</target> + <context-group purpose="location"><context context-type="linenumber">1120</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../sendcoinsdialog.cpp" datatype="cpp" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="SendCoinsDialog"> + <trans-unit id="_msg646"> + <source xml:space="preserve">Copy quantity</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">92</context></context-group> + </trans-unit> + <trans-unit id="_msg647"> + <source xml:space="preserve">Copy amount</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">93</context></context-group> + </trans-unit> + <trans-unit id="_msg648"> + <source xml:space="preserve">Copy fee</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">94</context></context-group> + </trans-unit> + <trans-unit id="_msg649"> + <source xml:space="preserve">Copy after fee</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">95</context></context-group> + </trans-unit> + <trans-unit id="_msg650"> + <source xml:space="preserve">Copy bytes</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">96</context></context-group> + </trans-unit> + <trans-unit id="_msg651"> + <source xml:space="preserve">Copy dust</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">97</context></context-group> + </trans-unit> + <trans-unit id="_msg652"> + <source xml:space="preserve">Copy change</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">98</context></context-group> + </trans-unit> + <trans-unit id="_msg653"> + <source xml:space="preserve">%1 (%2 blocks)</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">174</context></context-group> + </trans-unit> + <trans-unit id="_msg654"> + <source xml:space="preserve">Cr&eate Unsigned</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">203</context></context-group> + </trans-unit> + <trans-unit id="_msg655"> + <source xml:space="preserve">Creates a Partially Signed Bitcoin Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">204</context></context-group> + </trans-unit> + <trans-unit id="_msg656"> + <source xml:space="preserve"> from wallet '%1'</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">294</context></context-group> + </trans-unit> + <trans-unit id="_msg657"> + <source xml:space="preserve">%1 to '%2'</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">305</context></context-group> + </trans-unit> + <trans-unit id="_msg658"> + <source xml:space="preserve">%1 to %2</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">310</context></context-group> + </trans-unit> + <trans-unit id="_msg659"> + <source xml:space="preserve">Do you want to draft this transaction?</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">317</context></context-group> + </trans-unit> + <trans-unit id="_msg660"> + <source xml:space="preserve">Are you sure you want to send?</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">319</context></context-group> + </trans-unit> + <trans-unit id="_msg661"> + <source xml:space="preserve">Create Unsigned</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">390</context></context-group> + </trans-unit> + <trans-unit id="_msg662"> + <source xml:space="preserve">Save Transaction Data</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">434</context></context-group> + </trans-unit> + <trans-unit id="_msg663"> + <source xml:space="preserve">PSBT saved</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">442</context></context-group> + </trans-unit> + <trans-unit id="_msg664"> + <source xml:space="preserve">or</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">367</context></context-group> + </trans-unit> + <trans-unit id="_msg665"> + <source xml:space="preserve">You can increase the fee later (signals Replace-By-Fee, BIP-125).</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">348</context></context-group> + </trans-unit> + <trans-unit id="_msg666"> + <source xml:space="preserve">Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">324</context></context-group> + </trans-unit> + <trans-unit id="_msg667"> + <source xml:space="preserve">Please, review your transaction.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">326</context></context-group> + </trans-unit> + <trans-unit id="_msg668"> + <source xml:space="preserve">Transaction fee</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">334</context></context-group> + </trans-unit> + <trans-unit id="_msg669"> + <source xml:space="preserve">Not signalling Replace-By-Fee, BIP-125.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">350</context></context-group> + </trans-unit> + <trans-unit id="_msg670"> + <source xml:space="preserve">Total Amount</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">364</context></context-group> + </trans-unit> + <trans-unit id="_msg671"> + <source xml:space="preserve">To review recipient list click "Show Details..."</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">371</context></context-group> + </trans-unit> + <trans-unit id="_msg672"> + <source xml:space="preserve">Confirm send coins</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">389</context></context-group> + </trans-unit> + <trans-unit id="_msg673"> + <source xml:space="preserve">Confirm transaction proposal</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">389</context></context-group> + </trans-unit> + <trans-unit id="_msg674"> + <source xml:space="preserve">Send</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">390</context></context-group> + </trans-unit> + <trans-unit id="_msg675"> + <source xml:space="preserve">Partially Signed Transaction (Binary)</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">435</context></context-group> + <context-group><context context-type="x-gettext-msgctxt">Name of binary PSBT file format</context></context-group> + </trans-unit> + <trans-unit id="_msg676"> + <source xml:space="preserve">Watch-only balance:</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">618</context></context-group> + </trans-unit> + <trans-unit id="_msg677"> + <source xml:space="preserve">The recipient address is not valid. Please recheck.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">642</context></context-group> + </trans-unit> + <trans-unit id="_msg678"> + <source xml:space="preserve">The amount to pay must be larger than 0.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">645</context></context-group> + </trans-unit> + <trans-unit id="_msg679"> + <source xml:space="preserve">The amount exceeds your balance.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">648</context></context-group> + </trans-unit> + <trans-unit id="_msg680"> + <source xml:space="preserve">The total exceeds your balance when the %1 transaction fee is included.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">651</context></context-group> + </trans-unit> + <trans-unit id="_msg681"> + <source xml:space="preserve">Duplicate address found: addresses should only be used once each.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">654</context></context-group> + </trans-unit> + <trans-unit id="_msg682"> + <source xml:space="preserve">Transaction creation failed!</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">657</context></context-group> + </trans-unit> + <trans-unit id="_msg683"> + <source xml:space="preserve">A fee higher than %1 is considered an absurdly high fee.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">661</context></context-group> + </trans-unit> + <trans-unit id="_msg684"> + <source xml:space="preserve">Payment request expired.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">664</context></context-group> + </trans-unit> + <group restype="x-gettext-plurals"> + <context-group purpose="location"><context context-type="linenumber">788</context></context-group> + <trans-unit id="_msg685[0]" approved="yes"> + <source xml:space="preserve">Estimated to begin confirmation within %n block(s).</source> + <target xml:space="preserve">Estimated to begin confirmation within %n block.</target> + </trans-unit> + <trans-unit id="_msg685[1]" approved="yes"> + <source xml:space="preserve">Estimated to begin confirmation within %n block(s).</source> + <target xml:space="preserve">Estimated to begin confirmation within %n blocks.</target> + </trans-unit> + </group> + <trans-unit id="_msg686"> + <source xml:space="preserve">Warning: Invalid Bitcoin address</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">888</context></context-group> + </trans-unit> + <trans-unit id="_msg687"> + <source xml:space="preserve">Warning: Unknown change address</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">893</context></context-group> + </trans-unit> + <trans-unit id="_msg688"> + <source xml:space="preserve">Confirm custom change address</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">896</context></context-group> + </trans-unit> + <trans-unit id="_msg689"> + <source xml:space="preserve">The address you selected for change is not part of this wallet. Any or all funds in your wallet may be sent to this address. Are you sure?</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">896</context></context-group> + </trans-unit> + <trans-unit id="_msg690"> + <source xml:space="preserve">(no label)</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">917</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../forms/sendcoinsentry.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="SendCoinsEntry"> + <trans-unit id="_msg691" approved="yes"> + <source xml:space="preserve">A&mount:</source> + <target xml:space="preserve">A&mount:</target> + <context-group purpose="location"><context context-type="linenumber">155</context></context-group> + <context-group purpose="location"><context context-type="linenumber">705</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1238</context></context-group> + </trans-unit> + <trans-unit id="_msg692" approved="yes"> + <source xml:space="preserve">Pay &To:</source> + <target xml:space="preserve">Pay &To:</target> + <context-group purpose="location"><context context-type="linenumber">39</context></context-group> + </trans-unit> + <trans-unit id="_msg693" approved="yes"> + <source xml:space="preserve">&Label:</source> + <target xml:space="preserve">&Label:</target> + <context-group purpose="location"><context context-type="linenumber">132</context></context-group> + </trans-unit> + <trans-unit id="_msg694"> + <source xml:space="preserve">Choose previously used address</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">64</context></context-group> + </trans-unit> + <trans-unit id="_msg695"> + <source xml:space="preserve">The Bitcoin address to send the payment to</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">57</context></context-group> + </trans-unit> + <trans-unit id="_msg696" approved="yes"> + <source xml:space="preserve">Alt+A</source> + <target xml:space="preserve">Alt+A</target> + <context-group purpose="location"><context context-type="linenumber">80</context></context-group> + </trans-unit> + <trans-unit id="_msg697" approved="yes"> + <source xml:space="preserve">Paste address from clipboard</source> + <target xml:space="preserve">Paste address from clipboard</target> + <context-group purpose="location"><context context-type="linenumber">87</context></context-group> + </trans-unit> + <trans-unit id="_msg698" approved="yes"> + <source xml:space="preserve">Alt+P</source> + <target xml:space="preserve">Alt+P</target> + <context-group purpose="location"><context context-type="linenumber">103</context></context-group> + </trans-unit> + <trans-unit id="_msg699"> + <source xml:space="preserve">Remove this entry</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">110</context></context-group> + <context-group purpose="location"><context context-type="linenumber">672</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1205</context></context-group> + </trans-unit> + <trans-unit id="_msg700"> + <source xml:space="preserve">The amount to send in the selected unit</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">170</context></context-group> + </trans-unit> + <trans-unit id="_msg701"> + <source xml:space="preserve">The fee will be deducted from the amount being sent. The recipient will receive less bitcoins than you enter in the amount field. If multiple recipients are selected, the fee is split equally.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">177</context></context-group> + </trans-unit> + <trans-unit id="_msg702"> + <source xml:space="preserve">S&ubtract fee from amount</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">180</context></context-group> + </trans-unit> + <trans-unit id="_msg703"> + <source xml:space="preserve">Use available balance</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">187</context></context-group> + </trans-unit> + <trans-unit id="_msg704"> + <source xml:space="preserve">Message:</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">196</context></context-group> + </trans-unit> + <trans-unit id="_msg705"> + <source xml:space="preserve">This is an unauthenticated payment request.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">639</context></context-group> + </trans-unit> + <trans-unit id="_msg706"> + <source xml:space="preserve">This is an authenticated payment request.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1168</context></context-group> + </trans-unit> + <trans-unit id="_msg707"> + <source xml:space="preserve">Enter a label for this address to add it to the list of used addresses</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">145</context></context-group> + <context-group purpose="location"><context context-type="linenumber">148</context></context-group> + </trans-unit> + <trans-unit id="_msg708"> + <source xml:space="preserve">A message that was attached to the bitcoin: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Bitcoin network.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">206</context></context-group> + </trans-unit> + <trans-unit id="_msg709"> + <source xml:space="preserve">Pay To:</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">654</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1183</context></context-group> + </trans-unit> + <trans-unit id="_msg710"> + <source xml:space="preserve">Memo:</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">688</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1221</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../forms/signverifymessagedialog.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="SignVerifyMessageDialog"> + <trans-unit id="_msg711" approved="yes"> + <source xml:space="preserve">Signatures - Sign / Verify a Message</source> + <target xml:space="preserve">Signatures - Sign / Verify a Message</target> + <context-group purpose="location"><context context-type="linenumber">14</context></context-group> + </trans-unit> + <trans-unit id="_msg712" approved="yes"> + <source xml:space="preserve">&Sign Message</source> + <target xml:space="preserve">&Sign Message</target> + <context-group purpose="location"><context context-type="linenumber">27</context></context-group> + </trans-unit> + <trans-unit id="_msg713"> + <source xml:space="preserve">You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">33</context></context-group> + </trans-unit> + <trans-unit id="_msg714"> + <source xml:space="preserve">The Bitcoin address to sign the message with</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">51</context></context-group> + </trans-unit> + <trans-unit id="_msg715"> + <source xml:space="preserve">Choose previously used address</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">58</context></context-group> + <context-group purpose="location"><context context-type="linenumber">274</context></context-group> + </trans-unit> + <trans-unit id="_msg716" approved="yes"> + <source xml:space="preserve">Alt+A</source> + <target xml:space="preserve">Alt+A</target> + <context-group purpose="location"><context context-type="linenumber">68</context></context-group> + <context-group purpose="location"><context context-type="linenumber">284</context></context-group> + </trans-unit> + <trans-unit id="_msg717" approved="yes"> + <source xml:space="preserve">Paste address from clipboard</source> + <target xml:space="preserve">Paste address from clipboard</target> + <context-group purpose="location"><context context-type="linenumber">78</context></context-group> + </trans-unit> + <trans-unit id="_msg718" approved="yes"> + <source xml:space="preserve">Alt+P</source> + <target xml:space="preserve">Alt+P</target> + <context-group purpose="location"><context context-type="linenumber">88</context></context-group> + </trans-unit> + <trans-unit id="_msg719" approved="yes"> + <source xml:space="preserve">Enter the message you want to sign here</source> + <target xml:space="preserve">Enter the message you want to sign here</target> + <context-group purpose="location"><context context-type="linenumber">100</context></context-group> + <context-group purpose="location"><context context-type="linenumber">103</context></context-group> + </trans-unit> + <trans-unit id="_msg720" approved="yes"> + <source xml:space="preserve">Signature</source> + <target xml:space="preserve">Signature</target> + <context-group purpose="location"><context context-type="linenumber">110</context></context-group> + </trans-unit> + <trans-unit id="_msg721" approved="yes"> + <source xml:space="preserve">Copy the current signature to the system clipboard</source> + <target xml:space="preserve">Copy the current signature to the system clipboard</target> + <context-group purpose="location"><context context-type="linenumber">140</context></context-group> + </trans-unit> + <trans-unit id="_msg722" approved="yes"> + <source xml:space="preserve">Sign the message to prove you own this Bitcoin address</source> + <target xml:space="preserve">Sign the message to prove you own this Bitcoin address</target> + <context-group purpose="location"><context context-type="linenumber">161</context></context-group> + </trans-unit> + <trans-unit id="_msg723" approved="yes"> + <source xml:space="preserve">Sign &Message</source> + <target xml:space="preserve">Sign &Message</target> + <context-group purpose="location"><context context-type="linenumber">164</context></context-group> + </trans-unit> + <trans-unit id="_msg724" approved="yes"> + <source xml:space="preserve">Reset all sign message fields</source> + <target xml:space="preserve">Reset all sign message fields</target> + <context-group purpose="location"><context context-type="linenumber">178</context></context-group> + </trans-unit> + <trans-unit id="_msg725" approved="yes"> + <source xml:space="preserve">Clear &All</source> + <target xml:space="preserve">Clear &All</target> + <context-group purpose="location"><context context-type="linenumber">181</context></context-group> + <context-group purpose="location"><context context-type="linenumber">338</context></context-group> + </trans-unit> + <trans-unit id="_msg726" approved="yes"> + <source xml:space="preserve">&Verify Message</source> + <target xml:space="preserve">&Verify Message</target> + <context-group purpose="location"><context context-type="linenumber">240</context></context-group> + </trans-unit> + <trans-unit id="_msg727"> + <source xml:space="preserve">Enter the receiver's address, message (ensure you copy line breaks, spaces, tabs, etc. exactly) and signature below to verify the message. Be careful not to read more into the signature than what is in the signed message itself, to avoid being tricked by a man-in-the-middle attack. Note that this only proves the signing party receives with the address, it cannot prove sendership of any transaction!</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">246</context></context-group> + </trans-unit> + <trans-unit id="_msg728"> + <source xml:space="preserve">The Bitcoin address the message was signed with</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">267</context></context-group> + </trans-unit> + <trans-unit id="_msg729"> + <source xml:space="preserve">The signed message to verify</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">296</context></context-group> + <context-group purpose="location"><context context-type="linenumber">299</context></context-group> + </trans-unit> + <trans-unit id="_msg730"> + <source xml:space="preserve">The signature given when the message was signed</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">306</context></context-group> + <context-group purpose="location"><context context-type="linenumber">309</context></context-group> + </trans-unit> + <trans-unit id="_msg731" approved="yes"> + <source xml:space="preserve">Verify the message to ensure it was signed with the specified Bitcoin address</source> + <target xml:space="preserve">Verify the message to ensure it was signed with the specified Bitcoin address</target> + <context-group purpose="location"><context context-type="linenumber">318</context></context-group> + </trans-unit> + <trans-unit id="_msg732" approved="yes"> + <source xml:space="preserve">Verify &Message</source> + <target xml:space="preserve">Verify &Message</target> + <context-group purpose="location"><context context-type="linenumber">321</context></context-group> + </trans-unit> + <trans-unit id="_msg733" approved="yes"> + <source xml:space="preserve">Reset all verify message fields</source> + <target xml:space="preserve">Reset all verify message fields</target> + <context-group purpose="location"><context context-type="linenumber">335</context></context-group> + </trans-unit> + <trans-unit id="_msg734"> + <source xml:space="preserve">Click "Sign Message" to generate signature</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">125</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../signverifymessagedialog.cpp" datatype="cpp" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="SignVerifyMessageDialog"> + <trans-unit id="_msg735"> + <source xml:space="preserve">The entered address is invalid.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">120</context></context-group> + <context-group purpose="location"><context context-type="linenumber">219</context></context-group> + </trans-unit> + <trans-unit id="_msg736"> + <source xml:space="preserve">Please check the address and try again.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">120</context></context-group> + <context-group purpose="location"><context context-type="linenumber">127</context></context-group> + <context-group purpose="location"><context context-type="linenumber">220</context></context-group> + <context-group purpose="location"><context context-type="linenumber">227</context></context-group> + </trans-unit> + <trans-unit id="_msg737"> + <source xml:space="preserve">The entered address does not refer to a key.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">127</context></context-group> + <context-group purpose="location"><context context-type="linenumber">226</context></context-group> + </trans-unit> + <trans-unit id="_msg738"> + <source xml:space="preserve">Wallet unlock was cancelled.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">135</context></context-group> + </trans-unit> + <trans-unit id="_msg739"> + <source xml:space="preserve">No error</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">146</context></context-group> + </trans-unit> + <trans-unit id="_msg740"> + <source xml:space="preserve">Private key for the entered address is not available.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">149</context></context-group> + </trans-unit> + <trans-unit id="_msg741"> + <source xml:space="preserve">Message signing failed.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">152</context></context-group> + </trans-unit> + <trans-unit id="_msg742"> + <source xml:space="preserve">Message signed.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">164</context></context-group> + </trans-unit> + <trans-unit id="_msg743"> + <source xml:space="preserve">The signature could not be decoded.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">233</context></context-group> + </trans-unit> + <trans-unit id="_msg744"> + <source xml:space="preserve">Please check the signature and try again.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">234</context></context-group> + <context-group purpose="location"><context context-type="linenumber">241</context></context-group> + </trans-unit> + <trans-unit id="_msg745"> + <source xml:space="preserve">The signature did not match the message digest.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">240</context></context-group> + </trans-unit> + <trans-unit id="_msg746"> + <source xml:space="preserve">Message verification failed.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">246</context></context-group> + </trans-unit> + <trans-unit id="_msg747"> + <source xml:space="preserve">Message verified.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">214</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../trafficgraphwidget.cpp" datatype="cpp" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="TrafficGraphWidget"> + <trans-unit id="_msg748"> + <source xml:space="preserve">kB/s</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">82</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../transactiondesc.cpp" datatype="cpp" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="TransactionDesc"> + <group restype="x-gettext-plurals"> + <context-group purpose="location"><context context-type="linenumber">34</context></context-group> + <trans-unit id="_msg749[0]" approved="yes"> + <source xml:space="preserve">Open for %n more block(s)</source> + <target xml:space="preserve">Open for %n more block</target> + </trans-unit> + <trans-unit id="_msg749[1]" approved="yes"> + <source xml:space="preserve">Open for %n more block(s)</source> + <target xml:space="preserve">Open for %n more blocks</target> + </trans-unit> + </group> + <trans-unit id="_msg750"> + <source xml:space="preserve">Open until %1</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">36</context></context-group> + </trans-unit> + <trans-unit id="_msg751"> + <source xml:space="preserve">conflicted with a transaction with %1 confirmations</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">42</context></context-group> + </trans-unit> + <trans-unit id="_msg752"> + <source xml:space="preserve">0/unconfirmed, %1</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">44</context></context-group> + </trans-unit> + <trans-unit id="_msg753"> + <source xml:space="preserve">in memory pool</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">44</context></context-group> + </trans-unit> + <trans-unit id="_msg754"> + <source xml:space="preserve">not in memory pool</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">44</context></context-group> + </trans-unit> + <trans-unit id="_msg755"> + <source xml:space="preserve">abandoned</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">44</context></context-group> + </trans-unit> + <trans-unit id="_msg756"> + <source xml:space="preserve">%1/unconfirmed</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">46</context></context-group> + </trans-unit> + <trans-unit id="_msg757"> + <source xml:space="preserve">%1 confirmations</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">48</context></context-group> + </trans-unit> + <trans-unit id="_msg758"> + <source xml:space="preserve">Status</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">98</context></context-group> + </trans-unit> + <trans-unit id="_msg759"> + <source xml:space="preserve">Date</source> + <target xml:space="preserve" state="needs-review-translation">Date</target> + <context-group purpose="location"><context context-type="linenumber">101</context></context-group> + </trans-unit> + <trans-unit id="_msg760"> + <source xml:space="preserve">Source</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">108</context></context-group> + </trans-unit> + <trans-unit id="_msg761"> + <source xml:space="preserve">Generated</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">108</context></context-group> + </trans-unit> + <trans-unit id="_msg762"> + <source xml:space="preserve">From</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">113</context></context-group> + <context-group purpose="location"><context context-type="linenumber">127</context></context-group> + <context-group purpose="location"><context context-type="linenumber">199</context></context-group> + </trans-unit> + <trans-unit id="_msg763"> + <source xml:space="preserve">unknown</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">127</context></context-group> + </trans-unit> + <trans-unit id="_msg764"> + <source xml:space="preserve">To</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">128</context></context-group> + <context-group purpose="location"><context context-type="linenumber">148</context></context-group> + <context-group purpose="location"><context context-type="linenumber">218</context></context-group> + </trans-unit> + <trans-unit id="_msg765"> + <source xml:space="preserve">own address</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">130</context></context-group> + </trans-unit> + <trans-unit id="_msg766"> + <source xml:space="preserve">watch-only</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">130</context></context-group> + <context-group purpose="location"><context context-type="linenumber">199</context></context-group> + </trans-unit> + <trans-unit id="_msg767"> + <source xml:space="preserve">label</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">132</context></context-group> + </trans-unit> + <trans-unit id="_msg768"> + <source xml:space="preserve">Credit</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">168</context></context-group> + <context-group purpose="location"><context context-type="linenumber">180</context></context-group> + <context-group purpose="location"><context context-type="linenumber">234</context></context-group> + <context-group purpose="location"><context context-type="linenumber">264</context></context-group> + <context-group purpose="location"><context context-type="linenumber">324</context></context-group> + </trans-unit> + <group restype="x-gettext-plurals"> + <context-group purpose="location"><context context-type="linenumber">170</context></context-group> + <trans-unit id="_msg769[0]" approved="yes"> + <source xml:space="preserve">matures in %n more block(s)</source> + <target xml:space="preserve">matures in %n more block</target> + </trans-unit> + <trans-unit id="_msg769[1]" approved="yes"> + <source xml:space="preserve">matures in %n more block(s)</source> + <target xml:space="preserve">matures in %n more blocks</target> + </trans-unit> + </group> + <trans-unit id="_msg770"> + <source xml:space="preserve">not accepted</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">172</context></context-group> + </trans-unit> + <trans-unit id="_msg771"> + <source xml:space="preserve">Debit</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">232</context></context-group> + <context-group purpose="location"><context context-type="linenumber">258</context></context-group> + <context-group purpose="location"><context context-type="linenumber">321</context></context-group> + </trans-unit> + <trans-unit id="_msg772"> + <source xml:space="preserve">Total debit</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">242</context></context-group> + </trans-unit> + <trans-unit id="_msg773"> + <source xml:space="preserve">Total credit</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">243</context></context-group> + </trans-unit> + <trans-unit id="_msg774"> + <source xml:space="preserve">Transaction fee</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">248</context></context-group> + </trans-unit> + <trans-unit id="_msg775"> + <source xml:space="preserve">Net amount</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">270</context></context-group> + </trans-unit> + <trans-unit id="_msg776"> + <source xml:space="preserve">Message</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">276</context></context-group> + <context-group purpose="location"><context context-type="linenumber">288</context></context-group> + </trans-unit> + <trans-unit id="_msg777"> + <source xml:space="preserve">Comment</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">278</context></context-group> + </trans-unit> + <trans-unit id="_msg778"> + <source xml:space="preserve">Transaction ID</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">280</context></context-group> + </trans-unit> + <trans-unit id="_msg779"> + <source xml:space="preserve">Transaction total size</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">281</context></context-group> + </trans-unit> + <trans-unit id="_msg780"> + <source xml:space="preserve">Transaction virtual size</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">282</context></context-group> + </trans-unit> + <trans-unit id="_msg781"> + <source xml:space="preserve">Output index</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">283</context></context-group> + </trans-unit> + <trans-unit id="_msg782"> + <source xml:space="preserve"> (Certificate was not verified)</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">299</context></context-group> + </trans-unit> + <trans-unit id="_msg783"> + <source xml:space="preserve">Merchant</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">302</context></context-group> + </trans-unit> + <trans-unit id="_msg784"> + <source xml:space="preserve">Generated coins must mature %1 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to "not accepted" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">310</context></context-group> + </trans-unit> + <trans-unit id="_msg785"> + <source xml:space="preserve">Debug information</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">318</context></context-group> + </trans-unit> + <trans-unit id="_msg786"> + <source xml:space="preserve">Transaction</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">326</context></context-group> + </trans-unit> + <trans-unit id="_msg787"> + <source xml:space="preserve">Inputs</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">329</context></context-group> + </trans-unit> + <trans-unit id="_msg788"> + <source xml:space="preserve">Amount</source> + <target xml:space="preserve" state="needs-review-translation">Amount</target> + <context-group purpose="location"><context context-type="linenumber">350</context></context-group> + </trans-unit> + <trans-unit id="_msg789"> + <source xml:space="preserve">true</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">351</context></context-group> + <context-group purpose="location"><context context-type="linenumber">352</context></context-group> + </trans-unit> + <trans-unit id="_msg790"> + <source xml:space="preserve">false</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">351</context></context-group> + <context-group purpose="location"><context context-type="linenumber">352</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../forms/transactiondescdialog.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="TransactionDescDialog"> + <trans-unit id="_msg791" approved="yes"> + <source xml:space="preserve">This pane shows a detailed description of the transaction</source> + <target xml:space="preserve">This pane shows a detailed description of the transaction</target> + <context-group purpose="location"><context context-type="linenumber">20</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../transactiondescdialog.cpp" datatype="cpp" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="TransactionDescDialog"> + <trans-unit id="_msg792"> + <source xml:space="preserve">Details for %1</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">18</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../transactiontablemodel.cpp" datatype="cpp" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="TransactionTableModel"> + <trans-unit id="_msg793"> + <source xml:space="preserve">Date</source> + <target xml:space="preserve" state="needs-review-translation">Date</target> + <context-group purpose="location"><context context-type="linenumber">252</context></context-group> + </trans-unit> + <trans-unit id="_msg794"> + <source xml:space="preserve">Type</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">252</context></context-group> + </trans-unit> + <trans-unit id="_msg795"> + <source xml:space="preserve">Label</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">252</context></context-group> + </trans-unit> + <group restype="x-gettext-plurals"> + <context-group purpose="location"><context context-type="linenumber">314</context></context-group> + <trans-unit id="_msg796[0]" approved="yes"> + <source xml:space="preserve">Open for %n more block(s)</source> + <target xml:space="preserve">Open for %n more block</target> + </trans-unit> + <trans-unit id="_msg796[1]" approved="yes"> + <source xml:space="preserve">Open for %n more block(s)</source> + <target xml:space="preserve">Open for %n more blocks</target> + </trans-unit> + </group> + <trans-unit id="_msg797"> + <source xml:space="preserve">Open until %1</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">317</context></context-group> + </trans-unit> + <trans-unit id="_msg798"> + <source xml:space="preserve">Unconfirmed</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">320</context></context-group> + </trans-unit> + <trans-unit id="_msg799"> + <source xml:space="preserve">Abandoned</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">323</context></context-group> + </trans-unit> + <trans-unit id="_msg800"> + <source xml:space="preserve">Confirming (%1 of %2 recommended confirmations)</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">326</context></context-group> + </trans-unit> + <trans-unit id="_msg801"> + <source xml:space="preserve">Confirmed (%1 confirmations)</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">329</context></context-group> + </trans-unit> + <trans-unit id="_msg802"> + <source xml:space="preserve">Conflicted</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">332</context></context-group> + </trans-unit> + <trans-unit id="_msg803"> + <source xml:space="preserve">Immature (%1 confirmations, will be available after %2)</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">335</context></context-group> + </trans-unit> + <trans-unit id="_msg804"> + <source xml:space="preserve">Generated but not accepted</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">338</context></context-group> + </trans-unit> + <trans-unit id="_msg805"> + <source xml:space="preserve">Received with</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">377</context></context-group> + </trans-unit> + <trans-unit id="_msg806"> + <source xml:space="preserve">Received from</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">379</context></context-group> + </trans-unit> + <trans-unit id="_msg807"> + <source xml:space="preserve">Sent to</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">382</context></context-group> + </trans-unit> + <trans-unit id="_msg808"> + <source xml:space="preserve">Payment to yourself</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">384</context></context-group> + </trans-unit> + <trans-unit id="_msg809"> + <source xml:space="preserve">Mined</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">386</context></context-group> + </trans-unit> + <trans-unit id="_msg810"> + <source xml:space="preserve">watch-only</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">414</context></context-group> + </trans-unit> + <trans-unit id="_msg811"> + <source xml:space="preserve">(n/a)</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">430</context></context-group> + </trans-unit> + <trans-unit id="_msg812"> + <source xml:space="preserve">(no label)</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">640</context></context-group> + </trans-unit> + <trans-unit id="_msg813"> + <source xml:space="preserve">Transaction status. Hover over this field to show number of confirmations.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">679</context></context-group> + </trans-unit> + <trans-unit id="_msg814"> + <source xml:space="preserve">Date and time that the transaction was received.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">681</context></context-group> + </trans-unit> + <trans-unit id="_msg815"> + <source xml:space="preserve">Type of transaction.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">683</context></context-group> + </trans-unit> + <trans-unit id="_msg816"> + <source xml:space="preserve">Whether or not a watch-only address is involved in this transaction.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">685</context></context-group> + </trans-unit> + <trans-unit id="_msg817"> + <source xml:space="preserve">User-defined intent/purpose of the transaction.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">687</context></context-group> + </trans-unit> + <trans-unit id="_msg818"> + <source xml:space="preserve">Amount removed from or added to balance.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">689</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../transactionview.cpp" datatype="cpp" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="TransactionView"> + <trans-unit id="_msg819"> + <source xml:space="preserve">All</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">70</context></context-group> + <context-group purpose="location"><context context-type="linenumber">86</context></context-group> + </trans-unit> + <trans-unit id="_msg820"> + <source xml:space="preserve">Today</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">71</context></context-group> + </trans-unit> + <trans-unit id="_msg821"> + <source xml:space="preserve">This week</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">72</context></context-group> + </trans-unit> + <trans-unit id="_msg822"> + <source xml:space="preserve">This month</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">73</context></context-group> + </trans-unit> + <trans-unit id="_msg823"> + <source xml:space="preserve">Last month</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">74</context></context-group> + </trans-unit> + <trans-unit id="_msg824"> + <source xml:space="preserve">This year</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">75</context></context-group> + </trans-unit> + <trans-unit id="_msg825"> + <source xml:space="preserve">Range...</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">76</context></context-group> + </trans-unit> + <trans-unit id="_msg826"> + <source xml:space="preserve">Received with</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">87</context></context-group> + </trans-unit> + <trans-unit id="_msg827"> + <source xml:space="preserve">Sent to</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">89</context></context-group> + </trans-unit> + <trans-unit id="_msg828"> + <source xml:space="preserve">To yourself</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">91</context></context-group> + </trans-unit> + <trans-unit id="_msg829"> + <source xml:space="preserve">Mined</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">92</context></context-group> + </trans-unit> + <trans-unit id="_msg830"> + <source xml:space="preserve">Other</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">93</context></context-group> + </trans-unit> + <trans-unit id="_msg831"> + <source xml:space="preserve">Enter address, transaction id, or label to search</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">98</context></context-group> + </trans-unit> + <trans-unit id="_msg832"> + <source xml:space="preserve">Min amount</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">102</context></context-group> + </trans-unit> + <trans-unit id="_msg833"> + <source xml:space="preserve">Abandon transaction</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">165</context></context-group> + </trans-unit> + <trans-unit id="_msg834"> + <source xml:space="preserve">Increase transaction fee</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">166</context></context-group> + </trans-unit> + <trans-unit id="_msg835"> + <source xml:space="preserve">Copy address</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">168</context></context-group> + </trans-unit> + <trans-unit id="_msg836"> + <source xml:space="preserve">Copy label</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">169</context></context-group> + </trans-unit> + <trans-unit id="_msg837"> + <source xml:space="preserve">Copy amount</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">170</context></context-group> + </trans-unit> + <trans-unit id="_msg838"> + <source xml:space="preserve">Copy transaction ID</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">171</context></context-group> + </trans-unit> + <trans-unit id="_msg839"> + <source xml:space="preserve">Copy raw transaction</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">172</context></context-group> + </trans-unit> + <trans-unit id="_msg840"> + <source xml:space="preserve">Copy full transaction details</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">173</context></context-group> + </trans-unit> + <trans-unit id="_msg841"> + <source xml:space="preserve">Edit address label</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">174</context></context-group> + </trans-unit> + <trans-unit id="_msg842"> + <source xml:space="preserve">Comma separated file</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">360</context></context-group> + <context-group><context context-type="x-gettext-msgctxt">Name of CSV file format</context></context-group> + </trans-unit> + <trans-unit id="_msg843"> + <source xml:space="preserve">Show transaction details</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">175</context></context-group> + </trans-unit> + <trans-unit id="_msg844"> + <source xml:space="preserve">Export Transaction History</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">359</context></context-group> + </trans-unit> + <trans-unit id="_msg845"> + <source xml:space="preserve">Confirmed</source> + <target xml:space="preserve" state="needs-review-translation">Confirmed</target> + <context-group purpose="location"><context context-type="linenumber">369</context></context-group> + </trans-unit> + <trans-unit id="_msg846"> + <source xml:space="preserve">Watch-only</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">371</context></context-group> + </trans-unit> + <trans-unit id="_msg847"> + <source xml:space="preserve">Date</source> + <target xml:space="preserve" state="needs-review-translation">Date</target> + <context-group purpose="location"><context context-type="linenumber">372</context></context-group> + </trans-unit> + <trans-unit id="_msg848"> + <source xml:space="preserve">Type</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">373</context></context-group> + </trans-unit> + <trans-unit id="_msg849"> + <source xml:space="preserve">Label</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">374</context></context-group> + </trans-unit> + <trans-unit id="_msg850"> + <source xml:space="preserve">Address</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">375</context></context-group> + </trans-unit> + <trans-unit id="_msg851"> + <source xml:space="preserve">ID</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">377</context></context-group> + </trans-unit> + <trans-unit id="_msg852"> + <source xml:space="preserve">Exporting Failed</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">380</context></context-group> + </trans-unit> + <trans-unit id="_msg853"> + <source xml:space="preserve">There was an error trying to save the transaction history to %1.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">380</context></context-group> + </trans-unit> + <trans-unit id="_msg854"> + <source xml:space="preserve">Exporting Successful</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">384</context></context-group> + </trans-unit> + <trans-unit id="_msg855"> + <source xml:space="preserve">The transaction history was successfully saved to %1.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">384</context></context-group> + </trans-unit> + <trans-unit id="_msg856"> + <source xml:space="preserve">Range:</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">556</context></context-group> + </trans-unit> + <trans-unit id="_msg857"> + <source xml:space="preserve">to</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">564</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../walletframe.cpp" datatype="cpp" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="WalletFrame"> + <trans-unit id="_msg858"> + <source xml:space="preserve">No wallet has been loaded. +Go to File > Open Wallet to load a wallet. +- OR -</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">39</context></context-group> + </trans-unit> + <trans-unit id="_msg859"> + <source xml:space="preserve">Create a new wallet</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">44</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../walletmodel.cpp" datatype="cpp" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="WalletModel"> + <trans-unit id="_msg860"> + <source xml:space="preserve">Send Coins</source> + <target xml:space="preserve" state="needs-review-translation">Send Coins</target> + <context-group purpose="location"><context context-type="linenumber">218</context></context-group> + </trans-unit> + <trans-unit id="_msg861"> + <source xml:space="preserve">Fee bump error</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">497</context></context-group> + <context-group purpose="location"><context context-type="linenumber">549</context></context-group> + <context-group purpose="location"><context context-type="linenumber">562</context></context-group> + <context-group purpose="location"><context context-type="linenumber">567</context></context-group> + </trans-unit> + <trans-unit id="_msg862"> + <source xml:space="preserve">Increasing transaction fee failed</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">497</context></context-group> + </trans-unit> + <trans-unit id="_msg863"> + <source xml:space="preserve">Do you want to increase the fee?</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">505</context></context-group> + </trans-unit> + <trans-unit id="_msg864"> + <source xml:space="preserve">Do you want to draft a transaction with fee increase?</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">505</context></context-group> + </trans-unit> + <trans-unit id="_msg865"> + <source xml:space="preserve">Current fee:</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">509</context></context-group> + </trans-unit> + <trans-unit id="_msg866"> + <source xml:space="preserve">Increase:</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">513</context></context-group> + </trans-unit> + <trans-unit id="_msg867"> + <source xml:space="preserve">New fee:</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">517</context></context-group> + </trans-unit> + <trans-unit id="_msg868"> + <source xml:space="preserve">Warning: This may pay the additional fee by reducing change outputs or adding inputs, when necessary. It may add a new change output if one does not already exist. These changes may potentially leak privacy.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">525</context></context-group> + </trans-unit> + <trans-unit id="_msg869"> + <source xml:space="preserve">Confirm fee bump</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">528</context></context-group> + </trans-unit> + <trans-unit id="_msg870"> + <source xml:space="preserve">Can't draft transaction.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">549</context></context-group> + </trans-unit> + <trans-unit id="_msg871"> + <source xml:space="preserve">PSBT copied</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">556</context></context-group> + </trans-unit> + <trans-unit id="_msg872"> + <source xml:space="preserve">Can't sign transaction.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">562</context></context-group> + </trans-unit> + <trans-unit id="_msg873"> + <source xml:space="preserve">Could not commit transaction</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">567</context></context-group> + </trans-unit> + <trans-unit id="_msg874"> + <source xml:space="preserve">default wallet</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">587</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../walletview.cpp" datatype="cpp" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="WalletView"> + <trans-unit id="_msg875"> + <source xml:space="preserve">&Export</source> + <target xml:space="preserve" state="needs-review-translation">&Export</target> + <context-group purpose="location"><context context-type="linenumber">51</context></context-group> + </trans-unit> + <trans-unit id="_msg876"> + <source xml:space="preserve">Export the data in the current tab to a file</source> + <target xml:space="preserve" state="needs-review-translation">Export the data in the current tab to a file</target> + <context-group purpose="location"><context context-type="linenumber">52</context></context-group> + </trans-unit> + <trans-unit id="_msg877"> + <source xml:space="preserve">Error</source> + <target xml:space="preserve" state="needs-review-translation">Error</target> + <context-group purpose="location"><context context-type="linenumber">217</context></context-group> + <context-group purpose="location"><context context-type="linenumber">226</context></context-group> + <context-group purpose="location"><context context-type="linenumber">236</context></context-group> + </trans-unit> + <trans-unit id="_msg878"> + <source xml:space="preserve">Unable to decode PSBT from clipboard (invalid base64)</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">217</context></context-group> + </trans-unit> + <trans-unit id="_msg879"> + <source xml:space="preserve">Load Transaction Data</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">222</context></context-group> + </trans-unit> + <trans-unit id="_msg880"> + <source xml:space="preserve">Partially Signed Transaction (*.psbt)</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">223</context></context-group> + </trans-unit> + <trans-unit id="_msg881"> + <source xml:space="preserve">PSBT file must be smaller than 100 MiB</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">226</context></context-group> + </trans-unit> + <trans-unit id="_msg882"> + <source xml:space="preserve">Unable to decode PSBT</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">236</context></context-group> + </trans-unit> + <trans-unit id="_msg883"> + <source xml:space="preserve">Backup Wallet</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">275</context></context-group> + </trans-unit> + <trans-unit id="_msg884"> + <source xml:space="preserve">Wallet Data</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">276</context></context-group> + <context-group><context context-type="x-gettext-msgctxt">Name of wallet data file format</context></context-group> + </trans-unit> + <trans-unit id="_msg885"> + <source xml:space="preserve">Backup Failed</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">282</context></context-group> + </trans-unit> + <trans-unit id="_msg886"> + <source xml:space="preserve">There was an error trying to save the wallet data to %1.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">282</context></context-group> + </trans-unit> + <trans-unit id="_msg887"> + <source xml:space="preserve">Backup Successful</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">286</context></context-group> + </trans-unit> + <trans-unit id="_msg888"> + <source xml:space="preserve">The wallet data was successfully saved to %1.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">286</context></context-group> + </trans-unit> + <trans-unit id="_msg889"> + <source xml:space="preserve">Cancel</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">330</context></context-group> + </trans-unit> + </group> + </body></file> + <file original="../bitcoinstrings.cpp" datatype="cpp" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="bitcoin-core"> + <trans-unit id="_msg890"> + <source xml:space="preserve">Distributed under the MIT software license, see the accompanying file %s or %s</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">31</context></context-group> + </trans-unit> + <trans-unit id="_msg891"> + <source xml:space="preserve">Prune configured below the minimum of %d MiB. Please use a higher number.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">72</context></context-group> + </trans-unit> + <trans-unit id="_msg892"> + <source xml:space="preserve">Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">74</context></context-group> + </trans-unit> + <trans-unit id="_msg893"> + <source xml:space="preserve">Pruning blockstore...</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">198</context></context-group> + </trans-unit> + <trans-unit id="_msg894"> + <source xml:space="preserve">Unable to start HTTP server. See debug log for details.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">235</context></context-group> + </trans-unit> + <trans-unit id="_msg895"> + <source xml:space="preserve">The %s developers</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">12</context></context-group> + </trans-unit> + <trans-unit id="_msg896"> + <source xml:space="preserve">Cannot obtain a lock on data directory %s. %s is probably already running.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">22</context></context-group> + </trans-unit> + <trans-unit id="_msg897"> + <source xml:space="preserve">Cannot provide specific connections and have addrman find outgoing connections at the same.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">24</context></context-group> + </trans-unit> + <trans-unit id="_msg898"> + <source xml:space="preserve">Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">34</context></context-group> + </trans-unit> + <trans-unit id="_msg899"> + <source xml:space="preserve">More than one onion bind address is provided. Using %s for the automatically created Tor onion service.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">55</context></context-group> + </trans-unit> + <trans-unit id="_msg900"> + <source xml:space="preserve">Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">66</context></context-group> + </trans-unit> + <trans-unit id="_msg901"> + <source xml:space="preserve">Please contribute if you find %s useful. Visit %s for further information about the software.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">69</context></context-group> + </trans-unit> + <trans-unit id="_msg902"> + <source xml:space="preserve">SQLiteDatabase: Failed to prepare the statement to fetch sqlite wallet schema version: %s</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">77</context></context-group> + </trans-unit> + <trans-unit id="_msg903"> + <source xml:space="preserve">SQLiteDatabase: Failed to prepare the statement to fetch the application id: %s</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">80</context></context-group> + </trans-unit> + <trans-unit id="_msg904"> + <source xml:space="preserve">SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">83</context></context-group> + </trans-unit> + <trans-unit id="_msg905"> + <source xml:space="preserve">The block database contains a block which appears to be from the future. This may be due to your computer's date and time being set incorrectly. Only rebuild the block database if you are sure that your computer's date and time are correct</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">86</context></context-group> + </trans-unit> + <trans-unit id="_msg906"> + <source xml:space="preserve">This is a pre-release test build - use at your own risk - do not use for mining or merchant applications</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">97</context></context-group> + </trans-unit> + <trans-unit id="_msg907"> + <source xml:space="preserve">This is the transaction fee you may discard if change is smaller than dust at this level</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">103</context></context-group> + </trans-unit> + <trans-unit id="_msg908"> + <source xml:space="preserve">Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">114</context></context-group> + </trans-unit> + <trans-unit id="_msg909"> + <source xml:space="preserve">Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">117</context></context-group> + </trans-unit> + <trans-unit id="_msg910"> + <source xml:space="preserve">Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">128</context></context-group> + </trans-unit> + <trans-unit id="_msg911"> + <source xml:space="preserve">-maxmempool must be at least %d MB</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">135</context></context-group> + </trans-unit> + <trans-unit id="_msg912"> + <source xml:space="preserve">Cannot resolve -%s address: '%s'</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">137</context></context-group> + </trans-unit> + <trans-unit id="_msg913"> + <source xml:space="preserve">Change index out of range</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">140</context></context-group> + </trans-unit> + <trans-unit id="_msg914"> + <source xml:space="preserve">Config setting for %s only applied on %s network when in [%s] section.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">141</context></context-group> + </trans-unit> + <trans-unit id="_msg915"> + <source xml:space="preserve">Copyright (C) %i-%i</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">142</context></context-group> + </trans-unit> + <trans-unit id="_msg916" approved="yes"> + <source xml:space="preserve">Corrupted block database detected</source> + <target xml:space="preserve">Corrupted block database detected</target> + <context-group purpose="location"><context context-type="linenumber">143</context></context-group> + </trans-unit> + <trans-unit id="_msg917"> + <source xml:space="preserve">Could not find asmap file %s</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">144</context></context-group> + </trans-unit> + <trans-unit id="_msg918"> + <source xml:space="preserve">Could not parse asmap file %s</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">145</context></context-group> + </trans-unit> + <trans-unit id="_msg919" approved="yes"> + <source xml:space="preserve">Do you want to rebuild the block database now?</source> + <target xml:space="preserve">Do you want to rebuild the block database now?</target> + <context-group purpose="location"><context context-type="linenumber">147</context></context-group> + </trans-unit> + <trans-unit id="_msg920"> + <source xml:space="preserve">Dump file %s does not exist.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">149</context></context-group> + </trans-unit> + <trans-unit id="_msg921"> + <source xml:space="preserve">Error creating %s</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">150</context></context-group> + </trans-unit> + <trans-unit id="_msg922" approved="yes"> + <source xml:space="preserve">Error initializing block database</source> + <target xml:space="preserve">Error initializing block database</target> + <context-group purpose="location"><context context-type="linenumber">151</context></context-group> + </trans-unit> + <trans-unit id="_msg923" approved="yes"> + <source xml:space="preserve">Error initializing wallet database environment %s!</source> + <target xml:space="preserve">Error initializing wallet database environment %s!</target> + <context-group purpose="location"><context context-type="linenumber">152</context></context-group> + </trans-unit> + <trans-unit id="_msg924"> + <source xml:space="preserve">Error loading %s</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">153</context></context-group> + </trans-unit> + <trans-unit id="_msg925"> + <source xml:space="preserve">Error loading %s: Private keys can only be disabled during creation</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">154</context></context-group> + </trans-unit> + <trans-unit id="_msg926"> + <source xml:space="preserve">Error loading %s: Wallet corrupted</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">155</context></context-group> + </trans-unit> + <trans-unit id="_msg927"> + <source xml:space="preserve">Error loading %s: Wallet requires newer version of %s</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">156</context></context-group> + </trans-unit> + <trans-unit id="_msg928" approved="yes"> + <source xml:space="preserve">Error loading block database</source> + <target xml:space="preserve">Error loading block database</target> + <context-group purpose="location"><context context-type="linenumber">157</context></context-group> + </trans-unit> + <trans-unit id="_msg929" approved="yes"> + <source xml:space="preserve">Error opening block database</source> + <target xml:space="preserve">Error opening block database</target> + <context-group purpose="location"><context context-type="linenumber">158</context></context-group> + </trans-unit> + <trans-unit id="_msg930"> + <source xml:space="preserve">Error reading next record from wallet database</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">160</context></context-group> + </trans-unit> + <trans-unit id="_msg931"> + <source xml:space="preserve">Error: Couldn't create cursor into database</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">162</context></context-group> + </trans-unit> + <trans-unit id="_msg932"> + <source xml:space="preserve">Error: Dumpfile checksum does not match. Computed %s, expected %s</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">164</context></context-group> + </trans-unit> + <trans-unit id="_msg933"> + <source xml:space="preserve">Error: Got key that was not hex: %s</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">165</context></context-group> + </trans-unit> + <trans-unit id="_msg934"> + <source xml:space="preserve">Error: Got value that was not hex: %s</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">166</context></context-group> + </trans-unit> + <trans-unit id="_msg935"> + <source xml:space="preserve">Error: Missing checksum</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">168</context></context-group> + </trans-unit> + <trans-unit id="_msg936"> + <source xml:space="preserve">Error: Unable to parse version %u as a uint32_t</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">169</context></context-group> + </trans-unit> + <trans-unit id="_msg937"> + <source xml:space="preserve">Error: Unable to write record to new wallet</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">170</context></context-group> + </trans-unit> + <trans-unit id="_msg938" approved="yes"> + <source xml:space="preserve">Failed to listen on any port. Use -listen=0 if you want this.</source> + <target xml:space="preserve">Failed to listen on any port. Use -listen=0 if you want this.</target> + <context-group purpose="location"><context context-type="linenumber">171</context></context-group> + </trans-unit> + <trans-unit id="_msg939"> + <source xml:space="preserve">Failed to rescan the wallet during initialization</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">172</context></context-group> + </trans-unit> + <trans-unit id="_msg940"> + <source xml:space="preserve">Failed to verify database</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">173</context></context-group> + </trans-unit> + <trans-unit id="_msg941"> + <source xml:space="preserve">Ignoring duplicate -wallet %s.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">175</context></context-group> + </trans-unit> + <trans-unit id="_msg942"> + <source xml:space="preserve">Importing...</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">176</context></context-group> + </trans-unit> + <trans-unit id="_msg943" approved="yes"> + <source xml:space="preserve">Incorrect or no genesis block found. Wrong datadir for network?</source> + <target xml:space="preserve">Incorrect or no genesis block found. Wrong datadir for network?</target> + <context-group purpose="location"><context context-type="linenumber">177</context></context-group> + </trans-unit> + <trans-unit id="_msg944"> + <source xml:space="preserve">Initialization sanity check failed. %s is shutting down.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">178</context></context-group> + </trans-unit> + <trans-unit id="_msg945"> + <source xml:space="preserve">Invalid -i2psam address or hostname: '%s'</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">180</context></context-group> + </trans-unit> + <trans-unit id="_msg946"> + <source xml:space="preserve">Invalid P2P permission: '%s'</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">183</context></context-group> + </trans-unit> + <trans-unit id="_msg947"> + <source xml:space="preserve">Invalid amount for -%s=<amount>: '%s'</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">184</context></context-group> + </trans-unit> + <trans-unit id="_msg948"> + <source xml:space="preserve">Invalid amount for -discardfee=<amount>: '%s'</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">185</context></context-group> + </trans-unit> + <trans-unit id="_msg949"> + <source xml:space="preserve">Invalid amount for -fallbackfee=<amount>: '%s'</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">186</context></context-group> + </trans-unit> + <trans-unit id="_msg950"> + <source xml:space="preserve">SQLiteDatabase: Failed to execute statement to verify database: %s</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">203</context></context-group> + </trans-unit> + <trans-unit id="_msg951"> + <source xml:space="preserve">SQLiteDatabase: Failed to fetch sqlite wallet schema version: %s</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">204</context></context-group> + </trans-unit> + <trans-unit id="_msg952"> + <source xml:space="preserve">SQLiteDatabase: Failed to fetch the application id: %s</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">205</context></context-group> + </trans-unit> + <trans-unit id="_msg953"> + <source xml:space="preserve">SQLiteDatabase: Failed to prepare statement to verify database: %s</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">206</context></context-group> + </trans-unit> + <trans-unit id="_msg954"> + <source xml:space="preserve">SQLiteDatabase: Failed to read database verification error: %s</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">207</context></context-group> + </trans-unit> + <trans-unit id="_msg955"> + <source xml:space="preserve">SQLiteDatabase: Unexpected application id. Expected %u, got %u</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">208</context></context-group> + </trans-unit> + <trans-unit id="_msg956"> + <source xml:space="preserve">Specified blocks directory "%s" does not exist.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">214</context></context-group> + </trans-unit> + <trans-unit id="_msg957"> + <source xml:space="preserve">The specified config file %s does not exist</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">217</context></context-group> + </trans-unit> + <trans-unit id="_msg958"> + <source xml:space="preserve">Unable to open %s for writing</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">234</context></context-group> + </trans-unit> + <trans-unit id="_msg959"> + <source xml:space="preserve">Unknown address type '%s'</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">237</context></context-group> + </trans-unit> + <trans-unit id="_msg960"> + <source xml:space="preserve">Unknown change type '%s'</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">238</context></context-group> + </trans-unit> + <trans-unit id="_msg961"> + <source xml:space="preserve">Upgrading txindex database</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">242</context></context-group> + </trans-unit> + <trans-unit id="_msg962"> + <source xml:space="preserve">Loading P2P addresses...</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">189</context></context-group> + </trans-unit> + <trans-unit id="_msg963"> + <source xml:space="preserve">Cannot downgrade wallet from version %i to version %i. Wallet version unchanged.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">19</context></context-group> + </trans-unit> + <trans-unit id="_msg964"> + <source xml:space="preserve">Cannot upgrade a non HD split wallet from version %i to version %i without upgrading to support pre-split keypool. Please use version %i or no version specified.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">27</context></context-group> + </trans-unit> + <trans-unit id="_msg965"> + <source xml:space="preserve">Error: Dumpfile format record is incorrect. Got "%s", expected "format".</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">37</context></context-group> + </trans-unit> + <trans-unit id="_msg966"> + <source xml:space="preserve">Error: Dumpfile identifier record is incorrect. Got "%s", expected "%s".</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">39</context></context-group> + </trans-unit> + <trans-unit id="_msg967"> + <source xml:space="preserve">Error: Dumpfile version is not supported. This version of bitcoin-wallet only supports version 1 dumpfiles. Got dumpfile with version %s</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">41</context></context-group> + </trans-unit> + <trans-unit id="_msg968"> + <source xml:space="preserve">File %s already exists. If you are sure this is what you want, move it out of the way first.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">49</context></context-group> + </trans-unit> + <trans-unit id="_msg969"> + <source xml:space="preserve">No dump file provided. To use createfromdump, -dumpfile=<filename> must be provided.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">58</context></context-group> + </trans-unit> + <trans-unit id="_msg970"> + <source xml:space="preserve">No dump file provided. To use dump, -dumpfile=<filename> must be provided.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">61</context></context-group> + </trans-unit> + <trans-unit id="_msg971"> + <source xml:space="preserve">No wallet file format provided. To use createfromdump, -format=<format> must be provided.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">63</context></context-group> + </trans-unit> + <trans-unit id="_msg972"> + <source xml:space="preserve">Unknown wallet file format "%s" provided. Please provide one of "bdb" or "sqlite".</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">120</context></context-group> + </trans-unit> + <trans-unit id="_msg973"> + <source xml:space="preserve">Warning: Dumpfile wallet format "%s" does not match command line specified format "%s".</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">123</context></context-group> + </trans-unit> + <trans-unit id="_msg974"> + <source xml:space="preserve">Loading banlist...</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">190</context></context-group> + </trans-unit> + <trans-unit id="_msg975" approved="yes"> + <source xml:space="preserve">Not enough file descriptors available.</source> + <target xml:space="preserve">Not enough file descriptors available.</target> + <context-group purpose="location"><context context-type="linenumber">195</context></context-group> + </trans-unit> + <trans-unit id="_msg976"> + <source xml:space="preserve">Prune cannot be configured with a negative value.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">196</context></context-group> + </trans-unit> + <trans-unit id="_msg977"> + <source xml:space="preserve">Prune mode is incompatible with -txindex.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">197</context></context-group> + </trans-unit> + <trans-unit id="_msg978"> + <source xml:space="preserve">Replaying blocks...</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">200</context></context-group> + </trans-unit> + <trans-unit id="_msg979"> + <source xml:space="preserve">Rewinding blocks...</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">202</context></context-group> + </trans-unit> + <trans-unit id="_msg980"> + <source xml:space="preserve">The source code is available from %s.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">216</context></context-group> + </trans-unit> + <trans-unit id="_msg981"> + <source xml:space="preserve">Transaction fee and change calculation failed</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">225</context></context-group> + </trans-unit> + <trans-unit id="_msg982"> + <source xml:space="preserve">Unable to bind to %s on this computer. %s is probably already running.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">230</context></context-group> + </trans-unit> + <trans-unit id="_msg983"> + <source xml:space="preserve">Unable to generate keys</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">233</context></context-group> + </trans-unit> + <trans-unit id="_msg984"> + <source xml:space="preserve">Unsupported logging category %s=%s.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">240</context></context-group> + </trans-unit> + <trans-unit id="_msg985"> + <source xml:space="preserve">Upgrading UTXO database</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">241</context></context-group> + </trans-unit> + <trans-unit id="_msg986"> + <source xml:space="preserve">User Agent comment (%s) contains unsafe characters.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">243</context></context-group> + </trans-unit> + <trans-unit id="_msg987" approved="yes"> + <source xml:space="preserve">Verifying blocks...</source> + <target xml:space="preserve">Verifying blocks...</target> + <context-group purpose="location"><context context-type="linenumber">244</context></context-group> + </trans-unit> + <trans-unit id="_msg988"> + <source xml:space="preserve">Wallet needed to be rewritten: restart %s to complete</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">246</context></context-group> + </trans-unit> + <trans-unit id="_msg989"> + <source xml:space="preserve">Error: Listening for incoming connections failed (listen returned error %s)</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">44</context></context-group> + </trans-unit> + <trans-unit id="_msg990"> + <source xml:space="preserve">%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring a backup.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">13</context></context-group> + </trans-unit> + <trans-unit id="_msg991"> + <source xml:space="preserve">Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">52</context></context-group> + </trans-unit> + <trans-unit id="_msg992"> + <source xml:space="preserve">The transaction amount is too small to send after the fee has been deducted</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">91</context></context-group> + </trans-unit> + <trans-unit id="_msg993"> + <source xml:space="preserve">This error could occur if this wallet was not shutdown cleanly and was last loaded using a build with a newer version of Berkeley DB. If so, please use the software that last loaded this wallet</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">93</context></context-group> + </trans-unit> + <trans-unit id="_msg994"> + <source xml:space="preserve">This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">100</context></context-group> + </trans-unit> + <trans-unit id="_msg995"> + <source xml:space="preserve">Transaction needs a change address, but we can't generate it. Please call keypoolrefill first.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">111</context></context-group> + </trans-unit> + <trans-unit id="_msg996"> + <source xml:space="preserve">You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">131</context></context-group> + </trans-unit> + <trans-unit id="_msg997"> + <source xml:space="preserve">A fatal internal error occurred, see debug.log for details</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">136</context></context-group> + </trans-unit> + <trans-unit id="_msg998"> + <source xml:space="preserve">Cannot set -peerblockfilters without -blockfilterindex.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">138</context></context-group> + </trans-unit> + <trans-unit id="_msg999"> + <source xml:space="preserve">Disk space is too low!</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">146</context></context-group> + </trans-unit> + <trans-unit id="_msg1000"> + <source xml:space="preserve">Error reading from database, shutting down.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">159</context></context-group> + </trans-unit> + <trans-unit id="_msg1001"> + <source xml:space="preserve">Error upgrading chainstate database</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">161</context></context-group> + </trans-unit> + <trans-unit id="_msg1002"> + <source xml:space="preserve">Error: Disk space is low for %s</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">163</context></context-group> + </trans-unit> + <trans-unit id="_msg1003"> + <source xml:space="preserve">Error: Keypool ran out, please call keypoolrefill first</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">167</context></context-group> + </trans-unit> + <trans-unit id="_msg1004"> + <source xml:space="preserve">Fee rate (%s) is lower than the minimum fee rate setting (%s)</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">174</context></context-group> + </trans-unit> + <trans-unit id="_msg1005"> + <source xml:space="preserve">Invalid -onion address or hostname: '%s'</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">181</context></context-group> + </trans-unit> + <trans-unit id="_msg1006"> + <source xml:space="preserve">Invalid -proxy address or hostname: '%s'</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">182</context></context-group> + </trans-unit> + <trans-unit id="_msg1007"> + <source xml:space="preserve">Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">187</context></context-group> + </trans-unit> + <trans-unit id="_msg1008"> + <source xml:space="preserve">Invalid netmask specified in -whitelist: '%s'</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">188</context></context-group> + </trans-unit> + <trans-unit id="_msg1009"> + <source xml:space="preserve">Need to specify a port with -whitebind: '%s'</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">193</context></context-group> + </trans-unit> + <trans-unit id="_msg1010"> + <source xml:space="preserve">No proxy server specified. Use -proxy=<ip> or -proxy=<ip:port>.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">194</context></context-group> + </trans-unit> + <trans-unit id="_msg1011"> + <source xml:space="preserve">Reducing -maxconnections from %d to %d, because of system limitations.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">199</context></context-group> + </trans-unit> + <trans-unit id="_msg1012"> + <source xml:space="preserve">Section [%s] is not recognized.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">209</context></context-group> + </trans-unit> + <trans-unit id="_msg1013" approved="yes"> + <source xml:space="preserve">Signing transaction failed</source> + <target xml:space="preserve">Signing transaction failed</target> + <context-group purpose="location"><context context-type="linenumber">210</context></context-group> + </trans-unit> + <trans-unit id="_msg1014"> + <source xml:space="preserve">Specified -walletdir "%s" does not exist</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">211</context></context-group> + </trans-unit> + <trans-unit id="_msg1015"> + <source xml:space="preserve">Specified -walletdir "%s" is a relative path</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">212</context></context-group> + </trans-unit> + <trans-unit id="_msg1016"> + <source xml:space="preserve">Specified -walletdir "%s" is not a directory</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">213</context></context-group> + </trans-unit> + <trans-unit id="_msg1017"> + <source xml:space="preserve">The transaction amount is too small to pay the fee</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">218</context></context-group> + </trans-unit> + <trans-unit id="_msg1018"> + <source xml:space="preserve">This is experimental software.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">220</context></context-group> + </trans-unit> + <trans-unit id="_msg1019" approved="yes"> + <source xml:space="preserve">Transaction amount too small</source> + <target xml:space="preserve">Transaction amount too small</target> + <context-group purpose="location"><context context-type="linenumber">223</context></context-group> + </trans-unit> + <trans-unit id="_msg1020" approved="yes"> + <source xml:space="preserve">Transaction too large</source> + <target xml:space="preserve">Transaction too large</target> + <context-group purpose="location"><context context-type="linenumber">228</context></context-group> + </trans-unit> + <trans-unit id="_msg1021"> + <source xml:space="preserve">Unable to bind to %s on this computer (bind returned error %s)</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">229</context></context-group> + </trans-unit> + <trans-unit id="_msg1022"> + <source xml:space="preserve">Unable to create the PID file '%s': %s</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">231</context></context-group> + </trans-unit> + <trans-unit id="_msg1023"> + <source xml:space="preserve">Unable to generate initial keys</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">232</context></context-group> + </trans-unit> + <trans-unit id="_msg1024"> + <source xml:space="preserve">Unknown -blockfilterindex value %s.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">236</context></context-group> + </trans-unit> + <trans-unit id="_msg1025"> + <source xml:space="preserve">Verifying wallet(s)...</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">245</context></context-group> + </trans-unit> + <trans-unit id="_msg1026"> + <source xml:space="preserve">Warning: unknown new rules activated (versionbit %i)</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">247</context></context-group> + </trans-unit> + <trans-unit id="_msg1027"> + <source xml:space="preserve">-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">16</context></context-group> + </trans-unit> + <trans-unit id="_msg1028"> + <source xml:space="preserve">This is the transaction fee you may pay when fee estimates are not available.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">106</context></context-group> + </trans-unit> + <trans-unit id="_msg1029"> + <source xml:space="preserve">Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">108</context></context-group> + </trans-unit> + <trans-unit id="_msg1030"> + <source xml:space="preserve">%s is set very high!</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">134</context></context-group> + </trans-unit> + <trans-unit id="_msg1031"> + <source xml:space="preserve">Starting network threads...</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">215</context></context-group> + </trans-unit> + <trans-unit id="_msg1032"> + <source xml:space="preserve">The wallet will avoid paying less than the minimum relay fee.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">219</context></context-group> + </trans-unit> + <trans-unit id="_msg1033"> + <source xml:space="preserve">This is the minimum transaction fee you pay on every transaction.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">221</context></context-group> + </trans-unit> + <trans-unit id="_msg1034"> + <source xml:space="preserve">This is the transaction fee you will pay if you send a transaction.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">222</context></context-group> + </trans-unit> + <trans-unit id="_msg1035"> + <source xml:space="preserve">Transaction amounts must not be negative</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">224</context></context-group> + </trans-unit> + <trans-unit id="_msg1036"> + <source xml:space="preserve">Transaction has too long of a mempool chain</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">226</context></context-group> + </trans-unit> + <trans-unit id="_msg1037"> + <source xml:space="preserve">Transaction must have at least one recipient</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">227</context></context-group> + </trans-unit> + <trans-unit id="_msg1038" approved="yes"> + <source xml:space="preserve">Unknown network specified in -onlynet: '%s'</source> + <target xml:space="preserve">Unknown network specified in -onlynet: '%s'</target> + <context-group purpose="location"><context context-type="linenumber">239</context></context-group> + </trans-unit> + <trans-unit id="_msg1039" approved="yes"> + <source xml:space="preserve">Insufficient funds</source> + <target xml:space="preserve">Insufficient funds</target> + <context-group purpose="location"><context context-type="linenumber">179</context></context-group> + </trans-unit> + <trans-unit id="_msg1040"> + <source xml:space="preserve">Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">46</context></context-group> + </trans-unit> + <trans-unit id="_msg1041"> + <source xml:space="preserve">Warning: Private keys detected in wallet {%s} with disabled private keys</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">126</context></context-group> + </trans-unit> + <trans-unit id="_msg1042"> + <source xml:space="preserve">Cannot write to data directory '%s'; check permissions.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">139</context></context-group> + </trans-unit> + <trans-unit id="_msg1043" approved="yes"> + <source xml:space="preserve">Loading block index...</source> + <target xml:space="preserve">Loading block index...</target> + <context-group purpose="location"><context context-type="linenumber">191</context></context-group> + </trans-unit> + <trans-unit id="_msg1044" approved="yes"> + <source xml:space="preserve">Loading wallet...</source> + <target xml:space="preserve">Loading wallet...</target> + <context-group purpose="location"><context context-type="linenumber">192</context></context-group> + </trans-unit> + <trans-unit id="_msg1045" approved="yes"> + <source xml:space="preserve">Rescanning...</source> + <target xml:space="preserve">Rescanning...</target> + <context-group purpose="location"><context context-type="linenumber">201</context></context-group> + </trans-unit> + <trans-unit id="_msg1046" approved="yes"> + <source xml:space="preserve">Done loading</source> + <target xml:space="preserve">Done loading</target> + <context-group purpose="location"><context context-type="linenumber">148</context></context-group> + </trans-unit> + </group> + </body></file> +</xliff> diff --git a/src/qt/qrimagewidget.cpp b/src/qt/qrimagewidget.cpp index a71c8831e9..df6757ffd6 100644 --- a/src/qt/qrimagewidget.cpp +++ b/src/qt/qrimagewidget.cpp @@ -27,12 +27,8 @@ QRImageWidget::QRImageWidget(QWidget *parent): QLabel(parent), contextMenu(nullptr) { contextMenu = new QMenu(this); - QAction *saveImageAction = new QAction(tr("&Save Image..."), this); - connect(saveImageAction, &QAction::triggered, this, &QRImageWidget::saveImage); - contextMenu->addAction(saveImageAction); - QAction *copyImageAction = new QAction(tr("&Copy Image"), this); - connect(copyImageAction, &QAction::triggered, this, &QRImageWidget::copyImage); - contextMenu->addAction(copyImageAction); + contextMenu->addAction(tr("Save Image..."), this, &QRImageWidget::saveImage); + contextMenu->addAction(tr("Copy Image"), this, &QRImageWidget::copyImage); } bool QRImageWidget::setQR(const QString& data, const QString& text) diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp index 61cb89d75a..3f4d7f85e6 100644 --- a/src/qt/receivecoinsdialog.cpp +++ b/src/qt/receivecoinsdialog.cpp @@ -42,28 +42,14 @@ ReceiveCoinsDialog::ReceiveCoinsDialog(const PlatformStyle *_platformStyle, QWid ui->removeRequestButton->setIcon(_platformStyle->SingleColorIcon(":/icons/remove")); } - // context menu actions - QAction *copyURIAction = new QAction(tr("Copy URI"), this); - QAction* copyAddressAction = new QAction(tr("Copy address"), this); - copyLabelAction = new QAction(tr("Copy label"), this); - copyMessageAction = new QAction(tr("Copy message"), this); - copyAmountAction = new QAction(tr("Copy amount"), this); - // context menu contextMenu = new QMenu(this); - contextMenu->addAction(copyURIAction); - contextMenu->addAction(copyAddressAction); - contextMenu->addAction(copyLabelAction); - contextMenu->addAction(copyMessageAction); - contextMenu->addAction(copyAmountAction); - - // context menu signals + contextMenu->addAction(tr("Copy URI"), this, &ReceiveCoinsDialog::copyURI); + contextMenu->addAction(tr("Copy address"), this, &ReceiveCoinsDialog::copyAddress); + copyLabelAction = contextMenu->addAction(tr("Copy label"), this, &ReceiveCoinsDialog::copyLabel); + copyMessageAction = contextMenu->addAction(tr("Copy message"), this, &ReceiveCoinsDialog::copyMessage); + copyAmountAction = contextMenu->addAction(tr("Copy amount"), this, &ReceiveCoinsDialog::copyAmount); connect(ui->recentRequestsView, &QWidget::customContextMenuRequested, this, &ReceiveCoinsDialog::showMenu); - connect(copyURIAction, &QAction::triggered, this, &ReceiveCoinsDialog::copyURI); - connect(copyAddressAction, &QAction::triggered, this, &ReceiveCoinsDialog::copyAddress); - connect(copyLabelAction, &QAction::triggered, this, &ReceiveCoinsDialog::copyLabel); - connect(copyMessageAction, &QAction::triggered, this, &ReceiveCoinsDialog::copyMessage); - connect(copyAmountAction, &QAction::triggered, this, &ReceiveCoinsDialog::copyAmount); connect(ui->clearButton, &QPushButton::clicked, this, &ReceiveCoinsDialog::clear); diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 34d055e5a5..85412ca75b 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -616,29 +616,14 @@ void RPCConsole::setClientModel(ClientModel *model, int bestblock_height, int64_ ui->peerWidget->setColumnWidth(PeerTableModel::Ping, PING_COLUMN_WIDTH); ui->peerWidget->horizontalHeader()->setStretchLastSection(true); - // create peer table context menu actions - QAction* disconnectAction = new QAction(tr("&Disconnect"), this); - QAction* banAction1h = new QAction(ts.ban_for + " " + tr("1 &hour"), this); - QAction* banAction24h = new QAction(ts.ban_for + " " + tr("1 &day"), this); - QAction* banAction7d = new QAction(ts.ban_for + " " + tr("1 &week"), this); - QAction* banAction365d = new QAction(ts.ban_for + " " + tr("1 &year"), this); - // create peer table context menu peersTableContextMenu = new QMenu(this); - peersTableContextMenu->addAction(disconnectAction); - peersTableContextMenu->addAction(banAction1h); - peersTableContextMenu->addAction(banAction24h); - peersTableContextMenu->addAction(banAction7d); - peersTableContextMenu->addAction(banAction365d); - - connect(banAction1h, &QAction::triggered, [this] { banSelectedNode(60 * 60); }); - connect(banAction24h, &QAction::triggered, [this] { banSelectedNode(60 * 60 * 24); }); - connect(banAction7d, &QAction::triggered, [this] { banSelectedNode(60 * 60 * 24 * 7); }); - connect(banAction365d, &QAction::triggered, [this] { banSelectedNode(60 * 60 * 24 * 365); }); - - // peer table context menu signals + peersTableContextMenu->addAction(tr("Disconnect"), this, &RPCConsole::disconnectSelectedNode); + peersTableContextMenu->addAction(ts.ban_for + " " + tr("1 hour"), [this] { banSelectedNode(60 * 60); }); + peersTableContextMenu->addAction(ts.ban_for + " " + tr("1 day"), [this] { banSelectedNode(60 * 60 * 24); }); + peersTableContextMenu->addAction(ts.ban_for + " " + tr("1 week"), [this] { banSelectedNode(60 * 60 * 24 * 7); }); + peersTableContextMenu->addAction(ts.ban_for + " " + tr("1 year"), [this] { banSelectedNode(60 * 60 * 24 * 365); }); connect(ui->peerWidget, &QTableView::customContextMenuRequested, this, &RPCConsole::showPeersTableContextMenu); - connect(disconnectAction, &QAction::triggered, this, &RPCConsole::disconnectSelectedNode); // peer table signal handling - update peer details when selecting new node connect(ui->peerWidget->selectionModel(), &QItemSelectionModel::selectionChanged, this, &RPCConsole::updateDetailWidget); @@ -657,16 +642,10 @@ void RPCConsole::setClientModel(ClientModel *model, int bestblock_height, int64_ ui->banlistWidget->setColumnWidth(BanTableModel::Bantime, BANTIME_COLUMN_WIDTH); ui->banlistWidget->horizontalHeader()->setStretchLastSection(true); - // create ban table context menu action - QAction* unbanAction = new QAction(tr("&Unban"), this); - // create ban table context menu banTableContextMenu = new QMenu(this); - banTableContextMenu->addAction(unbanAction); - - // ban table context menu signals + banTableContextMenu->addAction(tr("Unban"), this, &RPCConsole::unbanSelectedNode); connect(ui->banlistWidget, &QTableView::customContextMenuRequested, this, &RPCConsole::showBanTableContextMenu); - connect(unbanAction, &QAction::triggered, this, &RPCConsole::unbanSelectedNode); // ban table signal handling - clear peer details when clicking a peer in the ban table connect(ui->banlistWidget, &QTableView::clicked, this, &RPCConsole::clearSelectedNode); diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 95e1ce2210..f0e720617c 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -129,6 +129,8 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *_platformStyle, QWidget *p ui->customFee->SetAllowEmpty(false); ui->customFee->setValue(settings.value("nTransactionFee").toLongLong()); minimizeFeeSection(settings.value("fFeeSectionMinimized").toBool()); + + GUIUtil::ExceptionSafeConnect(ui->sendButton, &QPushButton::clicked, this, &SendCoinsDialog::sendButtonClicked); } void SendCoinsDialog::setClientModel(ClientModel *_clientModel) @@ -375,7 +377,7 @@ bool SendCoinsDialog::PrepareSendText(QString& question_string, QString& informa return true; } -void SendCoinsDialog::on_sendButton_clicked() +void SendCoinsDialog::sendButtonClicked([[maybe_unused]] bool checked) { if(!model || !model->getOptionsModel()) return; diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h index 4fc2f57cd6..3e276201ba 100644 --- a/src/qt/sendcoinsdialog.h +++ b/src/qt/sendcoinsdialog.h @@ -80,7 +80,7 @@ private: void updateCoinControlState(CCoinControl& ctrl); private Q_SLOTS: - void on_sendButton_clicked(); + void sendButtonClicked(bool checked); void on_buttonChooseFee_clicked(); void on_buttonMinimizeFee_clicked(); void removeEntry(SendCoinsEntry* entry); diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp index 1107c44dc9..03460cd6eb 100644 --- a/src/qt/test/wallettests.cpp +++ b/src/qt/test/wallettests.cpp @@ -73,7 +73,7 @@ uint256 SendCoins(CWallet& wallet, SendCoinsDialog& sendCoinsDialog, const CTxDe if (status == CT_NEW) txid = hash; })); ConfirmSend(); - bool invoked = QMetaObject::invokeMethod(&sendCoinsDialog, "on_sendButton_clicked"); + bool invoked = QMetaObject::invokeMethod(&sendCoinsDialog, "sendButtonClicked", Q_ARG(bool, false)); assert(invoked); return txid; } diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp index 42e08c6af7..890d1a1740 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -161,32 +161,21 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa transactionView->horizontalHeader()->setStretchLastSection(true); } - // Actions - abandonAction = new QAction(tr("Abandon transaction"), this); - bumpFeeAction = new QAction(tr("Increase transaction fee"), this); - bumpFeeAction->setObjectName("bumpFeeAction"); - copyAddressAction = new QAction(tr("Copy address"), this); - copyLabelAction = new QAction(tr("Copy label"), this); - QAction *copyAmountAction = new QAction(tr("Copy amount"), this); - QAction *copyTxIDAction = new QAction(tr("Copy transaction ID"), this); - QAction *copyTxHexAction = new QAction(tr("Copy raw transaction"), this); - QAction *copyTxPlainText = new QAction(tr("Copy full transaction details"), this); - QAction *editLabelAction = new QAction(tr("Edit address label"), this); - QAction *showDetailsAction = new QAction(tr("Show transaction details"), this); - contextMenu = new QMenu(this); contextMenu->setObjectName("contextMenu"); - contextMenu->addAction(copyAddressAction); - contextMenu->addAction(copyLabelAction); - contextMenu->addAction(copyAmountAction); - contextMenu->addAction(copyTxIDAction); - contextMenu->addAction(copyTxHexAction); - contextMenu->addAction(copyTxPlainText); - contextMenu->addAction(showDetailsAction); + copyAddressAction = contextMenu->addAction(tr("Copy address"), this, &TransactionView::copyAddress); + copyLabelAction = contextMenu->addAction(tr("Copy label"), this, &TransactionView::copyLabel); + contextMenu->addAction(tr("Copy amount"), this, &TransactionView::copyAmount); + contextMenu->addAction(tr("Copy transaction ID"), this, &TransactionView::copyTxID); + contextMenu->addAction(tr("Copy raw transaction"), this, &TransactionView::copyTxHex); + contextMenu->addAction(tr("Copy full transaction details"), this, &TransactionView::copyTxPlainText); + contextMenu->addAction(tr("Show transaction details"), this, &TransactionView::showDetails); contextMenu->addSeparator(); - contextMenu->addAction(bumpFeeAction); - contextMenu->addAction(abandonAction); - contextMenu->addAction(editLabelAction); + bumpFeeAction = contextMenu->addAction(tr("Increase transaction fee")); + GUIUtil::ExceptionSafeConnect(bumpFeeAction, &QAction::triggered, this, &TransactionView::bumpFee); + bumpFeeAction->setObjectName("bumpFeeAction"); + abandonAction = contextMenu->addAction(tr("Abandon transaction"), this, &TransactionView::abandonTx); + contextMenu->addAction(tr("Edit address label"), this, &TransactionView::editLabel); connect(dateWidget, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this, &TransactionView::chooseDate); connect(typeWidget, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this, &TransactionView::chooseType); @@ -199,16 +188,6 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa connect(transactionView, &QTableView::doubleClicked, this, &TransactionView::doubleClicked); connect(transactionView, &QTableView::customContextMenuRequested, this, &TransactionView::contextualMenu); - connect(bumpFeeAction, &QAction::triggered, this, &TransactionView::bumpFee); - connect(abandonAction, &QAction::triggered, this, &TransactionView::abandonTx); - connect(copyAddressAction, &QAction::triggered, this, &TransactionView::copyAddress); - connect(copyLabelAction, &QAction::triggered, this, &TransactionView::copyLabel); - connect(copyAmountAction, &QAction::triggered, this, &TransactionView::copyAmount); - connect(copyTxIDAction, &QAction::triggered, this, &TransactionView::copyTxID); - connect(copyTxHexAction, &QAction::triggered, this, &TransactionView::copyTxHex); - connect(copyTxPlainText, &QAction::triggered, this, &TransactionView::copyTxPlainText); - connect(editLabelAction, &QAction::triggered, this, &TransactionView::editLabel); - connect(showDetailsAction, &QAction::triggered, this, &TransactionView::showDetails); // Double-clicking on a transaction on the transaction history page shows details connect(this, &TransactionView::doubleClicked, this, &TransactionView::showDetails); // Highlight transaction after fee bump @@ -424,7 +403,7 @@ void TransactionView::abandonTx() model->getTransactionTableModel()->updateTransaction(hashQStr, CT_UPDATED, false); } -void TransactionView::bumpFee() +void TransactionView::bumpFee([[maybe_unused]] bool checked) { if(!transactionView || !transactionView->selectionModel()) return; diff --git a/src/qt/transactionview.h b/src/qt/transactionview.h index 35ada4aa7a..66350bdc02 100644 --- a/src/qt/transactionview.h +++ b/src/qt/transactionview.h @@ -99,7 +99,7 @@ private Q_SLOTS: void openThirdPartyTxUrl(QString url); void updateWatchOnlyColumn(bool fHaveWatchOnly); void abandonTx(); - void bumpFee(); + void bumpFee(bool checked); Q_SIGNALS: void doubleClicked(const QModelIndex&); diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 02254da3ce..c6dd0c2ad6 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -65,7 +65,10 @@ WalletModel::~WalletModel() void WalletModel::startPollBalance() { // This timer will be fired repeatedly to update the balance - connect(timer, &QTimer::timeout, this, &WalletModel::pollBalanceChanged); + // Since the QTimer::timeout is a private signal, it cannot be used + // in the GUIUtil::ExceptionSafeConnect directly. + connect(timer, &QTimer::timeout, this, &WalletModel::timerTimeout); + GUIUtil::ExceptionSafeConnect(this, &WalletModel::timerTimeout, this, &WalletModel::pollBalanceChanged); timer->start(MODEL_UPDATE_DELAY); } diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index 9a3c3f2f66..4ca8643444 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -223,6 +223,8 @@ Q_SIGNALS: // Notify that there are now keys in the keypool void canGetAddressesChanged(); + void timerTimeout(); + public Q_SLOTS: /* Starts a timer to periodically update the balance */ void startPollBalance(); diff --git a/src/rest.cpp b/src/rest.cpp index 71d258b077..d41f374c49 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -8,6 +8,7 @@ #include <core_io.h> #include <httpserver.h> #include <index/txindex.h> +#include <node/blockstorage.h> #include <node/context.h> #include <primitives/block.h> #include <primitives/transaction.h> @@ -180,14 +181,16 @@ static bool rest_headers(const std::any& context, std::vector<const CBlockIndex *> headers; headers.reserve(count); { + ChainstateManager& chainman = EnsureAnyChainman(context); LOCK(cs_main); - tip = ::ChainActive().Tip(); - const CBlockIndex* pindex = g_chainman.m_blockman.LookupBlockIndex(hash); - while (pindex != nullptr && ::ChainActive().Contains(pindex)) { + CChain& active_chain = chainman.ActiveChain(); + tip = active_chain.Tip(); + const CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(hash); + while (pindex != nullptr && active_chain.Contains(pindex)) { headers.push_back(pindex); if (headers.size() == (unsigned long)count) break; - pindex = ::ChainActive().Next(pindex); + pindex = active_chain.Next(pindex); } } @@ -231,7 +234,8 @@ static bool rest_headers(const std::any& context, } } -static bool rest_block(HTTPRequest* req, +static bool rest_block(const std::any& context, + HTTPRequest* req, const std::string& strURIPart, bool showTxDetails) { @@ -248,9 +252,10 @@ static bool rest_block(HTTPRequest* req, CBlockIndex* pblockindex = nullptr; CBlockIndex* tip = nullptr; { + ChainstateManager& chainman = EnsureAnyChainman(context); LOCK(cs_main); - tip = ::ChainActive().Tip(); - pblockindex = g_chainman.m_blockman.LookupBlockIndex(hash); + tip = chainman.ActiveChain().Tip(); + pblockindex = chainman.m_blockman.LookupBlockIndex(hash); if (!pblockindex) { return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found"); } @@ -297,12 +302,12 @@ static bool rest_block(HTTPRequest* req, static bool rest_block_extended(const std::any& context, HTTPRequest* req, const std::string& strURIPart) { - return rest_block(req, strURIPart, true); + return rest_block(context, req, strURIPart, true); } static bool rest_block_notxdetails(const std::any& context, HTTPRequest* req, const std::string& strURIPart) { - return rest_block(req, strURIPart, false); + return rest_block(context, req, strURIPart, false); } // A bit of a hack - dependency on a function defined in rpc/blockchain.cpp @@ -536,6 +541,7 @@ static bool rest_getutxos(const std::any& context, HTTPRequest* req, const std:: std::string bitmapStringRepresentation; std::vector<bool> hits; bitmap.resize((vOutPoints.size() + 7) / 8); + ChainstateManager& chainman = EnsureAnyChainman(context); { auto process_utxos = [&vOutPoints, &outs, &hits](const CCoinsView& view, const CTxMemPool& mempool) { for (const COutPoint& vOutPoint : vOutPoints) { @@ -551,12 +557,12 @@ static bool rest_getutxos(const std::any& context, HTTPRequest* req, const std:: if (!mempool) return false; // use db+mempool as cache backend in case user likes to query mempool LOCK2(cs_main, mempool->cs); - CCoinsViewCache& viewChain = ::ChainstateActive().CoinsTip(); + CCoinsViewCache& viewChain = chainman.ActiveChainstate().CoinsTip(); CCoinsViewMemPool viewMempool(&viewChain, *mempool); process_utxos(viewMempool, *mempool); } else { LOCK(cs_main); // no need to lock mempool! - process_utxos(::ChainstateActive().CoinsTip(), CTxMemPool()); + process_utxos(chainman.ActiveChainstate().CoinsTip(), CTxMemPool()); } for (size_t i = 0; i < hits.size(); ++i) { @@ -571,7 +577,7 @@ static bool rest_getutxos(const std::any& context, HTTPRequest* req, const std:: // serialize data // use exact same output as mentioned in Bip64 CDataStream ssGetUTXOResponse(SER_NETWORK, PROTOCOL_VERSION); - ssGetUTXOResponse << ::ChainActive().Height() << ::ChainActive().Tip()->GetBlockHash() << bitmap << outs; + ssGetUTXOResponse << chainman.ActiveChain().Height() << chainman.ActiveChain().Tip()->GetBlockHash() << bitmap << outs; std::string ssGetUTXOResponseString = ssGetUTXOResponse.str(); req->WriteHeader("Content-Type", "application/octet-stream"); @@ -581,7 +587,7 @@ static bool rest_getutxos(const std::any& context, HTTPRequest* req, const std:: case RetFormat::HEX: { CDataStream ssGetUTXOResponse(SER_NETWORK, PROTOCOL_VERSION); - ssGetUTXOResponse << ::ChainActive().Height() << ::ChainActive().Tip()->GetBlockHash() << bitmap << outs; + ssGetUTXOResponse << chainman.ActiveChain().Height() << chainman.ActiveChain().Tip()->GetBlockHash() << bitmap << outs; std::string strHex = HexStr(ssGetUTXOResponse) + "\n"; req->WriteHeader("Content-Type", "text/plain"); @@ -594,8 +600,8 @@ static bool rest_getutxos(const std::any& context, HTTPRequest* req, const std:: // pack in some essentials // use more or less the same output as mentioned in Bip64 - objGetUTXOResponse.pushKV("chainHeight", ::ChainActive().Height()); - objGetUTXOResponse.pushKV("chaintipHash", ::ChainActive().Tip()->GetBlockHash().GetHex()); + objGetUTXOResponse.pushKV("chainHeight", chainman.ActiveChain().Height()); + objGetUTXOResponse.pushKV("chaintipHash", chainman.ActiveChain().Tip()->GetBlockHash().GetHex()); objGetUTXOResponse.pushKV("bitmap", bitmapStringRepresentation); UniValue utxos(UniValue::VARR); @@ -638,11 +644,13 @@ static bool rest_blockhash_by_height(const std::any& context, HTTPRequest* req, CBlockIndex* pblockindex = nullptr; { + ChainstateManager& chainman = EnsureAnyChainman(context); LOCK(cs_main); - if (blockheight > ::ChainActive().Height()) { + const CChain& active_chain = chainman.ActiveChain(); + if (blockheight > active_chain.Height()) { return RESTERR(req, HTTP_NOT_FOUND, "Block height out of range"); } - pblockindex = ::ChainActive()[blockheight]; + pblockindex = active_chain[blockheight]; } switch (rf) { case RetFormat::BINARY: { diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index e1501d7254..e7fd97ee1f 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -14,6 +14,7 @@ #include <core_io.h> #include <hash.h> #include <index/blockfilterindex.h> +#include <node/blockstorage.h> #include <node/coinstats.h> #include <node/context.h> #include <node/utxo_snapshot.h> @@ -55,7 +56,7 @@ static Mutex cs_blockchange; static std::condition_variable cond_blockchange; static CUpdatedBlock latestblock GUARDED_BY(cs_blockchange); -NodeContext& EnsureNodeContext(const std::any& context) +NodeContext& EnsureAnyNodeContext(const std::any& context) { auto node_context = util::AnyPtr<NodeContext>(context); if (!node_context) { @@ -64,33 +65,46 @@ NodeContext& EnsureNodeContext(const std::any& context) return *node_context; } -CTxMemPool& EnsureMemPool(const std::any& context) +CTxMemPool& EnsureMemPool(const NodeContext& node) { - const NodeContext& node = EnsureNodeContext(context); if (!node.mempool) { throw JSONRPCError(RPC_CLIENT_MEMPOOL_DISABLED, "Mempool disabled or instance not found"); } return *node.mempool; } -ChainstateManager& EnsureChainman(const std::any& context) +CTxMemPool& EnsureAnyMemPool(const std::any& context) +{ + return EnsureMemPool(EnsureAnyNodeContext(context)); +} + +ChainstateManager& EnsureChainman(const NodeContext& node) { - const NodeContext& node = EnsureNodeContext(context); if (!node.chainman) { throw JSONRPCError(RPC_INTERNAL_ERROR, "Node chainman not found"); } + WITH_LOCK(::cs_main, CHECK_NONFATAL(std::addressof(g_chainman) == std::addressof(*node.chainman))); return *node.chainman; } -CBlockPolicyEstimator& EnsureFeeEstimator(const std::any& context) +ChainstateManager& EnsureAnyChainman(const std::any& context) +{ + return EnsureChainman(EnsureAnyNodeContext(context)); +} + +CBlockPolicyEstimator& EnsureFeeEstimator(const NodeContext& node) { - NodeContext& node = EnsureNodeContext(context); if (!node.fee_estimator) { throw JSONRPCError(RPC_INTERNAL_ERROR, "Fee estimation disabled"); } return *node.fee_estimator; } +CBlockPolicyEstimator& EnsureAnyFeeEstimator(const std::any& context) +{ + return EnsureFeeEstimator(EnsureAnyNodeContext(context)); +} + /* Calculate the difficulty for a given block index. */ double GetDifficulty(const CBlockIndex* blockindex) @@ -197,8 +211,9 @@ static RPCHelpMan getblockcount() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { + ChainstateManager& chainman = EnsureAnyChainman(request.context); LOCK(cs_main); - return ::ChainActive().Height(); + return chainman.ActiveChain().Height(); }, }; } @@ -216,8 +231,9 @@ static RPCHelpMan getbestblockhash() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { + ChainstateManager& chainman = EnsureAnyChainman(request.context); LOCK(cs_main); - return ::ChainActive().Tip()->GetBlockHash().GetHex(); + return chainman.ActiveChain().Tip()->GetBlockHash().GetHex(); }, }; } @@ -238,7 +254,7 @@ static RPCHelpMan waitfornewblock() "\nWaits for a specific new block and returns useful info about it.\n" "\nReturns the current block on timeout or exit.\n", { - {"timeout", RPCArg::Type::NUM, /* default */ "0", "Time in milliseconds to wait for a response. 0 indicates no timeout."}, + {"timeout", RPCArg::Type::NUM, RPCArg::Default{0}, "Time in milliseconds to wait for a response. 0 indicates no timeout."}, }, RPCResult{ RPCResult::Type::OBJ, "", "", @@ -281,7 +297,7 @@ static RPCHelpMan waitforblock() "\nReturns the current block on timeout or exit.\n", { {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "Block hash to wait for."}, - {"timeout", RPCArg::Type::NUM, /* default */ "0", "Time in milliseconds to wait for a response. 0 indicates no timeout."}, + {"timeout", RPCArg::Type::NUM, RPCArg::Default{0}, "Time in milliseconds to wait for a response. 0 indicates no timeout."}, }, RPCResult{ RPCResult::Type::OBJ, "", "", @@ -328,7 +344,7 @@ static RPCHelpMan waitforblockheight() "\nReturns the current block on timeout or exit.\n", { {"height", RPCArg::Type::NUM, RPCArg::Optional::NO, "Block height to wait for."}, - {"timeout", RPCArg::Type::NUM, /* default */ "0", "Time in milliseconds to wait for a response. 0 indicates no timeout."}, + {"timeout", RPCArg::Type::NUM, RPCArg::Default{0}, "Time in milliseconds to wait for a response. 0 indicates no timeout."}, }, RPCResult{ RPCResult::Type::OBJ, "", "", @@ -397,8 +413,9 @@ static RPCHelpMan getdifficulty() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { + ChainstateManager& chainman = EnsureAnyChainman(request.context); LOCK(cs_main); - return GetDifficulty(::ChainActive().Tip()); + return GetDifficulty(chainman.ActiveChain().Tip()); }, }; } @@ -541,8 +558,8 @@ static RPCHelpMan getrawmempool() "\nReturns all transaction ids in memory pool as a json array of string transaction ids.\n" "\nHint: use getmempoolentry to fetch a specific transaction from the mempool.\n", { - {"verbose", RPCArg::Type::BOOL, /* default */ "false", "True for a json object, false for array of transaction ids"}, - {"mempool_sequence", RPCArg::Type::BOOL, /* default */ "false", "If verbose=false, returns a json object with transaction list and mempool sequence number attached."}, + {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "True for a json object, false for array of transaction ids"}, + {"mempool_sequence", RPCArg::Type::BOOL, RPCArg::Default{false}, "If verbose=false, returns a json object with transaction list and mempool sequence number attached."}, }, { RPCResult{"for verbose = false", @@ -580,7 +597,7 @@ static RPCHelpMan getrawmempool() include_mempool_sequence = request.params[1].get_bool(); } - return MempoolToJSON(EnsureMemPool(request.context), fVerbose, include_mempool_sequence); + return MempoolToJSON(EnsureAnyMemPool(request.context), fVerbose, include_mempool_sequence); }, }; } @@ -591,7 +608,7 @@ static RPCHelpMan getmempoolancestors() "\nIf txid is in the mempool, returns all in-mempool ancestors.\n", { {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id (must be in mempool)"}, - {"verbose", RPCArg::Type::BOOL, /* default */ "false", "True for a json object, false for array of transaction ids"}, + {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "True for a json object, false for array of transaction ids"}, }, { RPCResult{"for verbose = false", @@ -615,7 +632,7 @@ static RPCHelpMan getmempoolancestors() uint256 hash = ParseHashV(request.params[0], "parameter 1"); - const CTxMemPool& mempool = EnsureMemPool(request.context); + const CTxMemPool& mempool = EnsureAnyMemPool(request.context); LOCK(mempool.cs); CTxMemPool::txiter it = mempool.mapTx.find(hash); @@ -655,7 +672,7 @@ static RPCHelpMan getmempooldescendants() "\nIf txid is in the mempool, returns all in-mempool descendants.\n", { {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id (must be in mempool)"}, - {"verbose", RPCArg::Type::BOOL, /* default */ "false", "True for a json object, false for array of transaction ids"}, + {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "True for a json object, false for array of transaction ids"}, }, { RPCResult{"for verbose = false", @@ -679,7 +696,7 @@ static RPCHelpMan getmempooldescendants() uint256 hash = ParseHashV(request.params[0], "parameter 1"); - const CTxMemPool& mempool = EnsureMemPool(request.context); + const CTxMemPool& mempool = EnsureAnyMemPool(request.context); LOCK(mempool.cs); CTxMemPool::txiter it = mempool.mapTx.find(hash); @@ -731,7 +748,7 @@ static RPCHelpMan getmempoolentry() { uint256 hash = ParseHashV(request.params[0], "parameter 1"); - const CTxMemPool& mempool = EnsureMemPool(request.context); + const CTxMemPool& mempool = EnsureAnyMemPool(request.context); LOCK(mempool.cs); CTxMemPool::txiter it = mempool.mapTx.find(hash); @@ -762,13 +779,15 @@ static RPCHelpMan getblockhash() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { + ChainstateManager& chainman = EnsureAnyChainman(request.context); LOCK(cs_main); + const CChain& active_chain = chainman.ActiveChain(); int nHeight = request.params[0].get_int(); - if (nHeight < 0 || nHeight > ::ChainActive().Height()) + if (nHeight < 0 || nHeight > active_chain.Height()) throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range"); - CBlockIndex* pblockindex = ::ChainActive()[nHeight]; + CBlockIndex* pblockindex = active_chain[nHeight]; return pblockindex->GetBlockHash().GetHex(); }, }; @@ -781,7 +800,7 @@ static RPCHelpMan getblockheader() "If verbose is true, returns an Object with information about blockheader <hash>.\n", { {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash"}, - {"verbose", RPCArg::Type::BOOL, /* default */ "true", "true for a json object, false for the hex-encoded data"}, + {"verbose", RPCArg::Type::BOOL, RPCArg::Default{true}, "true for a json object, false for the hex-encoded data"}, }, { RPCResult{"for verbose = true", @@ -821,9 +840,10 @@ static RPCHelpMan getblockheader() const CBlockIndex* pblockindex; const CBlockIndex* tip; { + ChainstateManager& chainman = EnsureAnyChainman(request.context); LOCK(cs_main); - pblockindex = g_chainman.m_blockman.LookupBlockIndex(hash); - tip = ::ChainActive().Tip(); + pblockindex = chainman.m_blockman.LookupBlockIndex(hash); + tip = chainman.ActiveChain().Tip(); } if (!pblockindex) { @@ -882,7 +902,7 @@ static RPCHelpMan getblock() "If verbosity is 2, returns an Object with information about block <hash> and information about each transaction. \n", { {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash"}, - {"verbosity|verbose", RPCArg::Type::NUM, /* default */ "1", "0 for hex-encoded data, 1 for a json object, and 2 for json object with transaction data"}, + {"verbosity|verbose", RPCArg::Type::NUM, RPCArg::Default{1}, "0 for hex-encoded data, 1 for a json object, and 2 for json object with transaction data"}, }, { RPCResult{"for verbosity = 0", @@ -935,19 +955,21 @@ static RPCHelpMan getblock() int verbosity = 1; if (!request.params[1].isNull()) { - if(request.params[1].isNum()) - verbosity = request.params[1].get_int(); - else + if (request.params[1].isBool()) { verbosity = request.params[1].get_bool() ? 1 : 0; + } else { + verbosity = request.params[1].get_int(); + } } CBlock block; const CBlockIndex* pblockindex; const CBlockIndex* tip; { + ChainstateManager& chainman = EnsureAnyChainman(request.context); LOCK(cs_main); - pblockindex = g_chainman.m_blockman.LookupBlockIndex(hash); - tip = ::ChainActive().Tip(); + pblockindex = chainman.m_blockman.LookupBlockIndex(hash); + tip = chainman.ActiveChain().Tip(); if (!pblockindex) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); @@ -987,7 +1009,10 @@ static RPCHelpMan pruneblockchain() if (!fPruneMode) throw JSONRPCError(RPC_MISC_ERROR, "Cannot prune blocks because node is not in prune mode."); + ChainstateManager& chainman = EnsureAnyChainman(request.context); LOCK(cs_main); + CChainState& active_chainstate = chainman.ActiveChainstate(); + CChain& active_chain = active_chainstate.m_chain; int heightParam = request.params[0].get_int(); if (heightParam < 0) @@ -997,7 +1022,7 @@ static RPCHelpMan pruneblockchain() // too low to be a block time (corresponds to timestamp from Sep 2001). if (heightParam > 1000000000) { // Add a 2 hour buffer to include blocks which might have had old timestamps - CBlockIndex* pindex = ::ChainActive().FindEarliestAtLeast(heightParam - TIMESTAMP_WINDOW, 0); + CBlockIndex* pindex = active_chain.FindEarliestAtLeast(heightParam - TIMESTAMP_WINDOW, 0); if (!pindex) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Could not find block with at least the specified timestamp."); } @@ -1005,7 +1030,7 @@ static RPCHelpMan pruneblockchain() } unsigned int height = (unsigned int) heightParam; - unsigned int chainHeight = (unsigned int) ::ChainActive().Height(); + unsigned int chainHeight = (unsigned int) active_chain.Height(); if (chainHeight < Params().PruneAfterHeight()) throw JSONRPCError(RPC_MISC_ERROR, "Blockchain is too short for pruning."); else if (height > chainHeight) @@ -1015,8 +1040,8 @@ static RPCHelpMan pruneblockchain() height = chainHeight - MIN_BLOCKS_TO_KEEP; } - PruneBlockFilesManual(::ChainstateActive(), height); - const CBlockIndex* block = ::ChainActive().Tip(); + PruneBlockFilesManual(active_chainstate, height); + const CBlockIndex* block = active_chain.Tip(); CHECK_NONFATAL(block); while (block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA)) { block = block->pprev; @@ -1045,7 +1070,7 @@ static RPCHelpMan gettxoutsetinfo() "\nReturns statistics about the unspent transaction output set.\n" "Note this call may take some time.\n", { - {"hash_type", RPCArg::Type::STR, /* default */ "hash_serialized_2", "Which UTXO set hash should be calculated. Options: 'hash_serialized_2' (the legacy algorithm), 'muhash', 'none'."}, + {"hash_type", RPCArg::Type::STR, RPCArg::Default{"hash_serialized_2"}, "Which UTXO set hash should be calculated. Options: 'hash_serialized_2' (the legacy algorithm), 'muhash', 'none'."}, }, RPCResult{ RPCResult::Type::OBJ, "", "", @@ -1069,13 +1094,21 @@ static RPCHelpMan gettxoutsetinfo() UniValue ret(UniValue::VOBJ); CCoinsStats stats; - ::ChainstateActive().ForceFlushStateToDisk(); + NodeContext& node = EnsureAnyNodeContext(request.context); + ChainstateManager& chainman = EnsureChainman(node); + CChainState& active_chainstate = chainman.ActiveChainstate(); + active_chainstate.ForceFlushStateToDisk(); const CoinStatsHashType hash_type{request.params[0].isNull() ? CoinStatsHashType::HASH_SERIALIZED : ParseHashType(request.params[0].get_str())}; - CCoinsView* coins_view = WITH_LOCK(::cs_main, return &::ChainstateActive().CoinsDB()); - NodeContext& node = EnsureNodeContext(request.context); - if (GetUTXOStats(coins_view, WITH_LOCK(::cs_main, return std::ref(g_chainman.m_blockman)), stats, hash_type, node.rpc_interruption_point)) { + CCoinsView* coins_view; + BlockManager* blockman; + { + LOCK(::cs_main); + coins_view = &active_chainstate.CoinsDB(); + blockman = &active_chainstate.m_blockman; + } + if (GetUTXOStats(coins_view, *blockman, stats, hash_type, node.rpc_interruption_point)) { ret.pushKV("height", (int64_t)stats.nHeight); ret.pushKV("bestblock", stats.hashBlock.GetHex()); ret.pushKV("transactions", (int64_t)stats.nTransactions); @@ -1104,7 +1137,7 @@ static RPCHelpMan gettxout() { {"txid", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction id"}, {"n", RPCArg::Type::NUM, RPCArg::Optional::NO, "vout number"}, - {"include_mempool", RPCArg::Type::BOOL, /* default */ "true", "Whether to include the mempool. Note that an unspent output that is spent in the mempool won't appear."}, + {"include_mempool", RPCArg::Type::BOOL, RPCArg::Default{true}, "Whether to include the mempool. Note that an unspent output that is spent in the mempool won't appear."}, }, { RPCResult{"If the UTXO was not found", RPCResult::Type::NONE, "", ""}, @@ -1134,6 +1167,8 @@ static RPCHelpMan gettxout() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { + NodeContext& node = EnsureAnyNodeContext(request.context); + ChainstateManager& chainman = EnsureChainman(node); LOCK(cs_main); UniValue ret(UniValue::VOBJ); @@ -1146,10 +1181,11 @@ static RPCHelpMan gettxout() fMempool = request.params[2].get_bool(); Coin coin; - CCoinsViewCache* coins_view = &::ChainstateActive().CoinsTip(); + CChainState& active_chainstate = chainman.ActiveChainstate(); + CCoinsViewCache* coins_view = &active_chainstate.CoinsTip(); if (fMempool) { - const CTxMemPool& mempool = EnsureMemPool(request.context); + const CTxMemPool& mempool = EnsureMemPool(node); LOCK(mempool.cs); CCoinsViewMemPool view(coins_view, mempool); if (!view.GetCoin(out, coin) || mempool.isSpent(out)) { @@ -1161,7 +1197,7 @@ static RPCHelpMan gettxout() } } - const CBlockIndex* pindex = g_chainman.m_blockman.LookupBlockIndex(coins_view->GetBestBlock()); + const CBlockIndex* pindex = active_chainstate.m_blockman.LookupBlockIndex(coins_view->GetBestBlock()); ret.pushKV("bestblock", pindex->GetBlockHash().GetHex()); if (coin.nHeight == MEMPOOL_HEIGHT) { ret.pushKV("confirmations", 0); @@ -1184,9 +1220,9 @@ static RPCHelpMan verifychain() return RPCHelpMan{"verifychain", "\nVerifies blockchain database.\n", { - {"checklevel", RPCArg::Type::NUM, /* default */ strprintf("%d, range=0-4", DEFAULT_CHECKLEVEL), + {"checklevel", RPCArg::Type::NUM, RPCArg::DefaultHint{strprintf("%d, range=0-4", DEFAULT_CHECKLEVEL)}, strprintf("How thorough the block verification is:\n - %s", Join(CHECKLEVEL_DOC, "\n- "))}, - {"nblocks", RPCArg::Type::NUM, /* default */ strprintf("%d, 0=all", DEFAULT_CHECKBLOCKS), "The number of blocks to check."}, + {"nblocks", RPCArg::Type::NUM, RPCArg::DefaultHint{strprintf("%d, 0=all", DEFAULT_CHECKBLOCKS)}, "The number of blocks to check."}, }, RPCResult{ RPCResult::Type::BOOL, "", "Verified or not"}, @@ -1199,41 +1235,41 @@ static RPCHelpMan verifychain() const int check_level(request.params[0].isNull() ? DEFAULT_CHECKLEVEL : request.params[0].get_int()); const int check_depth{request.params[1].isNull() ? DEFAULT_CHECKBLOCKS : request.params[1].get_int()}; + ChainstateManager& chainman = EnsureAnyChainman(request.context); LOCK(cs_main); - return CVerifyDB().VerifyDB(Params(), ::ChainstateActive(), &::ChainstateActive().CoinsTip(), check_level, check_depth); + CChainState& active_chainstate = chainman.ActiveChainstate(); + return CVerifyDB().VerifyDB(Params(), active_chainstate, &active_chainstate.CoinsTip(), check_level, check_depth); }, }; } -static void BuriedForkDescPushBack(UniValue& softforks, const std::string &name, int height) EXCLUSIVE_LOCKS_REQUIRED(cs_main) +static void BuriedForkDescPushBack(UniValue& softforks, const std::string &name, int softfork_height, int tip_height) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { // For buried deployments. // A buried deployment is one where the height of the activation has been hardcoded into // the client implementation long after the consensus change has activated. See BIP 90. // Buried deployments with activation height value of // std::numeric_limits<int>::max() are disabled and thus hidden. - if (height == std::numeric_limits<int>::max()) return; + if (softfork_height == std::numeric_limits<int>::max()) return; UniValue rv(UniValue::VOBJ); rv.pushKV("type", "buried"); // getblockchaininfo reports the softfork as active from when the chain height is // one below the activation height - rv.pushKV("active", ::ChainActive().Tip()->nHeight + 1 >= height); - rv.pushKV("height", height); + rv.pushKV("active", tip_height + 1 >= softfork_height); + rv.pushKV("height", softfork_height); softforks.pushKV(name, rv); } -static void BIP9SoftForkDescPushBack(UniValue& softforks, const std::string &name, const Consensus::Params& consensusParams, Consensus::DeploymentPos id) EXCLUSIVE_LOCKS_REQUIRED(cs_main) +static void BIP9SoftForkDescPushBack(const CBlockIndex* active_chain_tip, UniValue& softforks, const std::string &name, const Consensus::Params& consensusParams, Consensus::DeploymentPos id) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { // For BIP9 deployments. - // Deployments (e.g. testdummy) with timeout value before Jan 1, 2009 are hidden. - // A timeout value of 0 guarantees a softfork will never be activated. - // This is used when merging logic to implement a proposed softfork without a specified deployment schedule. - if (consensusParams.vDeployments[id].nTimeout <= 1230768000) return; + // Deployments that are never active are hidden. + if (consensusParams.vDeployments[id].nStartTime == Consensus::BIP9Deployment::NEVER_ACTIVE) return; UniValue bip9(UniValue::VOBJ); - const ThresholdState thresholdState = VersionBitsState(::ChainActive().Tip(), consensusParams, id, versionbitscache); + const ThresholdState thresholdState = VersionBitsState(active_chain_tip, consensusParams, id, versionbitscache); switch (thresholdState) { case ThresholdState::DEFINED: bip9.pushKV("status", "defined"); break; case ThresholdState::STARTED: bip9.pushKV("status", "started"); break; @@ -1247,12 +1283,12 @@ static void BIP9SoftForkDescPushBack(UniValue& softforks, const std::string &nam } bip9.pushKV("start_time", consensusParams.vDeployments[id].nStartTime); bip9.pushKV("timeout", consensusParams.vDeployments[id].nTimeout); - int64_t since_height = VersionBitsStateSinceHeight(::ChainActive().Tip(), consensusParams, id, versionbitscache); + int64_t since_height = VersionBitsStateSinceHeight(active_chain_tip, consensusParams, id, versionbitscache); bip9.pushKV("since", since_height); if (ThresholdState::STARTED == thresholdState) { UniValue statsUV(UniValue::VOBJ); - BIP9Stats statsStruct = VersionBitsStatistics(::ChainActive().Tip(), consensusParams, id); + BIP9Stats statsStruct = VersionBitsStatistics(active_chain_tip, consensusParams, id); statsUV.pushKV("period", statsStruct.period); statsUV.pushKV("threshold", statsStruct.threshold); statsUV.pushKV("elapsed", statsStruct.elapsed); @@ -1260,6 +1296,7 @@ static void BIP9SoftForkDescPushBack(UniValue& softforks, const std::string &nam statsUV.pushKV("possible", statsStruct.possible); bip9.pushKV("statistics", statsUV); } + bip9.pushKV("min_activation_height", consensusParams.vDeployments[id].min_activation_height); UniValue rv(UniValue::VOBJ); rv.pushKV("type", "bip9"); @@ -1306,6 +1343,7 @@ RPCHelpMan getblockchaininfo() {RPCResult::Type::NUM_TIME, "start_time", "the minimum median time past of a block at which the bit gains its meaning"}, {RPCResult::Type::NUM_TIME, "timeout", "the median time past of a block at which the deployment is considered failed if not yet locked in"}, {RPCResult::Type::NUM, "since", "height of the first block to which the status applies"}, + {RPCResult::Type::NUM, "min_activation_height", "minimum height of blocks for which the rules may be enforced"}, {RPCResult::Type::OBJ, "statistics", "numeric statistics about BIP9 signalling for a softfork (only for \"started\" status)", { {RPCResult::Type::NUM, "period", "the length in blocks of the BIP9 signalling period"}, @@ -1327,18 +1365,22 @@ RPCHelpMan getblockchaininfo() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { + ChainstateManager& chainman = EnsureAnyChainman(request.context); LOCK(cs_main); + CChainState& active_chainstate = chainman.ActiveChainstate(); - const CBlockIndex* tip = ::ChainActive().Tip(); + const CBlockIndex* tip = active_chainstate.m_chain.Tip(); + CHECK_NONFATAL(tip); + const int height = tip->nHeight; UniValue obj(UniValue::VOBJ); obj.pushKV("chain", Params().NetworkIDString()); - obj.pushKV("blocks", (int)::ChainActive().Height()); + obj.pushKV("blocks", height); obj.pushKV("headers", pindexBestHeader ? pindexBestHeader->nHeight : -1); obj.pushKV("bestblockhash", tip->GetBlockHash().GetHex()); obj.pushKV("difficulty", (double)GetDifficulty(tip)); obj.pushKV("mediantime", (int64_t)tip->GetMedianTimePast()); obj.pushKV("verificationprogress", GuessVerificationProgress(Params().TxData(), tip)); - obj.pushKV("initialblockdownload", ::ChainstateActive().IsInitialBlockDownload()); + obj.pushKV("initialblockdownload", active_chainstate.IsInitialBlockDownload()); obj.pushKV("chainwork", tip->nChainWork.GetHex()); obj.pushKV("size_on_disk", CalculateCurrentUsage()); obj.pushKV("pruned", fPruneMode); @@ -1361,13 +1403,13 @@ RPCHelpMan getblockchaininfo() const Consensus::Params& consensusParams = Params().GetConsensus(); UniValue softforks(UniValue::VOBJ); - BuriedForkDescPushBack(softforks, "bip34", consensusParams.BIP34Height); - BuriedForkDescPushBack(softforks, "bip66", consensusParams.BIP66Height); - BuriedForkDescPushBack(softforks, "bip65", consensusParams.BIP65Height); - BuriedForkDescPushBack(softforks, "csv", consensusParams.CSVHeight); - BuriedForkDescPushBack(softforks, "segwit", consensusParams.SegwitHeight); - BIP9SoftForkDescPushBack(softforks, "testdummy", consensusParams, Consensus::DEPLOYMENT_TESTDUMMY); - BIP9SoftForkDescPushBack(softforks, "taproot", consensusParams, Consensus::DEPLOYMENT_TAPROOT); + BuriedForkDescPushBack(softforks, "bip34", consensusParams.BIP34Height, height); + BuriedForkDescPushBack(softforks, "bip66", consensusParams.BIP66Height, height); + BuriedForkDescPushBack(softforks, "bip65", consensusParams.BIP65Height, height); + BuriedForkDescPushBack(softforks, "csv", consensusParams.CSVHeight, height); + BuriedForkDescPushBack(softforks, "segwit", consensusParams.SegwitHeight, height); + BIP9SoftForkDescPushBack(tip, softforks, "testdummy", consensusParams, Consensus::DEPLOYMENT_TESTDUMMY); + BIP9SoftForkDescPushBack(tip, softforks, "taproot", consensusParams, Consensus::DEPLOYMENT_TAPROOT); obj.pushKV("softforks", softforks); obj.pushKV("warnings", GetWarnings(false).original); @@ -1418,8 +1460,9 @@ static RPCHelpMan getchaintips() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - ChainstateManager& chainman = EnsureChainman(request.context); + ChainstateManager& chainman = EnsureAnyChainman(request.context); LOCK(cs_main); + CChain& active_chain = chainman.ActiveChain(); /* * Idea: The set of chain tips is the active chain tip, plus orphan blocks which do not have another orphan building off of them. @@ -1433,7 +1476,7 @@ static RPCHelpMan getchaintips() std::set<const CBlockIndex*> setPrevs; for (const std::pair<const uint256, CBlockIndex*>& item : chainman.BlockIndex()) { - if (!chainman.ActiveChain().Contains(item.second)) { + if (!active_chain.Contains(item.second)) { setOrphans.insert(item.second); setPrevs.insert(item.second->pprev); } @@ -1446,7 +1489,7 @@ static RPCHelpMan getchaintips() } // Always report the currently active tip. - setTips.insert(chainman.ActiveChain().Tip()); + setTips.insert(active_chain.Tip()); /* Construct the output array. */ UniValue res(UniValue::VARR); @@ -1455,11 +1498,11 @@ static RPCHelpMan getchaintips() obj.pushKV("height", block->nHeight); obj.pushKV("hash", block->phashBlock->GetHex()); - const int branchLen = block->nHeight - chainman.ActiveChain().FindFork(block)->nHeight; + const int branchLen = block->nHeight - active_chain.FindFork(block)->nHeight; obj.pushKV("branchlen", branchLen); std::string status; - if (chainman.ActiveChain().Contains(block)) { + if (active_chain.Contains(block)) { // This block is part of the currently active chain. status = "active"; } else if (block->nStatus & BLOCK_FAILED_MASK) { @@ -1530,7 +1573,7 @@ static RPCHelpMan getmempoolinfo() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - return MempoolInfoToJSON(EnsureMemPool(request.context)); + return MempoolInfoToJSON(EnsureAnyMemPool(request.context)); }, }; } @@ -1554,16 +1597,17 @@ static RPCHelpMan preciousblock() uint256 hash(ParseHashV(request.params[0], "blockhash")); CBlockIndex* pblockindex; + ChainstateManager& chainman = EnsureAnyChainman(request.context); { LOCK(cs_main); - pblockindex = g_chainman.m_blockman.LookupBlockIndex(hash); + pblockindex = chainman.m_blockman.LookupBlockIndex(hash); if (!pblockindex) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); } } BlockValidationState state; - ::ChainstateActive().PreciousBlock(state, Params(), pblockindex); + chainman.ActiveChainstate().PreciousBlock(state, Params(), pblockindex); if (!state.IsValid()) { throw JSONRPCError(RPC_DATABASE_ERROR, state.ToString()); @@ -1591,18 +1635,19 @@ static RPCHelpMan invalidateblock() uint256 hash(ParseHashV(request.params[0], "blockhash")); BlockValidationState state; + ChainstateManager& chainman = EnsureAnyChainman(request.context); CBlockIndex* pblockindex; { LOCK(cs_main); - pblockindex = g_chainman.m_blockman.LookupBlockIndex(hash); + pblockindex = chainman.m_blockman.LookupBlockIndex(hash); if (!pblockindex) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); } } - ::ChainstateActive().InvalidateBlock(state, Params(), pblockindex); + chainman.ActiveChainstate().InvalidateBlock(state, Params(), pblockindex); if (state.IsValid()) { - ::ChainstateActive().ActivateBestChain(state, Params()); + chainman.ActiveChainstate().ActivateBestChain(state, Params()); } if (!state.IsValid()) { @@ -1629,20 +1674,21 @@ static RPCHelpMan reconsiderblock() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { + ChainstateManager& chainman = EnsureAnyChainman(request.context); uint256 hash(ParseHashV(request.params[0], "blockhash")); { LOCK(cs_main); - CBlockIndex* pblockindex = g_chainman.m_blockman.LookupBlockIndex(hash); + CBlockIndex* pblockindex = chainman.m_blockman.LookupBlockIndex(hash); if (!pblockindex) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); } - ::ChainstateActive().ResetBlockFailureFlags(pblockindex); + chainman.ActiveChainstate().ResetBlockFailureFlags(pblockindex); } BlockValidationState state; - ::ChainstateActive().ActivateBestChain(state, Params()); + chainman.ActiveChainstate().ActivateBestChain(state, Params()); if (!state.IsValid()) { throw JSONRPCError(RPC_DATABASE_ERROR, state.ToString()); @@ -1658,8 +1704,8 @@ static RPCHelpMan getchaintxstats() return RPCHelpMan{"getchaintxstats", "\nCompute statistics about the total number and rate of transactions in the chain.\n", { - {"nblocks", RPCArg::Type::NUM, /* default */ "one month", "Size of the window in number of blocks"}, - {"blockhash", RPCArg::Type::STR_HEX, /* default */ "chain tip", "The hash of the block that ends the window."}, + {"nblocks", RPCArg::Type::NUM, RPCArg::DefaultHint{"one month"}, "Size of the window in number of blocks"}, + {"blockhash", RPCArg::Type::STR_HEX, RPCArg::DefaultHint{"chain tip"}, "The hash of the block that ends the window."}, }, RPCResult{ RPCResult::Type::OBJ, "", "", @@ -1679,20 +1725,21 @@ static RPCHelpMan getchaintxstats() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { + ChainstateManager& chainman = EnsureAnyChainman(request.context); const CBlockIndex* pindex; int blockcount = 30 * 24 * 60 * 60 / Params().GetConsensus().nPowTargetSpacing; // By default: 1 month if (request.params[1].isNull()) { LOCK(cs_main); - pindex = ::ChainActive().Tip(); + pindex = chainman.ActiveChain().Tip(); } else { uint256 hash(ParseHashV(request.params[1], "blockhash")); LOCK(cs_main); - pindex = g_chainman.m_blockman.LookupBlockIndex(hash); + pindex = chainman.m_blockman.LookupBlockIndex(hash); if (!pindex) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); } - if (!::ChainActive().Contains(pindex)) { + if (!chainman.ActiveChain().Contains(pindex)) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Block is not in main chain"); } } @@ -1805,7 +1852,7 @@ static RPCHelpMan getblockstats() "It won't work for some heights with pruning.\n", { {"hash_or_height", RPCArg::Type::NUM, RPCArg::Optional::NO, "The block hash or height of the target block", "", {"", "string or numeric"}}, - {"stats", RPCArg::Type::ARR, /* default */ "all values", "Values to plot (see result below)", + {"stats", RPCArg::Type::ARR, RPCArg::DefaultHint{"all values"}, "Values to plot (see result below)", { {"height", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Selected statistic"}, {"time", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Selected statistic"}, @@ -1860,12 +1907,14 @@ static RPCHelpMan getblockstats() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { + ChainstateManager& chainman = EnsureAnyChainman(request.context); LOCK(cs_main); + CChain& active_chain = chainman.ActiveChain(); CBlockIndex* pindex; if (request.params[0].isNum()) { const int height = request.params[0].get_int(); - const int current_tip = ::ChainActive().Height(); + const int current_tip = active_chain.Height(); if (height < 0) { throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Target block height %d is negative", height)); } @@ -1873,14 +1922,14 @@ static RPCHelpMan getblockstats() throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Target block height %d after current tip %d", height, current_tip)); } - pindex = ::ChainActive()[height]; + pindex = active_chain[height]; } else { const uint256 hash(ParseHashV(request.params[0], "hash_or_height")); - pindex = g_chainman.m_blockman.LookupBlockIndex(hash); + pindex = chainman.m_blockman.LookupBlockIndex(hash); if (!pindex) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); } - if (!::ChainActive().Contains(pindex)) { + if (!active_chain.Contains(pindex)) { throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Block is not in chain %s", Params().NetworkIDString())); } } @@ -2071,7 +2120,7 @@ static RPCHelpMan savemempool() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - const CTxMemPool& mempool = EnsureMemPool(request.context); + const CTxMemPool& mempool = EnsureAnyMemPool(request.context); if (!mempool.IsLoaded()) { throw JSONRPCError(RPC_MISC_ERROR, "The mempool was not loaded yet"); @@ -2172,7 +2221,7 @@ static RPCHelpMan scantxoutset() {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "An object with output descriptor and metadata", { {"desc", RPCArg::Type::STR, RPCArg::Optional::NO, "An output descriptor"}, - {"range", RPCArg::Type::RANGE, /* default */ "1000", "The range of HD chain indexes to explore (either end or [begin,end])"}, + {"range", RPCArg::Type::RANGE, RPCArg::Default{1000}, "The range of HD chain indexes to explore (either end or [begin,end])"}, }}, }, "[scanobjects,...]"}, @@ -2261,15 +2310,17 @@ static RPCHelpMan scantxoutset() int64_t count = 0; std::unique_ptr<CCoinsViewCursor> pcursor; CBlockIndex* tip; + NodeContext& node = EnsureAnyNodeContext(request.context); { + ChainstateManager& chainman = EnsureChainman(node); LOCK(cs_main); - ::ChainstateActive().ForceFlushStateToDisk(); - pcursor = std::unique_ptr<CCoinsViewCursor>(::ChainstateActive().CoinsDB().Cursor()); + CChainState& active_chainstate = chainman.ActiveChainstate(); + active_chainstate.ForceFlushStateToDisk(); + pcursor = std::unique_ptr<CCoinsViewCursor>(active_chainstate.CoinsDB().Cursor()); CHECK_NONFATAL(pcursor); - tip = ::ChainActive().Tip(); + tip = active_chainstate.m_chain.Tip(); CHECK_NONFATAL(tip); } - NodeContext& node = EnsureNodeContext(request.context); bool res = FindScriptPubKey(g_scan_progress, g_should_abort_scan, count, pcursor.get(), needles, coins, node.rpc_interruption_point); result.pushKV("success", res); result.pushKV("txouts", count); @@ -2309,7 +2360,7 @@ static RPCHelpMan getblockfilter() "\nRetrieve a BIP 157 content filter for a particular block.\n", { {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hash of the block"}, - {"filtertype", RPCArg::Type::STR, /*default*/ "basic", "The type name of the filter"}, + {"filtertype", RPCArg::Type::STR, RPCArg::Default{"basic"}, "The type name of the filter"}, }, RPCResult{ RPCResult::Type::OBJ, "", "", @@ -2342,8 +2393,9 @@ static RPCHelpMan getblockfilter() const CBlockIndex* block_index; bool block_was_connected; { + ChainstateManager& chainman = EnsureAnyChainman(request.context); LOCK(cs_main); - block_index = g_chainman.m_blockman.LookupBlockIndex(block_hash); + block_index = chainman.m_blockman.LookupBlockIndex(block_hash); if (!block_index) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); } @@ -2426,7 +2478,7 @@ static RPCHelpMan dumptxoutset() FILE* file{fsbridge::fopen(temppath, "wb")}; CAutoFile afile{file, SER_DISK, CLIENT_VERSION}; - NodeContext& node = EnsureNodeContext(request.context); + NodeContext& node = EnsureAnyNodeContext(request.context); UniValue result = CreateUTXOSnapshot(node, node.chainman->ActiveChainstate(), afile); fs::rename(temppath, path); @@ -2464,7 +2516,7 @@ UniValue CreateUTXOSnapshot(NodeContext& node, CChainState& chainstate, CAutoFil } pcursor = std::unique_ptr<CCoinsViewCursor>(chainstate.CoinsDB().Cursor()); - tip = g_chainman.m_blockman.LookupBlockIndex(stats.hashBlock); + tip = chainstate.m_blockman.LookupBlockIndex(stats.hashBlock); CHECK_NONFATAL(tip); } diff --git a/src/rpc/blockchain.h b/src/rpc/blockchain.h index cd04c9a10f..ffb6f03b47 100644 --- a/src/rpc/blockchain.h +++ b/src/rpc/blockchain.h @@ -56,10 +56,13 @@ void CalculatePercentilesByWeight(CAmount result[NUM_GETBLOCKSTATS_PERCENTILES], void ScriptPubKeyToUniv(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex); void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex = true, int serialize_flags = 0, const CTxUndo* txundo = nullptr); -NodeContext& EnsureNodeContext(const std::any& context); -CTxMemPool& EnsureMemPool(const std::any& context); -ChainstateManager& EnsureChainman(const std::any& context); -CBlockPolicyEstimator& EnsureFeeEstimator(const std::any& context); +NodeContext& EnsureAnyNodeContext(const std::any& context); +CTxMemPool& EnsureMemPool(const NodeContext& node); +CTxMemPool& EnsureAnyMemPool(const std::any& context); +ChainstateManager& EnsureChainman(const NodeContext& node); +ChainstateManager& EnsureAnyChainman(const std::any& context); +CBlockPolicyEstimator& EnsureFeeEstimator(const NodeContext& node); +CBlockPolicyEstimator& EnsureAnyFeeEstimator(const std::any& context); /** * Helper to create UTXO snapshots given a chainstate and a file handle. diff --git a/src/rpc/external_signer.cpp b/src/rpc/external_signer.cpp index 0f8f197ad8..6ec2b1a07f 100644 --- a/src/rpc/external_signer.cpp +++ b/src/rpc/external_signer.cpp @@ -9,6 +9,9 @@ #include <util/strencodings.h> #include <rpc/protocol.h> +#include <string> +#include <vector> + #ifdef ENABLE_EXTERNAL_SIGNER static RPCHelpMan enumeratesigners() @@ -35,18 +38,18 @@ static RPCHelpMan enumeratesigners() { const std::string command = gArgs.GetArg("-signer", ""); if (command == "") throw JSONRPCError(RPC_MISC_ERROR, "Error: restart bitcoind with -signer=<cmd>"); - std::string chain = gArgs.GetChainName(); + const std::string chain = gArgs.GetChainName(); UniValue signers_res = UniValue::VARR; try { std::vector<ExternalSigner> signers; ExternalSigner::Enumerate(command, signers, chain); - for (ExternalSigner signer : signers) { + for (const ExternalSigner& signer : signers) { UniValue signer_res = UniValue::VOBJ; signer_res.pushKV("fingerprint", signer.m_fingerprint); signer_res.pushKV("name", signer.m_name); signers_res.push_back(signer_res); } - } catch (const ExternalSignerException& e) { + } catch (const std::exception& e) { throw JSONRPCError(RPC_MISC_ERROR, e.what()); } UniValue result(UniValue::VOBJ); diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 72ad0df199..f7cf1a7851 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -18,6 +18,7 @@ #include <pow.h> #include <rpc/blockchain.h> #include <rpc/mining.h> +#include <rpc/net.h> #include <rpc/server.h> #include <rpc/util.h> #include <script/descriptor.h> @@ -44,11 +45,12 @@ * or from the last difficulty change if 'lookup' is nonpositive. * If 'height' is nonnegative, compute the estimate at the time when a given block was found. */ -static UniValue GetNetworkHashPS(int lookup, int height) { - CBlockIndex *pb = ::ChainActive().Tip(); +static UniValue GetNetworkHashPS(int lookup, int height, const CChain& active_chain) { + const CBlockIndex* pb = active_chain.Tip(); - if (height >= 0 && height < ::ChainActive().Height()) - pb = ::ChainActive()[height]; + if (height >= 0 && height < active_chain.Height()) { + pb = active_chain[height]; + } if (pb == nullptr || !pb->nHeight) return 0; @@ -61,7 +63,7 @@ static UniValue GetNetworkHashPS(int lookup, int height) { if (lookup > pb->nHeight) lookup = pb->nHeight; - CBlockIndex *pb0 = pb; + const CBlockIndex* pb0 = pb; int64_t minTime = pb0->GetBlockTime(); int64_t maxTime = minTime; for (int i = 0; i < lookup; i++) { @@ -88,8 +90,8 @@ static RPCHelpMan getnetworkhashps() "Pass in [blocks] to override # of blocks, -1 specifies since last difficulty change.\n" "Pass in [height] to estimate the network speed at the time when a certain block was found.\n", { - {"nblocks", RPCArg::Type::NUM, /* default */ "120", "The number of blocks, or -1 for blocks since last difficulty change."}, - {"height", RPCArg::Type::NUM, /* default */ "-1", "To estimate at the time of the given height."}, + {"nblocks", RPCArg::Type::NUM, RPCArg::Default{120}, "The number of blocks, or -1 for blocks since last difficulty change."}, + {"height", RPCArg::Type::NUM, RPCArg::Default{-1}, "To estimate at the time of the given height."}, }, RPCResult{ RPCResult::Type::NUM, "", "Hashes per second estimated"}, @@ -99,8 +101,9 @@ static RPCHelpMan getnetworkhashps() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { + ChainstateManager& chainman = EnsureAnyChainman(request.context); LOCK(cs_main); - return GetNetworkHashPS(!request.params[0].isNull() ? request.params[0].get_int() : 120, !request.params[1].isNull() ? request.params[1].get_int() : -1); + return GetNetworkHashPS(!request.params[0].isNull() ? request.params[0].get_int() : 120, !request.params[1].isNull() ? request.params[1].get_int() : -1, chainman.ActiveChain()); }, }; } @@ -111,7 +114,8 @@ static bool GenerateBlock(ChainstateManager& chainman, CBlock& block, uint64_t& { LOCK(cs_main); - IncrementExtraNonce(&block, ::ChainActive().Tip(), extra_nonce); + CHECK_NONFATAL(std::addressof(::ChainActive()) == std::addressof(chainman.ActiveChain())); + IncrementExtraNonce(&block, chainman.ActiveChain().Tip(), extra_nonce); } CChainParams chainparams(Params()); @@ -143,7 +147,8 @@ static UniValue generateBlocks(ChainstateManager& chainman, const CTxMemPool& me { // Don't keep cs_main locked LOCK(cs_main); - nHeight = ::ChainActive().Height(); + CHECK_NONFATAL(std::addressof(::ChainActive()) == std::addressof(chainman.ActiveChain())); + nHeight = chainman.ActiveChain().Height(); nHeightEnd = nHeight+nGenerate; } unsigned int nExtraNonce = 0; @@ -210,7 +215,7 @@ static RPCHelpMan generatetodescriptor() { {"num_blocks", RPCArg::Type::NUM, RPCArg::Optional::NO, "How many blocks are generated immediately."}, {"descriptor", RPCArg::Type::STR, RPCArg::Optional::NO, "The descriptor to send the newly generated bitcoin to."}, - {"maxtries", RPCArg::Type::NUM, /* default */ ToString(DEFAULT_MAX_TRIES), "How many iterations to try."}, + {"maxtries", RPCArg::Type::NUM, RPCArg::Default{DEFAULT_MAX_TRIES}, "How many iterations to try."}, }, RPCResult{ RPCResult::Type::ARR, "", "hashes of blocks generated", @@ -231,8 +236,9 @@ static RPCHelpMan generatetodescriptor() throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, error); } - const CTxMemPool& mempool = EnsureMemPool(request.context); - ChainstateManager& chainman = EnsureChainman(request.context); + NodeContext& node = EnsureAnyNodeContext(request.context); + const CTxMemPool& mempool = EnsureMemPool(node); + ChainstateManager& chainman = EnsureChainman(node); return generateBlocks(chainman, mempool, coinbase_script, num_blocks, max_tries); }, @@ -253,7 +259,7 @@ static RPCHelpMan generatetoaddress() { {"nblocks", RPCArg::Type::NUM, RPCArg::Optional::NO, "How many blocks are generated immediately."}, {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The address to send the newly generated bitcoin to."}, - {"maxtries", RPCArg::Type::NUM, /* default */ ToString(DEFAULT_MAX_TRIES), "How many iterations to try."}, + {"maxtries", RPCArg::Type::NUM, RPCArg::Default{DEFAULT_MAX_TRIES}, "How many iterations to try."}, }, RPCResult{ RPCResult::Type::ARR, "", "hashes of blocks generated", @@ -276,8 +282,9 @@ static RPCHelpMan generatetoaddress() throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Error: Invalid address"); } - const CTxMemPool& mempool = EnsureMemPool(request.context); - ChainstateManager& chainman = EnsureChainman(request.context); + NodeContext& node = EnsureAnyNodeContext(request.context); + const CTxMemPool& mempool = EnsureMemPool(node); + ChainstateManager& chainman = EnsureChainman(node); CScript coinbase_script = GetScriptForDestination(destination); @@ -325,7 +332,8 @@ static RPCHelpMan generateblock() coinbase_script = GetScriptForDestination(destination); } - const CTxMemPool& mempool = EnsureMemPool(request.context); + NodeContext& node = EnsureAnyNodeContext(request.context); + const CTxMemPool& mempool = EnsureMemPool(node); std::vector<CTransactionRef> txs; const auto raw_txs_or_txids = request.params[1].get_array(); @@ -354,11 +362,12 @@ static RPCHelpMan generateblock() CChainParams chainparams(Params()); CBlock block; + ChainstateManager& chainman = EnsureChainman(node); { LOCK(cs_main); CTxMemPool empty_mempool; - std::unique_ptr<CBlockTemplate> blocktemplate(BlockAssembler(::ChainstateActive(), empty_mempool, chainparams).CreateNewBlock(coinbase_script)); + std::unique_ptr<CBlockTemplate> blocktemplate(BlockAssembler(chainman.ActiveChainstate(), empty_mempool, chainparams).CreateNewBlock(coinbase_script)); if (!blocktemplate) { throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block"); } @@ -369,13 +378,14 @@ static RPCHelpMan generateblock() // Add transactions block.vtx.insert(block.vtx.end(), txs.begin(), txs.end()); - RegenerateCommitments(block, WITH_LOCK(::cs_main, return std::ref(g_chainman.m_blockman))); + CBlockIndex* prev_block = WITH_LOCK(::cs_main, return chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock)); + RegenerateCommitments(block, prev_block); { LOCK(cs_main); BlockValidationState state; - if (!TestBlockValidity(state, chainparams, ::ChainstateActive(), block, g_chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock), false, false)) { + if (!TestBlockValidity(state, chainparams, chainman.ActiveChainstate(), block, chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock), false, false)) { throw JSONRPCError(RPC_VERIFY_ERROR, strprintf("TestBlockValidity failed: %s", state.ToString())); } } @@ -384,7 +394,7 @@ static RPCHelpMan generateblock() uint64_t max_tries{DEFAULT_MAX_TRIES}; unsigned int extra_nonce{0}; - if (!GenerateBlock(EnsureChainman(request.context), block, max_tries, extra_nonce, block_hash) || block_hash.IsNull()) { + if (!GenerateBlock(chainman, block, max_tries, extra_nonce, block_hash) || block_hash.IsNull()) { throw JSONRPCError(RPC_MISC_ERROR, "Failed to make block."); } @@ -418,14 +428,17 @@ static RPCHelpMan getmininginfo() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { + NodeContext& node = EnsureAnyNodeContext(request.context); + const CTxMemPool& mempool = EnsureMemPool(node); + ChainstateManager& chainman = EnsureChainman(node); LOCK(cs_main); - const CTxMemPool& mempool = EnsureMemPool(request.context); + const CChain& active_chain = chainman.ActiveChain(); UniValue obj(UniValue::VOBJ); - obj.pushKV("blocks", (int)::ChainActive().Height()); + obj.pushKV("blocks", active_chain.Height()); if (BlockAssembler::m_last_block_weight) obj.pushKV("currentblockweight", *BlockAssembler::m_last_block_weight); if (BlockAssembler::m_last_block_num_txs) obj.pushKV("currentblocktx", *BlockAssembler::m_last_block_num_txs); - obj.pushKV("difficulty", (double)GetDifficulty(::ChainActive().Tip())); + obj.pushKV("difficulty", (double)GetDifficulty(active_chain.Tip())); obj.pushKV("networkhashps", getnetworkhashps().HandleRequest(request)); obj.pushKV("pooledtx", (uint64_t)mempool.size()); obj.pushKV("chain", Params().NetworkIDString()); @@ -467,7 +480,7 @@ static RPCHelpMan prioritisetransaction() throw JSONRPCError(RPC_INVALID_PARAMETER, "Priority is no longer supported, dummy argument to prioritisetransaction must be 0."); } - EnsureMemPool(request.context).PrioritiseTransaction(hash, nAmount); + EnsureAnyMemPool(request.context).PrioritiseTransaction(hash, nAmount); return true; }, }; @@ -513,7 +526,7 @@ static RPCHelpMan getblocktemplate() " https://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki#getblocktemplate_changes\n" " https://github.com/bitcoin/bips/blob/master/bip-0145.mediawiki\n", { - {"template_request", RPCArg::Type::OBJ, "{}", "Format of the template", + {"template_request", RPCArg::Type::OBJ, RPCArg::Default{UniValue::VOBJ}, "Format of the template", { {"mode", RPCArg::Type::STR, /* treat as named arg */ RPCArg::Optional::OMITTED_NAMED_ARG, "This must be set to \"template\", \"proposal\" (see BIP 23), or omitted"}, {"capabilities", RPCArg::Type::ARR, /* treat as named arg */ RPCArg::Optional::OMITTED_NAMED_ARG, "A list of strings", @@ -588,12 +601,16 @@ static RPCHelpMan getblocktemplate() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { + NodeContext& node = EnsureAnyNodeContext(request.context); + ChainstateManager& chainman = EnsureChainman(node); LOCK(cs_main); std::string strMode = "template"; UniValue lpval = NullUniValue; std::set<std::string> setClientRules; int64_t nMaxVersionPreVB = -1; + CChainState& active_chainstate = chainman.ActiveChainstate(); + CChain& active_chain = active_chainstate.m_chain; if (!request.params[0].isNull()) { const UniValue& oparam = request.params[0].get_obj(); @@ -619,7 +636,7 @@ static RPCHelpMan getblocktemplate() throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed"); uint256 hash = block.GetHash(); - const CBlockIndex* pindex = g_chainman.m_blockman.LookupBlockIndex(hash); + const CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(hash); if (pindex) { if (pindex->IsValid(BLOCK_VALID_SCRIPTS)) return "duplicate"; @@ -628,12 +645,12 @@ static RPCHelpMan getblocktemplate() return "duplicate-inconclusive"; } - CBlockIndex* const pindexPrev = ::ChainActive().Tip(); + CBlockIndex* const pindexPrev = active_chain.Tip(); // TestBlockValidity only supports blocks built on the current Tip if (block.hashPrevBlock != pindexPrev->GetBlockHash()) return "inconclusive-not-best-prevblk"; BlockValidationState state; - TestBlockValidity(state, Params(), ::ChainstateActive(), block, pindexPrev, false, true); + TestBlockValidity(state, Params(), active_chainstate, block, pindexPrev, false, true); return BIP22ValidationResult(state); } @@ -655,22 +672,19 @@ static RPCHelpMan getblocktemplate() if (strMode != "template") throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode"); - NodeContext& node = EnsureNodeContext(request.context); - if(!node.connman) - throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); - if (!Params().IsTestChain()) { - if (node.connman->GetNodeCount(ConnectionDirection::Both) == 0) { + const CConnman& connman = EnsureConnman(node); + if (connman.GetNodeCount(ConnectionDirection::Both) == 0) { throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, PACKAGE_NAME " is not connected!"); } - if (::ChainstateActive().IsInitialBlockDownload()) { + if (active_chainstate.IsInitialBlockDownload()) { throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, PACKAGE_NAME " is in initial sync and waiting for blocks..."); } } static unsigned int nTransactionsUpdatedLast; - const CTxMemPool& mempool = EnsureMemPool(request.context); + const CTxMemPool& mempool = EnsureMemPool(node); if (!lpval.isNull()) { @@ -690,7 +704,7 @@ static RPCHelpMan getblocktemplate() else { // NOTE: Spec does not specify behaviour for non-string longpollid, but this makes testing easier - hashWatchedChain = ::ChainActive().Tip()->GetBlockHash(); + hashWatchedChain = active_chain.Tip()->GetBlockHash(); nTransactionsUpdatedLastLP = nTransactionsUpdatedLast; } @@ -735,7 +749,7 @@ static RPCHelpMan getblocktemplate() static CBlockIndex* pindexPrev; static int64_t nStart; static std::unique_ptr<CBlockTemplate> pblocktemplate; - if (pindexPrev != ::ChainActive().Tip() || + if (pindexPrev != active_chain.Tip() || (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 5)) { // Clear pindexPrev so future calls make a new block, despite any failures from here on @@ -743,12 +757,12 @@ static RPCHelpMan getblocktemplate() // Store the pindexBest used before CreateNewBlock, to avoid races nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); - CBlockIndex* pindexPrevNew = ::ChainActive().Tip(); + CBlockIndex* pindexPrevNew = active_chain.Tip(); nStart = GetTime(); // Create new block CScript scriptDummy = CScript() << OP_TRUE; - pblocktemplate = BlockAssembler(::ChainstateActive(), mempool, Params()).CreateNewBlock(scriptDummy); + pblocktemplate = BlockAssembler(active_chainstate, mempool, Params()).CreateNewBlock(scriptDummy); if (!pblocktemplate) throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory"); @@ -884,7 +898,7 @@ static RPCHelpMan getblocktemplate() result.pushKV("transactions", transactions); result.pushKV("coinbaseaux", aux); result.pushKV("coinbasevalue", (int64_t)pblock->vtx[0]->vout[0].nValue); - result.pushKV("longpollid", ::ChainActive().Tip()->GetBlockHash().GetHex() + ToString(nTransactionsUpdatedLast)); + result.pushKV("longpollid", active_chain.Tip()->GetBlockHash().GetHex() + ToString(nTransactionsUpdatedLast)); result.pushKV("target", hashTarget.GetHex()); result.pushKV("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1); result.pushKV("mutable", aMutable); @@ -945,7 +959,7 @@ static RPCHelpMan submitblock() "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.\n", { {"hexdata", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hex-encoded block data to submit"}, - {"dummy", RPCArg::Type::STR, /* default */ "ignored", "dummy value, for compatibility with BIP22. This value is ignored."}, + {"dummy", RPCArg::Type::STR, RPCArg::DefaultHint{"ignored"}, "dummy value, for compatibility with BIP22. This value is ignored."}, }, { RPCResult{"If the block was accepted", RPCResult::Type::NONE, "", ""}, @@ -967,10 +981,11 @@ static RPCHelpMan submitblock() throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block does not start with a coinbase"); } + ChainstateManager& chainman = EnsureAnyChainman(request.context); uint256 hash = block.GetHash(); { LOCK(cs_main); - const CBlockIndex* pindex = g_chainman.m_blockman.LookupBlockIndex(hash); + const CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(hash); if (pindex) { if (pindex->IsValid(BLOCK_VALID_SCRIPTS)) { return "duplicate"; @@ -983,7 +998,7 @@ static RPCHelpMan submitblock() { LOCK(cs_main); - const CBlockIndex* pindex = g_chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock); + const CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock); if (pindex) { UpdateUncommittedBlockStructures(block, pindex, Params().GetConsensus()); } @@ -992,7 +1007,7 @@ static RPCHelpMan submitblock() bool new_block; auto sc = std::make_shared<submitblock_StateCatcher>(block.GetHash()); RegisterSharedValidationInterface(sc); - bool accepted = EnsureChainman(request.context).ProcessNewBlock(Params(), blockptr, /* fForceProcessing */ true, /* fNewBlock */ &new_block); + bool accepted = chainman.ProcessNewBlock(Params(), blockptr, /* fForceProcessing */ true, /* fNewBlock */ &new_block); UnregisterSharedValidationInterface(sc); if (!new_block && accepted) { return "duplicate"; @@ -1025,15 +1040,16 @@ static RPCHelpMan submitheader() if (!DecodeHexBlockHeader(h, request.params[0].get_str())) { throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block header decode failed"); } + ChainstateManager& chainman = EnsureAnyChainman(request.context); { LOCK(cs_main); - if (!g_chainman.m_blockman.LookupBlockIndex(h.hashPrevBlock)) { + if (!chainman.m_blockman.LookupBlockIndex(h.hashPrevBlock)) { throw JSONRPCError(RPC_VERIFY_ERROR, "Must submit previous header (" + h.hashPrevBlock.GetHex() + ") first"); } } BlockValidationState state; - EnsureChainman(request.context).ProcessNewBlockHeaders({h}, state, Params()); + chainman.ProcessNewBlockHeaders({h}, state, Params()); if (state.IsValid()) return NullUniValue; if (state.IsError()) { throw JSONRPCError(RPC_VERIFY_ERROR, state.ToString()); @@ -1052,7 +1068,7 @@ static RPCHelpMan estimatesmartfee() "in BIP 141 (witness data is discounted).\n", { {"conf_target", RPCArg::Type::NUM, RPCArg::Optional::NO, "Confirmation target in blocks (1 - 1008)"}, - {"estimate_mode", RPCArg::Type::STR, /* default */ "conservative", "The fee estimate mode.\n" + {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"conservative"}, "The fee estimate mode.\n" " Whether to return a more conservative estimate which also satisfies\n" " a longer history. A conservative estimate potentially returns a\n" " higher feerate and is more likely to be sufficient for the desired\n" @@ -1082,7 +1098,7 @@ static RPCHelpMan estimatesmartfee() RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VSTR}); RPCTypeCheckArgument(request.params[0], UniValue::VNUM); - CBlockPolicyEstimator& fee_estimator = EnsureFeeEstimator(request.context); + CBlockPolicyEstimator& fee_estimator = EnsureAnyFeeEstimator(request.context); unsigned int max_target = fee_estimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE); unsigned int conf_target = ParseConfirmTarget(request.params[0], max_target); @@ -1123,7 +1139,7 @@ static RPCHelpMan estimaterawfee() "defined in BIP 141 (witness data is discounted).\n", { {"conf_target", RPCArg::Type::NUM, RPCArg::Optional::NO, "Confirmation target in blocks (1 - 1008)"}, - {"threshold", RPCArg::Type::NUM, /* default */ "0.95", "The proportion of transactions in a given feerate range that must have been\n" + {"threshold", RPCArg::Type::NUM, RPCArg::Default{0.95}, "The proportion of transactions in a given feerate range that must have been\n" " confirmed within conf_target in order to consider those feerates as high enough and proceed to check\n" " lower buckets."}, }, @@ -1170,7 +1186,7 @@ static RPCHelpMan estimaterawfee() RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VNUM}, true); RPCTypeCheckArgument(request.params[0], UniValue::VNUM); - CBlockPolicyEstimator& fee_estimator = EnsureFeeEstimator(request.context); + CBlockPolicyEstimator& fee_estimator = EnsureAnyFeeEstimator(request.context); unsigned int max_target = fee_estimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE); unsigned int conf_target = ParseConfirmTarget(request.params[0], max_target); diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index 8e98919391..00a06260ea 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -90,7 +90,7 @@ static RPCHelpMan createmultisig() { {"key", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "The hex-encoded public key"}, }}, - {"address_type", RPCArg::Type::STR, /* default */ "legacy", "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."}, + {"address_type", RPCArg::Type::STR, RPCArg::Default{"legacy"}, "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."}, }, RPCResult{ RPCResult::Type::OBJ, "", "", @@ -475,7 +475,7 @@ static RPCHelpMan getmemoryinfo() return RPCHelpMan{"getmemoryinfo", "Returns an object containing information about memory usage.\n", { - {"mode", RPCArg::Type::STR, /* default */ "\"stats\"", "determines what kind of information is returned.\n" + {"mode", RPCArg::Type::STR, RPCArg::Default{"stats"}, "determines what kind of information is returned.\n" " - \"stats\" returns general statistics about memory usage in the daemon.\n" " - \"mallocinfo\" returns an XML string describing low-level heap state (only available if compiled with glibc 2.10+)."}, }, diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 337f861903..2bfcaeafc9 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -39,6 +39,22 @@ const std::vector<std::string> CONNECTION_TYPE_DOC{ "feeler (short-lived automatic connection for testing addresses)" }; +CConnman& EnsureConnman(const NodeContext& node) +{ + if (!node.connman) { + throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); + } + return *node.connman; +} + +PeerManager& EnsurePeerman(const NodeContext& node) +{ + if (!node.peerman) { + throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); + } + return *node.peerman; +} + static RPCHelpMan getconnectioncount() { return RPCHelpMan{"getconnectioncount", @@ -53,11 +69,10 @@ static RPCHelpMan getconnectioncount() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - NodeContext& node = EnsureNodeContext(request.context); - if(!node.connman) - throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); + NodeContext& node = EnsureAnyNodeContext(request.context); + const CConnman& connman = EnsureConnman(node); - return (int)node.connman->GetNodeCount(ConnectionDirection::Both); + return (int)connman.GetNodeCount(ConnectionDirection::Both); }, }; } @@ -76,13 +91,11 @@ static RPCHelpMan ping() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - NodeContext& node = EnsureNodeContext(request.context); - if (!node.peerman) { - throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); - } + NodeContext& node = EnsureAnyNodeContext(request.context); + PeerManager& peerman = EnsurePeerman(node); // Request that each node send a ping during next message processing pass - node.peerman->SendPings(); + peerman.SendPings(); return NullUniValue; }, }; @@ -165,20 +178,19 @@ static RPCHelpMan getpeerinfo() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - NodeContext& node = EnsureNodeContext(request.context); - if(!node.connman || !node.peerman) { - throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); - } + NodeContext& node = EnsureAnyNodeContext(request.context); + const CConnman& connman = EnsureConnman(node); + const PeerManager& peerman = EnsurePeerman(node); std::vector<CNodeStats> vstats; - node.connman->GetNodeStats(vstats); + connman.GetNodeStats(vstats); UniValue ret(UniValue::VARR); for (const CNodeStats& stats : vstats) { UniValue obj(UniValue::VOBJ); CNodeStateStats statestats; - bool fStateStats = node.peerman->GetNodeStateStats(stats.nodeid, statestats); + bool fStateStats = peerman.GetNodeStateStats(stats.nodeid, statestats); obj.pushKV("id", stats.nodeid); obj.pushKV("addr", stats.addrName); if (stats.addrBind.IsValid()) { @@ -285,28 +297,29 @@ static RPCHelpMan addnode() self.ToString()); } - NodeContext& node = EnsureNodeContext(request.context); - if(!node.connman) - throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); + NodeContext& node = EnsureAnyNodeContext(request.context); + CConnman& connman = EnsureConnman(node); std::string strNode = request.params[0].get_str(); if (strCommand == "onetry") { CAddress addr; - node.connman->OpenNetworkConnection(addr, false, nullptr, strNode.c_str(), ConnectionType::MANUAL); + connman.OpenNetworkConnection(addr, false, nullptr, strNode.c_str(), ConnectionType::MANUAL); return NullUniValue; } if (strCommand == "add") { - if(!node.connman->AddNode(strNode)) + if (!connman.AddNode(strNode)) { throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: Node already added"); + } } else if(strCommand == "remove") { - if(!node.connman->RemoveAddedNode(strNode)) + if (!connman.RemoveAddedNode(strNode)) { throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, "Error: Node could not be removed. It has not been added previously."); + } } return NullUniValue; @@ -350,12 +363,10 @@ static RPCHelpMan addconnection() throw JSONRPCError(RPC_INVALID_PARAMETER, self.ToString()); } - NodeContext& node = EnsureNodeContext(request.context); - if (!node.connman) { - throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled."); - } + NodeContext& node = EnsureAnyNodeContext(request.context); + CConnman& connman = EnsureConnman(node); - const bool success = node.connman->AddConnection(address, conn_type); + const bool success = connman.AddConnection(address, conn_type); if (!success) { throw JSONRPCError(RPC_CLIENT_NODE_CAPACITY_REACHED, "Error: Already at capacity for specified connection type."); } @@ -376,8 +387,8 @@ static RPCHelpMan disconnectnode() "\nStrictly one out of 'address' and 'nodeid' can be provided to identify the node.\n" "\nTo disconnect by nodeid, either set 'address' to the empty string, or call using the named 'nodeid' argument only.\n", { - {"address", RPCArg::Type::STR, /* default */ "fallback to nodeid", "The IP address/port of the node"}, - {"nodeid", RPCArg::Type::NUM, /* default */ "fallback to address", "The node ID (see getpeerinfo for node IDs)"}, + {"address", RPCArg::Type::STR, RPCArg::DefaultHint{"fallback to nodeid"}, "The IP address/port of the node"}, + {"nodeid", RPCArg::Type::NUM, RPCArg::DefaultHint{"fallback to address"}, "The node ID (see getpeerinfo for node IDs)"}, }, RPCResult{RPCResult::Type::NONE, "", ""}, RPCExamples{ @@ -388,9 +399,8 @@ static RPCHelpMan disconnectnode() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - NodeContext& node = EnsureNodeContext(request.context); - if(!node.connman) - throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); + NodeContext& node = EnsureAnyNodeContext(request.context); + CConnman& connman = EnsureConnman(node); bool success; const UniValue &address_arg = request.params[0]; @@ -398,11 +408,11 @@ static RPCHelpMan disconnectnode() if (!address_arg.isNull() && id_arg.isNull()) { /* handle disconnect-by-address */ - success = node.connman->DisconnectNode(address_arg.get_str()); + success = connman.DisconnectNode(address_arg.get_str()); } else if (!id_arg.isNull() && (address_arg.isNull() || (address_arg.isStr() && address_arg.get_str().empty()))) { /* handle disconnect-by-id */ NodeId nodeid = (NodeId) id_arg.get_int64(); - success = node.connman->DisconnectNode(nodeid); + success = connman.DisconnectNode(nodeid); } else { throw JSONRPCError(RPC_INVALID_PARAMS, "Only one of address and nodeid should be provided."); } @@ -422,7 +432,7 @@ static RPCHelpMan getaddednodeinfo() "\nReturns information about the given added node, or all added nodes\n" "(note that onetry addnodes are not listed here)\n", { - {"node", RPCArg::Type::STR, /* default */ "all nodes", "If provided, return information about this specific node, otherwise all nodes are returned."}, + {"node", RPCArg::Type::STR, RPCArg::DefaultHint{"all nodes"}, "If provided, return information about this specific node, otherwise all nodes are returned."}, }, RPCResult{ RPCResult::Type::ARR, "", "", @@ -448,11 +458,10 @@ static RPCHelpMan getaddednodeinfo() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - NodeContext& node = EnsureNodeContext(request.context); - if(!node.connman) - throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); + NodeContext& node = EnsureAnyNodeContext(request.context); + const CConnman& connman = EnsureConnman(node); - std::vector<AddedNodeInfo> vInfo = node.connman->GetAddedNodeInfo(); + std::vector<AddedNodeInfo> vInfo = connman.GetAddedNodeInfo(); if (!request.params[0].isNull()) { bool found = false; @@ -519,22 +528,21 @@ static RPCHelpMan getnettotals() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - NodeContext& node = EnsureNodeContext(request.context); - if(!node.connman) - throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); + NodeContext& node = EnsureAnyNodeContext(request.context); + const CConnman& connman = EnsureConnman(node); UniValue obj(UniValue::VOBJ); - obj.pushKV("totalbytesrecv", node.connman->GetTotalBytesRecv()); - obj.pushKV("totalbytessent", node.connman->GetTotalBytesSent()); + obj.pushKV("totalbytesrecv", connman.GetTotalBytesRecv()); + obj.pushKV("totalbytessent", connman.GetTotalBytesSent()); obj.pushKV("timemillis", GetTimeMillis()); UniValue outboundLimit(UniValue::VOBJ); - outboundLimit.pushKV("timeframe", count_seconds(node.connman->GetMaxOutboundTimeframe())); - outboundLimit.pushKV("target", node.connman->GetMaxOutboundTarget()); - outboundLimit.pushKV("target_reached", node.connman->OutboundTargetReached(false)); - outboundLimit.pushKV("serve_historical_blocks", !node.connman->OutboundTargetReached(true)); - outboundLimit.pushKV("bytes_left_in_cycle", node.connman->GetOutboundTargetBytesLeft()); - outboundLimit.pushKV("time_left_in_cycle", count_seconds(node.connman->GetMaxOutboundTimeLeftInCycle())); + outboundLimit.pushKV("timeframe", count_seconds(connman.GetMaxOutboundTimeframe())); + outboundLimit.pushKV("target", connman.GetMaxOutboundTarget()); + outboundLimit.pushKV("target_reached", connman.OutboundTargetReached(false)); + outboundLimit.pushKV("serve_historical_blocks", !connman.OutboundTargetReached(true)); + outboundLimit.pushKV("bytes_left_in_cycle", connman.GetOutboundTargetBytesLeft()); + outboundLimit.pushKV("time_left_in_cycle", count_seconds(connman.GetMaxOutboundTimeLeftInCycle())); obj.pushKV("uploadtarget", outboundLimit); return obj; }, @@ -618,7 +626,7 @@ static RPCHelpMan getnetworkinfo() obj.pushKV("version", CLIENT_VERSION); obj.pushKV("subversion", strSubVersion); obj.pushKV("protocolversion",PROTOCOL_VERSION); - NodeContext& node = EnsureNodeContext(request.context); + NodeContext& node = EnsureAnyNodeContext(request.context); if (node.connman) { ServiceFlags services = node.connman->GetLocalServices(); obj.pushKV("localservices", strprintf("%016x", services)); @@ -663,8 +671,8 @@ static RPCHelpMan setban() { {"subnet", RPCArg::Type::STR, RPCArg::Optional::NO, "The IP/Subnet (see getpeerinfo for nodes IP) with an optional netmask (default is /32 = single IP)"}, {"command", RPCArg::Type::STR, RPCArg::Optional::NO, "'add' to add an IP/Subnet to the list, 'remove' to remove an IP/Subnet from the list"}, - {"bantime", RPCArg::Type::NUM, /* default */ "0", "time in seconds how long (or until when if [absolute] is set) the IP is banned (0 or empty means using the default time of 24h which can also be overwritten by the -bantime startup argument)"}, - {"absolute", RPCArg::Type::BOOL, /* default */ "false", "If set, the bantime must be an absolute timestamp expressed in " + UNIX_EPOCH_TIME}, + {"bantime", RPCArg::Type::NUM, RPCArg::Default{0}, "time in seconds how long (or until when if [absolute] is set) the IP is banned (0 or empty means using the default time of 24h which can also be overwritten by the -bantime startup argument)"}, + {"absolute", RPCArg::Type::BOOL, RPCArg::Default{false}, "If set, the bantime must be an absolute timestamp expressed in " + UNIX_EPOCH_TIME}, }, RPCResult{RPCResult::Type::NONE, "", ""}, RPCExamples{ @@ -680,7 +688,7 @@ static RPCHelpMan setban() if (strCommand != "add" && strCommand != "remove") { throw std::runtime_error(help.ToString()); } - NodeContext& node = EnsureNodeContext(request.context); + NodeContext& node = EnsureAnyNodeContext(request.context); if (!node.banman) { throw JSONRPCError(RPC_DATABASE_ERROR, "Error: Ban database not loaded"); } @@ -762,7 +770,7 @@ static RPCHelpMan listbanned() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - NodeContext& node = EnsureNodeContext(request.context); + NodeContext& node = EnsureAnyNodeContext(request.context); if(!node.banman) { throw JSONRPCError(RPC_DATABASE_ERROR, "Error: Ban database not loaded"); } @@ -802,7 +810,7 @@ static RPCHelpMan clearbanned() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - NodeContext& node = EnsureNodeContext(request.context); + NodeContext& node = EnsureAnyNodeContext(request.context); if (!node.banman) { throw JSONRPCError(RPC_DATABASE_ERROR, "Error: Ban database not loaded"); } @@ -825,14 +833,12 @@ static RPCHelpMan setnetworkactive() RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - NodeContext& node = EnsureNodeContext(request.context); - if (!node.connman) { - throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); - } + NodeContext& node = EnsureAnyNodeContext(request.context); + CConnman& connman = EnsureConnman(node); - node.connman->SetNetworkActive(request.params[0].get_bool()); + connman.SetNetworkActive(request.params[0].get_bool()); - return node.connman->GetNetworkActive(); + return connman.GetNetworkActive(); }, }; } @@ -842,7 +848,7 @@ static RPCHelpMan getnodeaddresses() return RPCHelpMan{"getnodeaddresses", "\nReturn known addresses, which can potentially be used to find new nodes in the network.\n", { - {"count", RPCArg::Type::NUM, /* default */ "1", "The maximum number of addresses to return. Specify 0 to return all known addresses."}, + {"count", RPCArg::Type::NUM, RPCArg::Default{1}, "The maximum number of addresses to return. Specify 0 to return all known addresses."}, }, RPCResult{ RPCResult::Type::ARR, "", "", @@ -863,16 +869,14 @@ static RPCHelpMan getnodeaddresses() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - NodeContext& node = EnsureNodeContext(request.context); - if (!node.connman) { - throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); - } + NodeContext& node = EnsureAnyNodeContext(request.context); + const CConnman& connman = EnsureConnman(node); const int count{request.params[0].isNull() ? 1 : request.params[0].get_int()}; if (count < 0) throw JSONRPCError(RPC_INVALID_PARAMETER, "Address count out of range"); // returns a shuffled list of CAddress - const std::vector<CAddress> vAddr{node.connman->GetAddresses(count, /* max_pct */ 0)}; + const std::vector<CAddress> vAddr{connman.GetAddresses(count, /* max_pct */ 0)}; UniValue ret(UniValue::VARR); for (const CAddress& addr : vAddr) { @@ -909,7 +913,7 @@ static RPCHelpMan addpeeraddress() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - NodeContext& node = EnsureNodeContext(request.context); + NodeContext& node = EnsureAnyNodeContext(request.context); if (!node.addrman) { throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Address manager functionality missing or disabled"); } diff --git a/src/rpc/net.h b/src/rpc/net.h new file mode 100644 index 0000000000..7a4d8440ba --- /dev/null +++ b/src/rpc/net.h @@ -0,0 +1,15 @@ +// Copyright (c) 2021 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_RPC_NET_H +#define BITCOIN_RPC_NET_H + +class CConnman; +class PeerManager; +struct NodeContext; + +CConnman& EnsureConnman(const NodeContext& node); +PeerManager& EnsurePeerman(const NodeContext& node); + +#endif // BITCOIN_RPC_NET_H diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 7932bd2915..16ca3bb47d 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -10,6 +10,7 @@ #include <index/txindex.h> #include <key_io.h> #include <merkleblock.h> +#include <node/blockstorage.h> #include <node/coin.h> #include <node/context.h> #include <node/psbt.h> @@ -40,7 +41,7 @@ #include <univalue.h> -static void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry) +static void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry, CChainState& active_chainstate) { // Call into TxToUniv() in bitcoin-common to decode the transaction hex. // @@ -53,10 +54,10 @@ static void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& LOCK(cs_main); entry.pushKV("blockhash", hashBlock.GetHex()); - CBlockIndex* pindex = g_chainman.m_blockman.LookupBlockIndex(hashBlock); + CBlockIndex* pindex = active_chainstate.m_blockman.LookupBlockIndex(hashBlock); if (pindex) { - if (::ChainActive().Contains(pindex)) { - entry.pushKV("confirmations", 1 + ::ChainActive().Height() - pindex->nHeight); + if (active_chainstate.m_chain.Contains(pindex)) { + entry.pushKV("confirmations", 1 + active_chainstate.m_chain.Height() - pindex->nHeight); entry.pushKV("time", pindex->GetBlockTime()); entry.pushKV("blocktime", pindex->GetBlockTime()); } @@ -84,7 +85,7 @@ static RPCHelpMan getrawtransaction() "If verbose is 'false' or omitted, returns a string that is serialized, hex-encoded data for 'txid'.\n", { {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"}, - {"verbose", RPCArg::Type::BOOL, /* default */ "false", "If false, return a string, otherwise return a json object"}, + {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "If false, return a string, otherwise return a json object"}, {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED_NAMED_ARG, "The block in which to look for the transaction"}, }, { @@ -157,7 +158,8 @@ static RPCHelpMan getrawtransaction() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - const NodeContext& node = EnsureNodeContext(request.context); + const NodeContext& node = EnsureAnyNodeContext(request.context); + ChainstateManager& chainman = EnsureChainman(node); bool in_active_chain = true; uint256 hash = ParseHashV(request.params[0], "parameter 1"); @@ -178,11 +180,11 @@ static RPCHelpMan getrawtransaction() LOCK(cs_main); uint256 blockhash = ParseHashV(request.params[2], "parameter 3"); - blockindex = g_chainman.m_blockman.LookupBlockIndex(blockhash); + blockindex = chainman.m_blockman.LookupBlockIndex(blockhash); if (!blockindex) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block hash not found"); } - in_active_chain = ::ChainActive().Contains(blockindex); + in_active_chain = chainman.ActiveChain().Contains(blockindex); } bool f_txindex_ready = false; @@ -215,7 +217,7 @@ static RPCHelpMan getrawtransaction() UniValue result(UniValue::VOBJ); if (blockindex) result.pushKV("in_active_chain", in_active_chain); - TxToJSON(*tx, hash_block, result); + TxToJSON(*tx, hash_block, result, chainman.ActiveChainstate()); return result; }, }; @@ -257,21 +259,23 @@ static RPCHelpMan gettxoutproof() CBlockIndex* pblockindex = nullptr; uint256 hashBlock; + ChainstateManager& chainman = EnsureAnyChainman(request.context); if (!request.params[1].isNull()) { LOCK(cs_main); hashBlock = ParseHashV(request.params[1], "blockhash"); - pblockindex = g_chainman.m_blockman.LookupBlockIndex(hashBlock); + pblockindex = chainman.m_blockman.LookupBlockIndex(hashBlock); if (!pblockindex) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); } } else { LOCK(cs_main); + CChainState& active_chainstate = chainman.ActiveChainstate(); // Loop through txids and try to find which block they're in. Exit loop once a block is found. for (const auto& tx : setTxids) { - const Coin& coin = AccessByTxid(::ChainstateActive().CoinsTip(), tx); + const Coin& coin = AccessByTxid(active_chainstate.CoinsTip(), tx); if (!coin.IsSpent()) { - pblockindex = ::ChainActive()[coin.nHeight]; + pblockindex = active_chainstate.m_chain[coin.nHeight]; break; } } @@ -290,7 +294,7 @@ static RPCHelpMan gettxoutproof() if (!tx || hashBlock.IsNull()) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not yet in block"); } - pblockindex = g_chainman.m_blockman.LookupBlockIndex(hashBlock); + pblockindex = chainman.m_blockman.LookupBlockIndex(hashBlock); if (!pblockindex) { throw JSONRPCError(RPC_INTERNAL_ERROR, "Transaction index corrupt"); } @@ -348,10 +352,11 @@ static RPCHelpMan verifytxoutproof() if (merkleBlock.txn.ExtractMatches(vMatch, vIndex) != merkleBlock.header.hashMerkleRoot) return res; + ChainstateManager& chainman = EnsureAnyChainman(request.context); LOCK(cs_main); - const CBlockIndex* pindex = g_chainman.m_blockman.LookupBlockIndex(merkleBlock.header.GetHash()); - if (!pindex || !::ChainActive().Contains(pindex) || pindex->nTx == 0) { + const CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(merkleBlock.header.GetHash()); + if (!pindex || !chainman.ActiveChain().Contains(pindex) || pindex->nTx == 0) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found in chain"); } @@ -382,7 +387,7 @@ static RPCHelpMan createrawtransaction() { {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"}, {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"}, - {"sequence", RPCArg::Type::NUM, /* default */ "depends on the value of the 'replaceable' and 'locktime' arguments", "The sequence number"}, + {"sequence", RPCArg::Type::NUM, RPCArg::DefaultHint{"depends on the value of the 'replaceable' and 'locktime' arguments"}, "The sequence number"}, }, }, }, @@ -404,8 +409,8 @@ static RPCHelpMan createrawtransaction() }, }, }, - {"locktime", RPCArg::Type::NUM, /* default */ "0", "Raw locktime. Non-0 value also locktime-activates inputs"}, - {"replaceable", RPCArg::Type::BOOL, /* default */ "false", "Marks this transaction as BIP125-replaceable.\n" + {"locktime", RPCArg::Type::NUM, RPCArg::Default{0}, "Raw locktime. Non-0 value also locktime-activates inputs"}, + {"replaceable", RPCArg::Type::BOOL, RPCArg::Default{false}, "Marks this transaction as BIP125-replaceable.\n" " Allows this transaction to be replaced by a transaction with higher fees. If provided, it is an error if explicit sequence numbers are incompatible."}, }, RPCResult{ @@ -444,7 +449,7 @@ static RPCHelpMan decoderawtransaction() "\nReturn a JSON object representing the serialized, hex-encoded transaction.\n", { {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction hex string"}, - {"iswitness", RPCArg::Type::BOOL, /* default */ "depends on heuristic tests", "Whether the transaction hex is a serialized witness transaction.\n" + {"iswitness", RPCArg::Type::BOOL, RPCArg::DefaultHint{"depends on heuristic tests"}, "Whether the transaction hex is a serialized witness transaction.\n" "If iswitness is not present, heuristic tests will be used in decoding.\n" "If true, only witness deserialization will be tried.\n" "If false, only non-witness deserialization will be tried.\n" @@ -675,10 +680,11 @@ static RPCHelpMan combinerawtransaction() CCoinsView viewDummy; CCoinsViewCache view(&viewDummy); { - const CTxMemPool& mempool = EnsureMemPool(request.context); - LOCK(cs_main); - LOCK(mempool.cs); - CCoinsViewCache &viewChain = ::ChainstateActive().CoinsTip(); + NodeContext& node = EnsureAnyNodeContext(request.context); + const CTxMemPool& mempool = EnsureMemPool(node); + ChainstateManager& chainman = EnsureChainman(node); + LOCK2(cs_main, mempool.cs); + CCoinsViewCache &viewChain = chainman.ActiveChainstate().CoinsTip(); CCoinsViewMemPool viewMempool(&viewChain, mempool); view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view @@ -746,7 +752,7 @@ static RPCHelpMan signrawtransactionwithkey() }, }, }, - {"sighashtype", RPCArg::Type::STR, /* default */ "ALL", "The signature hash type. Must be one of:\n" + {"sighashtype", RPCArg::Type::STR, RPCArg::Default{"ALL"}, "The signature hash type. Must be one of:\n" " \"ALL\"\n" " \"NONE\"\n" " \"SINGLE\"\n" @@ -802,7 +808,7 @@ static RPCHelpMan signrawtransactionwithkey() for (const CTxIn& txin : mtx.vin) { coins[txin.prevout]; // Create empty map entry keyed by prevout. } - NodeContext& node = EnsureNodeContext(request.context); + NodeContext& node = EnsureAnyNodeContext(request.context); FindCoins(node, coins); // Parse the prevtxs array @@ -826,7 +832,7 @@ static RPCHelpMan sendrawtransaction() "\nRelated RPCs: createrawtransaction, signrawtransactionwithkey\n", { {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex string of the raw transaction"}, - {"maxfeerate", RPCArg::Type::AMOUNT, /* default */ FormatMoney(DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK()), + {"maxfeerate", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK())}, "Reject transactions whose fee rate is higher than the specified value, expressed in " + CURRENCY_UNIT + "/kB.\nSet to 0 to accept any fee rate.\n"}, }, @@ -865,7 +871,7 @@ static RPCHelpMan sendrawtransaction() std::string err_string; AssertLockNotHeld(cs_main); - NodeContext& node = EnsureNodeContext(request.context); + NodeContext& node = EnsureAnyNodeContext(request.context); const TransactionError err = BroadcastTransaction(node, tx, err_string, max_raw_tx_fee, /*relay*/ true, /*wait_callback*/ true); if (TransactionError::OK != err) { throw JSONRPCTransactionError(err, err_string); @@ -889,7 +895,7 @@ static RPCHelpMan testmempoolaccept() {"rawtx", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, ""}, }, }, - {"maxfeerate", RPCArg::Type::AMOUNT, /* default */ FormatMoney(DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK()), "Reject transactions whose fee rate is higher than the specified value, expressed in " + CURRENCY_UNIT + "/kB\n"}, + {"maxfeerate", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK())}, "Reject transactions whose fee rate is higher than the specified value, expressed in " + CURRENCY_UNIT + "/kB\n"}, }, RPCResult{ RPCResult::Type::ARR, "", "The result of the mempool acceptance test for each raw transaction in the input array.\n" @@ -940,7 +946,9 @@ static RPCHelpMan testmempoolaccept() DEFAULT_MAX_RAW_TX_FEE_RATE : CFeeRate(AmountFromValue(request.params[1])); - CTxMemPool& mempool = EnsureMemPool(request.context); + NodeContext& node = EnsureAnyNodeContext(request.context); + + CTxMemPool& mempool = EnsureMemPool(node); int64_t virtual_size = GetVirtualTransactionSize(*tx); CAmount max_raw_tx_fee = max_raw_tx_fee_rate.GetFee(virtual_size); @@ -949,7 +957,8 @@ static RPCHelpMan testmempoolaccept() result_0.pushKV("txid", tx->GetHash().GetHex()); result_0.pushKV("wtxid", tx->GetWitnessHash().GetHex()); - const MempoolAcceptResult accept_result = WITH_LOCK(cs_main, return AcceptToMemoryPool(::ChainstateActive(), mempool, std::move(tx), + ChainstateManager& chainman = EnsureChainman(node); + const MempoolAcceptResult accept_result = WITH_LOCK(cs_main, return AcceptToMemoryPool(chainman.ActiveChainstate(), mempool, std::move(tx), false /* bypass_limits */, /* test_accept */ true)); // Only return the fee and vsize if the transaction would pass ATMP. @@ -1353,7 +1362,7 @@ static RPCHelpMan finalizepsbt() "Implements the Finalizer and Extractor roles.\n", { {"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "A base64 string of a PSBT"}, - {"extract", RPCArg::Type::BOOL, /* default */ "true", "If true and the transaction is complete,\n" + {"extract", RPCArg::Type::BOOL, RPCArg::Default{true}, "If true and the transaction is complete,\n" " extract and return the complete transaction in normal network serialization instead of the PSBT."}, }, RPCResult{ @@ -1415,7 +1424,7 @@ static RPCHelpMan createpsbt() { {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"}, {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"}, - {"sequence", RPCArg::Type::NUM, /* default */ "depends on the value of the 'replaceable' and 'locktime' arguments", "The sequence number"}, + {"sequence", RPCArg::Type::NUM, RPCArg::DefaultHint{"depends on the value of the 'replaceable' and 'locktime' arguments"}, "The sequence number"}, }, }, }, @@ -1437,8 +1446,8 @@ static RPCHelpMan createpsbt() }, }, }, - {"locktime", RPCArg::Type::NUM, /* default */ "0", "Raw locktime. Non-0 value also locktime-activates inputs"}, - {"replaceable", RPCArg::Type::BOOL, /* default */ "false", "Marks this transaction as BIP125 replaceable.\n" + {"locktime", RPCArg::Type::NUM, RPCArg::Default{0}, "Raw locktime. Non-0 value also locktime-activates inputs"}, + {"replaceable", RPCArg::Type::BOOL, RPCArg::Default{false}, "Marks this transaction as BIP125 replaceable.\n" " Allows this transaction to be replaced by a transaction with higher fees. If provided, it is an error if explicit sequence numbers are incompatible."}, }, RPCResult{ @@ -1490,9 +1499,9 @@ static RPCHelpMan converttopsbt() "createpsbt and walletcreatefundedpsbt should be used for new applications.\n", { {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex string of a raw transaction"}, - {"permitsigdata", RPCArg::Type::BOOL, /* default */ "false", "If true, any signatures in the input will be discarded and conversion\n" + {"permitsigdata", RPCArg::Type::BOOL, RPCArg::Default{false}, "If true, any signatures in the input will be discarded and conversion\n" " will continue. If false, RPC will fail if any signatures are present."}, - {"iswitness", RPCArg::Type::BOOL, /* default */ "depends on heuristic tests", "Whether the transaction hex is a serialized witness transaction.\n" + {"iswitness", RPCArg::Type::BOOL, RPCArg::DefaultHint{"depends on heuristic tests"}, "Whether the transaction hex is a serialized witness transaction.\n" "If iswitness is not present, heuristic tests will be used in decoding.\n" "If true, only witness deserialization will be tried.\n" "If false, only non-witness deserialization will be tried.\n" @@ -1562,7 +1571,7 @@ static RPCHelpMan utxoupdatepsbt() {"", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "An output descriptor"}, {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "An object with an output descriptor and extra information", { {"desc", RPCArg::Type::STR, RPCArg::Optional::NO, "An output descriptor"}, - {"range", RPCArg::Type::RANGE, "1000", "Up to what index HD chains should be explored (either end or [begin,end])"}, + {"range", RPCArg::Type::RANGE, RPCArg::Default{1000}, "Up to what index HD chains should be explored (either end or [begin,end])"}, }}, }}, }, @@ -1598,9 +1607,11 @@ static RPCHelpMan utxoupdatepsbt() CCoinsView viewDummy; CCoinsViewCache view(&viewDummy); { - const CTxMemPool& mempool = EnsureMemPool(request.context); + NodeContext& node = EnsureAnyNodeContext(request.context); + const CTxMemPool& mempool = EnsureMemPool(node); + ChainstateManager& chainman = EnsureChainman(node); LOCK2(cs_main, mempool.cs); - CCoinsViewCache &viewChain = ::ChainstateActive().CoinsTip(); + CCoinsViewCache &viewChain = chainman.ActiveChainstate().CoinsTip(); CCoinsViewMemPool viewMempool(&viewChain, mempool); view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 5d816ba5bb..cf80b08b96 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -135,7 +135,7 @@ static RPCHelpMan help() return RPCHelpMan{"help", "\nList all commands, or get help for a specified command.\n", { - {"command", RPCArg::Type::STR, /* default */ "all commands", "The command to get help on"}, + {"command", RPCArg::Type::STR, RPCArg::DefaultHint{"all commands"}, "The command to get help on"}, }, { RPCResult{RPCResult::Type::STR, "", "The help text"}, diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp index ba3105ca01..df3ee9f007 100644 --- a/src/rpc/util.cpp +++ b/src/rpc/util.cpp @@ -498,6 +498,33 @@ RPCHelpMan::RPCHelpMan(std::string name, std::string description, std::vector<RP for (const std::string& name : names) { CHECK_NONFATAL(named_args.insert(name).second); } + // Default value type should match argument type only when defined + if (arg.m_fallback.index() == 2) { + const RPCArg::Type type = arg.m_type; + switch (std::get<RPCArg::Default>(arg.m_fallback).getType()) { + case UniValue::VOBJ: + CHECK_NONFATAL(type == RPCArg::Type::OBJ); + break; + case UniValue::VARR: + CHECK_NONFATAL(type == RPCArg::Type::ARR); + break; + case UniValue::VSTR: + CHECK_NONFATAL(type == RPCArg::Type::STR || type == RPCArg::Type::STR_HEX || type == RPCArg::Type::AMOUNT); + break; + case UniValue::VNUM: + CHECK_NONFATAL(type == RPCArg::Type::NUM || type == RPCArg::Type::AMOUNT || type == RPCArg::Type::RANGE); + break; + case UniValue::VBOOL: + CHECK_NONFATAL(type == RPCArg::Type::BOOL); + break; + case UniValue::VNULL: + // Null values are accepted in all arguments + break; + default: + CHECK_NONFATAL(false); + break; + } + } } } @@ -646,7 +673,7 @@ std::string RPCArg::GetName() const bool RPCArg::IsOptional() const { - if (m_fallback.index() == 1) { + if (m_fallback.index() != 0) { return true; } else { return RPCArg::Optional::NO != std::get<RPCArg::Optional>(m_fallback); @@ -694,7 +721,9 @@ std::string RPCArg::ToDescriptionString() const } // no default case, so the compiler can warn about missing cases } if (m_fallback.index() == 1) { - ret += ", optional, default=" + std::get<std::string>(m_fallback); + ret += ", optional, default=" + std::get<RPCArg::DefaultHint>(m_fallback); + } else if (m_fallback.index() == 2) { + ret += ", optional, default=" + std::get<RPCArg::Default>(m_fallback).write(); } else { switch (std::get<RPCArg::Optional>(m_fallback)) { case RPCArg::Optional::OMITTED: { diff --git a/src/rpc/util.h b/src/rpc/util.h index 6e783e19fb..8ec18b2f35 100644 --- a/src/rpc/util.h +++ b/src/rpc/util.h @@ -145,7 +145,9 @@ struct RPCArg { */ OMITTED, }; - using Fallback = std::variant<Optional, /* default value for optional args */ std::string>; + using DefaultHint = std::string; + using Default = UniValue; + using Fallback = std::variant<Optional, /* hint for default value */ DefaultHint, /* default constant value */ Default>; const std::string m_names; //!< The name of the arg (can be empty for inner args, can contain multiple aliases separated by | for named request arguments) const Type m_type; const bool m_hidden; diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp index 30399dca51..f1433553bc 100644 --- a/src/script/descriptor.cpp +++ b/src/script/descriptor.cpp @@ -481,34 +481,35 @@ class DescriptorImpl : public Descriptor const std::string m_name; protected: - //! The sub-descriptor argument (nullptr for everything but SH and WSH). + //! The sub-descriptor arguments (empty for everything but SH and WSH). //! In doc/descriptors.m this is referred to as SCRIPT expressions sh(SCRIPT) //! and wsh(SCRIPT), and distinct from KEY expressions and ADDR expressions. - const std::unique_ptr<DescriptorImpl> m_subdescriptor_arg; + //! Subdescriptors can only ever generate a single script. + const std::vector<std::unique_ptr<DescriptorImpl>> m_subdescriptor_args; //! Return a serialization of anything except pubkey and script arguments, to be prepended to those. virtual std::string ToStringExtra() const { return ""; } /** A helper function to construct the scripts for this descriptor. * - * This function is invoked once for every CScript produced by evaluating - * m_subdescriptor_arg, or just once in case m_subdescriptor_arg is nullptr. - + * This function is invoked once by ExpandHelper. + * * @param pubkeys The evaluations of the m_pubkey_args field. - * @param script The evaluation of m_subdescriptor_arg (or nullptr when m_subdescriptor_arg is nullptr). + * @param scripts The evaluations of m_subdescriptor_args (one for each m_subdescriptor_args element). * @param out A FlatSigningProvider to put scripts or public keys in that are necessary to the solver. - * The script arguments to this function are automatically added, as is the origin info of the provided pubkeys. + * The origin info of the provided pubkeys is automatically added. * @return A vector with scriptPubKeys for this descriptor. */ - virtual std::vector<CScript> MakeScripts(const std::vector<CPubKey>& pubkeys, const CScript* script, FlatSigningProvider& out) const = 0; + virtual std::vector<CScript> MakeScripts(const std::vector<CPubKey>& pubkeys, Span<const CScript> scripts, FlatSigningProvider& out) const = 0; public: - DescriptorImpl(std::vector<std::unique_ptr<PubkeyProvider>> pubkeys, std::unique_ptr<DescriptorImpl> script, const std::string& name) : m_pubkey_args(std::move(pubkeys)), m_name(name), m_subdescriptor_arg(std::move(script)) {} + DescriptorImpl(std::vector<std::unique_ptr<PubkeyProvider>> pubkeys, const std::string& name) : m_pubkey_args(std::move(pubkeys)), m_name(name), m_subdescriptor_args() {} + DescriptorImpl(std::vector<std::unique_ptr<PubkeyProvider>> pubkeys, std::unique_ptr<DescriptorImpl> script, const std::string& name) : m_pubkey_args(std::move(pubkeys)), m_name(name), m_subdescriptor_args(Vector(std::move(script))) {} bool IsSolvable() const override { - if (m_subdescriptor_arg) { - if (!m_subdescriptor_arg->IsSolvable()) return false; + for (const auto& arg : m_subdescriptor_args) { + if (!arg->IsSolvable()) return false; } return true; } @@ -518,12 +519,24 @@ public: for (const auto& pubkey : m_pubkey_args) { if (pubkey->IsRange()) return true; } - if (m_subdescriptor_arg) { - if (m_subdescriptor_arg->IsRange()) return true; + for (const auto& arg : m_subdescriptor_args) { + if (arg->IsRange()) return true; } return false; } + virtual bool ToStringSubScriptHelper(const SigningProvider* arg, std::string& ret, bool priv, bool normalized) const + { + size_t pos = 0; + for (const auto& scriptarg : m_subdescriptor_args) { + if (pos++) ret += ","; + std::string tmp; + if (!scriptarg->ToStringHelper(arg, tmp, priv, normalized)) return false; + ret += std::move(tmp); + } + return true; + } + bool ToStringHelper(const SigningProvider* arg, std::string& out, bool priv, bool normalized) const { std::string extra = ToStringExtra(); @@ -541,13 +554,10 @@ public: } ret += std::move(tmp); } - if (m_subdescriptor_arg) { - if (pos++) ret += ","; - std::string tmp; - if (!m_subdescriptor_arg->ToStringHelper(arg, tmp, priv, normalized)) return false; - ret += std::move(tmp); - } - out = std::move(ret) + ")"; + std::string subscript; + if (!ToStringSubScriptHelper(arg, subscript, priv, normalized)) return false; + if (pos && subscript.size()) ret += ','; + out = std::move(ret) + std::move(subscript) + ")"; return true; } @@ -577,17 +587,20 @@ public: std::vector<std::pair<CPubKey, KeyOriginInfo>> entries; entries.reserve(m_pubkey_args.size()); - // Construct temporary data in `entries` and `subscripts`, to avoid producing output in case of failure. + // Construct temporary data in `entries`, `subscripts`, and `subprovider` to avoid producing output in case of failure. for (const auto& p : m_pubkey_args) { entries.emplace_back(); if (!p->GetPubKey(pos, arg, entries.back().first, entries.back().second, read_cache, write_cache)) return false; } std::vector<CScript> subscripts; - if (m_subdescriptor_arg) { - FlatSigningProvider subprovider; - if (!m_subdescriptor_arg->ExpandHelper(pos, arg, read_cache, subscripts, subprovider, write_cache)) return false; - out = Merge(out, subprovider); + FlatSigningProvider subprovider; + for (const auto& subarg : m_subdescriptor_args) { + std::vector<CScript> outscripts; + if (!subarg->ExpandHelper(pos, arg, read_cache, outscripts, subprovider, write_cache)) return false; + assert(outscripts.size() == 1); + subscripts.emplace_back(std::move(outscripts[0])); } + out = Merge(std::move(out), std::move(subprovider)); std::vector<CPubKey> pubkeys; pubkeys.reserve(entries.size()); @@ -595,17 +608,8 @@ public: pubkeys.push_back(entry.first); out.origins.emplace(entry.first.GetID(), std::make_pair<CPubKey, KeyOriginInfo>(CPubKey(entry.first), std::move(entry.second))); } - if (m_subdescriptor_arg) { - for (const auto& subscript : subscripts) { - out.scripts.emplace(CScriptID(subscript), subscript); - std::vector<CScript> addscripts = MakeScripts(pubkeys, &subscript, out); - for (auto& addscript : addscripts) { - output_scripts.push_back(std::move(addscript)); - } - } - } else { - output_scripts = MakeScripts(pubkeys, nullptr, out); - } + + output_scripts = MakeScripts(pubkeys, MakeSpan(subscripts), out); return true; } @@ -626,10 +630,8 @@ public: if (!p->GetPrivKey(pos, provider, key)) continue; out.keys.emplace(key.GetPubKey().GetID(), key); } - if (m_subdescriptor_arg) { - FlatSigningProvider subprovider; - m_subdescriptor_arg->ExpandPrivate(pos, provider, subprovider); - out = Merge(out, subprovider); + for (const auto& arg : m_subdescriptor_args) { + arg->ExpandPrivate(pos, provider, out); } } @@ -642,9 +644,9 @@ class AddressDescriptor final : public DescriptorImpl const CTxDestination m_destination; protected: std::string ToStringExtra() const override { return EncodeDestination(m_destination); } - std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript*, FlatSigningProvider&) const override { return Vector(GetScriptForDestination(m_destination)); } + std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, Span<const CScript>, FlatSigningProvider&) const override { return Vector(GetScriptForDestination(m_destination)); } public: - AddressDescriptor(CTxDestination destination) : DescriptorImpl({}, {}, "addr"), m_destination(std::move(destination)) {} + AddressDescriptor(CTxDestination destination) : DescriptorImpl({}, "addr"), m_destination(std::move(destination)) {} bool IsSolvable() const final { return false; } std::optional<OutputType> GetOutputType() const override @@ -668,9 +670,9 @@ class RawDescriptor final : public DescriptorImpl const CScript m_script; protected: std::string ToStringExtra() const override { return HexStr(m_script); } - std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript*, FlatSigningProvider&) const override { return Vector(m_script); } + std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, Span<const CScript>, FlatSigningProvider&) const override { return Vector(m_script); } public: - RawDescriptor(CScript script) : DescriptorImpl({}, {}, "raw"), m_script(std::move(script)) {} + RawDescriptor(CScript script) : DescriptorImpl({}, "raw"), m_script(std::move(script)) {} bool IsSolvable() const final { return false; } std::optional<OutputType> GetOutputType() const override @@ -694,9 +696,9 @@ public: class PKDescriptor final : public DescriptorImpl { protected: - std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, const CScript*, FlatSigningProvider&) const override { return Vector(GetScriptForRawPubKey(keys[0])); } + std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, Span<const CScript>, FlatSigningProvider&) const override { return Vector(GetScriptForRawPubKey(keys[0])); } public: - PKDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), {}, "pk") {} + PKDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), "pk") {} bool IsSingleType() const final { return true; } }; @@ -704,14 +706,14 @@ public: class PKHDescriptor final : public DescriptorImpl { protected: - std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, const CScript*, FlatSigningProvider& out) const override + std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, Span<const CScript>, FlatSigningProvider& out) const override { CKeyID id = keys[0].GetID(); out.pubkeys.emplace(id, keys[0]); return Vector(GetScriptForDestination(PKHash(id))); } public: - PKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), {}, "pkh") {} + PKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), "pkh") {} std::optional<OutputType> GetOutputType() const override { return OutputType::LEGACY; } bool IsSingleType() const final { return true; } }; @@ -720,14 +722,14 @@ public: class WPKHDescriptor final : public DescriptorImpl { protected: - std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, const CScript*, FlatSigningProvider& out) const override + std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, Span<const CScript>, FlatSigningProvider& out) const override { CKeyID id = keys[0].GetID(); out.pubkeys.emplace(id, keys[0]); return Vector(GetScriptForDestination(WitnessV0KeyHash(id))); } public: - WPKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), {}, "wpkh") {} + WPKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), "wpkh") {} std::optional<OutputType> GetOutputType() const override { return OutputType::BECH32; } bool IsSingleType() const final { return true; } }; @@ -736,7 +738,7 @@ public: class ComboDescriptor final : public DescriptorImpl { protected: - std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, const CScript*, FlatSigningProvider& out) const override + std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, Span<const CScript>, FlatSigningProvider& out) const override { std::vector<CScript> ret; CKeyID id = keys[0].GetID(); @@ -752,7 +754,7 @@ protected: return ret; } public: - ComboDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), {}, "combo") {} + ComboDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), "combo") {} bool IsSingleType() const final { return false; } }; @@ -763,7 +765,7 @@ class MultisigDescriptor final : public DescriptorImpl const bool m_sorted; protected: std::string ToStringExtra() const override { return strprintf("%i", m_threshold); } - std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, const CScript*, FlatSigningProvider&) const override { + std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, Span<const CScript>, FlatSigningProvider&) const override { if (m_sorted) { std::vector<CPubKey> sorted_keys(keys); std::sort(sorted_keys.begin(), sorted_keys.end()); @@ -772,7 +774,7 @@ protected: return Vector(GetScriptForMultisig(m_threshold, keys)); } public: - MultisigDescriptor(int threshold, std::vector<std::unique_ptr<PubkeyProvider>> providers, bool sorted = false) : DescriptorImpl(std::move(providers), {}, sorted ? "sortedmulti" : "multi"), m_threshold(threshold), m_sorted(sorted) {} + MultisigDescriptor(int threshold, std::vector<std::unique_ptr<PubkeyProvider>> providers, bool sorted = false) : DescriptorImpl(std::move(providers), sorted ? "sortedmulti" : "multi"), m_threshold(threshold), m_sorted(sorted) {} bool IsSingleType() const final { return true; } }; @@ -780,14 +782,19 @@ public: class SHDescriptor final : public DescriptorImpl { protected: - std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript* script, FlatSigningProvider&) const override { return Vector(GetScriptForDestination(ScriptHash(*script))); } + std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, Span<const CScript> scripts, FlatSigningProvider& out) const override + { + auto ret = Vector(GetScriptForDestination(ScriptHash(scripts[0]))); + if (ret.size()) out.scripts.emplace(CScriptID(scripts[0]), scripts[0]); + return ret; + } public: SHDescriptor(std::unique_ptr<DescriptorImpl> desc) : DescriptorImpl({}, std::move(desc), "sh") {} std::optional<OutputType> GetOutputType() const override { - assert(m_subdescriptor_arg); - if (m_subdescriptor_arg->GetOutputType() == OutputType::BECH32) return OutputType::P2SH_SEGWIT; + assert(m_subdescriptor_args.size() == 1); + if (m_subdescriptor_args[0]->GetOutputType() == OutputType::BECH32) return OutputType::P2SH_SEGWIT; return OutputType::LEGACY; } bool IsSingleType() const final { return true; } @@ -797,7 +804,12 @@ public: class WSHDescriptor final : public DescriptorImpl { protected: - std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript* script, FlatSigningProvider&) const override { return Vector(GetScriptForDestination(WitnessV0ScriptHash(*script))); } + std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, Span<const CScript> scripts, FlatSigningProvider& out) const override + { + auto ret = Vector(GetScriptForDestination(WitnessV0ScriptHash(scripts[0]))); + if (ret.size()) out.scripts.emplace(CScriptID(scripts[0]), scripts[0]); + return ret; + } public: WSHDescriptor(std::unique_ptr<DescriptorImpl> desc) : DescriptorImpl({}, std::move(desc), "wsh") {} std::optional<OutputType> GetOutputType() const override { return OutputType::BECH32; } @@ -809,9 +821,10 @@ public: //////////////////////////////////////////////////////////////////////////// enum class ParseScriptContext { - TOP, - P2SH, - P2WSH, + TOP, //!< Top-level context (script goes directly in scriptPubKey) + P2SH, //!< Inside sh() (script becomes P2SH redeemScript) + P2WPKH, //!< Inside wpkh() (no script, pubkey only) + P2WSH, //!< Inside wsh() (script becomes v0 witness script) }; /** Parse a key path, being passed a split list of elements (the first element is ignored). */ @@ -838,10 +851,11 @@ enum class ParseScriptContext { } /** Parse a public key that excludes origin information. */ -std::unique_ptr<PubkeyProvider> ParsePubkeyInner(uint32_t key_exp_index, const Span<const char>& sp, bool permit_uncompressed, FlatSigningProvider& out, std::string& error) +std::unique_ptr<PubkeyProvider> ParsePubkeyInner(uint32_t key_exp_index, const Span<const char>& sp, ParseScriptContext ctx, FlatSigningProvider& out, std::string& error) { using namespace spanparsing; + bool permit_uncompressed = ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH; auto split = Split(sp, '/'); std::string str(split[0].begin(), split[0].end()); if (str.size() == 0) { @@ -899,7 +913,7 @@ std::unique_ptr<PubkeyProvider> ParsePubkeyInner(uint32_t key_exp_index, const S } /** Parse a public key including origin information (if enabled). */ -std::unique_ptr<PubkeyProvider> ParsePubkey(uint32_t key_exp_index, const Span<const char>& sp, bool permit_uncompressed, FlatSigningProvider& out, std::string& error) +std::unique_ptr<PubkeyProvider> ParsePubkey(uint32_t key_exp_index, const Span<const char>& sp, ParseScriptContext ctx, FlatSigningProvider& out, std::string& error) { using namespace spanparsing; @@ -908,7 +922,7 @@ std::unique_ptr<PubkeyProvider> ParsePubkey(uint32_t key_exp_index, const Span<c error = "Multiple ']' characters found for a single pubkey"; return nullptr; } - if (origin_split.size() == 1) return ParsePubkeyInner(key_exp_index, origin_split[0], permit_uncompressed, out, error); + if (origin_split.size() == 1) return ParsePubkeyInner(key_exp_index, origin_split[0], ctx, out, error); if (origin_split[0].empty() || origin_split[0][0] != '[') { error = strprintf("Key origin start '[ character expected but not found, got '%c' instead", origin_split[0].empty() ? /** empty, implies split char */ ']' : origin_split[0][0]); @@ -930,34 +944,37 @@ std::unique_ptr<PubkeyProvider> ParsePubkey(uint32_t key_exp_index, const Span<c assert(fpr_bytes.size() == 4); std::copy(fpr_bytes.begin(), fpr_bytes.end(), info.fingerprint); if (!ParseKeyPath(slash_split, info.path, error)) return nullptr; - auto provider = ParsePubkeyInner(key_exp_index, origin_split[1], permit_uncompressed, out, error); + auto provider = ParsePubkeyInner(key_exp_index, origin_split[1], ctx, out, error); if (!provider) return nullptr; return std::make_unique<OriginPubkeyProvider>(key_exp_index, std::move(info), std::move(provider)); } /** Parse a script in a particular context. */ -std::unique_ptr<DescriptorImpl> ParseScript(uint32_t key_exp_index, Span<const char>& sp, ParseScriptContext ctx, FlatSigningProvider& out, std::string& error) +std::unique_ptr<DescriptorImpl> ParseScript(uint32_t& key_exp_index, Span<const char>& sp, ParseScriptContext ctx, FlatSigningProvider& out, std::string& error) { using namespace spanparsing; auto expr = Expr(sp); bool sorted_multi = false; if (Func("pk", expr)) { - auto pubkey = ParsePubkey(key_exp_index, expr, ctx != ParseScriptContext::P2WSH, out, error); + auto pubkey = ParsePubkey(key_exp_index, expr, ctx, out, error); if (!pubkey) return nullptr; + ++key_exp_index; return std::make_unique<PKDescriptor>(std::move(pubkey)); } if (Func("pkh", expr)) { - auto pubkey = ParsePubkey(key_exp_index, expr, ctx != ParseScriptContext::P2WSH, out, error); + auto pubkey = ParsePubkey(key_exp_index, expr, ctx, out, error); if (!pubkey) return nullptr; + ++key_exp_index; return std::make_unique<PKHDescriptor>(std::move(pubkey)); } if (ctx == ParseScriptContext::TOP && Func("combo", expr)) { - auto pubkey = ParsePubkey(key_exp_index, expr, true, out, error); + auto pubkey = ParsePubkey(key_exp_index, expr, ctx, out, error); if (!pubkey) return nullptr; + ++key_exp_index; return std::make_unique<ComboDescriptor>(std::move(pubkey)); - } else if (ctx != ParseScriptContext::TOP && Func("combo", expr)) { - error = "Cannot have combo in non-top level"; + } else if (Func("combo", expr)) { + error = "Can only have combo() at top level"; return nullptr; } if ((sorted_multi = Func("sortedmulti", expr)) || Func("multi", expr)) { @@ -975,7 +992,7 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t key_exp_index, Span<const c return nullptr; } auto arg = Expr(expr); - auto pk = ParsePubkey(key_exp_index, arg, ctx != ParseScriptContext::P2WSH, out, error); + auto pk = ParsePubkey(key_exp_index, arg, ctx, out, error); if (!pk) return nullptr; script_size += pk->GetSize() + 1; providers.emplace_back(std::move(pk)); @@ -1005,28 +1022,29 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t key_exp_index, Span<const c } return std::make_unique<MultisigDescriptor>(thres, std::move(providers), sorted_multi); } - if (ctx != ParseScriptContext::P2WSH && Func("wpkh", expr)) { - auto pubkey = ParsePubkey(key_exp_index, expr, false, out, error); + if ((ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH) && Func("wpkh", expr)) { + auto pubkey = ParsePubkey(key_exp_index, expr, ParseScriptContext::P2WPKH, out, error); if (!pubkey) return nullptr; + key_exp_index++; return std::make_unique<WPKHDescriptor>(std::move(pubkey)); - } else if (ctx == ParseScriptContext::P2WSH && Func("wpkh", expr)) { - error = "Cannot have wpkh within wsh"; + } else if (Func("wpkh", expr)) { + error = "Can only have wpkh() at top level or inside sh()"; return nullptr; } if (ctx == ParseScriptContext::TOP && Func("sh", expr)) { auto desc = ParseScript(key_exp_index, expr, ParseScriptContext::P2SH, out, error); if (!desc || expr.size()) return nullptr; return std::make_unique<SHDescriptor>(std::move(desc)); - } else if (ctx != ParseScriptContext::TOP && Func("sh", expr)) { - error = "Cannot have sh in non-top level"; + } else if (Func("sh", expr)) { + error = "Can only have sh() at top level"; return nullptr; } - if (ctx != ParseScriptContext::P2WSH && Func("wsh", expr)) { + if ((ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH) && Func("wsh", expr)) { auto desc = ParseScript(key_exp_index, expr, ParseScriptContext::P2WSH, out, error); if (!desc || expr.size()) return nullptr; return std::make_unique<WSHDescriptor>(std::move(desc)); - } else if (ctx == ParseScriptContext::P2WSH && Func("wsh", expr)) { - error = "Cannot have wsh within wsh"; + } else if (Func("wsh", expr)) { + error = "Can only have wsh() at top level or inside sh()"; return nullptr; } if (ctx == ParseScriptContext::TOP && Func("addr", expr)) { @@ -1036,6 +1054,9 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t key_exp_index, Span<const c return nullptr; } return std::make_unique<AddressDescriptor>(std::move(dest)); + } else if (Func("addr", expr)) { + error = "Can only have addr() at top level"; + return nullptr; } if (ctx == ParseScriptContext::TOP && Func("raw", expr)) { std::string str(expr.begin(), expr.end()); @@ -1045,6 +1066,9 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t key_exp_index, Span<const c } auto bytes = ParseHex(str); return std::make_unique<RawDescriptor>(CScript(bytes.begin(), bytes.end())); + } else if (Func("raw", expr)) { + error = "Can only have raw() at top level"; + return nullptr; } if (ctx == ParseScriptContext::P2SH) { error = "A function is needed within P2SH"; @@ -1174,7 +1198,8 @@ std::unique_ptr<Descriptor> Parse(const std::string& descriptor, FlatSigningProv { Span<const char> sp{descriptor}; if (!CheckChecksum(sp, require_checksum, error)) return nullptr; - auto ret = ParseScript(0, sp, ParseScriptContext::TOP, out, error); + uint32_t key_exp_index = 0; + auto ret = ParseScript(key_exp_index, sp, ParseScriptContext::TOP, out, error); if (sp.size() == 0 && ret) return std::unique_ptr<Descriptor>(std::move(ret)); return nullptr; } diff --git a/src/shutdown.cpp b/src/shutdown.cpp index 2fc195e2d1..35faf3c412 100644 --- a/src/shutdown.cpp +++ b/src/shutdown.cpp @@ -6,7 +6,9 @@ #include <shutdown.h> #include <logging.h> +#include <node/ui_interface.h> #include <util/tokenpipe.h> +#include <warnings.h> #include <config/bitcoin-config.h> @@ -16,6 +18,18 @@ #include <condition_variable> #endif +bool AbortNode(const std::string& strMessage, bilingual_str user_message) +{ + SetMiscWarning(Untranslated(strMessage)); + LogPrintf("*** %s\n", strMessage); + if (user_message.empty()) { + user_message = _("A fatal internal error occurred, see debug.log for details"); + } + AbortError(user_message); + StartShutdown(); + return false; +} + static std::atomic<bool> fRequestShutdown(false); #ifdef WIN32 /** On windows it is possible to simply use a condition variable. */ diff --git a/src/shutdown.h b/src/shutdown.h index b2fbdb8cfb..ff56c6bd87 100644 --- a/src/shutdown.h +++ b/src/shutdown.h @@ -6,6 +6,11 @@ #ifndef BITCOIN_SHUTDOWN_H #define BITCOIN_SHUTDOWN_H +#include <util/translation.h> // For bilingual_str + +/** Abort with a message */ +bool AbortNode(const std::string& strMessage, bilingual_str user_message = bilingual_str{}); + /** Initialize shutdown state. This must be called before using either StartShutdown(), * AbortShutdown() or WaitForShutdown(). Calling ShutdownRequested() is always safe. */ diff --git a/src/test/data/tx_invalid.json b/src/test/data/tx_invalid.json index c394356798..41bebab2a0 100644 --- a/src/test/data/tx_invalid.json +++ b/src/test/data/tx_invalid.json @@ -124,15 +124,15 @@ ["CHECKLOCKTIMEVERIFY tests"], ["By-height locks, with argument just beyond tx nLockTime"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1 CHECKLOCKTIMEVERIFY 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1 CHECKLOCKTIMEVERIFY"]], "010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "CHECKLOCKTIMEVERIFY"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 CHECKLOCKTIMEVERIFY 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 CHECKLOCKTIMEVERIFY"]], "0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000fe64cd1d", "CHECKLOCKTIMEVERIFY"], ["By-time locks, with argument just beyond tx nLockTime (but within numerical boundaries)"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000001 CHECKLOCKTIMEVERIFY 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000001 CHECKLOCKTIMEVERIFY"]], "01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "CHECKLOCKTIMEVERIFY"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 CHECKLOCKTIMEVERIFY 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 CHECKLOCKTIMEVERIFY"]], "0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000feffffff", "CHECKLOCKTIMEVERIFY"], ["Argument missing"], @@ -142,11 +142,11 @@ "010000000100010000000000000000000000000000000000000000000000000000000000000000000001b1010000000100000000000000000000000000", "CHECKLOCKTIMEVERIFY"], ["Argument negative with by-blockheight nLockTime=0"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 CHECKLOCKTIMEVERIFY 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 CHECKLOCKTIMEVERIFY"]], "010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "CHECKLOCKTIMEVERIFY"], ["Argument negative with by-blocktime nLockTime=500,000,000"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 CHECKLOCKTIMEVERIFY 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 CHECKLOCKTIMEVERIFY"]], "01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "CHECKLOCKTIMEVERIFY"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]], "010000000100010000000000000000000000000000000000000000000000000000000000000000000004005194b1010000000100000000000000000002000000", "CHECKLOCKTIMEVERIFY"], @@ -167,19 +167,19 @@ "01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "CHECKLOCKTIMEVERIFY"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0"]], "01000000010001000000000000000000000000000000000000000000000000000000000000000000000251b100000000010000000000000000000065cd1d", "NONE"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 CHECKLOCKTIMEVERIFY 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 CHECKLOCKTIMEVERIFY"]], "01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "CHECKLOCKTIMEVERIFY"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 CHECKLOCKTIMEVERIFY 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 CHECKLOCKTIMEVERIFY"]], "010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "CHECKLOCKTIMEVERIFY"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 CHECKLOCKTIMEVERIFY 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 CHECKLOCKTIMEVERIFY"]], "0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ff64cd1d", "CHECKLOCKTIMEVERIFY"], ["Argument 2^32 with nLockTime=2^32-1"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x050000000001 CHECKLOCKTIMEVERIFY 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x050000000001 CHECKLOCKTIMEVERIFY"]], "0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffffff", "CHECKLOCKTIMEVERIFY"], ["Same, but with nLockTime=2^31-1"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 CHECKLOCKTIMEVERIFY 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 CHECKLOCKTIMEVERIFY"]], "0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffff7f", "CHECKLOCKTIMEVERIFY"], ["6 byte non-minimally-encoded arguments are invalid even if their contents are valid"], @@ -201,15 +201,15 @@ ["CHECKSEQUENCEVERIFY tests"], ["By-height locks, with argument just beyond txin.nSequence"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1 CHECKSEQUENCEVERIFY 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1 CHECKSEQUENCEVERIFY"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "CHECKSEQUENCEVERIFY"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 CHECKSEQUENCEVERIFY 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 CHECKSEQUENCEVERIFY"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000feff40000100000000000000000000000000", "CHECKSEQUENCEVERIFY"], ["By-time locks, with argument just beyond txin.nSequence (but within numerical boundaries)"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194305 CHECKSEQUENCEVERIFY 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194305 CHECKSEQUENCEVERIFY"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "CHECKSEQUENCEVERIFY"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 CHECKSEQUENCEVERIFY 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 CHECKSEQUENCEVERIFY"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000feff40000100000000000000000000000000", "CHECKSEQUENCEVERIFY"], ["Argument missing"], @@ -217,21 +217,21 @@ "020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "CHECKSEQUENCEVERIFY"], ["Argument negative with by-blockheight txin.nSequence=0"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 CHECKSEQUENCEVERIFY 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 CHECKSEQUENCEVERIFY"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "CHECKSEQUENCEVERIFY"], ["Argument negative with by-blocktime txin.nSequence=CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 CHECKSEQUENCEVERIFY 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 CHECKSEQUENCEVERIFY"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "CHECKSEQUENCEVERIFY"], ["Argument/tx height/time mismatch, both versions"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 CHECKSEQUENCEVERIFY 1"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "CHECKSEQUENCEVERIFY"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "65535 CHECKSEQUENCEVERIFY 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "65535 CHECKSEQUENCEVERIFY"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "CHECKSEQUENCEVERIFY"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194304 CHECKSEQUENCEVERIFY 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194304 CHECKSEQUENCEVERIFY"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "CHECKSEQUENCEVERIFY"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 CHECKSEQUENCEVERIFY 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 CHECKSEQUENCEVERIFY"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "CHECKSEQUENCEVERIFY"], ["6 byte non-minimally-encoded arguments are invalid even if their contents are valid"], @@ -249,7 +249,7 @@ ["Failure due to insufficient tx.nVersion (<2)"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 CHECKSEQUENCEVERIFY 1"]], "010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "CHECKSEQUENCEVERIFY"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194304 CHECKSEQUENCEVERIFY 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194304 CHECKSEQUENCEVERIFY"]], "010000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "CHECKSEQUENCEVERIFY"], ["Unknown witness program version (with DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM)"], diff --git a/src/test/data/tx_valid.json b/src/test/data/tx_valid.json index 2727af5abd..b874f6f26c 100644 --- a/src/test/data/tx_valid.json +++ b/src/test/data/tx_valid.json @@ -62,10 +62,6 @@ ["c76168ef1a272a4f176e55e73157ecfce040cfad16a5272f6296eb7089dca846", 1, "DUP HASH160 0x14 0x34fea2c5a75414fd945273ae2d029ce1f28dafcf EQUALVERIFY CHECKSIG"]], "010000000390d31c6107013d754529d8818eff285fe40a3e7635f6930fec5d12eb02107a43010000006b483045022100f40815ae3c81a0dd851cc8d376d6fd226c88416671346a9033468cca2cdcc6c202204f764623903e6c4bed1b734b75d82c40f1725e4471a55ad4f51218f86130ac038321033d710ab45bb54ac99618ad23b3c1da661631aa25f23bfe9d22b41876f1d46e4effffffff3ff04a68e22bdd52e7c8cb848156d2d158bd5515b3c50adabc87d0ca2cd3482d010000006a4730440220598d263c107004008e9e26baa1e770be30fd31ee55ded1898f7c00da05a75977022045536bead322ca246779698b9c3df3003377090f41afeca7fb2ce9e328ec4af2832102b738b531def73020bd637f32935924cc88549c8206976226d968edd3a42fc2d7ffffffff46a8dc8970eb96622f27a516adcf40e0fcec5731e7556e174f2a271aef6861c7010000006b483045022100c5b90a777a9fdc90c208dbef7290d1fc1be651f47151ee4ccff646872a454cf90220640cfbc4550446968fbbe9d12528f3adf7d87b31541569c59e790db8a220482583210391332546e22bbe8fe3af54addfad6f8b83d05fa4f5e047593d4c07ae938795beffffffff028036be26000000001976a914ddfb29efad43a667465ac59ff14dc6442a1adfca88ac3d5cba01000000001976a914b64dde7a505a13ca986c40e86e984a8dc81368b688ac00000000", "NONE"], -["An invalid P2SH Transaction"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7a052c840ba73af26755de42cf01cc9e0a49fef0 EQUAL"]], -"010000000100010000000000000000000000000000000000000000000000000000000000000000000009085768617420697320ffffffff010000000000000000015100000000", "P2SH,CLEANSTACK,WITNESS"], - ["A valid P2SH Transaction using the standard transaction type put forth in BIP 16"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x8febbed40483661de6958d957412f82deed8e2f7 EQUAL"]], "01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100c66c9cdf4c43609586d15424c54707156e316d88b0a1534c9e6b0d4f311406310221009c0fe51dbc9c4ab7cc25d3fdbeccf6679fe6827f08edf2b4a9f16ee3eb0e438a0123210338e8034509af564c62644c07691942e0c056752008a173c89f60ab2a88ac2ebfacffffffff010000000000000000015100000000", "LOW_S"], diff --git a/src/test/dbwrapper_tests.cpp b/src/test/dbwrapper_tests.cpp index a6080ad3dd..b5f3bb2fa4 100644 --- a/src/test/dbwrapper_tests.cpp +++ b/src/test/dbwrapper_tests.cpp @@ -26,7 +26,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper) { // Perform tests both obfuscated and non-obfuscated. for (const bool obfuscate : {false, true}) { - fs::path ph = GetDataDir() / (obfuscate ? "dbwrapper_obfuscate_true" : "dbwrapper_obfuscate_false"); + fs::path ph = m_args.GetDataDirPath() / (obfuscate ? "dbwrapper_obfuscate_true" : "dbwrapper_obfuscate_false"); CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate); char key = 'k'; uint256 in = InsecureRand256(); @@ -45,7 +45,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper_basic_data) { // Perform tests both obfuscated and non-obfuscated. for (bool obfuscate : {false, true}) { - fs::path ph = GetDataDir() / (obfuscate ? "dbwrapper_1_obfuscate_true" : "dbwrapper_1_obfuscate_false"); + fs::path ph = m_args.GetDataDirPath() / (obfuscate ? "dbwrapper_1_obfuscate_true" : "dbwrapper_1_obfuscate_false"); CDBWrapper dbw(ph, (1 << 20), false, true, obfuscate); uint256 res; @@ -126,7 +126,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper_batch) { // Perform tests both obfuscated and non-obfuscated. for (const bool obfuscate : {false, true}) { - fs::path ph = GetDataDir() / (obfuscate ? "dbwrapper_batch_obfuscate_true" : "dbwrapper_batch_obfuscate_false"); + fs::path ph = m_args.GetDataDirPath() / (obfuscate ? "dbwrapper_batch_obfuscate_true" : "dbwrapper_batch_obfuscate_false"); CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate); char key = 'i'; @@ -162,7 +162,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper_iterator) { // Perform tests both obfuscated and non-obfuscated. for (const bool obfuscate : {false, true}) { - fs::path ph = GetDataDir() / (obfuscate ? "dbwrapper_iterator_obfuscate_true" : "dbwrapper_iterator_obfuscate_false"); + fs::path ph = m_args.GetDataDirPath() / (obfuscate ? "dbwrapper_iterator_obfuscate_true" : "dbwrapper_iterator_obfuscate_false"); CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate); // The two keys are intentionally chosen for ordering @@ -202,7 +202,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper_iterator) BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate) { // We're going to share this fs::path between two wrappers - fs::path ph = GetDataDir() / "existing_data_no_obfuscate"; + fs::path ph = m_args.GetDataDirPath() / "existing_data_no_obfuscate"; create_directories(ph); // Set up a non-obfuscated wrapper to write some initial data. @@ -243,7 +243,7 @@ BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate) BOOST_AUTO_TEST_CASE(existing_data_reindex) { // We're going to share this fs::path between two wrappers - fs::path ph = GetDataDir() / "existing_data_reindex"; + fs::path ph = m_args.GetDataDirPath() / "existing_data_reindex"; create_directories(ph); // Set up a non-obfuscated wrapper to write some initial data. @@ -278,7 +278,7 @@ BOOST_AUTO_TEST_CASE(existing_data_reindex) BOOST_AUTO_TEST_CASE(iterator_ordering) { - fs::path ph = GetDataDir() / "iterator_ordering"; + fs::path ph = m_args.GetDataDirPath() / "iterator_ordering"; CDBWrapper dbw(ph, (1 << 20), true, false, false); for (int x=0x00; x<256; ++x) { uint8_t key = x; @@ -358,7 +358,7 @@ BOOST_AUTO_TEST_CASE(iterator_string_ordering) { char buf[10]; - fs::path ph = GetDataDir() / "iterator_string_ordering"; + fs::path ph = m_args.GetDataDirPath() / "iterator_string_ordering"; CDBWrapper dbw(ph, (1 << 20), true, false, false); for (int x=0x00; x<10; ++x) { for (int y = 0; y < 10; y++) { @@ -404,7 +404,7 @@ BOOST_AUTO_TEST_CASE(unicodepath) // On Windows this test will fail if the directory is created using // the ANSI CreateDirectoryA call and the code page isn't UTF8. // It will succeed if created with CreateDirectoryW. - fs::path ph = GetDataDir() / "test_runner_₿_🏃_20191128_104644"; + fs::path ph = m_args.GetDataDirPath() / "test_runner_₿_🏃_20191128_104644"; CDBWrapper dbw(ph, (1 << 20)); fs::path lockPath = ph / "LOCK"; diff --git a/src/test/denialofservice_tests.cpp b/src/test/denialofservice_tests.cpp index e7cb12dbba..ddf0e0ca90 100644 --- a/src/test/denialofservice_tests.cpp +++ b/src/test/denialofservice_tests.cpp @@ -116,7 +116,6 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction) BOOST_CHECK(peerLogic->SendMessages(&dummyNode1)); // should result in disconnect } BOOST_CHECK(dummyNode1.fDisconnect == true); - SetMockTime(0); peerLogic->FinalizeNode(dummyNode1); } @@ -209,7 +208,7 @@ BOOST_AUTO_TEST_CASE(stale_tip_peer_management) BOOST_AUTO_TEST_CASE(peer_discouragement) { const CChainParams& chainparams = Params(); - auto banman = std::make_unique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME); + auto banman = std::make_unique<BanMan>(m_args.GetDataDirPath() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME); auto connman = std::make_unique<CConnmanTest>(0x1337, 0x1337, *m_node.addrman); auto peerLogic = PeerManager::make(chainparams, *connman, *m_node.addrman, banman.get(), *m_node.scheduler, *m_node.chainman, *m_node.mempool, false); @@ -303,7 +302,7 @@ BOOST_AUTO_TEST_CASE(peer_discouragement) BOOST_AUTO_TEST_CASE(DoS_bantime) { const CChainParams& chainparams = Params(); - auto banman = std::make_unique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME); + auto banman = std::make_unique<BanMan>(m_args.GetDataDirPath() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME); auto connman = std::make_unique<CConnman>(0x1337, 0x1337, *m_node.addrman); auto peerLogic = PeerManager::make(chainparams, *connman, *m_node.addrman, banman.get(), *m_node.scheduler, *m_node.chainman, *m_node.mempool, false); diff --git a/src/test/descriptor_tests.cpp b/src/test/descriptor_tests.cpp index aecf955fee..ea41a03728 100644 --- a/src/test/descriptor_tests.cpp +++ b/src/test/descriptor_tests.cpp @@ -24,7 +24,7 @@ void CheckUnparsable(const std::string& prv, const std::string& pub, const std:: auto parse_pub = Parse(pub, keys_pub, error); BOOST_CHECK_MESSAGE(!parse_priv, prv); BOOST_CHECK_MESSAGE(!parse_pub, pub); - BOOST_CHECK(error == expected_error); + BOOST_CHECK_EQUAL(error, expected_error); } constexpr int DEFAULT = 0; @@ -355,12 +355,12 @@ BOOST_AUTO_TEST_CASE(descriptor_test) // Check for invalid nesting of structures CheckUnparsable("sh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "sh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "A function is needed within P2SH"); // P2SH needs a script, not a key - CheckUnparsable("sh(combo(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))", "sh(combo(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", "Cannot have combo in non-top level"); // Old must be top level + CheckUnparsable("sh(combo(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))", "sh(combo(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", "Can only have combo() at top level"); // Old must be top level CheckUnparsable("wsh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "wsh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "A function is needed within P2WSH"); // P2WSH needs a script, not a key - CheckUnparsable("wsh(wpkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))", "wsh(wpkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", "Cannot have wpkh within wsh"); // Cannot embed witness inside witness - CheckUnparsable("wsh(sh(pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)))", "wsh(sh(pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))", "Cannot have sh in non-top level"); // Cannot embed P2SH inside P2WSH - CheckUnparsable("sh(sh(pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)))", "sh(sh(pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))", "Cannot have sh in non-top level"); // Cannot embed P2SH inside P2SH - CheckUnparsable("wsh(wsh(pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)))", "wsh(wsh(pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))", "Cannot have wsh within wsh"); // Cannot embed P2WSH inside P2WSH + CheckUnparsable("wsh(wpkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))", "wsh(wpkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", "Can only have wpkh() at top level or inside sh()"); // Cannot embed witness inside witness + CheckUnparsable("wsh(sh(pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)))", "wsh(sh(pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))", "Can only have sh() at top level"); // Cannot embed P2SH inside P2WSH + CheckUnparsable("sh(sh(pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)))", "sh(sh(pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))", "Can only have sh() at top level"); // Cannot embed P2SH inside P2SH + CheckUnparsable("wsh(wsh(pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)))", "wsh(wsh(pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))", "Can only have wsh() at top level or inside sh()"); // Cannot embed P2WSH inside P2WSH // Checksums Check("sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))#ggrsrxfy", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))#tjg09x5t", "sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))#ggrsrxfy", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))#tjg09x5t", DEFAULT, {{"a91445a9a622a8b0a1269944be477640eedc447bbd8487"}}, OutputType::LEGACY, {{0x8000006FUL,222},{0}}); diff --git a/src/test/flatfile_tests.cpp b/src/test/flatfile_tests.cpp index 0c5c19113d..9194ed8130 100644 --- a/src/test/flatfile_tests.cpp +++ b/src/test/flatfile_tests.cpp @@ -14,7 +14,7 @@ BOOST_FIXTURE_TEST_SUITE(flatfile_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(flatfile_filename) { - const auto data_dir = GetDataDir(); + const auto data_dir = m_args.GetDataDirPath(); FlatFilePos pos(456, 789); @@ -27,7 +27,7 @@ BOOST_AUTO_TEST_CASE(flatfile_filename) BOOST_AUTO_TEST_CASE(flatfile_open) { - const auto data_dir = GetDataDir(); + const auto data_dir = m_args.GetDataDirPath(); FlatFileSeq seq(data_dir, "a", 16 * 1024); std::string line1("A purely peer-to-peer version of electronic cash would allow online " @@ -88,7 +88,7 @@ BOOST_AUTO_TEST_CASE(flatfile_open) BOOST_AUTO_TEST_CASE(flatfile_allocate) { - const auto data_dir = GetDataDir(); + const auto data_dir = m_args.GetDataDirPath(); FlatFileSeq seq(data_dir, "a", 100); bool out_of_space; @@ -108,7 +108,7 @@ BOOST_AUTO_TEST_CASE(flatfile_allocate) BOOST_AUTO_TEST_CASE(flatfile_flush) { - const auto data_dir = GetDataDir(); + const auto data_dir = m_args.GetDataDirPath(); FlatFileSeq seq(data_dir, "a", 100); bool out_of_space; diff --git a/src/test/fs_tests.cpp b/src/test/fs_tests.cpp index e52cd5230c..452bc06bbb 100644 --- a/src/test/fs_tests.cpp +++ b/src/test/fs_tests.cpp @@ -13,7 +13,7 @@ BOOST_FIXTURE_TEST_SUITE(fs_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(fsbridge_fstream) { - fs::path tmpfolder = GetDataDir(); + fs::path tmpfolder = m_args.GetDataDirPath(); // tmpfile1 should be the same as tmpfile2 fs::path tmpfile1 = tmpfolder / "fs_tests_₿_🏃"; fs::path tmpfile2 = tmpfolder / "fs_tests_₿_🏃"; diff --git a/src/test/fuzz/util.cpp b/src/test/fuzz/util.cpp index cf5244e314..b8d846a995 100644 --- a/src/test/fuzz/util.cpp +++ b/src/test/fuzz/util.cpp @@ -7,15 +7,196 @@ #include <util/rbf.h> #include <version.h> -bool FuzzedSock::Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred ) const +FuzzedSock::FuzzedSock(FuzzedDataProvider& fuzzed_data_provider) + : m_fuzzed_data_provider{fuzzed_data_provider} { - if (!m_fuzzed_data_provider.ConsumeBool()) { + m_socket = fuzzed_data_provider.ConsumeIntegralInRange<SOCKET>(INVALID_SOCKET - 1, INVALID_SOCKET); +} + +FuzzedSock::~FuzzedSock() +{ + // Sock::~Sock() will be called after FuzzedSock::~FuzzedSock() and it will call + // Sock::Reset() (not FuzzedSock::Reset()!) which will call CloseSocket(m_socket). + // Avoid closing an arbitrary file descriptor (m_socket is just a random very high number which + // theoretically may concide with a real opened file descriptor). + Reset(); +} + +FuzzedSock& FuzzedSock::operator=(Sock&& other) +{ + assert(false && "Move of Sock into FuzzedSock not allowed."); + return *this; +} + +void FuzzedSock::Reset() +{ + m_socket = INVALID_SOCKET; +} + +ssize_t FuzzedSock::Send(const void* data, size_t len, int flags) const +{ + constexpr std::array send_errnos{ + EACCES, + EAGAIN, + EALREADY, + EBADF, + ECONNRESET, + EDESTADDRREQ, + EFAULT, + EINTR, + EINVAL, + EISCONN, + EMSGSIZE, + ENOBUFS, + ENOMEM, + ENOTCONN, + ENOTSOCK, + EOPNOTSUPP, + EPIPE, + EWOULDBLOCK, + }; + if (m_fuzzed_data_provider.ConsumeBool()) { + return len; + } + const ssize_t r = m_fuzzed_data_provider.ConsumeIntegralInRange<ssize_t>(-1, len); + if (r == -1) { + SetFuzzedErrNo(m_fuzzed_data_provider, send_errnos); + } + return r; +} + +ssize_t FuzzedSock::Recv(void* buf, size_t len, int flags) const +{ + // Have a permanent error at recv_errnos[0] because when the fuzzed data is exhausted + // SetFuzzedErrNo() will always return the first element and we want to avoid Recv() + // returning -1 and setting errno to EAGAIN repeatedly. + constexpr std::array recv_errnos{ + ECONNREFUSED, + EAGAIN, + EBADF, + EFAULT, + EINTR, + EINVAL, + ENOMEM, + ENOTCONN, + ENOTSOCK, + EWOULDBLOCK, + }; + assert(buf != nullptr || len == 0); + if (len == 0 || m_fuzzed_data_provider.ConsumeBool()) { + const ssize_t r = m_fuzzed_data_provider.ConsumeBool() ? 0 : -1; + if (r == -1) { + SetFuzzedErrNo(m_fuzzed_data_provider, recv_errnos); + } + return r; + } + std::vector<uint8_t> random_bytes; + bool pad_to_len_bytes{m_fuzzed_data_provider.ConsumeBool()}; + if (m_peek_data.has_value()) { + // `MSG_PEEK` was used in the preceding `Recv()` call, return `m_peek_data`. + random_bytes.assign({m_peek_data.value()}); + if ((flags & MSG_PEEK) == 0) { + m_peek_data.reset(); + } + pad_to_len_bytes = false; + } else if ((flags & MSG_PEEK) != 0) { + // New call with `MSG_PEEK`. + random_bytes = m_fuzzed_data_provider.ConsumeBytes<uint8_t>(1); + if (!random_bytes.empty()) { + m_peek_data = random_bytes[0]; + pad_to_len_bytes = false; + } + } else { + random_bytes = m_fuzzed_data_provider.ConsumeBytes<uint8_t>( + m_fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, len)); + } + if (random_bytes.empty()) { + const ssize_t r = m_fuzzed_data_provider.ConsumeBool() ? 0 : -1; + if (r == -1) { + SetFuzzedErrNo(m_fuzzed_data_provider, recv_errnos); + } + return r; + } + std::memcpy(buf, random_bytes.data(), random_bytes.size()); + if (pad_to_len_bytes) { + if (len > random_bytes.size()) { + std::memset((char*)buf + random_bytes.size(), 0, len - random_bytes.size()); + } + return len; + } + if (m_fuzzed_data_provider.ConsumeBool() && std::getenv("FUZZED_SOCKET_FAKE_LATENCY") != nullptr) { + std::this_thread::sleep_for(std::chrono::milliseconds{2}); + } + return random_bytes.size(); +} + +int FuzzedSock::Connect(const sockaddr*, socklen_t) const +{ + // Have a permanent error at connect_errnos[0] because when the fuzzed data is exhausted + // SetFuzzedErrNo() will always return the first element and we want to avoid Connect() + // returning -1 and setting errno to EAGAIN repeatedly. + constexpr std::array connect_errnos{ + ECONNREFUSED, + EAGAIN, + ECONNRESET, + EHOSTUNREACH, + EINPROGRESS, + EINTR, + ENETUNREACH, + ETIMEDOUT, + }; + if (m_fuzzed_data_provider.ConsumeBool()) { + SetFuzzedErrNo(m_fuzzed_data_provider, connect_errnos); + return -1; + } + return 0; +} + +int FuzzedSock::GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const +{ + constexpr std::array getsockopt_errnos{ + ENOMEM, + ENOBUFS, + }; + if (m_fuzzed_data_provider.ConsumeBool()) { + SetFuzzedErrNo(m_fuzzed_data_provider, getsockopt_errnos); + return -1; + } + if (opt_val == nullptr) { + return 0; + } + std::memcpy(opt_val, + ConsumeFixedLengthByteVector(m_fuzzed_data_provider, *opt_len).data(), + *opt_len); + return 0; +} + +bool FuzzedSock::Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred) const +{ + constexpr std::array wait_errnos{ + EBADF, + EINTR, + EINVAL, + }; + if (m_fuzzed_data_provider.ConsumeBool()) { + SetFuzzedErrNo(m_fuzzed_data_provider, wait_errnos); return false; } - if (occurred) *occurred = 0; + if (occurred != nullptr) { + *occurred = m_fuzzed_data_provider.ConsumeBool() ? requested : 0; + } return true; } +bool FuzzedSock::IsConnected(std::string& errmsg) const +{ + if (m_fuzzed_data_provider.ConsumeBool()) { + return true; + } + errmsg = "disconnected at random by the fuzzer"; + return false; +} + void FillNode(FuzzedDataProvider& fuzzed_data_provider, CNode& node, bool init_version) noexcept { const ServiceFlags remote_services = ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS); diff --git a/src/test/fuzz/util.h b/src/test/fuzz/util.h index adcdd71748..8f4f87fbdc 100644 --- a/src/test/fuzz/util.h +++ b/src/test/fuzz/util.h @@ -575,179 +575,25 @@ class FuzzedSock : public Sock mutable std::optional<uint8_t> m_peek_data; public: - explicit FuzzedSock(FuzzedDataProvider& fuzzed_data_provider) : m_fuzzed_data_provider{fuzzed_data_provider} - { - m_socket = fuzzed_data_provider.ConsumeIntegral<SOCKET>(); - } + explicit FuzzedSock(FuzzedDataProvider& fuzzed_data_provider); - ~FuzzedSock() override - { - // Sock::~Sock() will be called after FuzzedSock::~FuzzedSock() and it will call - // Sock::Reset() (not FuzzedSock::Reset()!) which will call CloseSocket(m_socket). - // Avoid closing an arbitrary file descriptor (m_socket is just a random number which - // may concide with a real opened file descriptor). - Reset(); - } + ~FuzzedSock() override; - FuzzedSock& operator=(Sock&& other) override - { - assert(false && "Move of Sock into FuzzedSock not allowed."); - return *this; - } + FuzzedSock& operator=(Sock&& other) override; - void Reset() override - { - m_socket = INVALID_SOCKET; - } + void Reset() override; - ssize_t Send(const void* data, size_t len, int flags) const override - { - constexpr std::array send_errnos{ - EACCES, - EAGAIN, - EALREADY, - EBADF, - ECONNRESET, - EDESTADDRREQ, - EFAULT, - EINTR, - EINVAL, - EISCONN, - EMSGSIZE, - ENOBUFS, - ENOMEM, - ENOTCONN, - ENOTSOCK, - EOPNOTSUPP, - EPIPE, - EWOULDBLOCK, - }; - if (m_fuzzed_data_provider.ConsumeBool()) { - return len; - } - const ssize_t r = m_fuzzed_data_provider.ConsumeIntegralInRange<ssize_t>(-1, len); - if (r == -1) { - SetFuzzedErrNo(m_fuzzed_data_provider, send_errnos); - } - return r; - } + ssize_t Send(const void* data, size_t len, int flags) const override; - ssize_t Recv(void* buf, size_t len, int flags) const override - { - // Have a permanent error at recv_errnos[0] because when the fuzzed data is exhausted - // SetFuzzedErrNo() will always return the first element and we want to avoid Recv() - // returning -1 and setting errno to EAGAIN repeatedly. - constexpr std::array recv_errnos{ - ECONNREFUSED, - EAGAIN, - EBADF, - EFAULT, - EINTR, - EINVAL, - ENOMEM, - ENOTCONN, - ENOTSOCK, - EWOULDBLOCK, - }; - assert(buf != nullptr || len == 0); - if (len == 0 || m_fuzzed_data_provider.ConsumeBool()) { - const ssize_t r = m_fuzzed_data_provider.ConsumeBool() ? 0 : -1; - if (r == -1) { - SetFuzzedErrNo(m_fuzzed_data_provider, recv_errnos); - } - return r; - } - std::vector<uint8_t> random_bytes; - bool pad_to_len_bytes{m_fuzzed_data_provider.ConsumeBool()}; - if (m_peek_data.has_value()) { - // `MSG_PEEK` was used in the preceding `Recv()` call, return `m_peek_data`. - random_bytes.assign({m_peek_data.value()}); - if ((flags & MSG_PEEK) == 0) { - m_peek_data.reset(); - } - pad_to_len_bytes = false; - } else if ((flags & MSG_PEEK) != 0) { - // New call with `MSG_PEEK`. - random_bytes = m_fuzzed_data_provider.ConsumeBytes<uint8_t>(1); - if (!random_bytes.empty()) { - m_peek_data = random_bytes[0]; - pad_to_len_bytes = false; - } - } else { - random_bytes = m_fuzzed_data_provider.ConsumeBytes<uint8_t>( - m_fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, len)); - } - if (random_bytes.empty()) { - const ssize_t r = m_fuzzed_data_provider.ConsumeBool() ? 0 : -1; - if (r == -1) { - SetFuzzedErrNo(m_fuzzed_data_provider, recv_errnos); - } - return r; - } - std::memcpy(buf, random_bytes.data(), random_bytes.size()); - if (pad_to_len_bytes) { - if (len > random_bytes.size()) { - std::memset((char*)buf + random_bytes.size(), 0, len - random_bytes.size()); - } - return len; - } - if (m_fuzzed_data_provider.ConsumeBool() && std::getenv("FUZZED_SOCKET_FAKE_LATENCY") != nullptr) { - std::this_thread::sleep_for(std::chrono::milliseconds{2}); - } - return random_bytes.size(); - } + ssize_t Recv(void* buf, size_t len, int flags) const override; - int Connect(const sockaddr*, socklen_t) const override - { - // Have a permanent error at connect_errnos[0] because when the fuzzed data is exhausted - // SetFuzzedErrNo() will always return the first element and we want to avoid Connect() - // returning -1 and setting errno to EAGAIN repeatedly. - constexpr std::array connect_errnos{ - ECONNREFUSED, - EAGAIN, - ECONNRESET, - EHOSTUNREACH, - EINPROGRESS, - EINTR, - ENETUNREACH, - ETIMEDOUT, - }; - if (m_fuzzed_data_provider.ConsumeBool()) { - SetFuzzedErrNo(m_fuzzed_data_provider, connect_errnos); - return -1; - } - return 0; - } + int Connect(const sockaddr*, socklen_t) const override; - int GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const override - { - constexpr std::array getsockopt_errnos{ - ENOMEM, - ENOBUFS, - }; - if (m_fuzzed_data_provider.ConsumeBool()) { - SetFuzzedErrNo(m_fuzzed_data_provider, getsockopt_errnos); - return -1; - } - if (opt_val == nullptr) { - return 0; - } - std::memcpy(opt_val, - ConsumeFixedLengthByteVector(m_fuzzed_data_provider, *opt_len).data(), - *opt_len); - return 0; - } + int GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const override; bool Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred = nullptr) const override; - bool IsConnected(std::string& errmsg) const override - { - if (m_fuzzed_data_provider.ConsumeBool()) { - return true; - } - errmsg = "disconnected at random by the fuzzer"; - return false; - } + bool IsConnected(std::string& errmsg) const override; }; [[nodiscard]] inline FuzzedSock ConsumeSock(FuzzedDataProvider& fuzzed_data_provider) diff --git a/src/test/fuzz/versionbits.cpp b/src/test/fuzz/versionbits.cpp index 88c1a1a9cb..9186821836 100644 --- a/src/test/fuzz/versionbits.cpp +++ b/src/test/fuzz/versionbits.cpp @@ -29,14 +29,16 @@ public: const int64_t m_end; const int m_period; const int m_threshold; + const int m_min_activation_height; const int m_bit; - TestConditionChecker(int64_t begin, int64_t end, int period, int threshold, int bit) - : m_begin{begin}, m_end{end}, m_period{period}, m_threshold{threshold}, m_bit{bit} + TestConditionChecker(int64_t begin, int64_t end, int period, int threshold, int min_activation_height, int bit) + : m_begin{begin}, m_end{end}, m_period{period}, m_threshold{threshold}, m_min_activation_height{min_activation_height}, m_bit{bit} { assert(m_period > 0); assert(0 <= m_threshold && m_threshold <= m_period); assert(0 <= m_bit && m_bit < 32 && m_bit < VERSIONBITS_NUM_BITS); + assert(0 <= m_min_activation_height); } bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const override { return Condition(pindex->nVersion); } @@ -44,6 +46,7 @@ public: int64_t EndTime(const Consensus::Params& params) const override { return m_end; } int Period(const Consensus::Params& params) const override { return m_period; } int Threshold(const Consensus::Params& params) const override { return m_threshold; } + int MinActivationHeight(const Consensus::Params& params) const override { return m_min_activation_height; } ThresholdState GetStateFor(const CBlockIndex* pindexPrev) const { return AbstractThresholdConditionChecker::GetStateFor(pindexPrev, dummy_params, m_cache); } int GetStateSinceHeightFor(const CBlockIndex* pindexPrev) const { return AbstractThresholdConditionChecker::GetStateSinceHeightFor(pindexPrev, dummy_params, m_cache); } @@ -144,32 +147,27 @@ FUZZ_TARGET_INIT(versionbits, initialize) // pick the timestamp to switch based on a block // note states will change *after* these blocks because mediantime lags int start_block = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, period * (max_periods - 3)); - int end_block = fuzzed_data_provider.ConsumeIntegralInRange<int>(start_block, period * (max_periods - 3)); + int end_block = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, period * (max_periods - 3)); start_time = block_start_time + start_block * interval; timeout = block_start_time + end_block * interval; - assert(start_time <= timeout); - // allow for times to not exactly match a block if (fuzzed_data_provider.ConsumeBool()) start_time += interval / 2; if (fuzzed_data_provider.ConsumeBool()) timeout += interval / 2; - - // this may make timeout too early; if so, don't run the test - if (start_time > timeout) return; } else { if (fuzzed_data_provider.ConsumeBool()) { start_time = Consensus::BIP9Deployment::ALWAYS_ACTIVE; - timeout = Consensus::BIP9Deployment::NO_TIMEOUT; always_active_test = true; } else { - start_time = 1199145601; // January 1, 2008 - timeout = 1230767999; // December 31, 2008 + start_time = Consensus::BIP9Deployment::NEVER_ACTIVE; never_active_test = true; } + timeout = fuzzed_data_provider.ConsumeBool() ? Consensus::BIP9Deployment::NO_TIMEOUT : fuzzed_data_provider.ConsumeIntegral<int64_t>(); } + int min_activation = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, period * max_periods); - TestConditionChecker checker(start_time, timeout, period, threshold, bit); + TestConditionChecker checker(start_time, timeout, period, threshold, min_activation, bit); // Early exit if the versions don't signal sensibly for the deployment if (!checker.Condition(ver_signal)) return; @@ -294,28 +292,35 @@ FUZZ_TARGET_INIT(versionbits, initialize) assert(since == 0); assert(exp_state == ThresholdState::DEFINED); assert(current_block->GetMedianTimePast() < checker.m_begin); - assert(current_block->GetMedianTimePast() < checker.m_end); break; case ThresholdState::STARTED: assert(current_block->GetMedianTimePast() >= checker.m_begin); - assert(current_block->GetMedianTimePast() < checker.m_end); if (exp_state == ThresholdState::STARTED) { assert(blocks_sig < threshold); + assert(current_block->GetMedianTimePast() < checker.m_end); } else { assert(exp_state == ThresholdState::DEFINED); } break; case ThresholdState::LOCKED_IN: - assert(exp_state == ThresholdState::STARTED); - assert(current_block->GetMedianTimePast() < checker.m_end); - assert(blocks_sig >= threshold); + if (exp_state == ThresholdState::LOCKED_IN) { + assert(current_block->nHeight + 1 < min_activation); + } else { + assert(exp_state == ThresholdState::STARTED); + assert(blocks_sig >= threshold); + } break; case ThresholdState::ACTIVE: + assert(always_active_test || min_activation <= current_block->nHeight + 1); assert(exp_state == ThresholdState::ACTIVE || exp_state == ThresholdState::LOCKED_IN); break; case ThresholdState::FAILED: - assert(current_block->GetMedianTimePast() >= checker.m_end); - assert(exp_state != ThresholdState::LOCKED_IN && exp_state != ThresholdState::ACTIVE); + assert(never_active_test || current_block->GetMedianTimePast() >= checker.m_end); + if (exp_state == ThresholdState::STARTED) { + assert(blocks_sig < threshold); + } else { + assert(exp_state == ThresholdState::FAILED); + } break; default: assert(false); @@ -326,26 +331,20 @@ FUZZ_TARGET_INIT(versionbits, initialize) assert(state == ThresholdState::ACTIVE || state == ThresholdState::FAILED); } - // "always active" has additional restrictions if (always_active_test) { + // "always active" has additional restrictions assert(state == ThresholdState::ACTIVE); assert(exp_state == ThresholdState::ACTIVE); assert(since == 0); + } else if (never_active_test) { + // "never active" does too + assert(state == ThresholdState::FAILED); + assert(exp_state == ThresholdState::FAILED); + assert(since == 0); } else { - // except for always active, the initial state is always DEFINED + // for signalled deployments, the initial state is always DEFINED assert(since > 0 || state == ThresholdState::DEFINED); assert(exp_since > 0 || exp_state == ThresholdState::DEFINED); } - - // "never active" does too - if (never_active_test) { - assert(state == ThresholdState::FAILED); - assert(since == period); - if (exp_since == 0) { - assert(exp_state == ThresholdState::DEFINED); - } else { - assert(exp_state == ThresholdState::FAILED); - } - } } } // namespace diff --git a/src/test/getarg_tests.cpp b/src/test/getarg_tests.cpp index 45c9b90ee9..2a217f3455 100644 --- a/src/test/getarg_tests.cpp +++ b/src/test/getarg_tests.cpp @@ -18,7 +18,7 @@ namespace getarg_tests{ protected: void SetupArgs(const std::vector<std::pair<std::string, unsigned int>>& args); void ResetArgs(const std::string& strArg); - ArgsManager m_args; + ArgsManager m_local_args; }; } @@ -39,14 +39,14 @@ void LocalTestingSetup :: ResetArgs(const std::string& strArg) vecChar.push_back(s.c_str()); std::string error; - BOOST_CHECK(m_args.ParseParameters(vecChar.size(), vecChar.data(), error)); + BOOST_CHECK(m_local_args.ParseParameters(vecChar.size(), vecChar.data(), error)); } void LocalTestingSetup :: SetupArgs(const std::vector<std::pair<std::string, unsigned int>>& args) { - m_args.ClearArgs(); + m_local_args.ClearArgs(); for (const auto& arg : args) { - m_args.AddArg(arg.first, "", arg.second, OptionsCategory::OPTIONS); + m_local_args.AddArg(arg.first, "", arg.second, OptionsCategory::OPTIONS); } } @@ -55,52 +55,52 @@ BOOST_AUTO_TEST_CASE(boolarg) const auto foo = std::make_pair("-foo", ArgsManager::ALLOW_ANY); SetupArgs({foo}); ResetArgs("-foo"); - BOOST_CHECK(m_args.GetBoolArg("-foo", false)); - BOOST_CHECK(m_args.GetBoolArg("-foo", true)); + BOOST_CHECK(m_local_args.GetBoolArg("-foo", false)); + BOOST_CHECK(m_local_args.GetBoolArg("-foo", true)); - BOOST_CHECK(!m_args.GetBoolArg("-fo", false)); - BOOST_CHECK(m_args.GetBoolArg("-fo", true)); + BOOST_CHECK(!m_local_args.GetBoolArg("-fo", false)); + BOOST_CHECK(m_local_args.GetBoolArg("-fo", true)); - BOOST_CHECK(!m_args.GetBoolArg("-fooo", false)); - BOOST_CHECK(m_args.GetBoolArg("-fooo", true)); + BOOST_CHECK(!m_local_args.GetBoolArg("-fooo", false)); + BOOST_CHECK(m_local_args.GetBoolArg("-fooo", true)); ResetArgs("-foo=0"); - BOOST_CHECK(!m_args.GetBoolArg("-foo", false)); - BOOST_CHECK(!m_args.GetBoolArg("-foo", true)); + BOOST_CHECK(!m_local_args.GetBoolArg("-foo", false)); + BOOST_CHECK(!m_local_args.GetBoolArg("-foo", true)); ResetArgs("-foo=1"); - BOOST_CHECK(m_args.GetBoolArg("-foo", false)); - BOOST_CHECK(m_args.GetBoolArg("-foo", true)); + BOOST_CHECK(m_local_args.GetBoolArg("-foo", false)); + BOOST_CHECK(m_local_args.GetBoolArg("-foo", true)); // New 0.6 feature: auto-map -nosomething to !-something: ResetArgs("-nofoo"); - BOOST_CHECK(!m_args.GetBoolArg("-foo", false)); - BOOST_CHECK(!m_args.GetBoolArg("-foo", true)); + BOOST_CHECK(!m_local_args.GetBoolArg("-foo", false)); + BOOST_CHECK(!m_local_args.GetBoolArg("-foo", true)); ResetArgs("-nofoo=1"); - BOOST_CHECK(!m_args.GetBoolArg("-foo", false)); - BOOST_CHECK(!m_args.GetBoolArg("-foo", true)); + BOOST_CHECK(!m_local_args.GetBoolArg("-foo", false)); + BOOST_CHECK(!m_local_args.GetBoolArg("-foo", true)); ResetArgs("-foo -nofoo"); // -nofoo should win - BOOST_CHECK(!m_args.GetBoolArg("-foo", false)); - BOOST_CHECK(!m_args.GetBoolArg("-foo", true)); + BOOST_CHECK(!m_local_args.GetBoolArg("-foo", false)); + BOOST_CHECK(!m_local_args.GetBoolArg("-foo", true)); ResetArgs("-foo=1 -nofoo=1"); // -nofoo should win - BOOST_CHECK(!m_args.GetBoolArg("-foo", false)); - BOOST_CHECK(!m_args.GetBoolArg("-foo", true)); + BOOST_CHECK(!m_local_args.GetBoolArg("-foo", false)); + BOOST_CHECK(!m_local_args.GetBoolArg("-foo", true)); ResetArgs("-foo=0 -nofoo=0"); // -nofoo=0 should win - BOOST_CHECK(m_args.GetBoolArg("-foo", false)); - BOOST_CHECK(m_args.GetBoolArg("-foo", true)); + BOOST_CHECK(m_local_args.GetBoolArg("-foo", false)); + BOOST_CHECK(m_local_args.GetBoolArg("-foo", true)); // New 0.6 feature: treat -- same as -: ResetArgs("--foo=1"); - BOOST_CHECK(m_args.GetBoolArg("-foo", false)); - BOOST_CHECK(m_args.GetBoolArg("-foo", true)); + BOOST_CHECK(m_local_args.GetBoolArg("-foo", false)); + BOOST_CHECK(m_local_args.GetBoolArg("-foo", true)); ResetArgs("--nofoo=1"); - BOOST_CHECK(!m_args.GetBoolArg("-foo", false)); - BOOST_CHECK(!m_args.GetBoolArg("-foo", true)); + BOOST_CHECK(!m_local_args.GetBoolArg("-foo", false)); + BOOST_CHECK(!m_local_args.GetBoolArg("-foo", true)); } @@ -110,24 +110,24 @@ BOOST_AUTO_TEST_CASE(stringarg) const auto bar = std::make_pair("-bar", ArgsManager::ALLOW_ANY); SetupArgs({foo, bar}); ResetArgs(""); - BOOST_CHECK_EQUAL(m_args.GetArg("-foo", ""), ""); - BOOST_CHECK_EQUAL(m_args.GetArg("-foo", "eleven"), "eleven"); + BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", ""), ""); + BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", "eleven"), "eleven"); ResetArgs("-foo -bar"); - BOOST_CHECK_EQUAL(m_args.GetArg("-foo", ""), ""); - BOOST_CHECK_EQUAL(m_args.GetArg("-foo", "eleven"), ""); + BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", ""), ""); + BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", "eleven"), ""); ResetArgs("-foo="); - BOOST_CHECK_EQUAL(m_args.GetArg("-foo", ""), ""); - BOOST_CHECK_EQUAL(m_args.GetArg("-foo", "eleven"), ""); + BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", ""), ""); + BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", "eleven"), ""); ResetArgs("-foo=11"); - BOOST_CHECK_EQUAL(m_args.GetArg("-foo", ""), "11"); - BOOST_CHECK_EQUAL(m_args.GetArg("-foo", "eleven"), "11"); + BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", ""), "11"); + BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", "eleven"), "11"); ResetArgs("-foo=eleven"); - BOOST_CHECK_EQUAL(m_args.GetArg("-foo", ""), "eleven"); - BOOST_CHECK_EQUAL(m_args.GetArg("-foo", "eleven"), "eleven"); + BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", ""), "eleven"); + BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", "eleven"), "eleven"); } @@ -137,20 +137,20 @@ BOOST_AUTO_TEST_CASE(intarg) const auto bar = std::make_pair("-bar", ArgsManager::ALLOW_ANY); SetupArgs({foo, bar}); ResetArgs(""); - BOOST_CHECK_EQUAL(m_args.GetArg("-foo", 11), 11); - BOOST_CHECK_EQUAL(m_args.GetArg("-foo", 0), 0); + BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", 11), 11); + BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", 0), 0); ResetArgs("-foo -bar"); - BOOST_CHECK_EQUAL(m_args.GetArg("-foo", 11), 0); - BOOST_CHECK_EQUAL(m_args.GetArg("-bar", 11), 0); + BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", 11), 0); + BOOST_CHECK_EQUAL(m_local_args.GetArg("-bar", 11), 0); ResetArgs("-foo=11 -bar=12"); - BOOST_CHECK_EQUAL(m_args.GetArg("-foo", 0), 11); - BOOST_CHECK_EQUAL(m_args.GetArg("-bar", 11), 12); + BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", 0), 11); + BOOST_CHECK_EQUAL(m_local_args.GetArg("-bar", 11), 12); ResetArgs("-foo=NaN -bar=NotANumber"); - BOOST_CHECK_EQUAL(m_args.GetArg("-foo", 1), 0); - BOOST_CHECK_EQUAL(m_args.GetArg("-bar", 11), 0); + BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", 1), 0); + BOOST_CHECK_EQUAL(m_local_args.GetArg("-bar", 11), 0); } BOOST_AUTO_TEST_CASE(doubledash) @@ -159,11 +159,11 @@ BOOST_AUTO_TEST_CASE(doubledash) const auto bar = std::make_pair("-bar", ArgsManager::ALLOW_ANY); SetupArgs({foo, bar}); ResetArgs("--foo"); - BOOST_CHECK_EQUAL(m_args.GetBoolArg("-foo", false), true); + BOOST_CHECK_EQUAL(m_local_args.GetBoolArg("-foo", false), true); ResetArgs("--foo=verbose --bar=1"); - BOOST_CHECK_EQUAL(m_args.GetArg("-foo", ""), "verbose"); - BOOST_CHECK_EQUAL(m_args.GetArg("-bar", 0), 1); + BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", ""), "verbose"); + BOOST_CHECK_EQUAL(m_local_args.GetArg("-bar", 0), 1); } BOOST_AUTO_TEST_CASE(boolargno) @@ -172,24 +172,24 @@ BOOST_AUTO_TEST_CASE(boolargno) const auto bar = std::make_pair("-bar", ArgsManager::ALLOW_ANY); SetupArgs({foo, bar}); ResetArgs("-nofoo"); - BOOST_CHECK(!m_args.GetBoolArg("-foo", true)); - BOOST_CHECK(!m_args.GetBoolArg("-foo", false)); + BOOST_CHECK(!m_local_args.GetBoolArg("-foo", true)); + BOOST_CHECK(!m_local_args.GetBoolArg("-foo", false)); ResetArgs("-nofoo=1"); - BOOST_CHECK(!m_args.GetBoolArg("-foo", true)); - BOOST_CHECK(!m_args.GetBoolArg("-foo", false)); + BOOST_CHECK(!m_local_args.GetBoolArg("-foo", true)); + BOOST_CHECK(!m_local_args.GetBoolArg("-foo", false)); ResetArgs("-nofoo=0"); - BOOST_CHECK(m_args.GetBoolArg("-foo", true)); - BOOST_CHECK(m_args.GetBoolArg("-foo", false)); + BOOST_CHECK(m_local_args.GetBoolArg("-foo", true)); + BOOST_CHECK(m_local_args.GetBoolArg("-foo", false)); ResetArgs("-foo --nofoo"); // --nofoo should win - BOOST_CHECK(!m_args.GetBoolArg("-foo", true)); - BOOST_CHECK(!m_args.GetBoolArg("-foo", false)); + BOOST_CHECK(!m_local_args.GetBoolArg("-foo", true)); + BOOST_CHECK(!m_local_args.GetBoolArg("-foo", false)); ResetArgs("-nofoo -foo"); // foo always wins: - BOOST_CHECK(m_args.GetBoolArg("-foo", true)); - BOOST_CHECK(m_args.GetBoolArg("-foo", false)); + BOOST_CHECK(m_local_args.GetBoolArg("-foo", true)); + BOOST_CHECK(m_local_args.GetBoolArg("-foo", false)); } BOOST_AUTO_TEST_CASE(logargs) @@ -209,7 +209,7 @@ BOOST_AUTO_TEST_CASE(logargs) }); // Log the arguments - m_args.LogArgs(); + m_local_args.LogArgs(); LogInstance().DeleteCallback(print_connection); // Check that what should appear does, and what shouldn't doesn't. diff --git a/src/test/logging_tests.cpp b/src/test/logging_tests.cpp index 25655b8894..e99c6e0fc8 100644 --- a/src/test/logging_tests.cpp +++ b/src/test/logging_tests.cpp @@ -14,7 +14,6 @@ BOOST_FIXTURE_TEST_SUITE(logging_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(logging_timer) { - SetMockTime(1); auto sec_timer = BCLog::Timer<std::chrono::seconds>("tests", "end_msg"); SetMockTime(2); @@ -29,8 +28,6 @@ BOOST_AUTO_TEST_CASE(logging_timer) auto micro_timer = BCLog::Timer<std::chrono::microseconds>("tests", "end_msg"); SetMockTime(2); BOOST_CHECK_EQUAL(micro_timer.LogMsg("test micros"), "tests: test micros (1000000.00μs)"); - - SetMockTime(0); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/mempool_tests.cpp b/src/test/mempool_tests.cpp index 38fed51af2..bf36f8a6c9 100644 --- a/src/test/mempool_tests.cpp +++ b/src/test/mempool_tests.cpp @@ -571,8 +571,6 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest) SetMockTime(42 + 8*CTxMemPool::ROLLING_FEE_HALFLIFE + CTxMemPool::ROLLING_FEE_HALFLIFE/2 + CTxMemPool::ROLLING_FEE_HALFLIFE/4); BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), 0); // ... unless it has gone all the way to 0 (after getting past 1000/2) - - SetMockTime(0); } inline CTransactionRef make_tx(std::vector<CAmount>&& output_values, std::vector<CTransactionRef>&& inputs=std::vector<CTransactionRef>(), std::vector<uint32_t>&& input_indices=std::vector<uint32_t>()) diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp index 8eab26f3d5..1c397481dc 100644 --- a/src/test/net_tests.cpp +++ b/src/test/net_tests.cpp @@ -307,9 +307,6 @@ BOOST_AUTO_TEST_CASE(cnetaddr_basic) BOOST_REQUIRE(addr.IsValid()); BOOST_REQUIRE(addr.IsIPv6()); BOOST_CHECK(!addr.IsBindAny()); - const std::string addr_str{addr.ToString()}; - BOOST_CHECK(addr_str == scoped_addr || addr_str == "fe80:0:0:0:0:0:0:1"); - // The fallback case "fe80:0:0:0:0:0:0:1" is needed for macOS 10.14/10.15 and (probably) later. // Test that the delimiter "%" and default zone id of 0 can be omitted for the default scope. BOOST_REQUIRE(LookupHost(link_local + "%0", addr, false)); BOOST_REQUIRE(addr.IsValid()); diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp index 3b6faf7bbb..67fbc9f8a2 100644 --- a/src/test/rpc_tests.cpp +++ b/src/test/rpc_tests.cpp @@ -275,7 +275,11 @@ BOOST_AUTO_TEST_CASE(rpc_ban) BOOST_CHECK_NO_THROW(CallRPC(std::string("clearbanned"))); + auto now = 10'000s; + SetMockTime(now); BOOST_CHECK_NO_THROW(r = CallRPC(std::string("setban 127.0.0.0/24 add 200"))); + SetMockTime(now += 2s); + const int64_t time_remaining_expected{198}; BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned"))); ar = r.get_array(); o1 = ar[0].get_obj(); @@ -284,12 +288,10 @@ BOOST_AUTO_TEST_CASE(rpc_ban) const int64_t ban_created{find_value(o1, "ban_created").get_int64()}; const int64_t ban_duration{find_value(o1, "ban_duration").get_int64()}; const int64_t time_remaining{find_value(o1, "time_remaining").get_int64()}; - const int64_t now{GetTime()}; BOOST_CHECK_EQUAL(adr.get_str(), "127.0.0.0/24"); - BOOST_CHECK(banned_until > now); - BOOST_CHECK(banned_until - now <= 200); + BOOST_CHECK_EQUAL(banned_until, time_remaining_expected + now.count()); BOOST_CHECK_EQUAL(ban_duration, banned_until - ban_created); - BOOST_CHECK_EQUAL(time_remaining, banned_until - now); + BOOST_CHECK_EQUAL(time_remaining, time_remaining_expected); // must throw an exception because 127.0.0.1 is in already banned subnet range BOOST_CHECK_THROW(r = CallRPC(std::string("setban 127.0.0.1 add")), std::runtime_error); diff --git a/src/test/settings_tests.cpp b/src/test/settings_tests.cpp index 548fd020a6..f5ae9f86d1 100644 --- a/src/test/settings_tests.cpp +++ b/src/test/settings_tests.cpp @@ -45,7 +45,7 @@ BOOST_FIXTURE_TEST_SUITE(settings_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(ReadWrite) { - fs::path path = GetDataDir() / "settings.json"; + fs::path path = m_args.GetDataDirPath() / "settings.json"; WriteText(path, R"({ "string": "string", diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index aaa6caa4f1..9bbf9567f5 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -20,6 +20,7 @@ #include <script/signingprovider.h> #include <script/standard.h> #include <streams.h> +#include <test/util/script.h> #include <test/util/transaction_utils.h> #include <util/strencodings.h> #include <util/string.h> @@ -59,6 +60,9 @@ static std::map<std::string, unsigned int> mapFlagNames = { {std::string("WITNESS_PUBKEYTYPE"), (unsigned int)SCRIPT_VERIFY_WITNESS_PUBKEYTYPE}, {std::string("CONST_SCRIPTCODE"), (unsigned int)SCRIPT_VERIFY_CONST_SCRIPTCODE}, {std::string("TAPROOT"), (unsigned int)SCRIPT_VERIFY_TAPROOT}, + {std::string("DISCOURAGE_UPGRADABLE_PUBKEYTYPE"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE}, + {std::string("DISCOURAGE_OP_SUCCESS"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS}, + {std::string("DISCOURAGE_UPGRADABLE_TAPROOT_VERSION"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION}, }; unsigned int ParseScriptFlags(std::string strFlags) @@ -78,6 +82,16 @@ unsigned int ParseScriptFlags(std::string strFlags) return flags; } +// Check that all flags in STANDARD_SCRIPT_VERIFY_FLAGS are present in mapFlagNames. +bool CheckMapFlagNames() +{ + unsigned int standard_flags_missing{STANDARD_SCRIPT_VERIFY_FLAGS}; + for (const auto& pair : mapFlagNames) { + standard_flags_missing &= ~(pair.second); + } + return standard_flags_missing == 0; +} + std::string FormatScriptFlags(unsigned int flags) { if (flags == 0) { @@ -139,6 +153,7 @@ unsigned int TrimFlags(unsigned int flags) // CLEANSTACK requires WITNESS (and transitively CLEANSTACK requires P2SH) if (!(flags & SCRIPT_VERIFY_WITNESS)) flags &= ~(unsigned int)SCRIPT_VERIFY_CLEANSTACK; + Assert(IsValidFlagCombination(flags)); return flags; } @@ -149,17 +164,21 @@ unsigned int FillFlags(unsigned int flags) // WITNESS implies P2SH (and transitively CLEANSTACK implies P2SH) if (flags & SCRIPT_VERIFY_WITNESS) flags |= SCRIPT_VERIFY_P2SH; + Assert(IsValidFlagCombination(flags)); return flags; } -// Return valid flags that are all except one flag for each flag -std::vector<unsigned int> ExcludeIndividualFlags(unsigned int flags) +// Exclude each possible script verify flag from flags. Returns a set of these flag combinations +// that are valid and without duplicates. For example: if flags=1111 and the 4 possible flags are +// 0001, 0010, 0100, and 1000, this should return the set {0111, 1011, 1101, 1110}. +// Assumes that mapFlagNames contains all script verify flags. +std::set<unsigned int> ExcludeIndividualFlags(unsigned int flags) { - std::vector<unsigned int> flags_combos; - for (unsigned int i = 0; i < mapFlagNames.size(); ++i) { - const unsigned int flags_excluding_i = TrimFlags(flags & ~(1U << i)); - if (flags != flags_excluding_i && std::find(flags_combos.begin(), flags_combos.end(), flags_excluding_i) != flags_combos.end()) { - flags_combos.push_back(flags_excluding_i); + std::set<unsigned int> flags_combos; + for (const auto& pair : mapFlagNames) { + const unsigned int flags_excluding_one = TrimFlags(flags & ~(pair.second)); + if (flags != flags_excluding_one) { + flags_combos.insert(flags_excluding_one); } } return flags_combos; @@ -169,6 +188,7 @@ BOOST_FIXTURE_TEST_SUITE(transaction_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(tx_valid) { + BOOST_CHECK_MESSAGE(CheckMapFlagNames(), "mapFlagNames is missing a script verification flag"); // Read tests from test/data/tx_valid.json UniValue tests = read_json(std::string(json_tests::tx_valid, json_tests::tx_valid + sizeof(json_tests::tx_valid))); @@ -228,16 +248,15 @@ BOOST_AUTO_TEST_CASE(tx_valid) BOOST_ERROR("Bad test flags: " << strTest); } - if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, ~verify_flags, txdata, strTest, /* expect_valid */ true)) { - BOOST_ERROR("Tx unexpectedly failed: " << strTest); - } + BOOST_CHECK_MESSAGE(CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, ~verify_flags, txdata, strTest, /* expect_valid */ true), + "Tx unexpectedly failed: " << strTest); // Backwards compatibility of script verification flags: Removing any flag(s) should not invalidate a valid transaction - for (size_t i = 0; i < mapFlagNames.size(); ++i) { + for (const auto& [name, flag] : mapFlagNames) { // Removing individual flags - unsigned int flags = TrimFlags(~(verify_flags | (1U << i))); + unsigned int flags = TrimFlags(~(verify_flags | flag)); if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, flags, txdata, strTest, /* expect_valid */ true)) { - BOOST_ERROR("Tx unexpectedly failed with flag " << ToString(i) << " unset: " << strTest); + BOOST_ERROR("Tx unexpectedly failed with flag " << name << " unset: " << strTest); } // Removing random combinations of flags flags = TrimFlags(~(verify_flags | (unsigned int)InsecureRandBits(mapFlagNames.size()))); @@ -247,7 +266,7 @@ BOOST_AUTO_TEST_CASE(tx_valid) } // Check that flags are maximal: transaction should fail if any unset flags are set. - for (auto flags_excluding_one: ExcludeIndividualFlags(verify_flags)) { + for (auto flags_excluding_one : ExcludeIndividualFlags(verify_flags)) { if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, ~flags_excluding_one, txdata, strTest, /* expect_valid */ false)) { BOOST_ERROR("Too many flags unset: " << strTest); } @@ -314,27 +333,31 @@ BOOST_AUTO_TEST_CASE(tx_invalid) PrecomputedTransactionData txdata(tx); unsigned int verify_flags = ParseScriptFlags(test[2].get_str()); - // Not using FillFlags() in the main test, in order to detect invalid verifyFlags combination - if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, verify_flags, txdata, strTest, /* expect_valid */ false)) { - BOOST_ERROR("Tx unexpectedly passed: " << strTest); + // Check that the test gives a valid combination of flags (otherwise VerifyScript will throw). Don't edit the flags. + if (verify_flags != FillFlags(verify_flags)) { + BOOST_ERROR("Bad test flags: " << strTest); } + // Not using FillFlags() in the main test, in order to detect invalid verifyFlags combination + BOOST_CHECK_MESSAGE(CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, verify_flags, txdata, strTest, /* expect_valid */ false), + "Tx unexpectedly passed: " << strTest); + // Backwards compatibility of script verification flags: Adding any flag(s) should not validate an invalid transaction - for (size_t i = 0; i < mapFlagNames.size(); i++) { - unsigned int flags = FillFlags(verify_flags | (1U << i)); + for (const auto& [name, flag] : mapFlagNames) { + unsigned int flags = FillFlags(verify_flags | flag); // Adding individual flags if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, flags, txdata, strTest, /* expect_valid */ false)) { - BOOST_ERROR("Tx unexpectedly passed with flag " << ToString(i) << " set: " << strTest); + BOOST_ERROR("Tx unexpectedly passed with flag " << name << " set: " << strTest); } // Adding random combinations of flags flags = FillFlags(verify_flags | (unsigned int)InsecureRandBits(mapFlagNames.size())); if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, flags, txdata, strTest, /* expect_valid */ false)) { - BOOST_ERROR("Tx unexpectedly passed with random flags " << ToString(flags) << ": " << strTest); + BOOST_ERROR("Tx unexpectedly passed with random flags " << name << ": " << strTest); } } // Check that flags are minimal: transaction should succeed if any set flags are unset. - for (auto flags_excluding_one: ExcludeIndividualFlags(verify_flags)) { + for (auto flags_excluding_one : ExcludeIndividualFlags(verify_flags)) { if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, flags_excluding_one, txdata, strTest, /* expect_valid */ true)) { BOOST_ERROR("Too many flags set: " << strTest); } diff --git a/src/test/util/blockfilter.cpp b/src/test/util/blockfilter.cpp index bccff5e5a6..b8ab9d2344 100644 --- a/src/test/util/blockfilter.cpp +++ b/src/test/util/blockfilter.cpp @@ -5,6 +5,7 @@ #include <test/util/blockfilter.h> #include <chainparams.h> +#include <node/blockstorage.h> #include <validation.h> diff --git a/src/test/util/net.h b/src/test/util/net.h index 2b7988413f..9268d60a1e 100644 --- a/src/test/util/net.h +++ b/src/test/util/net.h @@ -78,8 +78,7 @@ public: explicit StaticContentsSock(const std::string& contents) : m_contents{contents}, m_consumed{0} { // Just a dummy number that is not INVALID_SOCKET. - static_assert(INVALID_SOCKET != 1000); - m_socket = 1000; + m_socket = INVALID_SOCKET - 1; } ~StaticContentsSock() override { Reset(); } diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp index 2d7f335a04..ffc5115145 100644 --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -71,7 +71,8 @@ std::ostream& operator<<(std::ostream& os, const uint256& num) } BasicTestingSetup::BasicTestingSetup(const std::string& chainName, const std::vector<const char*>& extra_args) - : m_path_root{fs::temp_directory_path() / "test_common_" PACKAGE_NAME / g_insecure_rand_ctx_temp_path.rand256().ToString()} + : m_path_root{fs::temp_directory_path() / "test_common_" PACKAGE_NAME / g_insecure_rand_ctx_temp_path.rand256().ToString()}, + m_args{} { const std::vector<const char*> arguments = Cat( { @@ -87,8 +88,9 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName, const std::ve extra_args); util::ThreadRename("test"); fs::create_directories(m_path_root); + m_args.ForceSetArg("-datadir", m_path_root.string()); gArgs.ForceSetArg("-datadir", m_path_root.string()); - ClearDatadirCache(); + gArgs.ClearPathCache(); { SetupServerArgs(m_node); std::string error; @@ -120,6 +122,7 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName, const std::ve BasicTestingSetup::~BasicTestingSetup() { + SetMockTime(0s); // Reset mocktime for following tests LogInstance().DisconnectTestLogger(); fs::remove_all(m_path_root); gArgs.ClearArgs(); @@ -190,7 +193,7 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vector<const } m_node.addrman = std::make_unique<CAddrMan>(); - m_node.banman = std::make_unique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME); + m_node.banman = std::make_unique<BanMan>(m_args.GetDataDirPath() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME); m_node.connman = std::make_unique<CConnman>(0x1337, 0x1337, *m_node.addrman); // Deterministic randomness for tests. m_node.peerman = PeerManager::make(chainparams, *m_node.connman, *m_node.addrman, m_node.banman.get(), *m_node.scheduler, *m_node.chainman, @@ -241,7 +244,8 @@ CBlock TestChain100Setup::CreateAndProcessBlock(const std::vector<CMutableTransa for (const CMutableTransaction& tx : txns) { block.vtx.push_back(MakeTransactionRef(tx)); } - RegenerateCommitments(block, WITH_LOCK(::cs_main, return std::ref(g_chainman.m_blockman))); + CBlockIndex* prev_block = WITH_LOCK(::cs_main, return g_chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock)); + RegenerateCommitments(block, prev_block); while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) ++block.nNonce; @@ -303,7 +307,6 @@ CMutableTransaction TestChain100Setup::CreateValidMempoolTransaction(CTransactio TestChain100Setup::~TestChain100Setup() { gArgs.ForceSetArg("-segwitheight", "0"); - SetMockTime(0); } CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CMutableTransaction& tx) const diff --git a/src/test/util/setup_common.h b/src/test/util/setup_common.h index a32f1f3805..b19dd75765 100644 --- a/src/test/util/setup_common.h +++ b/src/test/util/setup_common.h @@ -8,6 +8,7 @@ #include <chainparamsbase.h> #include <fs.h> #include <key.h> +#include <util/system.h> #include <node/context.h> #include <pubkey.h> #include <random.h> @@ -80,6 +81,7 @@ struct BasicTestingSetup { ~BasicTestingSetup(); const fs::path m_path_root; + ArgsManager m_args; }; /** Testing setup that performs all steps up until right before diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index 5ac09b05db..04b908829b 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -49,24 +49,27 @@ BOOST_FIXTURE_TEST_SUITE(util_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(util_datadir) { - ClearDatadirCache(); - const fs::path dd_norm = GetDataDir(); + // Use local args variable instead of m_args to avoid making assumptions about test setup + ArgsManager args; + args.ForceSetArg("-datadir", m_path_root.string()); - gArgs.ForceSetArg("-datadir", dd_norm.string() + "/"); - ClearDatadirCache(); - BOOST_CHECK_EQUAL(dd_norm, GetDataDir()); + const fs::path dd_norm = args.GetDataDirPath(); - gArgs.ForceSetArg("-datadir", dd_norm.string() + "/."); - ClearDatadirCache(); - BOOST_CHECK_EQUAL(dd_norm, GetDataDir()); + args.ForceSetArg("-datadir", dd_norm.string() + "/"); + args.ClearPathCache(); + BOOST_CHECK_EQUAL(dd_norm, args.GetDataDirPath()); - gArgs.ForceSetArg("-datadir", dd_norm.string() + "/./"); - ClearDatadirCache(); - BOOST_CHECK_EQUAL(dd_norm, GetDataDir()); + args.ForceSetArg("-datadir", dd_norm.string() + "/."); + args.ClearPathCache(); + BOOST_CHECK_EQUAL(dd_norm, args.GetDataDirPath()); - gArgs.ForceSetArg("-datadir", dd_norm.string() + "/.//"); - ClearDatadirCache(); - BOOST_CHECK_EQUAL(dd_norm, GetDataDir()); + args.ForceSetArg("-datadir", dd_norm.string() + "/./"); + args.ClearPathCache(); + BOOST_CHECK_EQUAL(dd_norm, args.GetDataDirPath()); + + args.ForceSetArg("-datadir", dd_norm.string() + "/.//"); + args.ClearPathCache(); + BOOST_CHECK_EQUAL(dd_norm, args.GetDataDirPath()); } BOOST_AUTO_TEST_CASE(util_check) @@ -1143,21 +1146,23 @@ BOOST_AUTO_TEST_CASE(util_ReadWriteSettings) { // Test writing setting. TestArgsManager args1; + args1.ForceSetArg("-datadir", m_path_root.string()); args1.LockSettings([&](util::Settings& settings) { settings.rw_settings["name"] = "value"; }); args1.WriteSettingsFile(); // Test reading setting. TestArgsManager args2; + args2.ForceSetArg("-datadir", m_path_root.string()); args2.ReadSettingsFile(); args2.LockSettings([&](util::Settings& settings) { BOOST_CHECK_EQUAL(settings.rw_settings["name"].get_str(), "value"); }); // Test error logging, and remove previously written setting. { ASSERT_DEBUG_LOG("Failed renaming settings file"); - fs::remove(GetDataDir() / "settings.json"); - fs::create_directory(GetDataDir() / "settings.json"); + fs::remove(args1.GetDataDirPath() / "settings.json"); + fs::create_directory(args1.GetDataDirPath() / "settings.json"); args2.WriteSettingsFile(); - fs::remove(GetDataDir() / "settings.json"); + fs::remove(args1.GetDataDirPath() / "settings.json"); } } @@ -1766,7 +1771,7 @@ static constexpr char LockCommand = 'L'; static constexpr char UnlockCommand = 'U'; static constexpr char ExitCommand = 'X'; -static void TestOtherProcess(fs::path dirname, std::string lockname, int fd) +[[noreturn]] static void TestOtherProcess(fs::path dirname, std::string lockname, int fd) { char ch; while (true) { @@ -1796,7 +1801,7 @@ static void TestOtherProcess(fs::path dirname, std::string lockname, int fd) BOOST_AUTO_TEST_CASE(test_LockDirectory) { - fs::path dirname = GetDataDir() / "lock_dir"; + fs::path dirname = m_args.GetDataDirPath() / "lock_dir"; const std::string lockname = ".lock"; #ifndef WIN32 // Revert SIGCHLD to default, otherwise boost.test will catch and fail on @@ -1885,7 +1890,7 @@ BOOST_AUTO_TEST_CASE(test_LockDirectory) BOOST_AUTO_TEST_CASE(test_DirIsWritable) { // Should be able to write to the data dir. - fs::path tmpdirname = GetDataDir(); + fs::path tmpdirname = m_args.GetDataDirPath(); BOOST_CHECK_EQUAL(DirIsWritable(tmpdirname), true); // Should not be able to write to a non-existent dir. diff --git a/src/test/versionbits_tests.cpp b/src/test/versionbits_tests.cpp index 8841a540f2..304cd8feb0 100644 --- a/src/test/versionbits_tests.cpp +++ b/src/test/versionbits_tests.cpp @@ -44,6 +44,12 @@ public: int GetStateSinceHeightFor(const CBlockIndex* pindexPrev) const { return AbstractThresholdConditionChecker::GetStateSinceHeightFor(pindexPrev, paramsDummy, cache); } }; +class TestDelayedActivationConditionChecker : public TestConditionChecker +{ +public: + int MinActivationHeight(const Consensus::Params& params) const override { return 15000; } +}; + class TestAlwaysActiveConditionChecker : public TestConditionChecker { public: @@ -53,8 +59,7 @@ public: class TestNeverActiveConditionChecker : public TestConditionChecker { public: - int64_t BeginTime(const Consensus::Params& params) const override { return 0; } - int64_t EndTime(const Consensus::Params& params) const override { return 1230768000; } + int64_t BeginTime(const Consensus::Params& params) const override { return Consensus::BIP9Deployment::NEVER_ACTIVE; } }; #define CHECKERS 6 @@ -68,23 +73,27 @@ class VersionBitsTester // The first one performs all checks, the second only 50%, the third only 25%, etc... // This is to test whether lack of cached information leads to the same results. TestConditionChecker checker[CHECKERS]; + // Another 6 that assume delayed activation + TestDelayedActivationConditionChecker checker_delayed[CHECKERS]; // Another 6 that assume always active activation TestAlwaysActiveConditionChecker checker_always[CHECKERS]; // Another 6 that assume never active activation TestNeverActiveConditionChecker checker_never[CHECKERS]; // Test counter (to identify failures) - int num; + int num{1000}; public: - VersionBitsTester() : num(0) {} - VersionBitsTester& Reset() { + // Have each group of tests be counted by the 1000s part, starting at 1000 + num = num - (num % 1000) + 1000; + for (unsigned int i = 0; i < vpblock.size(); i++) { delete vpblock[i]; } for (unsigned int i = 0; i < CHECKERS; i++) { checker[i] = TestConditionChecker(); + checker_delayed[i] = TestDelayedActivationConditionChecker(); checker_always[i] = TestAlwaysActiveConditionChecker(); checker_never[i] = TestNeverActiveConditionChecker(); } @@ -100,7 +109,7 @@ public: while (vpblock.size() < height) { CBlockIndex* pindex = new CBlockIndex(); pindex->nHeight = vpblock.size(); - pindex->pprev = vpblock.size() > 0 ? vpblock.back() : nullptr; + pindex->pprev = Tip(); pindex->nTime = nTime; pindex->nVersion = nVersion; pindex->BuildSkip(); @@ -109,34 +118,53 @@ public: return *this; } - VersionBitsTester& TestStateSinceHeight(int height) { + VersionBitsTester& TestStateSinceHeight(int height) + { + return TestStateSinceHeight(height, height); + } + + VersionBitsTester& TestStateSinceHeight(int height, int height_delayed) + { + const CBlockIndex* tip = Tip(); for (int i = 0; i < CHECKERS; i++) { if (InsecureRandBits(i) == 0) { - BOOST_CHECK_MESSAGE(checker[i].GetStateSinceHeightFor(vpblock.empty() ? nullptr : vpblock.back()) == height, strprintf("Test %i for StateSinceHeight", num)); - BOOST_CHECK_MESSAGE(checker_always[i].GetStateSinceHeightFor(vpblock.empty() ? nullptr : vpblock.back()) == 0, strprintf("Test %i for StateSinceHeight (always active)", num)); - - // never active may go from DEFINED -> FAILED at the first period - const auto never_height = checker_never[i].GetStateSinceHeightFor(vpblock.empty() ? nullptr : vpblock.back()); - BOOST_CHECK_MESSAGE(never_height == 0 || never_height == checker_never[i].Period(paramsDummy), strprintf("Test %i for StateSinceHeight (never active)", num)); + BOOST_CHECK_MESSAGE(checker[i].GetStateSinceHeightFor(tip) == height, strprintf("Test %i for StateSinceHeight", num)); + BOOST_CHECK_MESSAGE(checker_delayed[i].GetStateSinceHeightFor(tip) == height_delayed, strprintf("Test %i for StateSinceHeight (delayed)", num)); + BOOST_CHECK_MESSAGE(checker_always[i].GetStateSinceHeightFor(tip) == 0, strprintf("Test %i for StateSinceHeight (always active)", num)); + BOOST_CHECK_MESSAGE(checker_never[i].GetStateSinceHeightFor(tip) == 0, strprintf("Test %i for StateSinceHeight (never active)", num)); } } num++; return *this; } - VersionBitsTester& TestState(ThresholdState exp) { + VersionBitsTester& TestState(ThresholdState exp) + { + return TestState(exp, exp); + } + + VersionBitsTester& TestState(ThresholdState exp, ThresholdState exp_delayed) + { + if (exp != exp_delayed) { + // only expected differences are that delayed stays in locked_in longer + BOOST_CHECK_EQUAL(exp, ThresholdState::ACTIVE); + BOOST_CHECK_EQUAL(exp_delayed, ThresholdState::LOCKED_IN); + } + + const CBlockIndex* pindex = Tip(); for (int i = 0; i < CHECKERS; i++) { if (InsecureRandBits(i) == 0) { - const CBlockIndex* pindex = vpblock.empty() ? nullptr : vpblock.back(); ThresholdState got = checker[i].GetStateFor(pindex); + ThresholdState got_delayed = checker_delayed[i].GetStateFor(pindex); ThresholdState got_always = checker_always[i].GetStateFor(pindex); ThresholdState got_never = checker_never[i].GetStateFor(pindex); // nHeight of the next block. If vpblock is empty, the next (ie first) // block should be the genesis block with nHeight == 0. int height = pindex == nullptr ? 0 : pindex->nHeight + 1; BOOST_CHECK_MESSAGE(got == exp, strprintf("Test %i for %s height %d (got %s)", num, StateName(exp), height, StateName(got))); + BOOST_CHECK_MESSAGE(got_delayed == exp_delayed, strprintf("Test %i for %s height %d (got %s; delayed case)", num, StateName(exp_delayed), height, StateName(got_delayed))); BOOST_CHECK_MESSAGE(got_always == ThresholdState::ACTIVE, strprintf("Test %i for ACTIVE height %d (got %s; always active case)", num, height, StateName(got_always))); - BOOST_CHECK_MESSAGE(got_never == ThresholdState::DEFINED|| got_never == ThresholdState::FAILED, strprintf("Test %i for DEFINED/FAILED height %d (got %s; never active case)", num, height, StateName(got_never))); + BOOST_CHECK_MESSAGE(got_never == ThresholdState::FAILED, strprintf("Test %i for FAILED height %d (got %s; never active case)", num, height, StateName(got_never))); } } num++; @@ -149,7 +177,10 @@ public: VersionBitsTester& TestActive() { return TestState(ThresholdState::ACTIVE); } VersionBitsTester& TestFailed() { return TestState(ThresholdState::FAILED); } - CBlockIndex * Tip() { return vpblock.size() ? vpblock.back() : nullptr; } + // non-delayed should be active; delayed should still be locked in + VersionBitsTester& TestActiveDelayed() { return TestState(ThresholdState::ACTIVE, ThresholdState::LOCKED_IN); } + + CBlockIndex* Tip() { return vpblock.empty() ? nullptr : vpblock.back(); } }; BOOST_FIXTURE_TEST_SUITE(versionbits_tests, TestingSetup) @@ -157,18 +188,19 @@ BOOST_FIXTURE_TEST_SUITE(versionbits_tests, TestingSetup) BOOST_AUTO_TEST_CASE(versionbits_test) { for (int i = 0; i < 64; i++) { - // DEFINED -> FAILED + // DEFINED -> STARTED after timeout reached -> FAILED VersionBitsTester().TestDefined().TestStateSinceHeight(0) .Mine(1, TestTime(1), 0x100).TestDefined().TestStateSinceHeight(0) .Mine(11, TestTime(11), 0x100).TestDefined().TestStateSinceHeight(0) .Mine(989, TestTime(989), 0x100).TestDefined().TestStateSinceHeight(0) - .Mine(999, TestTime(20000), 0x100).TestDefined().TestStateSinceHeight(0) - .Mine(1000, TestTime(20000), 0x100).TestFailed().TestStateSinceHeight(1000) - .Mine(1999, TestTime(30001), 0x100).TestFailed().TestStateSinceHeight(1000) - .Mine(2000, TestTime(30002), 0x100).TestFailed().TestStateSinceHeight(1000) - .Mine(2001, TestTime(30003), 0x100).TestFailed().TestStateSinceHeight(1000) - .Mine(2999, TestTime(30004), 0x100).TestFailed().TestStateSinceHeight(1000) - .Mine(3000, TestTime(30005), 0x100).TestFailed().TestStateSinceHeight(1000) + .Mine(999, TestTime(20000), 0x100).TestDefined().TestStateSinceHeight(0) // Timeout and start time reached simultaneously + .Mine(1000, TestTime(20000), 0).TestStarted().TestStateSinceHeight(1000) // Hit started, stop signalling + .Mine(1999, TestTime(30001), 0).TestStarted().TestStateSinceHeight(1000) + .Mine(2000, TestTime(30002), 0x100).TestFailed().TestStateSinceHeight(2000) // Hit failed, start signalling again + .Mine(2001, TestTime(30003), 0x100).TestFailed().TestStateSinceHeight(2000) + .Mine(2999, TestTime(30004), 0x100).TestFailed().TestStateSinceHeight(2000) + .Mine(3000, TestTime(30005), 0x100).TestFailed().TestStateSinceHeight(2000) + .Mine(4000, TestTime(30006), 0x100).TestFailed().TestStateSinceHeight(2000) // DEFINED -> STARTED -> FAILED .Reset().TestDefined().TestStateSinceHeight(0) @@ -180,19 +212,19 @@ BOOST_AUTO_TEST_CASE(versionbits_test) .Mine(3000, TestTime(20000), 0).TestFailed().TestStateSinceHeight(3000) // 50 old blocks (so 899 out of the past 1000) .Mine(4000, TestTime(20010), 0x100).TestFailed().TestStateSinceHeight(3000) - // DEFINED -> STARTED -> FAILED while threshold reached + // DEFINED -> STARTED -> LOCKEDIN after timeout reached -> ACTIVE .Reset().TestDefined().TestStateSinceHeight(0) .Mine(1, TestTime(1), 0).TestDefined().TestStateSinceHeight(0) .Mine(1000, TestTime(10000) - 1, 0x101).TestDefined().TestStateSinceHeight(0) // One second more and it would be defined .Mine(2000, TestTime(10000), 0x101).TestStarted().TestStateSinceHeight(2000) // So that's what happens the next period .Mine(2999, TestTime(30000), 0x100).TestStarted().TestStateSinceHeight(2000) // 999 new blocks - .Mine(3000, TestTime(30000), 0x100).TestFailed().TestStateSinceHeight(3000) // 1 new block (so 1000 out of the past 1000 are new) - .Mine(3999, TestTime(30001), 0).TestFailed().TestStateSinceHeight(3000) - .Mine(4000, TestTime(30002), 0).TestFailed().TestStateSinceHeight(3000) - .Mine(14333, TestTime(30003), 0).TestFailed().TestStateSinceHeight(3000) - .Mine(24000, TestTime(40000), 0).TestFailed().TestStateSinceHeight(3000) + .Mine(3000, TestTime(30000), 0x100).TestLockedIn().TestStateSinceHeight(3000) // 1 new block (so 1000 out of the past 1000 are new) + .Mine(3999, TestTime(30001), 0).TestLockedIn().TestStateSinceHeight(3000) + .Mine(4000, TestTime(30002), 0).TestActiveDelayed().TestStateSinceHeight(4000, 3000) + .Mine(14333, TestTime(30003), 0).TestActiveDelayed().TestStateSinceHeight(4000, 3000) + .Mine(24000, TestTime(40000), 0).TestActive().TestStateSinceHeight(4000, 15000) - // DEFINED -> STARTED -> LOCKEDIN at the last minute -> ACTIVE + // DEFINED -> STARTED -> LOCKEDIN before timeout -> ACTIVE .Reset().TestDefined() .Mine(1, TestTime(1), 0).TestDefined().TestStateSinceHeight(0) .Mine(1000, TestTime(10000) - 1, 0x101).TestDefined().TestStateSinceHeight(0) // One second more and it would be defined @@ -202,9 +234,10 @@ BOOST_AUTO_TEST_CASE(versionbits_test) .Mine(2999, TestTime(19999), 0x200).TestStarted().TestStateSinceHeight(2000) // 49 old blocks .Mine(3000, TestTime(29999), 0x200).TestLockedIn().TestStateSinceHeight(3000) // 1 old block (so 900 out of the past 1000) .Mine(3999, TestTime(30001), 0).TestLockedIn().TestStateSinceHeight(3000) - .Mine(4000, TestTime(30002), 0).TestActive().TestStateSinceHeight(4000) - .Mine(14333, TestTime(30003), 0).TestActive().TestStateSinceHeight(4000) - .Mine(24000, TestTime(40000), 0).TestActive().TestStateSinceHeight(4000) + .Mine(4000, TestTime(30002), 0).TestActiveDelayed().TestStateSinceHeight(4000, 3000) // delayed will not become active until height=15000 + .Mine(14333, TestTime(30003), 0).TestActiveDelayed().TestStateSinceHeight(4000, 3000) + .Mine(15000, TestTime(40000), 0).TestActive().TestStateSinceHeight(4000, 15000) + .Mine(24000, TestTime(40000), 0).TestActive().TestStateSinceHeight(4000, 15000) // DEFINED multiple periods -> STARTED multiple periods -> FAILED .Reset().TestDefined().TestStateSinceHeight(0) @@ -214,109 +247,135 @@ BOOST_AUTO_TEST_CASE(versionbits_test) .Mine(3000, TestTime(10000), 0).TestStarted().TestStateSinceHeight(3000) .Mine(4000, TestTime(10000), 0).TestStarted().TestStateSinceHeight(3000) .Mine(5000, TestTime(10000), 0).TestStarted().TestStateSinceHeight(3000) + .Mine(5999, TestTime(20000), 0).TestStarted().TestStateSinceHeight(3000) .Mine(6000, TestTime(20000), 0).TestFailed().TestStateSinceHeight(6000) - .Mine(7000, TestTime(20000), 0x100).TestFailed().TestStateSinceHeight(6000); - } - - // Sanity checks of version bit deployments - const auto chainParams = CreateChainParams(*m_node.args, CBaseChainParams::MAIN); - const Consensus::Params &mainnetParams = chainParams->GetConsensus(); - for (int i=0; i<(int) Consensus::MAX_VERSION_BITS_DEPLOYMENTS; i++) { - uint32_t bitmask = VersionBitsMask(mainnetParams, static_cast<Consensus::DeploymentPos>(i)); - // Make sure that no deployment tries to set an invalid bit. - BOOST_CHECK_EQUAL(bitmask & ~(uint32_t)VERSIONBITS_TOP_MASK, bitmask); - - // Verify that the deployment windows of different deployment using the - // same bit are disjoint. - // This test may need modification at such time as a new deployment - // is proposed that reuses the bit of an activated soft fork, before the - // end time of that soft fork. (Alternatively, the end time of that - // activated soft fork could be later changed to be earlier to avoid - // overlap.) - for (int j=i+1; j<(int) Consensus::MAX_VERSION_BITS_DEPLOYMENTS; j++) { - if (VersionBitsMask(mainnetParams, static_cast<Consensus::DeploymentPos>(j)) == bitmask) { - BOOST_CHECK(mainnetParams.vDeployments[j].nStartTime > mainnetParams.vDeployments[i].nTimeout || - mainnetParams.vDeployments[i].nStartTime > mainnetParams.vDeployments[j].nTimeout); - } - } + .Mine(7000, TestTime(20000), 0x100).TestFailed().TestStateSinceHeight(6000) + .Mine(24000, TestTime(20000), 0x100).TestFailed().TestStateSinceHeight(6000) // stay in FAILED no matter how much we signal + ; } } -BOOST_AUTO_TEST_CASE(versionbits_computeblockversion) +/** Check that ComputeBlockVersion will set the appropriate bit correctly */ +static void check_computeblockversion(const Consensus::Params& params, Consensus::DeploymentPos dep) { - // Check that ComputeBlockVersion will set the appropriate bit correctly - // on mainnet. - const auto chainParams = CreateChainParams(*m_node.args, CBaseChainParams::MAIN); - const Consensus::Params &mainnetParams = chainParams->GetConsensus(); + // This implicitly uses versionbitscache, so clear it every time + versionbitscache.Clear(); + + int64_t bit = params.vDeployments[dep].bit; + int64_t nStartTime = params.vDeployments[dep].nStartTime; + int64_t nTimeout = params.vDeployments[dep].nTimeout; + int min_activation_height = params.vDeployments[dep].min_activation_height; + + // should not be any signalling for first block + BOOST_CHECK_EQUAL(ComputeBlockVersion(nullptr, params), VERSIONBITS_TOP_BITS); + + // always/never active deployments shouldn't need to be tested further + if (nStartTime == Consensus::BIP9Deployment::ALWAYS_ACTIVE || + nStartTime == Consensus::BIP9Deployment::NEVER_ACTIVE) + { + BOOST_CHECK_EQUAL(min_activation_height, 0); + return; + } - // Use the TESTDUMMY deployment for testing purposes. - int64_t bit = mainnetParams.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit; - int64_t nStartTime = mainnetParams.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime; - int64_t nTimeout = mainnetParams.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout; + BOOST_REQUIRE(nStartTime < nTimeout); + BOOST_REQUIRE(nStartTime >= 0); + BOOST_REQUIRE(nTimeout <= std::numeric_limits<uint32_t>::max() || nTimeout == Consensus::BIP9Deployment::NO_TIMEOUT); + BOOST_REQUIRE(0 <= bit && bit < 32); + // Make sure that no deployment tries to set an invalid bit. + BOOST_REQUIRE(((1 << bit) & VERSIONBITS_TOP_MASK) == 0); + BOOST_REQUIRE(min_activation_height >= 0); + // Check min_activation_height is on a retarget boundary + BOOST_REQUIRE_EQUAL(min_activation_height % params.nMinerConfirmationWindow, 0U); - assert(nStartTime < nTimeout); + const uint32_t bitmask{VersionBitsMask(params, dep)}; + BOOST_CHECK_EQUAL(bitmask, uint32_t{1} << bit); // In the first chain, test that the bit is set by CBV until it has failed. // In the second chain, test the bit is set by CBV while STARTED and // LOCKED-IN, and then no longer set while ACTIVE. VersionBitsTester firstChain, secondChain; - // Start generating blocks before nStartTime - int64_t nTime = nStartTime - 1; + int64_t nTime = nStartTime; + + const CBlockIndex *lastBlock = nullptr; // Before MedianTimePast of the chain has crossed nStartTime, the bit // should not be set. - CBlockIndex *lastBlock = nullptr; - lastBlock = firstChain.Mine(mainnetParams.nMinerConfirmationWindow, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); - BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit), 0); - - // Mine more blocks (4 less than the adjustment period) at the old time, and check that CBV isn't setting the bit yet. - for (uint32_t i = 1; i < mainnetParams.nMinerConfirmationWindow - 4; i++) { - lastBlock = firstChain.Mine(mainnetParams.nMinerConfirmationWindow + i, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); - // This works because VERSIONBITS_LAST_OLD_BLOCK_VERSION happens - // to be 4, and the bit we're testing happens to be bit 28. - BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit), 0); - } - // Now mine 5 more blocks at the start time -- MTP should not have passed yet, so - // CBV should still not yet set the bit. - nTime = nStartTime; - for (uint32_t i = mainnetParams.nMinerConfirmationWindow - 4; i <= mainnetParams.nMinerConfirmationWindow; i++) { - lastBlock = firstChain.Mine(mainnetParams.nMinerConfirmationWindow + i, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); - BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit), 0); + if (nTime == 0) { + // since CBlockIndex::nTime is uint32_t we can't represent any + // earlier time, so will transition from DEFINED to STARTED at the + // end of the first period by mining blocks at nTime == 0 + lastBlock = firstChain.Mine(params.nMinerConfirmationWindow - 1, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); + BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, params) & (1<<bit), 0); + lastBlock = firstChain.Mine(params.nMinerConfirmationWindow, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); + BOOST_CHECK((ComputeBlockVersion(lastBlock, params) & (1<<bit)) != 0); + // then we'll keep mining at nStartTime... + } else { + // use a time 1s earlier than start time to check we stay DEFINED + --nTime; + + // Start generating blocks before nStartTime + lastBlock = firstChain.Mine(params.nMinerConfirmationWindow, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); + BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, params) & (1<<bit), 0); + + // Mine more blocks (4 less than the adjustment period) at the old time, and check that CBV isn't setting the bit yet. + for (uint32_t i = 1; i < params.nMinerConfirmationWindow - 4; i++) { + lastBlock = firstChain.Mine(params.nMinerConfirmationWindow + i, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); + BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, params) & (1<<bit), 0); + } + // Now mine 5 more blocks at the start time -- MTP should not have passed yet, so + // CBV should still not yet set the bit. + nTime = nStartTime; + for (uint32_t i = params.nMinerConfirmationWindow - 4; i <= params.nMinerConfirmationWindow; i++) { + lastBlock = firstChain.Mine(params.nMinerConfirmationWindow + i, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); + BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, params) & (1<<bit), 0); + } + // Next we will advance to the next period and transition to STARTED, } - // Advance to the next period and transition to STARTED, - lastBlock = firstChain.Mine(mainnetParams.nMinerConfirmationWindow * 3, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); + lastBlock = firstChain.Mine(params.nMinerConfirmationWindow * 3, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); // so ComputeBlockVersion should now set the bit, - BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0); + BOOST_CHECK((ComputeBlockVersion(lastBlock, params) & (1<<bit)) != 0); // and should also be using the VERSIONBITS_TOP_BITS. - BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & VERSIONBITS_TOP_MASK, VERSIONBITS_TOP_BITS); + BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, params) & VERSIONBITS_TOP_MASK, VERSIONBITS_TOP_BITS); // Check that ComputeBlockVersion will set the bit until nTimeout nTime += 600; - uint32_t blocksToMine = mainnetParams.nMinerConfirmationWindow * 2; // test blocks for up to 2 time periods - uint32_t nHeight = mainnetParams.nMinerConfirmationWindow * 3; + uint32_t blocksToMine = params.nMinerConfirmationWindow * 2; // test blocks for up to 2 time periods + uint32_t nHeight = params.nMinerConfirmationWindow * 3; // These blocks are all before nTimeout is reached. while (nTime < nTimeout && blocksToMine > 0) { lastBlock = firstChain.Mine(nHeight+1, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); - BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0); - BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & VERSIONBITS_TOP_MASK, VERSIONBITS_TOP_BITS); + BOOST_CHECK((ComputeBlockVersion(lastBlock, params) & (1<<bit)) != 0); + BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, params) & VERSIONBITS_TOP_MASK, VERSIONBITS_TOP_BITS); blocksToMine--; nTime += 600; nHeight += 1; } - nTime = nTimeout; - // FAILED is only triggered at the end of a period, so CBV should be setting - // the bit until the period transition. - for (uint32_t i = 0; i < mainnetParams.nMinerConfirmationWindow - 1; i++) { + if (nTimeout != Consensus::BIP9Deployment::NO_TIMEOUT) { + // can reach any nTimeout other than NO_TIMEOUT due to earlier BOOST_REQUIRE + + nTime = nTimeout; + + // finish the last period before we start timing out + while (nHeight % params.nMinerConfirmationWindow != 0) { + lastBlock = firstChain.Mine(nHeight+1, nTime - 1, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); + BOOST_CHECK((ComputeBlockVersion(lastBlock, params) & (1<<bit)) != 0); + nHeight += 1; + } + + // FAILED is only triggered at the end of a period, so CBV should be setting + // the bit until the period transition. + for (uint32_t i = 0; i < params.nMinerConfirmationWindow - 1; i++) { + lastBlock = firstChain.Mine(nHeight+1, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); + BOOST_CHECK((ComputeBlockVersion(lastBlock, params) & (1<<bit)) != 0); + nHeight += 1; + } + // The next block should trigger no longer setting the bit. lastBlock = firstChain.Mine(nHeight+1, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); - BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0); - nHeight += 1; + BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, params) & (1<<bit), 0); } - // The next block should trigger no longer setting the bit. - lastBlock = firstChain.Mine(nHeight+1, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); - BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit), 0); // On a new chain: // verify that the bit will be set after lock-in, and then stop being set @@ -325,26 +384,72 @@ BOOST_AUTO_TEST_CASE(versionbits_computeblockversion) // Mine one period worth of blocks, and check that the bit will be on for the // next period. - lastBlock = secondChain.Mine(mainnetParams.nMinerConfirmationWindow, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); - BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0); + lastBlock = secondChain.Mine(params.nMinerConfirmationWindow, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); + BOOST_CHECK((ComputeBlockVersion(lastBlock, params) & (1<<bit)) != 0); // Mine another period worth of blocks, signaling the new bit. - lastBlock = secondChain.Mine(mainnetParams.nMinerConfirmationWindow * 2, nTime, VERSIONBITS_TOP_BITS | (1<<bit)).Tip(); + lastBlock = secondChain.Mine(params.nMinerConfirmationWindow * 2, nTime, VERSIONBITS_TOP_BITS | (1<<bit)).Tip(); // After one period of setting the bit on each block, it should have locked in. // We keep setting the bit for one more period though, until activation. - BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0); + BOOST_CHECK((ComputeBlockVersion(lastBlock, params) & (1<<bit)) != 0); // Now check that we keep mining the block until the end of this period, and // then stop at the beginning of the next period. - lastBlock = secondChain.Mine((mainnetParams.nMinerConfirmationWindow * 3) - 1, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); - BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1 << bit)) != 0); - lastBlock = secondChain.Mine(mainnetParams.nMinerConfirmationWindow * 3, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); - BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit), 0); - - // Finally, verify that after a soft fork has activated, CBV no longer uses - // VERSIONBITS_LAST_OLD_BLOCK_VERSION. - //BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & VERSIONBITS_TOP_MASK, VERSIONBITS_TOP_BITS); + lastBlock = secondChain.Mine((params.nMinerConfirmationWindow * 3) - 1, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); + BOOST_CHECK((ComputeBlockVersion(lastBlock, params) & (1 << bit)) != 0); + lastBlock = secondChain.Mine(params.nMinerConfirmationWindow * 3, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); + + if (lastBlock->nHeight + 1 < min_activation_height) { + // check signalling continues while min_activation_height is not reached + lastBlock = secondChain.Mine(min_activation_height - 1, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); + BOOST_CHECK((ComputeBlockVersion(lastBlock, params) & (1 << bit)) != 0); + // then reach min_activation_height, which was already REQUIRE'd to start a new period + lastBlock = secondChain.Mine(min_activation_height, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); + } + + // Check that we don't signal after activation + BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, params) & (1<<bit), 0); } +BOOST_AUTO_TEST_CASE(versionbits_computeblockversion) +{ + // check that any deployment on any chain can conceivably reach both + // ACTIVE and FAILED states in roughly the way we expect + for (const auto& chain_name : {CBaseChainParams::MAIN, CBaseChainParams::TESTNET, CBaseChainParams::SIGNET, CBaseChainParams::REGTEST}) { + const auto chainParams = CreateChainParams(*m_node.args, chain_name); + uint32_t chain_all_vbits{0}; + for (int i = 0; i < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++i) { + const auto dep = static_cast<Consensus::DeploymentPos>(i); + // Check that no bits are re-used (within the same chain). This is + // disallowed because the transition to FAILED (on timeout) does + // not take precedence over STARTED/LOCKED_IN. So all softforks on + // the same bit might overlap, even when non-overlapping start-end + // times are picked. + const uint32_t dep_mask{VersionBitsMask(chainParams->GetConsensus(), dep)}; + BOOST_CHECK(!(chain_all_vbits & dep_mask)); + chain_all_vbits |= dep_mask; + check_computeblockversion(chainParams->GetConsensus(), dep); + } + } + + { + // Use regtest/testdummy to ensure we always exercise some + // deployment that's not always/never active + ArgsManager args; + args.ForceSetArg("-vbparams", "testdummy:1199145601:1230767999"); // January 1, 2008 - December 31, 2008 + const auto chainParams = CreateChainParams(args, CBaseChainParams::REGTEST); + check_computeblockversion(chainParams->GetConsensus(), Consensus::DEPLOYMENT_TESTDUMMY); + } + + { + // Use regtest/testdummy to ensure we always exercise the + // min_activation_height test, even if we're not using that in a + // live deployment + ArgsManager args; + args.ForceSetArg("-vbparams", "testdummy:1199145601:1230767999:403200"); // January 1, 2008 - December 31, 2008, min act height 403200 + const auto chainParams = CreateChainParams(args, CBaseChainParams::REGTEST); + check_computeblockversion(chainParams->GetConsensus(), Consensus::DEPLOYMENT_TESTDUMMY); + } +} BOOST_AUTO_TEST_SUITE_END() diff --git a/src/util/system.cpp b/src/util/system.cpp index 0b83a76504..9b3bd46b38 100644 --- a/src/util/system.cpp +++ b/src/util/system.cpp @@ -235,6 +235,19 @@ static bool CheckValid(const std::string& key, const util::SettingsValue& val, u return true; } +namespace { +fs::path StripRedundantLastElementsOfPath(const fs::path& path) +{ + auto result = path; + while (result.filename().string() == ".") { + result = result.parent_path(); + } + + assert(fs::equivalent(result, path)); + return result; +} +} // namespace + // Define default constructor and destructor that are not inline, so code instantiating this class doesn't need to // #include class definitions for all members. // For example, m_settings has an internal dependency on univalue. @@ -375,6 +388,72 @@ std::optional<unsigned int> ArgsManager::GetArgFlags(const std::string& name) co return std::nullopt; } +const fs::path& ArgsManager::GetBlocksDirPath() +{ + LOCK(cs_args); + fs::path& path = m_cached_blocks_path; + + // Cache the path to avoid calling fs::create_directories on every call of + // this function + if (!path.empty()) return path; + + if (IsArgSet("-blocksdir")) { + path = fs::system_complete(GetArg("-blocksdir", "")); + if (!fs::is_directory(path)) { + path = ""; + return path; + } + } else { + path = GetDataDirPath(false); + } + + path /= BaseParams().DataDir(); + path /= "blocks"; + fs::create_directories(path); + path = StripRedundantLastElementsOfPath(path); + return path; +} + +const fs::path& ArgsManager::GetDataDirPath(bool net_specific) const +{ + LOCK(cs_args); + fs::path& path = net_specific ? m_cached_network_datadir_path : m_cached_datadir_path; + + // Cache the path to avoid calling fs::create_directories on every call of + // this function + if (!path.empty()) return path; + + std::string datadir = GetArg("-datadir", ""); + if (!datadir.empty()) { + path = fs::system_complete(datadir); + if (!fs::is_directory(path)) { + path = ""; + return path; + } + } else { + path = GetDefaultDataDir(); + } + if (net_specific) + path /= BaseParams().DataDir(); + + if (fs::create_directories(path)) { + // This is the first run, create wallets subdirectory too + fs::create_directories(path / "wallets"); + } + + path = StripRedundantLastElementsOfPath(path); + return path; +} + +void ArgsManager::ClearPathCache() +{ + LOCK(cs_args); + + m_cached_datadir_path = fs::path(); + m_cached_network_datadir_path = fs::path(); + m_cached_blocks_path = fs::path(); +} + std::optional<const ArgsManager::Command> ArgsManager::GetCommand() const { Command ret; @@ -434,7 +513,7 @@ bool ArgsManager::GetSettingsPath(fs::path* filepath, bool temp) const } if (filepath) { std::string settings = GetArg("-settings", BITCOIN_SETTINGS_FILENAME); - *filepath = fsbridge::AbsPathJoin(GetDataDir(/* net_specific= */ true), temp ? settings + ".tmp" : settings); + *filepath = fsbridge::AbsPathJoin(GetDataDirPath(/* net_specific= */ true), temp ? settings + ".tmp" : settings); } return true; } @@ -723,79 +802,9 @@ fs::path GetDefaultDataDir() #endif } -namespace { -fs::path StripRedundantLastElementsOfPath(const fs::path& path) -{ - auto result = path; - while (result.filename().string() == ".") { - result = result.parent_path(); - } - - assert(fs::equivalent(result, path)); - return result; -} -} // namespace - -static fs::path g_blocks_path_cache_net_specific; -static fs::path pathCached; -static fs::path pathCachedNetSpecific; -static RecursiveMutex csPathCached; - -const fs::path &GetBlocksDir() -{ - LOCK(csPathCached); - fs::path &path = g_blocks_path_cache_net_specific; - - // Cache the path to avoid calling fs::create_directories on every call of - // this function - if (!path.empty()) return path; - - if (gArgs.IsArgSet("-blocksdir")) { - path = fs::system_complete(gArgs.GetArg("-blocksdir", "")); - if (!fs::is_directory(path)) { - path = ""; - return path; - } - } else { - path = GetDataDir(false); - } - - path /= BaseParams().DataDir(); - path /= "blocks"; - fs::create_directories(path); - path = StripRedundantLastElementsOfPath(path); - return path; -} - const fs::path &GetDataDir(bool fNetSpecific) { - LOCK(csPathCached); - fs::path &path = fNetSpecific ? pathCachedNetSpecific : pathCached; - - // Cache the path to avoid calling fs::create_directories on every call of - // this function - if (!path.empty()) return path; - - std::string datadir = gArgs.GetArg("-datadir", ""); - if (!datadir.empty()) { - path = fs::system_complete(datadir); - if (!fs::is_directory(path)) { - path = ""; - return path; - } - } else { - path = GetDefaultDataDir(); - } - if (fNetSpecific) - path /= BaseParams().DataDir(); - - if (fs::create_directories(path)) { - // This is the first run, create wallets subdirectory too - fs::create_directories(path / "wallets"); - } - - path = StripRedundantLastElementsOfPath(path); - return path; + return gArgs.GetDataDirPath(fNetSpecific); } bool CheckDataDirOption() @@ -804,15 +813,6 @@ bool CheckDataDirOption() return datadir.empty() || fs::is_directory(fs::system_complete(datadir)); } -void ClearDatadirCache() -{ - LOCK(csPathCached); - - pathCached = fs::path(); - pathCachedNetSpecific = fs::path(); - g_blocks_path_cache_net_specific = fs::path(); -} - fs::path GetConfigFile(const std::string& confPath) { return AbsPathForConfigVal(fs::path(confPath), false); @@ -971,7 +971,7 @@ bool ArgsManager::ReadConfigFiles(std::string& error, bool ignore_invalid_keys) } // If datadir is changed in .conf file: - ClearDatadirCache(); + gArgs.ClearPathCache(); if (!CheckDataDirOption()) { error = strprintf("specified data directory \"%s\" does not exist.", GetArg("-datadir", "")); return false; diff --git a/src/util/system.h b/src/util/system.h index 29657e56e2..61f862c93a 100644 --- a/src/util/system.h +++ b/src/util/system.h @@ -91,13 +91,9 @@ void ReleaseDirectoryLocks(); bool TryCreateDirectories(const fs::path& p); fs::path GetDefaultDataDir(); -// The blocks directory is always net specific. -const fs::path &GetBlocksDir(); const fs::path &GetDataDir(bool fNetSpecific = true); // Return true if -datadir option points to a valid directory or is not specified. bool CheckDataDirOption(); -/** Tests only */ -void ClearDatadirCache(); fs::path GetConfigFile(const std::string& confPath); #ifdef WIN32 fs::path GetSpecialFolderPath(int nFolder, bool fCreate = true); @@ -200,6 +196,9 @@ protected: std::map<OptionsCategory, std::map<std::string, Arg>> m_available_args GUARDED_BY(cs_args); bool m_accept_any_command GUARDED_BY(cs_args){true}; std::list<SectionInfo> m_config_sections GUARDED_BY(cs_args); + fs::path m_cached_blocks_path GUARDED_BY(cs_args); + mutable fs::path m_cached_datadir_path GUARDED_BY(cs_args); + mutable fs::path m_cached_network_datadir_path GUARDED_BY(cs_args); [[nodiscard]] bool ReadConfigStream(std::istream& stream, const std::string& filepath, std::string& error, bool ignore_invalid_keys = false); @@ -264,6 +263,27 @@ public: std::optional<const Command> GetCommand() const; /** + * Get blocks directory path + * + * @return Blocks path which is network specific + */ + const fs::path& GetBlocksDirPath(); + + /** + * Get data directory path + * + * @param net_specific Append network identifier to the returned path + * @return Absolute path on success, otherwise an empty path when a non-directory path would be returned + * @post Returned directory path is created unless it is empty + */ + const fs::path& GetDataDirPath(bool net_specific = true) const; + + /** + * Clear cached directory paths + */ + void ClearPathCache(); + + /** * Return a vector of strings of the given argument * * @param strArg Argument to get (e.g. "-foo") diff --git a/src/validation.cpp b/src/validation.cpp index 619d3cea98..2bf505e26b 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -21,6 +21,7 @@ #include <index/txindex.h> #include <logging.h> #include <logging/timer.h> +#include <node/blockstorage.h> #include <node/coinstats.h> #include <node/ui_interface.h> #include <policy/policy.h> @@ -1148,123 +1149,6 @@ CTransactionRef GetTransaction(const CBlockIndex* const block_index, const CTxMe return nullptr; } -////////////////////////////////////////////////////////////////////////////// -// -// CBlock and CBlockIndex -// - -static bool WriteBlockToDisk(const CBlock& block, FlatFilePos& pos, const CMessageHeader::MessageStartChars& messageStart) -{ - // Open history file to append - CAutoFile fileout(OpenBlockFile(pos), SER_DISK, CLIENT_VERSION); - if (fileout.IsNull()) - return error("WriteBlockToDisk: OpenBlockFile failed"); - - // Write index header - unsigned int nSize = GetSerializeSize(block, fileout.GetVersion()); - fileout << messageStart << nSize; - - // Write block - long fileOutPos = ftell(fileout.Get()); - if (fileOutPos < 0) - return error("WriteBlockToDisk: ftell failed"); - pos.nPos = (unsigned int)fileOutPos; - fileout << block; - - return true; -} - -bool ReadBlockFromDisk(CBlock& block, const FlatFilePos& pos, const Consensus::Params& consensusParams) -{ - block.SetNull(); - - // Open history file to read - CAutoFile filein(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION); - if (filein.IsNull()) - return error("ReadBlockFromDisk: OpenBlockFile failed for %s", pos.ToString()); - - // Read block - try { - filein >> block; - } - catch (const std::exception& e) { - return error("%s: Deserialize or I/O error - %s at %s", __func__, e.what(), pos.ToString()); - } - - // Check the header - if (!CheckProofOfWork(block.GetHash(), block.nBits, consensusParams)) - return error("ReadBlockFromDisk: Errors in block header at %s", pos.ToString()); - - // Signet only: check block solution - if (consensusParams.signet_blocks && !CheckSignetBlockSolution(block, consensusParams)) { - return error("ReadBlockFromDisk: Errors in block solution at %s", pos.ToString()); - } - - return true; -} - -bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const Consensus::Params& consensusParams) -{ - FlatFilePos blockPos; - { - LOCK(cs_main); - blockPos = pindex->GetBlockPos(); - } - - if (!ReadBlockFromDisk(block, blockPos, consensusParams)) - return false; - if (block.GetHash() != pindex->GetBlockHash()) - return error("ReadBlockFromDisk(CBlock&, CBlockIndex*): GetHash() doesn't match index for %s at %s", - pindex->ToString(), pindex->GetBlockPos().ToString()); - return true; -} - -bool ReadRawBlockFromDisk(std::vector<uint8_t>& block, const FlatFilePos& pos, const CMessageHeader::MessageStartChars& message_start) -{ - FlatFilePos hpos = pos; - hpos.nPos -= 8; // Seek back 8 bytes for meta header - CAutoFile filein(OpenBlockFile(hpos, true), SER_DISK, CLIENT_VERSION); - if (filein.IsNull()) { - return error("%s: OpenBlockFile failed for %s", __func__, pos.ToString()); - } - - try { - CMessageHeader::MessageStartChars blk_start; - unsigned int blk_size; - - filein >> blk_start >> blk_size; - - if (memcmp(blk_start, message_start, CMessageHeader::MESSAGE_START_SIZE)) { - return error("%s: Block magic mismatch for %s: %s versus expected %s", __func__, pos.ToString(), - HexStr(blk_start), - HexStr(message_start)); - } - - if (blk_size > MAX_SIZE) { - return error("%s: Block data is larger than maximum deserialization size for %s: %s versus %s", __func__, pos.ToString(), - blk_size, MAX_SIZE); - } - - block.resize(blk_size); // Zeroing of memory is intentional here - filein.read((char*)block.data(), blk_size); - } catch(const std::exception& e) { - return error("%s: Read from block file failed: %s for %s", __func__, e.what(), pos.ToString()); - } - - return true; -} - -bool ReadRawBlockFromDisk(std::vector<uint8_t>& block, const CBlockIndex* pindex, const CMessageHeader::MessageStartChars& message_start) -{ - FlatFilePos block_pos; - { - LOCK(cs_main); - block_pos = pindex->GetBlockPos(); - } - - return ReadRawBlockFromDisk(block, block_pos, message_start); -} - CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams) { int halvings = nHeight / consensusParams.nSubsidyHalvingInterval; @@ -1636,19 +1520,6 @@ bool UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex* pindex) return true; } -/** Abort with a message */ -static bool AbortNode(const std::string& strMessage, bilingual_str user_message = bilingual_str()) -{ - SetMiscWarning(Untranslated(strMessage)); - LogPrintf("*** %s\n", strMessage); - if (user_message.empty()) { - user_message = _("A fatal internal error occurred, see debug.log for details"); - } - AbortError(user_message); - StartShutdown(); - return false; -} - static bool AbortNode(BlockValidationState& state, const std::string& strMessage, const bilingual_str& userMessage = bilingual_str()) { AbortNode(strMessage, userMessage); @@ -2333,7 +2204,7 @@ bool CChainState::FlushStateToDisk( // Write blocks and block index to disk. if (fDoFullFlush || fPeriodicWrite) { // Depend on nMinDiskSpace to ensure we can write block index - if (!CheckDiskSpace(GetBlocksDir())) { + if (!CheckDiskSpace(gArgs.GetBlocksDirPath())) { return AbortNode(state, "Disk space is too low!", _("Disk space is too low!")); } { @@ -3231,7 +3102,8 @@ void CChainState::ReceivedBlockTransactions(const CBlock& block, CBlockIndex* pi } } -static bool FindBlockPos(FlatFilePos &pos, unsigned int nAddSize, unsigned int nHeight, CChain& active_chain, uint64_t nTime, bool fKnown = false) +// TODO move to blockstorage +bool FindBlockPos(FlatFilePos& pos, unsigned int nAddSize, unsigned int nHeight, CChain& active_chain, uint64_t nTime, bool fKnown = false) { LOCK(cs_LastBlockFile); @@ -3709,25 +3581,6 @@ bool ChainstateManager::ProcessNewBlockHeaders(const std::vector<CBlockHeader>& } /** Store block on disk. If dbp is non-nullptr, the file is known to already reside on disk */ -static FlatFilePos SaveBlockToDisk(const CBlock& block, int nHeight, CChain& active_chain, const CChainParams& chainparams, const FlatFilePos* dbp) { - unsigned int nBlockSize = ::GetSerializeSize(block, CLIENT_VERSION); - FlatFilePos blockPos; - if (dbp != nullptr) - blockPos = *dbp; - if (!FindBlockPos(blockPos, nBlockSize+8, nHeight, active_chain, block.GetBlockTime(), dbp != nullptr)) { - error("%s: FindBlockPos failed", __func__); - return FlatFilePos(); - } - if (dbp == nullptr) { - if (!WriteBlockToDisk(block, blockPos, chainparams.MessageStart())) { - AbortNode("Failed to write block"); - return FlatFilePos(); - } - } - return blockPos; -} - -/** Store block on disk. If dbp is non-nullptr, the file is known to already reside on disk */ bool CChainState::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, BlockValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const FlatFilePos* dbp, bool* fNewBlock) { const CBlock& block = *pblock; @@ -4037,12 +3890,12 @@ void BlockManager::FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPr static FlatFileSeq BlockFileSeq() { - return FlatFileSeq(GetBlocksDir(), "blk", gArgs.GetBoolArg("-fastprune", false) ? 0x4000 /* 16kb */ : BLOCKFILE_CHUNK_SIZE); + return FlatFileSeq(gArgs.GetBlocksDirPath(), "blk", gArgs.GetBoolArg("-fastprune", false) ? 0x4000 /* 16kb */ : BLOCKFILE_CHUNK_SIZE); } static FlatFileSeq UndoFileSeq() { - return FlatFileSeq(GetBlocksDir(), "rev", UNDOFILE_CHUNK_SIZE); + return FlatFileSeq(gArgs.GetBlocksDirPath(), "rev", UNDOFILE_CHUNK_SIZE); } FILE* OpenBlockFile(const FlatFilePos &pos, bool fReadOnly) { @@ -5345,12 +5198,12 @@ bool ChainstateManager::PopulateAndValidateSnapshot( while (coins_left > 0) { try { coins_file >> outpoint; + coins_file >> coin; } catch (const std::ios_base::failure&) { - LogPrintf("[snapshot] bad snapshot - no coins left after deserializing %d coins\n", - coins_count - coins_left); + LogPrintf("[snapshot] bad snapshot format or truncated snapshot after deserializing %d coins\n", + coins_count - coins_left); return false; } - coins_file >> coin; coins_cache.EmplaceCoinInternalDANGER(std::move(outpoint), std::move(coin)); --coins_left; diff --git a/src/validation.h b/src/validation.h index 9f2c244482..de121ab46a 100644 --- a/src/validation.h +++ b/src/validation.h @@ -35,6 +35,7 @@ #include <set> #include <stdint.h> #include <string> +#include <thread> #include <utility> #include <vector> @@ -299,15 +300,6 @@ public: /** Initializes the script-execution cache */ void InitScriptExecutionCache(); - -/** Functions for disk access for blocks */ -bool ReadBlockFromDisk(CBlock& block, const FlatFilePos& pos, const Consensus::Params& consensusParams); -bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const Consensus::Params& consensusParams); -bool ReadRawBlockFromDisk(std::vector<uint8_t>& block, const FlatFilePos& pos, const CMessageHeader::MessageStartChars& message_start); -bool ReadRawBlockFromDisk(std::vector<uint8_t>& block, const CBlockIndex* pindex, const CMessageHeader::MessageStartChars& message_start); - -bool UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex* pindex); - /** Functions for validating blocks and updating the block tree */ /** Context-independent validity checks */ @@ -869,6 +861,7 @@ private: friend CChain& ChainActive(); public: + std::thread m_load_block; //! A single BlockManager instance is shared across each constructed //! chainstate to avoid duplicating block metadata. BlockManager m_blockman GUARDED_BY(::cs_main); diff --git a/src/versionbits.cpp b/src/versionbits.cpp index af07c67ccf..df2ec4e056 100644 --- a/src/versionbits.cpp +++ b/src/versionbits.cpp @@ -9,6 +9,7 @@ ThresholdState AbstractThresholdConditionChecker::GetStateFor(const CBlockIndex* { int nPeriod = Period(params); int nThreshold = Threshold(params); + int min_activation_height = MinActivationHeight(params); int64_t nTimeStart = BeginTime(params); int64_t nTimeTimeout = EndTime(params); @@ -17,6 +18,11 @@ ThresholdState AbstractThresholdConditionChecker::GetStateFor(const CBlockIndex* return ThresholdState::ACTIVE; } + // Check if this deployment is never active. + if (nTimeStart == Consensus::BIP9Deployment::NEVER_ACTIVE) { + return ThresholdState::FAILED; + } + // A block's state is always the same as that of the first of its period, so it is computed based on a pindexPrev whose height equals a multiple of nPeriod - 1. if (pindexPrev != nullptr) { pindexPrev = pindexPrev->GetAncestor(pindexPrev->nHeight - ((pindexPrev->nHeight + 1) % nPeriod)); @@ -51,18 +57,12 @@ ThresholdState AbstractThresholdConditionChecker::GetStateFor(const CBlockIndex* switch (state) { case ThresholdState::DEFINED: { - if (pindexPrev->GetMedianTimePast() >= nTimeTimeout) { - stateNext = ThresholdState::FAILED; - } else if (pindexPrev->GetMedianTimePast() >= nTimeStart) { + if (pindexPrev->GetMedianTimePast() >= nTimeStart) { stateNext = ThresholdState::STARTED; } break; } case ThresholdState::STARTED: { - if (pindexPrev->GetMedianTimePast() >= nTimeTimeout) { - stateNext = ThresholdState::FAILED; - break; - } // We need to count const CBlockIndex* pindexCount = pindexPrev; int count = 0; @@ -74,12 +74,16 @@ ThresholdState AbstractThresholdConditionChecker::GetStateFor(const CBlockIndex* } if (count >= nThreshold) { stateNext = ThresholdState::LOCKED_IN; + } else if (pindexPrev->GetMedianTimePast() >= nTimeTimeout) { + stateNext = ThresholdState::FAILED; } break; } case ThresholdState::LOCKED_IN: { - // Always progresses into ACTIVE. - stateNext = ThresholdState::ACTIVE; + // Progresses into ACTIVE provided activation height will have been reached. + if (pindexPrev->nHeight + 1 >= min_activation_height) { + stateNext = ThresholdState::ACTIVE; + } break; } case ThresholdState::FAILED: @@ -126,7 +130,7 @@ BIP9Stats AbstractThresholdConditionChecker::GetStateStatisticsFor(const CBlockI int AbstractThresholdConditionChecker::GetStateSinceHeightFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const { int64_t start_time = BeginTime(params); - if (start_time == Consensus::BIP9Deployment::ALWAYS_ACTIVE) { + if (start_time == Consensus::BIP9Deployment::ALWAYS_ACTIVE || start_time == Consensus::BIP9Deployment::NEVER_ACTIVE) { return 0; } @@ -170,6 +174,7 @@ private: protected: int64_t BeginTime(const Consensus::Params& params) const override { return params.vDeployments[id].nStartTime; } int64_t EndTime(const Consensus::Params& params) const override { return params.vDeployments[id].nTimeout; } + int MinActivationHeight(const Consensus::Params& params) const override { return params.vDeployments[id].min_activation_height; } int Period(const Consensus::Params& params) const override { return params.nMinerConfirmationWindow; } int Threshold(const Consensus::Params& params) const override { return params.nRuleChangeActivationThreshold; } diff --git a/src/versionbits.h b/src/versionbits.h index 6df1db8814..634a848ef5 100644 --- a/src/versionbits.h +++ b/src/versionbits.h @@ -25,7 +25,7 @@ static const int32_t VERSIONBITS_NUM_BITS = 29; enum class ThresholdState { DEFINED, // First state that each softfork starts out as. The genesis block is by definition in this state for each deployment. STARTED, // For blocks past the starttime. - LOCKED_IN, // For one retarget period after the first retarget period with STARTED blocks of which at least threshold have the associated bit set in nVersion. + LOCKED_IN, // For at least one retarget period after the first retarget period with STARTED blocks of which at least threshold have the associated bit set in nVersion, until min_activation_height is reached. ACTIVE, // For all blocks after the LOCKED_IN retarget period (final state) FAILED, // For all blocks once the first retarget period after the timeout time is hit, if LOCKED_IN wasn't already reached (final state) }; @@ -57,6 +57,7 @@ protected: virtual bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const =0; virtual int64_t BeginTime(const Consensus::Params& params) const =0; virtual int64_t EndTime(const Consensus::Params& params) const =0; + virtual int MinActivationHeight(const Consensus::Params& params) const { return 0; } virtual int Period(const Consensus::Params& params) const =0; virtual int Threshold(const Consensus::Params& params) const =0; diff --git a/src/wallet/external_signer_scriptpubkeyman.cpp b/src/wallet/external_signer_scriptpubkeyman.cpp index a113c128d7..fe2c810afa 100644 --- a/src/wallet/external_signer_scriptpubkeyman.cpp +++ b/src/wallet/external_signer_scriptpubkeyman.cpp @@ -6,6 +6,13 @@ #include <external_signer.h> #include <wallet/external_signer_scriptpubkeyman.h> +#include <iostream> +#include <memory> +#include <stdexcept> +#include <string> +#include <utility> +#include <vector> + #ifdef ENABLE_EXTERNAL_SIGNER bool ExternalSignerScriptPubKeyMan::SetupDescriptor(std::unique_ptr<Descriptor> desc) diff --git a/src/wallet/external_signer_scriptpubkeyman.h b/src/wallet/external_signer_scriptpubkeyman.h index e60d7b8004..1786958912 100644 --- a/src/wallet/external_signer_scriptpubkeyman.h +++ b/src/wallet/external_signer_scriptpubkeyman.h @@ -8,6 +8,8 @@ #ifdef ENABLE_EXTERNAL_SIGNER #include <wallet/scriptpubkeyman.h> +#include <memory> + class ExternalSignerScriptPubKeyMan : public DescriptorScriptPubKeyMan { public: diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp index fdeead1fa5..0dc220b6fd 100644 --- a/src/wallet/init.cpp +++ b/src/wallet/init.cpp @@ -82,6 +82,12 @@ void WalletInit::AddWalletOptions(ArgsManager& argsman) const argsman.AddHiddenArgs({"-dblogsize", "-flushwallet", "-privdb"}); #endif +#ifdef USE_SQLITE + argsman.AddArg("-unsafesqlitesync", "Set SQLite synchronous=OFF to disable waiting for the database to sync to disk. This is unsafe and can cause data loss and corruption. This option is only used by tests to improve their performance (default: false)", ArgsManager::ALLOW_BOOL | ArgsManager::DEBUG_ONLY, OptionsCategory::WALLET_DEBUG_TEST); +#else + argsman.AddHiddenArgs({"-unsafesqlitesync"}); +#endif + argsman.AddArg("-walletrejectlongchains", strprintf("Wallet will not create transactions that violate mempool chain limits (default: %u)", DEFAULT_WALLET_REJECT_LONG_CHAINS), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::WALLET_DEBUG_TEST); argsman.AddHiddenArgs({"-zapwallettxes"}); diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index 769987ccf2..653dbdfc1d 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -100,8 +100,8 @@ RPCHelpMan importprivkey() "Note: Use \"getwalletinfo\" to query the scanning progress.\n", { {"privkey", RPCArg::Type::STR, RPCArg::Optional::NO, "The private key (see dumpprivkey)"}, - {"label", RPCArg::Type::STR, /* default */ "current label if address exists, otherwise \"\"", "An optional label"}, - {"rescan", RPCArg::Type::BOOL, /* default */ "true", "Rescan the wallet for transactions"}, + {"label", RPCArg::Type::STR, RPCArg::DefaultHint{"current label if address exists, otherwise \"\""}, "An optional label"}, + {"rescan", RPCArg::Type::BOOL, RPCArg::Default{true}, "Rescan the wallet for transactions"}, }, RPCResult{RPCResult::Type::NONE, "", ""}, RPCExamples{ @@ -232,9 +232,9 @@ RPCHelpMan importaddress() "Note: Use \"getwalletinfo\" to query the scanning progress.\n", { {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The Bitcoin address (or hex-encoded script)"}, - {"label", RPCArg::Type::STR, /* default */ "\"\"", "An optional label"}, - {"rescan", RPCArg::Type::BOOL, /* default */ "true", "Rescan the wallet for transactions"}, - {"p2sh", RPCArg::Type::BOOL, /* default */ "false", "Add the P2SH version of the script as well"}, + {"label", RPCArg::Type::STR, RPCArg::Default{""}, "An optional label"}, + {"rescan", RPCArg::Type::BOOL, RPCArg::Default{true}, "Rescan the wallet for transactions"}, + {"p2sh", RPCArg::Type::BOOL, RPCArg::Default{false}, "Add the P2SH version of the script as well"}, }, RPCResult{RPCResult::Type::NONE, "", ""}, RPCExamples{ @@ -426,8 +426,8 @@ RPCHelpMan importpubkey() "Note: Use \"getwalletinfo\" to query the scanning progress.\n", { {"pubkey", RPCArg::Type::STR, RPCArg::Optional::NO, "The hex-encoded public key"}, - {"label", RPCArg::Type::STR, /* default */ "\"\"", "An optional label"}, - {"rescan", RPCArg::Type::BOOL, /* default */ "true", "Rescan the wallet for transactions"}, + {"label", RPCArg::Type::STR, RPCArg::Default{""}, "An optional label"}, + {"rescan", RPCArg::Type::BOOL, RPCArg::Default{true}, "Rescan the wallet for transactions"}, }, RPCResult{RPCResult::Type::NONE, "", ""}, RPCExamples{ @@ -1279,28 +1279,28 @@ RPCHelpMan importmulti() }, {"redeemscript", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Allowed only if the scriptPubKey is a P2SH or P2SH-P2WSH address/scriptPubKey"}, {"witnessscript", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Allowed only if the scriptPubKey is a P2SH-P2WSH or P2WSH address/scriptPubKey"}, - {"pubkeys", RPCArg::Type::ARR, /* default */ "empty array", "Array of strings giving pubkeys to import. They must occur in P2PKH or P2WPKH scripts. They are not required when the private key is also provided (see the \"keys\" argument).", + {"pubkeys", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "Array of strings giving pubkeys to import. They must occur in P2PKH or P2WPKH scripts. They are not required when the private key is also provided (see the \"keys\" argument).", { {"pubKey", RPCArg::Type::STR, RPCArg::Optional::OMITTED, ""}, } }, - {"keys", RPCArg::Type::ARR, /* default */ "empty array", "Array of strings giving private keys to import. The corresponding public keys must occur in the output or redeemscript.", + {"keys", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "Array of strings giving private keys to import. The corresponding public keys must occur in the output or redeemscript.", { {"key", RPCArg::Type::STR, RPCArg::Optional::OMITTED, ""}, } }, {"range", RPCArg::Type::RANGE, RPCArg::Optional::OMITTED, "If a ranged descriptor is used, this specifies the end or the range (in the form [begin,end]) to import"}, - {"internal", RPCArg::Type::BOOL, /* default */ "false", "Stating whether matching outputs should be treated as not incoming payments (also known as change)"}, - {"watchonly", RPCArg::Type::BOOL, /* default */ "false", "Stating whether matching outputs should be considered watchonly."}, - {"label", RPCArg::Type::STR, /* default */ "''", "Label to assign to the address, only allowed with internal=false"}, - {"keypool", RPCArg::Type::BOOL, /* default */ "false", "Stating whether imported public keys should be added to the keypool for when users request new addresses. Only allowed when wallet private keys are disabled"}, + {"internal", RPCArg::Type::BOOL, RPCArg::Default{false}, "Stating whether matching outputs should be treated as not incoming payments (also known as change)"}, + {"watchonly", RPCArg::Type::BOOL, RPCArg::Default{false}, "Stating whether matching outputs should be considered watchonly."}, + {"label", RPCArg::Type::STR, RPCArg::Default{""}, "Label to assign to the address, only allowed with internal=false"}, + {"keypool", RPCArg::Type::BOOL, RPCArg::Default{false}, "Stating whether imported public keys should be added to the keypool for when users request new addresses. Only allowed when wallet private keys are disabled"}, }, }, }, "\"requests\""}, {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "", { - {"rescan", RPCArg::Type::BOOL, /* default */ "true", "Stating if should rescan the blockchain after all imports"}, + {"rescan", RPCArg::Type::BOOL, RPCArg::Default{true}, "Stating if should rescan the blockchain after all imports"}, }, "\"options\""}, }, @@ -1591,7 +1591,7 @@ RPCHelpMan importdescriptors() {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "", { {"desc", RPCArg::Type::STR, RPCArg::Optional::NO, "Descriptor to import."}, - {"active", RPCArg::Type::BOOL, /* default */ "false", "Set this descriptor to be the active descriptor for the corresponding output type/externality"}, + {"active", RPCArg::Type::BOOL, RPCArg::Default{false}, "Set this descriptor to be the active descriptor for the corresponding output type/externality"}, {"range", RPCArg::Type::RANGE, RPCArg::Optional::OMITTED, "If a ranged descriptor is used, this specifies the end or the range (in the form [begin,end]) to import"}, {"next_index", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "If a ranged descriptor is set to active, this specifies the next index to generate addresses from"}, {"timestamp", RPCArg::Type::NUM, RPCArg::Optional::NO, "Time from which to start rescanning the blockchain for this descriptor, in " + UNIX_EPOCH_TIME + "\n" @@ -1601,8 +1601,8 @@ RPCHelpMan importdescriptors() " of all descriptors being imported will be scanned.", /* oneline_description */ "", {"timestamp | \"now\"", "integer / string"} }, - {"internal", RPCArg::Type::BOOL, /* default */ "false", "Whether matching outputs should be treated as not incoming payments (e.g. change)"}, - {"label", RPCArg::Type::STR, /* default */ "''", "Label to assign to the address, only allowed with internal=false"}, + {"internal", RPCArg::Type::BOOL, RPCArg::Default{false}, "Whether matching outputs should be treated as not incoming payments (e.g. change)"}, + {"label", RPCArg::Type::STR, RPCArg::Default{""}, "Label to assign to the address, only allowed with internal=false"}, }, }, }, diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index a3e42a34d9..67d9d56133 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -237,8 +237,8 @@ static RPCHelpMan getnewaddress() "If 'label' is specified, it is added to the address book \n" "so payments received with the address will be associated with 'label'.\n", { - {"label", RPCArg::Type::STR, /* default */ "\"\"", "The label name for the address to be linked to. It can also be set to the empty string \"\" to represent the default label. The label does not need to exist, it will be created if there is no label by the given name."}, - {"address_type", RPCArg::Type::STR, /* default */ "set by -addresstype", "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."}, + {"label", RPCArg::Type::STR, RPCArg::Default{""}, "The label name for the address to be linked to. It can also be set to the empty string \"\" to represent the default label. The label does not need to exist, it will be created if there is no label by the given name."}, + {"address_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -addresstype"}, "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."}, }, RPCResult{ RPCResult::Type::STR, "address", "The new bitcoin address" @@ -287,7 +287,7 @@ static RPCHelpMan getrawchangeaddress() "\nReturns a new Bitcoin address, for receiving change.\n" "This is for use with raw transactions, NOT normal use.\n", { - {"address_type", RPCArg::Type::STR, /* default */ "set by -changetype", "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."}, + {"address_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -changetype"}, "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."}, }, RPCResult{ RPCResult::Type::STR, "address", "The address" @@ -439,16 +439,16 @@ static RPCHelpMan sendtoaddress() {"comment_to", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "A comment to store the name of the person or organization\n" "to which you're sending the transaction. This is not part of the \n" "transaction, just kept in your wallet."}, - {"subtractfeefromamount", RPCArg::Type::BOOL, /* default */ "false", "The fee will be deducted from the amount being sent.\n" + {"subtractfeefromamount", RPCArg::Type::BOOL, RPCArg::Default{false}, "The fee will be deducted from the amount being sent.\n" "The recipient will receive less bitcoins than you enter in the amount field."}, - {"replaceable", RPCArg::Type::BOOL, /* default */ "wallet default", "Allow this transaction to be replaced by a transaction with higher fees via BIP 125"}, - {"conf_target", RPCArg::Type::NUM, /* default */ "wallet -txconfirmtarget", "Confirmation target in blocks"}, - {"estimate_mode", RPCArg::Type::STR, /* default */ "unset", std::string() + "The fee estimate mode, must be one of (case insensitive):\n" + {"replaceable", RPCArg::Type::BOOL, RPCArg::DefaultHint{"wallet default"}, "Allow this transaction to be replaced by a transaction with higher fees via BIP 125"}, + {"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks"}, + {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, std::string() + "The fee estimate mode, must be one of (case insensitive):\n" " \"" + FeeModes("\"\n\"") + "\""}, - {"avoid_reuse", RPCArg::Type::BOOL, /* default */ "true", "(only available if avoid_reuse wallet flag is set) Avoid spending from dirty addresses; addresses are considered\n" + {"avoid_reuse", RPCArg::Type::BOOL, RPCArg::Default{true}, "(only available if avoid_reuse wallet flag is set) Avoid spending from dirty addresses; addresses are considered\n" "dirty if they have previously been used in a transaction."}, - {"fee_rate", RPCArg::Type::AMOUNT, /* default */ "not set, fall back to wallet fee estimation", "Specify a fee rate in " + CURRENCY_ATOM + "/vB."}, - {"verbose", RPCArg::Type::BOOL, /* default */ "false", "If true, return extra information about the transaction."}, + {"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."}, + {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "If true, return extra information about the transaction."}, }, { RPCResult{"if verbose is not set or set to false", @@ -697,7 +697,7 @@ static RPCHelpMan getreceivedbyaddress() "\nReturns the total amount received by the given address in transactions with at least minconf confirmations.\n", { {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address for transactions."}, - {"minconf", RPCArg::Type::NUM, /* default */ "1", "Only include transactions confirmed at least this many times."}, + {"minconf", RPCArg::Type::NUM, RPCArg::Default{1}, "Only include transactions confirmed at least this many times."}, }, RPCResult{ RPCResult::Type::STR_AMOUNT, "amount", "The total amount in " + CURRENCY_UNIT + " received at this address." @@ -735,7 +735,7 @@ static RPCHelpMan getreceivedbylabel() "\nReturns the total amount received by addresses with <label> in transactions with at least [minconf] confirmations.\n", { {"label", RPCArg::Type::STR, RPCArg::Optional::NO, "The selected label, may be the default label using \"\"."}, - {"minconf", RPCArg::Type::NUM, /* default */ "1", "Only include transactions confirmed at least this many times."}, + {"minconf", RPCArg::Type::NUM, RPCArg::Default{1}, "Only include transactions confirmed at least this many times."}, }, RPCResult{ RPCResult::Type::STR_AMOUNT, "amount", "The total amount in " + CURRENCY_UNIT + " received for this label." @@ -775,9 +775,9 @@ static RPCHelpMan getbalance() "thus affected by options which limit spendability such as -spendzeroconfchange.\n", { {"dummy", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "Remains for backward compatibility. Must be excluded or set to \"*\"."}, - {"minconf", RPCArg::Type::NUM, /* default */ "0", "Only include transactions confirmed at least this many times."}, - {"include_watchonly", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false", "Also include balance in watch-only addresses (see 'importaddress')"}, - {"avoid_reuse", RPCArg::Type::BOOL, /* default */ "true", "(only available if avoid_reuse wallet flag is set) Do not include balance in dirty outputs; addresses are considered dirty if they have previously been used in a transaction."}, + {"minconf", RPCArg::Type::NUM, RPCArg::Default{0}, "Only include transactions confirmed at least this many times."}, + {"include_watchonly", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Also include balance in watch-only addresses (see 'importaddress')"}, + {"avoid_reuse", RPCArg::Type::BOOL, RPCArg::Default{true}, "(only available if avoid_reuse wallet flag is set) Do not include balance in dirty outputs; addresses are considered dirty if they have previously been used in a transaction."}, }, RPCResult{ RPCResult::Type::STR_AMOUNT, "amount", "The total amount in " + CURRENCY_UNIT + " received for this wallet." @@ -868,12 +868,12 @@ static RPCHelpMan sendmany() {"address", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Subtract fee from this address"}, }, }, - {"replaceable", RPCArg::Type::BOOL, /* default */ "wallet default", "Allow this transaction to be replaced by a transaction with higher fees via BIP 125"}, - {"conf_target", RPCArg::Type::NUM, /* default */ "wallet -txconfirmtarget", "Confirmation target in blocks"}, - {"estimate_mode", RPCArg::Type::STR, /* default */ "unset", std::string() + "The fee estimate mode, must be one of (case insensitive):\n" + {"replaceable", RPCArg::Type::BOOL, RPCArg::DefaultHint{"wallet default"}, "Allow this transaction to be replaced by a transaction with higher fees via BIP 125"}, + {"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks"}, + {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, std::string() + "The fee estimate mode, must be one of (case insensitive):\n" " \"" + FeeModes("\"\n\"") + "\""}, - {"fee_rate", RPCArg::Type::AMOUNT, /* default */ "not set, fall back to wallet fee estimation", "Specify a fee rate in " + CURRENCY_ATOM + "/vB."}, - {"verbose", RPCArg::Type::BOOL, /* default */ "false", "If true, return extra infomration about the transaction."}, + {"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."}, + {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "If true, return extra infomration about the transaction."}, }, { RPCResult{"if verbose is not set or set to false", @@ -956,7 +956,7 @@ static RPCHelpMan addmultisigaddress() }, }, {"label", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "A label to assign the addresses to."}, - {"address_type", RPCArg::Type::STR, /* default */ "set by -addresstype", "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."}, + {"address_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -addresstype"}, "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."}, }, RPCResult{ RPCResult::Type::OBJ, "", "", @@ -1185,9 +1185,9 @@ static RPCHelpMan listreceivedbyaddress() return RPCHelpMan{"listreceivedbyaddress", "\nList balances by receiving address.\n", { - {"minconf", RPCArg::Type::NUM, /* default */ "1", "The minimum number of confirmations before payments are included."}, - {"include_empty", RPCArg::Type::BOOL, /* default */ "false", "Whether to include addresses that haven't received any payments."}, - {"include_watchonly", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false", "Whether to include watch-only addresses (see 'importaddress')"}, + {"minconf", RPCArg::Type::NUM, RPCArg::Default{1}, "The minimum number of confirmations before payments are included."}, + {"include_empty", RPCArg::Type::BOOL, RPCArg::Default{false}, "Whether to include addresses that haven't received any payments."}, + {"include_watchonly", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Whether to include watch-only addresses (see 'importaddress')"}, {"address_filter", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "If present, only return information on this address."}, }, RPCResult{ @@ -1234,9 +1234,9 @@ static RPCHelpMan listreceivedbylabel() return RPCHelpMan{"listreceivedbylabel", "\nList received transactions by label.\n", { - {"minconf", RPCArg::Type::NUM, /* default */ "1", "The minimum number of confirmations before payments are included."}, - {"include_empty", RPCArg::Type::BOOL, /* default */ "false", "Whether to include labels that haven't received any payments."}, - {"include_watchonly", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false", "Whether to include watch-only addresses (see 'importaddress')"}, + {"minconf", RPCArg::Type::NUM, RPCArg::Default{1}, "The minimum number of confirmations before payments are included."}, + {"include_empty", RPCArg::Type::BOOL, RPCArg::Default{false}, "Whether to include labels that haven't received any payments."}, + {"include_watchonly", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Whether to include watch-only addresses (see 'importaddress')"}, }, RPCResult{ RPCResult::Type::ARR, "", "", @@ -1396,9 +1396,9 @@ static RPCHelpMan listtransactions() { {"label|dummy", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "If set, should be a valid label name to return only incoming transactions\n" "with the specified label, or \"*\" to disable filtering and return all transactions."}, - {"count", RPCArg::Type::NUM, /* default */ "10", "The number of transactions to return"}, - {"skip", RPCArg::Type::NUM, /* default */ "0", "The number of transactions to skip"}, - {"include_watchonly", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false", "Include transactions to watch-only addresses (see 'importaddress')"}, + {"count", RPCArg::Type::NUM, RPCArg::Default{10}, "The number of transactions to return"}, + {"skip", RPCArg::Type::NUM, RPCArg::Default{0}, "The number of transactions to skip"}, + {"include_watchonly", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Include transactions to watch-only addresses (see 'importaddress')"}, }, RPCResult{ RPCResult::Type::ARR, "", "", @@ -1507,9 +1507,9 @@ static RPCHelpMan listsinceblock() "Additionally, if include_removed is set, transactions affecting the wallet which were removed are returned in the \"removed\" array.\n", { {"blockhash", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "If set, the block hash to list transactions since, otherwise list all transactions."}, - {"target_confirmations", RPCArg::Type::NUM, /* default */ "1", "Return the nth block hash from the main chain. e.g. 1 would mean the best block hash. Note: this is not used as a filter, but only affects [lastblock] in the return value"}, - {"include_watchonly", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false", "Include transactions to watch-only addresses (see 'importaddress')"}, - {"include_removed", RPCArg::Type::BOOL, /* default */ "true", "Show transactions that were removed due to a reorg in the \"removed\" array\n" + {"target_confirmations", RPCArg::Type::NUM, RPCArg::Default{1}, "Return the nth block hash from the main chain. e.g. 1 would mean the best block hash. Note: this is not used as a filter, but only affects [lastblock] in the return value"}, + {"include_watchonly", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Include transactions to watch-only addresses (see 'importaddress')"}, + {"include_removed", RPCArg::Type::BOOL, RPCArg::Default{true}, "Show transactions that were removed due to a reorg in the \"removed\" array\n" "(not guaranteed to work on pruned nodes)"}, }, RPCResult{ @@ -1645,9 +1645,9 @@ static RPCHelpMan gettransaction() "\nGet detailed information about in-wallet transaction <txid>\n", { {"txid", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction id"}, - {"include_watchonly", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false", + {"include_watchonly", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Whether to include watch-only addresses in balance calculation and details[]"}, - {"verbose", RPCArg::Type::BOOL, /* default */ "false", + {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "Whether to include a `decoded` field containing the decoded transaction (equivalent to RPC decoderawtransaction)"}, }, RPCResult{ @@ -1832,7 +1832,7 @@ static RPCHelpMan keypoolrefill() "\nFills the keypool."+ HELP_REQUIRING_PASSPHRASE, { - {"newsize", RPCArg::Type::NUM, /* default */ "100", "The new keypool size"}, + {"newsize", RPCArg::Type::NUM, RPCArg::Default{100}, "The new keypool size"}, }, RPCResult{RPCResult::Type::NONE, "", ""}, RPCExamples{ @@ -2124,7 +2124,7 @@ static RPCHelpMan lockunspent() "Also see the listunspent call\n", { {"unlock", RPCArg::Type::BOOL, RPCArg::Optional::NO, "Whether to unlock (true) or lock (false) the specified transactions"}, - {"transactions", RPCArg::Type::ARR, /* default */ "empty array", "The transaction outputs and within each, the txid (string) vout (numeric).", + {"transactions", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "The transaction outputs and within each, the txid (string) vout (numeric).", { {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "", { @@ -2567,7 +2567,7 @@ static RPCHelpMan loadwallet() "\napplied to the new wallet (eg -rescan, etc).\n", { {"filename", RPCArg::Type::STR, RPCArg::Optional::NO, "The wallet directory or .dat file."}, - {"load_on_startup", RPCArg::Type::BOOL, /* default */ "null", "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."}, + {"load_on_startup", RPCArg::Type::BOOL, RPCArg::Default{UniValue::VNULL}, "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, "", "", @@ -2630,7 +2630,7 @@ static RPCHelpMan setwalletflag() "\nChange the state of the given wallet flag for a wallet.\n", { {"flag", RPCArg::Type::STR, RPCArg::Optional::NO, "The name of the flag to change. Current available flags: " + flags}, - {"value", RPCArg::Type::BOOL, /* default */ "true", "The new state."}, + {"value", RPCArg::Type::BOOL, RPCArg::Default{true}, "The new state."}, }, RPCResult{ RPCResult::Type::OBJ, "", "", @@ -2693,13 +2693,13 @@ static RPCHelpMan createwallet() "\nCreates and loads a new wallet.\n", { {"wallet_name", RPCArg::Type::STR, RPCArg::Optional::NO, "The name for the new wallet. If this is a path, the wallet will be created at the path location."}, - {"disable_private_keys", RPCArg::Type::BOOL, /* default */ "false", "Disable the possibility of private keys (only watchonlys are possible in this mode)."}, - {"blank", RPCArg::Type::BOOL, /* default */ "false", "Create a blank wallet. A blank wallet has no keys or HD seed. One can be set using sethdseed."}, + {"disable_private_keys", RPCArg::Type::BOOL, RPCArg::Default{false}, "Disable the possibility of private keys (only watchonlys are possible in this mode)."}, + {"blank", RPCArg::Type::BOOL, RPCArg::Default{false}, "Create a blank wallet. A blank wallet has no keys or HD seed. One can be set using sethdseed."}, {"passphrase", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Encrypt the wallet with this passphrase."}, - {"avoid_reuse", RPCArg::Type::BOOL, /* default */ "false", "Keep track of coin reuse, and treat dirty and clean coins differently with privacy considerations in mind."}, - {"descriptors", RPCArg::Type::BOOL, /* default */ "false", "Create a native descriptor wallet. The wallet will use descriptors internally to handle address creation"}, - {"load_on_startup", RPCArg::Type::BOOL, /* default */ "null", "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."}, - {"external_signer", RPCArg::Type::BOOL, /* default */ "false", "Use an external signer such as a hardware wallet. Requires -signer to be configured. Wallet creation will fail if keys cannot be fetched. Requires disable_private_keys and descriptors set to true."}, + {"avoid_reuse", RPCArg::Type::BOOL, RPCArg::Default{false}, "Keep track of coin reuse, and treat dirty and clean coins differently with privacy considerations in mind."}, + {"descriptors", RPCArg::Type::BOOL, RPCArg::Default{false}, "Create a native descriptor wallet. The wallet will use descriptors internally to handle address creation"}, + {"load_on_startup", RPCArg::Type::BOOL, RPCArg::Default{UniValue::VNULL}, "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."}, + {"external_signer", RPCArg::Type::BOOL, RPCArg::Default{false}, "Use an external signer such as a hardware wallet. Requires -signer to be configured. Wallet creation will fail if keys cannot be fetched. Requires disable_private_keys and descriptors set to true."}, }, RPCResult{ RPCResult::Type::OBJ, "", "", @@ -2750,7 +2750,7 @@ static RPCHelpMan createwallet() #ifdef ENABLE_EXTERNAL_SIGNER flags |= WALLET_FLAG_EXTERNAL_SIGNER; #else - throw JSONRPCError(RPC_WALLET_ERROR, "Configure with --enable-external-signer to use this"); + throw JSONRPCError(RPC_WALLET_ERROR, "Compiled without external signing support (required for external signing)"); #endif } @@ -2788,8 +2788,8 @@ static RPCHelpMan unloadwallet() "Unloads the wallet referenced by the request endpoint otherwise unloads the wallet specified in the argument.\n" "Specifying the wallet name on a wallet endpoint is invalid.", { - {"wallet_name", RPCArg::Type::STR, /* default */ "the wallet name from the RPC endpoint", "The name of the wallet to unload. If provided both here and in the RPC endpoint, the two must be identical."}, - {"load_on_startup", RPCArg::Type::BOOL, /* default */ "null", "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."}, + {"wallet_name", RPCArg::Type::STR, RPCArg::DefaultHint{"the wallet name from the RPC endpoint"}, "The name of the wallet to unload. If provided both here and in the RPC endpoint, the two must be identical."}, + {"load_on_startup", RPCArg::Type::BOOL, RPCArg::Default{UniValue::VNULL}, "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, "warning", "Warning message if wallet was not unloaded cleanly."}, @@ -2840,21 +2840,21 @@ static RPCHelpMan listunspent() "with between minconf and maxconf (inclusive) confirmations.\n" "Optionally filter to only include txouts paid to specified addresses.\n", { - {"minconf", RPCArg::Type::NUM, /* default */ "1", "The minimum confirmations to filter"}, - {"maxconf", RPCArg::Type::NUM, /* default */ "9999999", "The maximum confirmations to filter"}, - {"addresses", RPCArg::Type::ARR, /* default */ "empty array", "The bitcoin addresses to filter", + {"minconf", RPCArg::Type::NUM, RPCArg::Default{1}, "The minimum confirmations to filter"}, + {"maxconf", RPCArg::Type::NUM, RPCArg::Default{9999999}, "The maximum confirmations to filter"}, + {"addresses", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "The bitcoin addresses to filter", { {"address", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "bitcoin address"}, }, }, - {"include_unsafe", RPCArg::Type::BOOL, /* default */ "true", "Include outputs that are not safe to spend\n" + {"include_unsafe", RPCArg::Type::BOOL, RPCArg::Default{true}, "Include outputs that are not safe to spend\n" "See description of \"safe\" attribute below."}, {"query_options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "JSON with query options", { - {"minimumAmount", RPCArg::Type::AMOUNT, /* default */ "0", "Minimum value of each UTXO in " + CURRENCY_UNIT + ""}, - {"maximumAmount", RPCArg::Type::AMOUNT, /* default */ "unlimited", "Maximum value of each UTXO in " + CURRENCY_UNIT + ""}, - {"maximumCount", RPCArg::Type::NUM, /* default */ "unlimited", "Maximum number of UTXOs"}, - {"minimumSumAmount", RPCArg::Type::AMOUNT, /* default */ "unlimited", "Minimum sum value of all UTXOs in " + CURRENCY_UNIT + ""}, + {"minimumAmount", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(0)}, "Minimum value of each UTXO in " + CURRENCY_UNIT + ""}, + {"maximumAmount", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"unlimited"}, "Maximum value of each UTXO in " + CURRENCY_UNIT + ""}, + {"maximumCount", RPCArg::Type::NUM, RPCArg::DefaultHint{"unlimited"}, "Maximum number of UTXOs"}, + {"minimumSumAmount", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"unlimited"}, "Minimum sum value of all UTXOs in " + CURRENCY_UNIT + ""}, }, "query_options"}, }, @@ -3204,17 +3204,17 @@ static RPCHelpMan fundrawtransaction() {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex string of the raw transaction"}, {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "for backward compatibility: passing in a true instead of an object will result in {\"includeWatching\":true}", { - {"add_inputs", RPCArg::Type::BOOL, /* default */ "true", "For a transaction with existing inputs, automatically include more if they are not enough."}, - {"changeAddress", RPCArg::Type::STR, /* default */ "pool address", "The bitcoin address to receive the change"}, - {"changePosition", RPCArg::Type::NUM, /* default */ "random", "The index of the change output"}, - {"change_type", RPCArg::Type::STR, /* default */ "set by -changetype", "The output type to use. Only valid if changeAddress is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."}, - {"includeWatching", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false", "Also select inputs which are watch only.\n" + {"add_inputs", RPCArg::Type::BOOL, RPCArg::Default{true}, "For a transaction with existing inputs, automatically include more if they are not enough."}, + {"changeAddress", RPCArg::Type::STR, RPCArg::DefaultHint{"pool address"}, "The bitcoin address to receive the change"}, + {"changePosition", RPCArg::Type::NUM, RPCArg::DefaultHint{"random"}, "The index of the change output"}, + {"change_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -changetype"}, "The output type to use. Only valid if changeAddress is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."}, + {"includeWatching", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Also select inputs which are watch only.\n" "Only solvable inputs can be used. Watch-only destinations are solvable if the public key and/or output script was imported,\n" "e.g. with 'importpubkey' or 'importmulti' with the 'pubkeys' or 'desc' field."}, - {"lockUnspents", RPCArg::Type::BOOL, /* default */ "false", "Lock selected unspent outputs"}, - {"fee_rate", RPCArg::Type::AMOUNT, /* default */ "not set, fall back to wallet fee estimation", "Specify a fee rate in " + CURRENCY_ATOM + "/vB."}, - {"feeRate", RPCArg::Type::AMOUNT, /* default */ "not set, fall back to wallet fee estimation", "Specify a fee rate in " + CURRENCY_UNIT + "/kvB."}, - {"subtractFeeFromOutputs", RPCArg::Type::ARR, /* default */ "empty array", "The integers.\n" + {"lockUnspents", RPCArg::Type::BOOL, RPCArg::Default{false}, "Lock selected unspent outputs"}, + {"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."}, + {"feeRate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_UNIT + "/kvB."}, + {"subtractFeeFromOutputs", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "The integers.\n" "The fee will be equally deducted from the amount of each specified output.\n" "Those recipients will receive less bitcoins than you enter in their corresponding amount field.\n" "If no outputs are specified here, the sender pays the fee.", @@ -3222,14 +3222,14 @@ static RPCHelpMan fundrawtransaction() {"vout_index", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "The zero-based output index, before a change output is added."}, }, }, - {"replaceable", RPCArg::Type::BOOL, /* default */ "wallet default", "Marks this transaction as BIP125 replaceable.\n" + {"replaceable", RPCArg::Type::BOOL, RPCArg::DefaultHint{"wallet default"}, "Marks this transaction as BIP125 replaceable.\n" "Allows this transaction to be replaced by a transaction with higher fees"}, - {"conf_target", RPCArg::Type::NUM, /* default */ "wallet -txconfirmtarget", "Confirmation target in blocks"}, - {"estimate_mode", RPCArg::Type::STR, /* default */ "unset", std::string() + "The fee estimate mode, must be one of (case insensitive):\n" + {"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks"}, + {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, std::string() + "The fee estimate mode, must be one of (case insensitive):\n" " \"" + FeeModes("\"\n\"") + "\""}, }, "options"}, - {"iswitness", RPCArg::Type::BOOL, /* default */ "depends on heuristic tests", "Whether the transaction hex is a serialized witness transaction.\n" + {"iswitness", RPCArg::Type::BOOL, RPCArg::DefaultHint{"depends on heuristic tests"}, "Whether the transaction hex is a serialized witness transaction.\n" "If iswitness is not present, heuristic tests will be used in decoding.\n" "If true, only witness deserialization will be tried.\n" "If false, only non-witness deserialization will be tried.\n" @@ -3310,7 +3310,7 @@ RPCHelpMan signrawtransactionwithwallet() }, }, }, - {"sighashtype", RPCArg::Type::STR, /* default */ "ALL", "The signature hash type. Must be one of\n" + {"sighashtype", RPCArg::Type::STR, RPCArg::Default{"ALL"}, "The signature hash type. Must be one of\n" " \"ALL\"\n" " \"NONE\"\n" " \"SINGLE\"\n" @@ -3402,19 +3402,19 @@ static RPCHelpMan bumpfee_helper(std::string method_name) {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The txid to be bumped"}, {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "", { - {"conf_target", RPCArg::Type::NUM, /* default */ "wallet -txconfirmtarget", "Confirmation target in blocks\n"}, - {"fee_rate", RPCArg::Type::AMOUNT, /* default */ "not set, fall back to wallet fee estimation", + {"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks\n"}, + {"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "\nSpecify a fee rate in " + CURRENCY_ATOM + "/vB instead of relying on the built-in fee estimator.\n" "Must be at least " + incremental_fee + " higher than the current transaction fee rate.\n" "WARNING: before version 0.21, fee_rate was in " + CURRENCY_UNIT + "/kvB. As of 0.21, fee_rate is in " + CURRENCY_ATOM + "/vB.\n"}, - {"replaceable", RPCArg::Type::BOOL, /* default */ "true", "Whether the new transaction should still be\n" + {"replaceable", RPCArg::Type::BOOL, RPCArg::Default{true}, "Whether the new transaction should still be\n" "marked bip-125 replaceable. If true, the sequence numbers in the transaction will\n" "be left unchanged from the original. If false, any input sequence numbers in the\n" "original transaction that were less than 0xfffffffe will be increased to 0xfffffffe\n" "so the new transaction will not be explicitly bip-125 replaceable (though it may\n" "still be replaceable in practice, for example if it has unconfirmed ancestors which\n" "are replaceable).\n"}, - {"estimate_mode", RPCArg::Type::STR, /* default */ "unset", std::string() + "The fee estimate mode, must be one of (case insensitive):\n" + {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, "The fee estimate mode, must be one of (case insensitive):\n" "\"" + FeeModes("\"\n\"") + "\""}, }, "options"}, @@ -3564,7 +3564,7 @@ static RPCHelpMan rescanblockchain() "\nRescan the local blockchain for wallet related transactions.\n" "Note: Use \"getwalletinfo\" to query the scanning progress.\n", { - {"start_height", RPCArg::Type::NUM, /* default */ "0", "block height where the rescan should start"}, + {"start_height", RPCArg::Type::NUM, RPCArg::Default{0}, "block height where the rescan should start"}, {"stop_height", RPCArg::Type::NUM, RPCArg::Optional::OMITTED_NAMED_ARG, "the last block height that should be scanned. If none is provided it will rescan up to the tip at return time of this call."}, }, RPCResult{ @@ -4023,35 +4023,35 @@ static RPCHelpMan send() }, }, }, - {"conf_target", RPCArg::Type::NUM, /* default */ "wallet -txconfirmtarget", "Confirmation target in blocks"}, - {"estimate_mode", RPCArg::Type::STR, /* default */ "unset", std::string() + "The fee estimate mode, must be one of (case insensitive):\n" + {"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks"}, + {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, std::string() + "The fee estimate mode, must be one of (case insensitive):\n" " \"" + FeeModes("\"\n\"") + "\""}, - {"fee_rate", RPCArg::Type::AMOUNT, /* default */ "not set, fall back to wallet fee estimation", "Specify a fee rate in " + CURRENCY_ATOM + "/vB."}, + {"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."}, {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "", { - {"add_inputs", RPCArg::Type::BOOL, /* default */ "false", "If inputs are specified, automatically include more if they are not enough."}, - {"add_to_wallet", RPCArg::Type::BOOL, /* default */ "true", "When false, returns a serialized transaction which will not be added to the wallet or broadcast"}, - {"change_address", RPCArg::Type::STR_HEX, /* default */ "pool address", "The bitcoin address to receive the change"}, - {"change_position", RPCArg::Type::NUM, /* default */ "random", "The index of the change output"}, - {"change_type", RPCArg::Type::STR, /* default */ "set by -changetype", "The output type to use. Only valid if change_address is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."}, - {"conf_target", RPCArg::Type::NUM, /* default */ "wallet -txconfirmtarget", "Confirmation target in blocks"}, - {"estimate_mode", RPCArg::Type::STR, /* default */ "unset", std::string() + "The fee estimate mode, must be one of (case insensitive):\n" + {"add_inputs", RPCArg::Type::BOOL, RPCArg::Default{false}, "If inputs are specified, automatically include more if they are not enough."}, + {"add_to_wallet", RPCArg::Type::BOOL, RPCArg::Default{true}, "When false, returns a serialized transaction which will not be added to the wallet or broadcast"}, + {"change_address", RPCArg::Type::STR_HEX, RPCArg::DefaultHint{"pool address"}, "The bitcoin address to receive the change"}, + {"change_position", RPCArg::Type::NUM, RPCArg::DefaultHint{"random"}, "The index of the change output"}, + {"change_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -changetype"}, "The output type to use. Only valid if change_address is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."}, + {"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks"}, + {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, std::string() + "The fee estimate mode, must be one of (case insensitive):\n" " \"" + FeeModes("\"\n\"") + "\""}, - {"fee_rate", RPCArg::Type::AMOUNT, /* default */ "not set, fall back to wallet fee estimation", "Specify a fee rate in " + CURRENCY_ATOM + "/vB."}, - {"include_watching", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false", "Also select inputs which are watch only.\n" + {"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."}, + {"include_watching", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Also select inputs which are watch only.\n" "Only solvable inputs can be used. Watch-only destinations are solvable if the public key and/or output script was imported,\n" "e.g. with 'importpubkey' or 'importmulti' with the 'pubkeys' or 'desc' field."}, - {"inputs", RPCArg::Type::ARR, /* default */ "empty array", "Specify inputs instead of adding them automatically. A JSON array of JSON objects", + {"inputs", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "Specify inputs instead of adding them automatically. A JSON array of JSON objects", { {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"}, {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"}, {"sequence", RPCArg::Type::NUM, RPCArg::Optional::NO, "The sequence number"}, }, }, - {"locktime", RPCArg::Type::NUM, /* default */ "0", "Raw locktime. Non-0 value also locktime-activates inputs"}, - {"lock_unspents", RPCArg::Type::BOOL, /* default */ "false", "Lock selected unspent outputs"}, - {"psbt", RPCArg::Type::BOOL, /* default */ "automatic", "Always return a PSBT, implies add_to_wallet=false."}, - {"subtract_fee_from_outputs", RPCArg::Type::ARR, /* default */ "empty array", "Outputs to subtract the fee from, specified as integer indices.\n" + {"locktime", RPCArg::Type::NUM, RPCArg::Default{0}, "Raw locktime. Non-0 value also locktime-activates inputs"}, + {"lock_unspents", RPCArg::Type::BOOL, RPCArg::Default{false}, "Lock selected unspent outputs"}, + {"psbt", RPCArg::Type::BOOL, RPCArg::DefaultHint{"automatic"}, "Always return a PSBT, implies add_to_wallet=false."}, + {"subtract_fee_from_outputs", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "Outputs to subtract the fee from, specified as integer indices.\n" "The fee will be equally deducted from the amount of each specified output.\n" "Those recipients will receive less bitcoins than you enter in their corresponding amount field.\n" "If no outputs are specified here, the sender pays the fee.", @@ -4059,7 +4059,7 @@ static RPCHelpMan send() {"vout_index", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "The zero-based output index, before a change output is added."}, }, }, - {"replaceable", RPCArg::Type::BOOL, /* default */ "wallet default", "Marks this transaction as BIP125 replaceable.\n" + {"replaceable", RPCArg::Type::BOOL, RPCArg::DefaultHint{"wallet default"}, "Marks this transaction as BIP125 replaceable.\n" "Allows this transaction to be replaced by a transaction with higher fees"}, }, "options"}, @@ -4207,11 +4207,11 @@ static RPCHelpMan sethdseed() "\nNote that you will need to MAKE A NEW BACKUP of your wallet after setting the HD wallet seed." + HELP_REQUIRING_PASSPHRASE, { - {"newkeypool", RPCArg::Type::BOOL, /* default */ "true", "Whether to flush old unused addresses, including change addresses, from the keypool and regenerate it.\n" + {"newkeypool", RPCArg::Type::BOOL, RPCArg::Default{true}, "Whether to flush old unused addresses, including change addresses, from the keypool and regenerate it.\n" "If true, the next address from getnewaddress and change address from getrawchangeaddress will be from this new seed.\n" "If false, addresses (including change addresses if the wallet already had HD Chain Split enabled) from the existing\n" "keypool will be used until it has been depleted."}, - {"seed", RPCArg::Type::STR, /* default */ "random seed", "The WIF private key to use as the new HD seed.\n" + {"seed", RPCArg::Type::STR, RPCArg::DefaultHint{"random seed"}, "The WIF private key to use as the new HD seed.\n" "The seed value can be retrieved using the dumpwallet command. It is the private key marked hdseed=1"}, }, RPCResult{RPCResult::Type::NONE, "", ""}, @@ -4278,15 +4278,15 @@ static RPCHelpMan walletprocesspsbt() HELP_REQUIRING_PASSPHRASE, { {"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction base64 string"}, - {"sign", RPCArg::Type::BOOL, /* default */ "true", "Also sign the transaction when updating"}, - {"sighashtype", RPCArg::Type::STR, /* default */ "ALL", "The signature hash type to sign with if not specified by the PSBT. Must be one of\n" + {"sign", RPCArg::Type::BOOL, RPCArg::Default{true}, "Also sign the transaction when updating"}, + {"sighashtype", RPCArg::Type::STR, RPCArg::Default{"ALL"}, "The signature hash type to sign with if not specified by the PSBT. Must be one of\n" " \"ALL\"\n" " \"NONE\"\n" " \"SINGLE\"\n" " \"ALL|ANYONECANPAY\"\n" " \"NONE|ANYONECANPAY\"\n" " \"SINGLE|ANYONECANPAY\""}, - {"bip32derivs", RPCArg::Type::BOOL, /* default */ "true", "Include BIP 32 derivation paths for public keys if we know them"}, + {"bip32derivs", RPCArg::Type::BOOL, RPCArg::Default{true}, "Include BIP 32 derivation paths for public keys if we know them"}, }, RPCResult{ RPCResult::Type::OBJ, "", "", @@ -4347,7 +4347,7 @@ static RPCHelpMan walletcreatefundedpsbt() { {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"}, {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"}, - {"sequence", RPCArg::Type::NUM, /* default */ "depends on the value of the 'locktime' and 'options.replaceable' arguments", "The sequence number"}, + {"sequence", RPCArg::Type::NUM, RPCArg::DefaultHint{"depends on the value of the 'locktime' and 'options.replaceable' arguments"}, "The sequence number"}, }, }, }, @@ -4369,18 +4369,18 @@ static RPCHelpMan walletcreatefundedpsbt() }, }, }, - {"locktime", RPCArg::Type::NUM, /* default */ "0", "Raw locktime. Non-0 value also locktime-activates inputs"}, + {"locktime", RPCArg::Type::NUM, RPCArg::Default{0}, "Raw locktime. Non-0 value also locktime-activates inputs"}, {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "", { - {"add_inputs", RPCArg::Type::BOOL, /* default */ "false", "If inputs are specified, automatically include more if they are not enough."}, - {"changeAddress", RPCArg::Type::STR_HEX, /* default */ "pool address", "The bitcoin address to receive the change"}, - {"changePosition", RPCArg::Type::NUM, /* default */ "random", "The index of the change output"}, - {"change_type", RPCArg::Type::STR, /* default */ "set by -changetype", "The output type to use. Only valid if changeAddress is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."}, - {"includeWatching", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false", "Also select inputs which are watch only"}, - {"lockUnspents", RPCArg::Type::BOOL, /* default */ "false", "Lock selected unspent outputs"}, - {"fee_rate", RPCArg::Type::AMOUNT, /* default */ "not set, fall back to wallet fee estimation", "Specify a fee rate in " + CURRENCY_ATOM + "/vB."}, - {"feeRate", RPCArg::Type::AMOUNT, /* default */ "not set, fall back to wallet fee estimation", "Specify a fee rate in " + CURRENCY_UNIT + "/kvB."}, - {"subtractFeeFromOutputs", RPCArg::Type::ARR, /* default */ "empty array", "The outputs to subtract the fee from.\n" + {"add_inputs", RPCArg::Type::BOOL, RPCArg::Default{false}, "If inputs are specified, automatically include more if they are not enough."}, + {"changeAddress", RPCArg::Type::STR_HEX, RPCArg::DefaultHint{"pool address"}, "The bitcoin address to receive the change"}, + {"changePosition", RPCArg::Type::NUM, RPCArg::DefaultHint{"random"}, "The index of the change output"}, + {"change_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -changetype"}, "The output type to use. Only valid if changeAddress is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."}, + {"includeWatching", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Also select inputs which are watch only"}, + {"lockUnspents", RPCArg::Type::BOOL, RPCArg::Default{false}, "Lock selected unspent outputs"}, + {"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."}, + {"feeRate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_UNIT + "/kvB."}, + {"subtractFeeFromOutputs", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "The outputs to subtract the fee from.\n" "The fee will be equally deducted from the amount of each specified output.\n" "Those recipients will receive less bitcoins than you enter in their corresponding amount field.\n" "If no outputs are specified here, the sender pays the fee.", @@ -4388,14 +4388,14 @@ static RPCHelpMan walletcreatefundedpsbt() {"vout_index", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "The zero-based output index, before a change output is added."}, }, }, - {"replaceable", RPCArg::Type::BOOL, /* default */ "wallet default", "Marks this transaction as BIP125 replaceable.\n" + {"replaceable", RPCArg::Type::BOOL, RPCArg::DefaultHint{"wallet default"}, "Marks this transaction as BIP125 replaceable.\n" "Allows this transaction to be replaced by a transaction with higher fees"}, - {"conf_target", RPCArg::Type::NUM, /* default */ "wallet -txconfirmtarget", "Confirmation target in blocks"}, - {"estimate_mode", RPCArg::Type::STR, /* default */ "unset", std::string() + "The fee estimate mode, must be one of (case insensitive):\n" + {"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks"}, + {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, std::string() + "The fee estimate mode, must be one of (case insensitive):\n" " \"" + FeeModes("\"\n\"") + "\""}, }, "options"}, - {"bip32derivs", RPCArg::Type::BOOL, /* default */ "true", "Include BIP 32 derivation paths for public keys if we know them"}, + {"bip32derivs", RPCArg::Type::BOOL, RPCArg::Default{true}, "Include BIP 32 derivation paths for public keys if we know them"}, }, RPCResult{ RPCResult::Type::OBJ, "", "", @@ -4468,7 +4468,7 @@ static RPCHelpMan upgradewallet() "\nUpgrade the wallet. Upgrades to the latest version if no version number is specified.\n" "New keys may be generated and a new wallet backup will need to be made.", { - {"version", RPCArg::Type::NUM, /* default */ strprintf("%d", FEATURE_LATEST), "The version number to upgrade to. Default is the latest wallet version."} + {"version", RPCArg::Type::NUM, RPCArg::Default{FEATURE_LATEST}, "The version number to upgrade to. Default is the latest wallet version."} }, RPCResult{ RPCResult::Type::OBJ, "", "", diff --git a/src/wallet/sqlite.cpp b/src/wallet/sqlite.cpp index 91891c5fc2..e245a277e4 100644 --- a/src/wallet/sqlite.cpp +++ b/src/wallet/sqlite.cpp @@ -233,6 +233,15 @@ void SQLiteDatabase::Open() throw std::runtime_error(strprintf("SQLiteDatabase: Failed to enable fullfsync: %s\n", sqlite3_errstr(ret))); } + if (gArgs.GetBoolArg("-unsafesqlitesync", false)) { + // Use normal synchronous mode for the journal + LogPrintf("WARNING SQLite is configured to not wait for data to be flushed to disk. Data loss and corruption may occur.\n"); + ret = sqlite3_exec(m_db, "PRAGMA synchronous = OFF", nullptr, nullptr, nullptr); + if (ret != SQLITE_OK) { + throw std::runtime_error(strprintf("SQLiteDatabase: Failed to set synchronous mode to OFF: %s\n", sqlite3_errstr(ret))); + } + } + // Make the table for our key-value pairs // First check that the main table exists sqlite3_stmt* check_main_stmt{nullptr}; diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index 01f2dfe06b..011d59ecaf 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -295,8 +295,6 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup) BOOST_CHECK_EQUAL(found, expected); } } - - SetMockTime(0); } // Check that GetImmatureCredit() returns a newly calculated value instead of @@ -377,9 +375,6 @@ BOOST_AUTO_TEST_CASE(ComputeTimeSmart) // If there are future entries, new transaction should use time of the // newest entry that is no more than 300 seconds ahead of the clock time. BOOST_CHECK_EQUAL(AddTx(*m_node.chainman, m_wallet, 5, 50, 600), 300); - - // Reset mock time for other tests. - SetMockTime(0); } BOOST_AUTO_TEST_CASE(LoadReceiveRequests) @@ -692,6 +687,7 @@ BOOST_FIXTURE_TEST_CASE(wallet_descriptor_test, BasicTestingSetup) //! rescanning where new transactions in new blocks could be lost. BOOST_FIXTURE_TEST_CASE(CreateWallet, TestChain100Setup) { + gArgs.ForceSetArg("-unsafesqlitesync", "1"); // Create new wallet with known key and unload it. auto wallet = TestLoadWallet(*m_node.chain); CKey key; @@ -787,6 +783,7 @@ BOOST_FIXTURE_TEST_CASE(CreateWallet, TestChain100Setup) BOOST_FIXTURE_TEST_CASE(ZapSelectTx, TestChain100Setup) { + gArgs.ForceSetArg("-unsafesqlitesync", "1"); auto wallet = TestLoadWallet(*m_node.chain); CKey key; key.MakeNewKey(true); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index b00fa851fd..332e7b1397 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -3594,19 +3594,6 @@ void ReserveDestination::ReturnDestination() address = CNoDestination(); } -#ifdef ENABLE_EXTERNAL_SIGNER -ExternalSigner CWallet::GetExternalSigner() -{ - const std::string command = gArgs.GetArg("-signer", ""); - if (command == "") throw std::runtime_error(std::string(__func__) + ": restart bitcoind with -signer=<cmd>"); - std::vector<ExternalSigner> signers; - ExternalSigner::Enumerate(command, signers, Params().NetworkIDString()); - if (signers.empty()) throw std::runtime_error(std::string(__func__) + ": No external signers found"); - // TODO: add fingerprint argument in case of multiple signers - return signers[0]; -} -#endif - bool CWallet::DisplayAddress(const CTxDestination& dest) { #ifdef ENABLE_EXTERNAL_SIGNER @@ -3619,7 +3606,7 @@ bool CWallet::DisplayAddress(const CTxDestination& dest) if (signer_spk_man == nullptr) { return false; } - ExternalSigner signer = GetExternalSigner(); // TODO: move signer in spk_man + ExternalSigner signer = ExternalSignerScriptPubKeyMan::GetExternalSigner(); return signer_spk_man->DisplayAddress(scriptPubKey, signer); #else return false; @@ -4516,7 +4503,7 @@ void CWallet::LoadDescriptorScriptPubKeyMan(uint256 id, WalletDescriptor& desc) auto spk_manager = std::unique_ptr<ScriptPubKeyMan>(new ExternalSignerScriptPubKeyMan(*this, desc)); m_spk_managers[id] = std::move(spk_manager); #else - throw std::runtime_error(std::string(__func__) + ": Configure with --enable-external-signer to use external signer wallets"); + throw std::runtime_error(std::string(__func__) + ": Compiled without external signing support (required for external signing)"); #endif } else { auto spk_manager = std::unique_ptr<ScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this, desc)); @@ -4585,8 +4572,8 @@ void CWallet::SetupDescriptorScriptPubKeyMans() } } #else - throw std::runtime_error(std::string(__func__) + ": Wallets with external signers require Boost::Process library."); -#endif + throw std::runtime_error(std::string(__func__) + ": Compiled without external signing support (required for external signing)"); +#endif // ENABLE_EXTERNAL_SIGNER } } diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 5bf3c91bec..c4acef8705 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -845,9 +845,6 @@ public: std::vector<OutputGroup> GroupOutputs(const std::vector<COutput>& outputs, bool separate_coins, const CFeeRate& effective_feerate, const CFeeRate& long_term_feerate, const CoinEligibilityFilter& filter, bool positive_only) const; -#ifdef ENABLE_EXTERNAL_SIGNER - ExternalSigner GetExternalSigner() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); -#endif /** Display address on an external signer. Returns false if external signer support is not compiled */ bool DisplayAddress(const CTxDestination& dest) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); diff --git a/src/zmq/zmqpublishnotifier.cpp b/src/zmq/zmqpublishnotifier.cpp index 168ba841c8..25afa94d0f 100644 --- a/src/zmq/zmqpublishnotifier.cpp +++ b/src/zmq/zmqpublishnotifier.cpp @@ -6,10 +6,11 @@ #include <chain.h> #include <chainparams.h> +#include <node/blockstorage.h> #include <rpc/server.h> #include <streams.h> #include <util/system.h> -#include <validation.h> +#include <validation.h> // For cs_main #include <zmq/zmqutil.h> #include <zmq.h> diff --git a/test/functional/feature_cltv.py b/test/functional/feature_cltv.py index b7c2887ee8..f2130fb588 100755 --- a/test/functional/feature_cltv.py +++ b/test/functional/feature_cltv.py @@ -8,10 +8,24 @@ Test that the CHECKLOCKTIMEVERIFY soft-fork activates at (regtest) block height 1351. """ -from test_framework.blocktools import create_coinbase, create_block, create_transaction -from test_framework.messages import CTransaction, msg_block, ToHex +from test_framework.blocktools import ( + create_block, + create_coinbase, + create_transaction, +) +from test_framework.messages import ( + CTransaction, + ToHex, + msg_block, +) from test_framework.p2p import P2PInterface -from test_framework.script import CScript, OP_1NEGATE, OP_CHECKLOCKTIMEVERIFY, OP_DROP, CScriptNum +from test_framework.script import ( + CScript, + CScriptNum, + OP_1NEGATE, + OP_CHECKLOCKTIMEVERIFY, + OP_DROP, +) from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, @@ -23,32 +37,54 @@ from io import BytesIO CLTV_HEIGHT = 1351 -def cltv_invalidate(tx): - '''Modify the signature in vin 0 of the tx to fail CLTV +# Helper function to modify a transaction by +# 1) prepending a given script to the scriptSig of vin 0 and +# 2) (optionally) modify the nSequence of vin 0 and the tx's nLockTime +def cltv_modify_tx(node, tx, prepend_scriptsig, nsequence=None, nlocktime=None): + if nsequence is not None: + tx.vin[0].nSequence = nsequence + tx.nLockTime = nlocktime + + # Need to re-sign, since nSequence and nLockTime changed + signed_result = node.signrawtransactionwithwallet(ToHex(tx)) + new_tx = CTransaction() + new_tx.deserialize(BytesIO(hex_str_to_bytes(signed_result['hex']))) + else: + new_tx = tx + + new_tx.vin[0].scriptSig = CScript(prepend_scriptsig + list(CScript(new_tx.vin[0].scriptSig))) + return new_tx + - Prepends -1 CLTV DROP in the scriptSig itself. +def cltv_invalidate(node, tx, failure_reason): + # Modify the signature in vin 0 and nSequence/nLockTime of the tx to fail CLTV + # + # According to BIP65, OP_CHECKLOCKTIMEVERIFY can fail due the following reasons: + # 1) the stack is empty + # 2) the top item on the stack is less than 0 + # 3) the lock-time type (height vs. timestamp) of the top stack item and the + # nLockTime field are not the same + # 4) the top stack item is greater than the transaction's nLockTime field + # 5) the nSequence field of the txin is 0xffffffff + assert failure_reason in range(5) + scheme = [ + # | Script to prepend to scriptSig | nSequence | nLockTime | + # +-------------------------------------------------+------------+--------------+ + [[OP_CHECKLOCKTIMEVERIFY], None, None], + [[OP_1NEGATE, OP_CHECKLOCKTIMEVERIFY, OP_DROP], None, None], + [[CScriptNum(1000), OP_CHECKLOCKTIMEVERIFY, OP_DROP], 0, 1296688602], # timestamp of genesis block + [[CScriptNum(1000), OP_CHECKLOCKTIMEVERIFY, OP_DROP], 0, 500], + [[CScriptNum(500), OP_CHECKLOCKTIMEVERIFY, OP_DROP], 0xffffffff, 500], + ][failure_reason] + + return cltv_modify_tx(node, tx, prepend_scriptsig=scheme[0], nsequence=scheme[1], nlocktime=scheme[2]) - TODO: test more ways that transactions using CLTV could be invalid (eg - locktime requirements fail, sequence time requirements fail, etc). - ''' - tx.vin[0].scriptSig = CScript([OP_1NEGATE, OP_CHECKLOCKTIMEVERIFY, OP_DROP] + - list(CScript(tx.vin[0].scriptSig))) def cltv_validate(node, tx, height): - '''Modify the signature in vin 0 of the tx to pass CLTV - Prepends <height> CLTV DROP in the scriptSig, and sets - the locktime to height''' - tx.vin[0].nSequence = 0 - tx.nLockTime = height - - # Need to re-sign, since nSequence and nLockTime changed - signed_result = node.signrawtransactionwithwallet(ToHex(tx)) - new_tx = CTransaction() - new_tx.deserialize(BytesIO(hex_str_to_bytes(signed_result['hex']))) - - new_tx.vin[0].scriptSig = CScript([CScriptNum(height), OP_CHECKLOCKTIMEVERIFY, OP_DROP] + - list(CScript(new_tx.vin[0].scriptSig))) - return new_tx + # Modify the signature in vin 0 and nSequence/nLockTime of the tx to pass CLTV + scheme = [[CScriptNum(height), OP_CHECKLOCKTIMEVERIFY, OP_DROP], 0, height] + + return cltv_modify_tx(node, tx, prepend_scriptsig=scheme[0], nsequence=scheme[1], nlocktime=scheme[2]) class BIP65Test(BitcoinTestFramework): @@ -66,8 +102,7 @@ class BIP65Test(BitcoinTestFramework): self.skip_if_no_wallet() def test_cltv_info(self, *, is_active): - assert_equal(self.nodes[0].getblockchaininfo()['softforks']['bip65'], - { + assert_equal(self.nodes[0].getblockchaininfo()['softforks']['bip65'], { "active": is_active, "height": CLTV_HEIGHT, "type": "buried", @@ -83,18 +118,22 @@ class BIP65Test(BitcoinTestFramework): self.coinbase_txids = [self.nodes[0].getblock(b)['tx'][0] for b in self.nodes[0].generate(CLTV_HEIGHT - 2)] self.nodeaddress = self.nodes[0].getnewaddress() - self.log.info("Test that an invalid-according-to-CLTV transaction can still appear in a block") + self.log.info("Test that invalid-according-to-CLTV transactions can still appear in a block") - spendtx = create_transaction(self.nodes[0], self.coinbase_txids[0], - self.nodeaddress, amount=1.0) - cltv_invalidate(spendtx) - spendtx.rehash() + # create one invalid tx per CLTV failure reason (5 in total) and collect them + invalid_ctlv_txs = [] + for i in range(5): + spendtx = create_transaction(self.nodes[0], self.coinbase_txids[i], + self.nodeaddress, amount=1.0) + spendtx = cltv_invalidate(self.nodes[0], spendtx, i) + spendtx.rehash() + invalid_ctlv_txs.append(spendtx) tip = self.nodes[0].getbestblockhash() block_time = self.nodes[0].getblockheader(tip)['mediantime'] + 1 block = create_block(int(tip, 16), create_coinbase(CLTV_HEIGHT - 1), block_time) block.nVersion = 3 - block.vtx.append(spendtx) + block.vtx.extend(invalid_ctlv_txs) block.hashMerkleRoot = block.calc_merkle_root() block.solve() @@ -115,35 +154,46 @@ class BIP65Test(BitcoinTestFramework): assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip) peer.sync_with_ping() - self.log.info("Test that invalid-according-to-cltv transactions cannot appear in a block") + self.log.info("Test that invalid-according-to-CLTV transactions cannot appear in a block") block.nVersion = 4 - - spendtx = create_transaction(self.nodes[0], self.coinbase_txids[1], - self.nodeaddress, amount=1.0) - cltv_invalidate(spendtx) - spendtx.rehash() - - # First we show that this tx is valid except for CLTV by getting it - # rejected from the mempool for exactly that reason. - assert_equal( - [{ - 'txid': spendtx.hash, - 'wtxid': spendtx.getwtxid(), - 'allowed': False, - 'reject-reason': 'non-mandatory-script-verify-flag (Negative locktime)', - }], - self.nodes[0].testmempoolaccept(rawtxs=[spendtx.serialize().hex()], maxfeerate=0), - ) - - # Now we verify that a block with this transaction is also invalid. - block.vtx.append(spendtx) - block.hashMerkleRoot = block.calc_merkle_root() - block.solve() - - with self.nodes[0].assert_debug_log(expected_msgs=['CheckInputScripts on {} failed with non-mandatory-script-verify-flag (Negative locktime)'.format(block.vtx[-1].hash)]): - peer.send_and_ping(msg_block(block)) - assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip) - peer.sync_with_ping() + block.vtx.append(CTransaction()) # dummy tx after coinbase that will be replaced later + + # create and test one invalid tx per CLTV failure reason (5 in total) + for i in range(5): + spendtx = create_transaction(self.nodes[0], self.coinbase_txids[10+i], + self.nodeaddress, amount=1.0) + spendtx = cltv_invalidate(self.nodes[0], spendtx, i) + spendtx.rehash() + + expected_cltv_reject_reason = [ + "non-mandatory-script-verify-flag (Operation not valid with the current stack size)", + "non-mandatory-script-verify-flag (Negative locktime)", + "non-mandatory-script-verify-flag (Locktime requirement not satisfied)", + "non-mandatory-script-verify-flag (Locktime requirement not satisfied)", + "non-mandatory-script-verify-flag (Locktime requirement not satisfied)", + ][i] + # First we show that this tx is valid except for CLTV by getting it + # rejected from the mempool for exactly that reason. + assert_equal( + [{ + 'txid': spendtx.hash, + 'wtxid': spendtx.getwtxid(), + 'allowed': False, + 'reject-reason': expected_cltv_reject_reason, + }], + self.nodes[0].testmempoolaccept(rawtxs=[spendtx.serialize().hex()], maxfeerate=0), + ) + + # Now we verify that a block with this transaction is also invalid. + block.vtx[1] = spendtx + block.hashMerkleRoot = block.calc_merkle_root() + block.solve() + + with self.nodes[0].assert_debug_log(expected_msgs=['CheckInputScripts on {} failed with {}'.format( + block.vtx[-1].hash, expected_cltv_reject_reason)]): + peer.send_and_ping(msg_block(block)) + assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip) + peer.sync_with_ping() self.log.info("Test that a version 4 block with a valid-according-to-CLTV transaction is accepted") spendtx = cltv_validate(self.nodes[0], spendtx, CLTV_HEIGHT - 1) diff --git a/test/functional/feature_csv_activation.py b/test/functional/feature_csv_activation.py index 46ba18b9b5..8fa3f52de8 100755 --- a/test/functional/feature_csv_activation.py +++ b/test/functional/feature_csv_activation.py @@ -9,8 +9,8 @@ BIP 68 - nSequence relative lock times BIP 112 - CHECKSEQUENCEVERIFY BIP 113 - MedianTimePast semantics for nLockTime -mine 82 blocks whose coinbases will be used to generate inputs for our tests -mine 345 blocks and seed block chain with the 82 inputs will use for our tests at height 427 +mine 83 blocks whose coinbases will be used to generate inputs for our tests +mine 344 blocks and seed block chain with the 83 inputs used for our tests at height 427 mine 2 blocks and verify soft fork not yet activated mine 1 block and test that soft fork is activated (rules enforced for next block) Test BIP 113 is enforced diff --git a/test/functional/rpc_blockchain.py b/test/functional/rpc_blockchain.py index e090030205..ac53a280b4 100755 --- a/test/functional/rpc_blockchain.py +++ b/test/functional/rpc_blockchain.py @@ -149,6 +149,7 @@ class BlockchainTest(BitcoinTestFramework): 'count': 57, 'possible': True, }, + 'min_activation_height': 0, }, 'active': False }, @@ -158,7 +159,8 @@ class BlockchainTest(BitcoinTestFramework): 'status': 'active', 'start_time': -1, 'timeout': 9223372036854775807, - 'since': 0 + 'since': 0, + 'min_activation_height': 0, }, 'height': 0, 'active': True @@ -408,6 +410,9 @@ class BlockchainTest(BitcoinTestFramework): self.log.info("Test that getblock with verbosity 2 still works with pruned Undo data") datadir = get_datadir_path(self.options.tmpdir, 0) + self.log.info("Test that getblock with invalid verbosity type returns proper error message") + assert_raises_rpc_error(-1, "JSON value is not an integer as expected", node.getblock, blockhash, "2") + def move_block_file(old, new): old_path = os.path.join(datadir, self.chain, 'blocks', old) new_path = os.path.join(datadir, self.chain, 'blocks', new) diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py index 5c774934be..55166ba0ad 100644 --- a/test/functional/test_framework/util.py +++ b/test/functional/test_framework/util.py @@ -374,6 +374,8 @@ def write_config(config_path, *, n, chain, extra_config=""): f.write("upnp=0\n") f.write("natpmp=0\n") f.write("shrinkdebugfile=0\n") + # To improve SQLite wallet performance so that the tests don't timeout, use -unsafesqlitesync + f.write("unsafesqlitesync=1\n") f.write(extra_config) diff --git a/test/functional/wallet_basic.py b/test/functional/wallet_basic.py index dc6f8ed9c4..46eecae611 100755 --- a/test/functional/wallet_basic.py +++ b/test/functional/wallet_basic.py @@ -95,6 +95,8 @@ class WalletTest(BitcoinTestFramework): # but invisible if you include mempool txout = self.nodes[0].gettxout(confirmed_txid, confirmed_index, False) assert_equal(txout['value'], 50) + txout = self.nodes[0].gettxout(confirmed_txid, confirmed_index) # by default include_mempool=True + assert txout is None txout = self.nodes[0].gettxout(confirmed_txid, confirmed_index, True) assert txout is None # new utxo from mempool should be invisible if you exclude mempool diff --git a/test/lint/lint-circular-dependencies.sh b/test/lint/lint-circular-dependencies.sh index 0b15f99448..ad2333a808 100755 --- a/test/lint/lint-circular-dependencies.sh +++ b/test/lint/lint-circular-dependencies.sh @@ -11,7 +11,9 @@ export LC_ALL=C EXPECTED_CIRCULAR_DEPENDENCIES=( "chainparamsbase -> util/system -> chainparamsbase" "index/txindex -> validation -> index/txindex" - "index/blockfilterindex -> validation -> index/blockfilterindex" + "node/blockstorage -> validation -> node/blockstorage" + "index/blockfilterindex -> node/blockstorage -> validation -> index/blockfilterindex" + "index/base -> validation -> index/blockfilterindex -> index/base" "policy/fees -> txmempool -> policy/fees" "qt/addresstablemodel -> qt/walletmodel -> qt/addresstablemodel" "qt/bitcoingui -> qt/walletframe -> qt/bitcoingui" diff --git a/test/sanitizer_suppressions/tsan b/test/sanitizer_suppressions/tsan index 5b832b5763..7db051ca37 100644 --- a/test/sanitizer_suppressions/tsan +++ b/test/sanitizer_suppressions/tsan @@ -3,31 +3,12 @@ # # https://github.com/google/sanitizers/wiki/ThreadSanitizerSuppressions -# double locks (TODO fix) -mutex:g_genesis_wait_mutex -mutex:Interrupt -mutex:CThreadInterrupt -mutex:CConnman::Interrupt -mutex:CConnman::WakeMessageHandler -mutex:CConnman::ThreadOpenConnections -mutex:CConnman::ThreadOpenAddedConnections -mutex:CConnman::SocketHandler -mutex:UpdateTip -mutex:PeerManagerImpl::UpdatedBlockTip -mutex:g_best_block_mutex - # race (TODO fix) -race:CConnman::WakeMessageHandler -race:CConnman::ThreadMessageHandler -race:fHaveGenesis -race:ProcessNewBlock -race:ThreadImport race:LoadWallet race:WalletBatch::WriteHDChain race:BerkeleyBatch race:BerkeleyDatabase race:DatabaseBatch -race:leveldb::DBImpl::DeleteObsoleteFiles race:zmq::* race:bitcoin-qt @@ -35,7 +16,7 @@ race:bitcoin-qt deadlock:CChainState::ConnectTip # Intentional deadlock in tests -deadlock:TestPotentialDeadLockDetected +deadlock:sync_tests::potential_deadlock_detected # Wildcard for all gui tests, should be replaced with non-wildcard suppressions race:src/qt/test/* |