aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml6
-rw-r--r--SECURITY.md1
-rw-r--r--build-aux/m4/ax_boost_base.m414
-rwxr-xr-xci/test/06_script_b.sh1
-rw-r--r--configure.ac19
-rwxr-xr-xcontrib/guix/libexec/build.sh1
-rw-r--r--contrib/guix/manifest.scm33
-rw-r--r--contrib/guix/patches/glibc-2.24-guix-prefix.patch2
-rw-r--r--contrib/guix/patches/glibc-2.27-guix-prefix.patch2
-rwxr-xr-xcontrib/message-capture/message-capture-parser.py3
-rwxr-xr-xcontrib/seeds/makeseeds.py7
-rw-r--r--contrib/seeds/nodes_main.txt1502
-rw-r--r--contrib/seeds/nodes_main_manual.txt77
-rw-r--r--contrib/seeds/nodes_test.txt99
-rw-r--r--depends/packages/qt.mk1
-rw-r--r--doc/README.md1
-rw-r--r--doc/build-osx.md8
-rw-r--r--doc/descriptors.md7
-rw-r--r--doc/design/assumeutxo.md4
-rw-r--r--doc/developer-notes.md10
-rw-r--r--doc/i2p.md26
-rw-r--r--doc/managing-wallets.md27
-rw-r--r--doc/release-notes-15936.md15
-rw-r--r--doc/release-notes-24098.md22
-rw-r--r--doc/release-notes-24118.md10
-rw-r--r--doc/release-notes-24148.md23
-rw-r--r--doc/release-notes-24198.md6
-rw-r--r--doc/release-notes-24494.md2
-rw-r--r--doc/release-notes-25504.md6
-rw-r--r--doc/release-notes-25610.md12
-rw-r--r--doc/release-notes.md124
-rw-r--r--doc/release-notes/release-notes-24408.md5
-rw-r--r--doc/release-notes/release-notes-471.md4
-rw-r--r--src/.clang-tidy7
-rw-r--r--src/Makefile.am19
-rw-r--r--src/Makefile.bench.include2
-rw-r--r--src/Makefile.qt.include2
-rw-r--r--src/Makefile.qttest.include2
-rw-r--r--src/Makefile.test.include9
-rw-r--r--src/Makefile.test_fuzz.include2
-rw-r--r--src/Makefile.test_util.include2
-rw-r--r--src/addrdb.cpp4
-rw-r--r--src/banman.cpp8
-rw-r--r--src/bitcoin-chainstate.cpp9
-rw-r--r--src/blockfilter.cpp16
-rw-r--r--src/blockfilter.h11
-rw-r--r--src/chain.cpp47
-rw-r--r--src/chain.h10
-rw-r--r--src/chainparams.cpp40
-rw-r--r--src/chainparamsseeds.h1174
-rw-r--r--src/consensus/validation.h1
-rw-r--r--src/fs.cpp2
-rw-r--r--src/hash.cpp2
-rw-r--r--src/headerssync.cpp317
-rw-r--r--src/headerssync.h277
-rw-r--r--src/httpserver.cpp6
-rw-r--r--src/i2p.cpp64
-rw-r--r--src/i2p.h19
-rw-r--r--src/index/base.cpp7
-rw-r--r--src/index/base.h11
-rw-r--r--src/index/blockfilterindex.cpp4
-rw-r--r--src/index/blockfilterindex.h6
-rw-r--r--src/index/coinstatsindex.cpp9
-rw-r--r--src/index/coinstatsindex.h14
-rw-r--r--src/index/txindex.cpp2
-rw-r--r--src/index/txindex.h2
-rw-r--r--src/init.cpp63
-rw-r--r--src/init/common.cpp28
-rw-r--r--src/init/common.h1
-rw-r--r--src/interfaces/node.h2
-rw-r--r--src/kernel/mempool_persist.cpp2
-rw-r--r--src/kernel/mempool_persist.h4
-rw-r--r--src/logging.cpp83
-rw-r--r--src/logging.h55
-rw-r--r--src/net.cpp125
-rw-r--r--src/net.h60
-rw-r--r--src/net_processing.cpp472
-rw-r--r--src/net_processing.h1
-rw-r--r--src/node/blockstorage.cpp2
-rw-r--r--src/node/blockstorage.h6
-rw-r--r--src/node/chainstate.cpp25
-rw-r--r--src/node/interface_ui.cpp2
-rw-r--r--src/node/interface_ui.h2
-rw-r--r--src/node/interfaces.cpp10
-rw-r--r--src/node/mempool_args.cpp1
-rw-r--r--src/node/miner.cpp4
-rw-r--r--src/node/miner.h6
-rw-r--r--src/node/utxo_snapshot.h2
-rw-r--r--src/pow.cpp51
-rw-r--r--src/pow.h14
-rw-r--r--src/primitives/block.h2
-rw-r--r--src/qt/bitcoin.cpp2
-rw-r--r--src/qt/bitcoingui.cpp28
-rw-r--r--src/qt/bitcoingui.h5
-rw-r--r--src/qt/bitcoinstrings.cpp49
-rw-r--r--src/qt/clientmodel.cpp18
-rw-r--r--src/qt/clientmodel.h10
-rw-r--r--src/qt/forms/intro.ui2
-rw-r--r--src/qt/guiutil.cpp2
-rw-r--r--src/qt/locale/bitcoin_en.ts213
-rw-r--r--src/qt/locale/bitcoin_en.xlf2578
-rw-r--r--src/qt/modaloverlay.cpp12
-rw-r--r--src/qt/modaloverlay.h3
-rw-r--r--src/qt/rpcconsole.cpp10
-rw-r--r--src/qt/rpcconsole.h4
-rw-r--r--src/qt/sendcoinsdialog.cpp2
-rw-r--r--src/qt/sendcoinsdialog.h4
-rw-r--r--src/rpc/blockchain.cpp22
-rw-r--r--src/rpc/blockchain.h4
-rw-r--r--src/rpc/mempool.cpp4
-rw-r--r--src/rpc/mining.cpp8
-rw-r--r--src/rpc/net.cpp4
-rw-r--r--src/rpc/rawtransaction.cpp2
-rw-r--r--src/rpc/server.cpp2
-rw-r--r--src/rpc/txoutproof.cpp2
-rw-r--r--src/rpc/util.cpp3
-rw-r--r--src/script/descriptor.cpp10
-rw-r--r--src/sync.h2
-rw-r--r--src/test/blockfilter_index_tests.cpp8
-rw-r--r--src/test/coinstatsindex_tests.cpp13
-rw-r--r--src/test/denialofservice_tests.cpp1
-rw-r--r--src/test/descriptor_tests.cpp95
-rw-r--r--src/test/fuzz/bitdeque.cpp542
-rw-r--r--src/test/fuzz/mempool_utils.h2
-rw-r--r--src/test/fuzz/pow.cpp37
-rw-r--r--src/test/fuzz/tx_pool.cpp4
-rw-r--r--src/test/fuzz/txorphan.cpp1
-rw-r--r--src/test/fuzz/util.cpp1
-rw-r--r--src/test/fuzz/util.h7
-rw-r--r--src/test/fuzz/utxo_snapshot.cpp2
-rw-r--r--src/test/headers_sync_chainwork_tests.cpp146
-rw-r--r--src/test/i2p_tests.cpp6
-rw-r--r--src/test/logging_tests.cpp125
-rw-r--r--src/test/miner_tests.cpp2
-rw-r--r--src/test/net_tests.cpp2
-rw-r--r--src/test/pow_tests.cpp27
-rw-r--r--src/test/skiplist_tests.cpp2
-rw-r--r--src/test/util/chainstate.h7
-rw-r--r--src/test/util/mining.cpp2
-rw-r--r--src/test/util/net.cpp2
-rw-r--r--src/test/util/net.h1
-rw-r--r--src/test/util/setup_common.cpp7
-rw-r--r--src/test/util/setup_common.h4
-rw-r--r--src/test/util/validation.h2
-rw-r--r--src/test/util_tests.cpp19
-rw-r--r--src/test/validation_block_tests.cpp10
-rw-r--r--src/test/validation_chainstate_tests.cpp10
-rw-r--r--src/test/validation_chainstatemanager_tests.cpp22
-rw-r--r--src/test/validation_flush_tests.cpp4
-rw-r--r--src/threadinterrupt.h1
-rw-r--r--src/txmempool.cpp48
-rw-r--r--src/txmempool.h2
-rw-r--r--src/uint256.h11
-rw-r--r--src/univalue/include/univalue.h8
-rw-r--r--src/univalue/lib/univalue.cpp20
-rw-r--r--src/util/bip32.cpp2
-rw-r--r--src/util/bitdeque.h469
-rw-r--r--src/util/message.cpp1
-rw-r--r--src/util/strencodings.cpp1
-rw-r--r--src/util/string.cpp3
-rw-r--r--src/util/string.h37
-rw-r--r--src/util/system.cpp10
-rw-r--r--src/util/system.h2
-rw-r--r--src/util/thread.cpp6
-rw-r--r--src/util/thread.h3
-rw-r--r--src/validation.cpp192
-rw-r--r--src/validation.h89
-rw-r--r--src/wallet/bdb.cpp8
-rw-r--r--src/wallet/load.cpp2
-rw-r--r--src/wallet/rpc/backup.cpp67
-rw-r--r--src/wallet/rpc/spend.cpp25
-rw-r--r--src/wallet/rpc/wallet.cpp54
-rw-r--r--src/wallet/scriptpubkeyman.cpp323
-rw-r--r--src/wallet/scriptpubkeyman.h14
-rw-r--r--src/wallet/spend.cpp2
-rw-r--r--src/wallet/test/ismine_tests.cpp37
-rw-r--r--src/wallet/test/walletload_tests.cpp54
-rw-r--r--src/wallet/transaction.h7
-rw-r--r--src/wallet/wallet.cpp624
-rw-r--r--src/wallet/wallet.h30
-rw-r--r--src/wallet/walletdb.cpp67
-rw-r--r--src/wallet/walletdb.h9
-rw-r--r--src/wallet/walletutil.h14
-rwxr-xr-xtest/functional/feature_block.py2
-rwxr-xr-xtest/functional/feature_config_args.py3
-rwxr-xr-xtest/functional/feature_proxy.py21
-rwxr-xr-xtest/functional/mempool_accept.py2
-rwxr-xr-xtest/functional/mempool_expiry.py2
-rwxr-xr-xtest/functional/p2p_compactblocks.py24
-rwxr-xr-xtest/functional/p2p_dos_header_tree.py3
-rwxr-xr-xtest/functional/p2p_headers_sync_with_minchainwork.py164
-rwxr-xr-xtest/functional/p2p_i2p_sessions.py36
-rwxr-xr-xtest/functional/p2p_leak.py5
-rwxr-xr-xtest/functional/p2p_unrequested_blocks.py14
-rwxr-xr-xtest/functional/rpc_blockchain.py21
-rwxr-xr-xtest/functional/rpc_estimatefee.py8
-rwxr-xr-xtest/functional/rpc_fundrawtransaction.py120
-rwxr-xr-xtest/functional/rpc_getblockfrompeer.py4
-rwxr-xr-xtest/functional/rpc_getdescriptorinfo.py2
-rwxr-xr-xtest/functional/rpc_invalidateblock.py5
-rwxr-xr-xtest/functional/rpc_rawtransaction.py6
-rwxr-xr-xtest/functional/test_framework/messages.py1
-rwxr-xr-xtest/functional/test_framework/test_node.py2
-rwxr-xr-xtest/functional/test_runner.py11
-rwxr-xr-xtest/functional/tool_wallet.py10
-rwxr-xr-xtest/functional/wallet_balance.py1
-rwxr-xr-xtest/functional/wallet_basic.py73
-rwxr-xr-xtest/functional/wallet_bumpfee.py2
-rwxr-xr-xtest/functional/wallet_groups.py7
-rwxr-xr-xtest/functional/wallet_listsinceblock.py3
-rwxr-xr-xtest/functional/wallet_migration.py407
-rwxr-xr-xtest/functional/wallet_resendwallettransactions.py74
-rwxr-xr-xtest/functional/wallet_sendall.py32
-rw-r--r--test/sanitizer_suppressions/tsan2
214 files changed, 8970 insertions, 3667 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index f2a08cdd48..ae962f2906 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -97,8 +97,8 @@ task:
name: "Win64 native [vs2022]"
<< : *FILTER_TEMPLATE
windows_container:
- cpu: 4
- memory: 8G
+ cpu: 6
+ memory: 12G
image: cirrusci/windowsservercore:visualstudio2022
timeout_in: 120m
env:
@@ -162,7 +162,7 @@ task:
ccache_cache:
folder: '%CCACHE_DIR%'
install_tools_script:
- - choco install --yes --no-progress ccache
+ - choco install --yes --no-progress ccache --version=4.6.1
- choco install --yes --no-progress python3 --version=3.9.6
- pip install zmq
- ccache --version
diff --git a/SECURITY.md b/SECURITY.md
index c6a496edf1..c0660e7042 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -15,5 +15,6 @@ The following keys may be used to communicate sensitive information to developer
|------|-------------|
| Pieter Wuille | 133E AC17 9436 F14A 5CF1 B794 860F EB80 4E66 9320 |
| Michael Ford | E777 299F C265 DD04 7930 70EB 944D 35F9 AC3D B76A |
+| Andrew Chow | 1528 1230 0785 C964 44D3 334D 1756 5732 E08E 5E41 |
You can import a key by running the following command with that individual’s fingerprint: `gpg --keyserver hkps://keys.openpgp.org --recv-keys "<fingerprint>"` Ensure that you put quotes around fingerprints containing spaces.
diff --git a/build-aux/m4/ax_boost_base.m4 b/build-aux/m4/ax_boost_base.m4
index 7aac53c815..6c944b160f 100644
--- a/build-aux/m4/ax_boost_base.m4
+++ b/build-aux/m4/ax_boost_base.m4
@@ -11,9 +11,9 @@
# Test for the Boost C++ libraries of a particular version (or newer)
#
# If no path to the installed boost library is given the macro searchs
-# under /usr, /usr/local, /opt, /opt/local and /opt/homebrew and evaluates the
-# $BOOST_ROOT environment variable. Further documentation is available at
-# <http://randspringer.de/boost/index.html>.
+# under /usr, /usr/local, /opt, /opt/local and /opt/homebrew and evaluates
+# the $BOOST_ROOT environment variable. Further documentation is available
+# at <http://randspringer.de/boost/index.html>.
#
# This macro calls:
#
@@ -33,7 +33,7 @@
# and this notice are preserved. This file is offered as-is, without any
# warranty.
-#serial 48
+#serial 51
# example boost program (need to pass version)
m4_define([_AX_BOOST_BASE_PROGRAM],
@@ -114,7 +114,7 @@ AC_DEFUN([_AX_BOOST_BASE_RUNDETECT],[
AS_CASE([${host_cpu}],
[x86_64],[libsubdirs="lib64 libx32 lib lib64"],
[mips*64*],[libsubdirs="lib64 lib32 lib lib64"],
- [ppc64|powerpc64|s390x|sparc64|aarch64|ppc64le|powerpc64le|riscv64],[libsubdirs="lib64 lib lib64"],
+ [ppc64|powerpc64|s390x|sparc64|aarch64|ppc64le|powerpc64le|riscv64|e2k],[libsubdirs="lib64 lib lib64"],
[libsubdirs="lib"]
)
@@ -128,7 +128,7 @@ AC_DEFUN([_AX_BOOST_BASE_RUNDETECT],[
)
dnl first we check the system location for boost libraries
- dnl this location ist chosen if boost libraries are installed with the --layout=system option
+ dnl this location is chosen if boost libraries are installed with the --layout=system option
dnl or if you install boost with RPM
AS_IF([test "x$_AX_BOOST_BASE_boost_path" != "x"],[
AC_MSG_CHECKING([for boostlib >= $1 ($WANT_BOOST_VERSION) includes in "$_AX_BOOST_BASE_boost_path/include"])
@@ -151,7 +151,7 @@ AC_DEFUN([_AX_BOOST_BASE_RUNDETECT],[
else
search_libsubdirs="$multiarch_libsubdir $libsubdirs"
fi
- for _AX_BOOST_BASE_boost_path_tmp in /usr /usr/local /opt /opt/local /opt/homebrew/; do
+ for _AX_BOOST_BASE_boost_path_tmp in /usr /usr/local /opt /opt/local /opt/homebrew ; do
if test -d "$_AX_BOOST_BASE_boost_path_tmp/include/boost" && test -r "$_AX_BOOST_BASE_boost_path_tmp/include/boost" ; then
for libsubdir in $search_libsubdirs ; do
if ls "$_AX_BOOST_BASE_boost_path_tmp/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi
diff --git a/ci/test/06_script_b.sh b/ci/test/06_script_b.sh
index f1b0c1ac15..5bdb392ba3 100755
--- a/ci/test/06_script_b.sh
+++ b/ci/test/06_script_b.sh
@@ -65,6 +65,7 @@ if [ "${RUN_TIDY}" = "true" ]; then
" src/util/serfloat.cpp"\
" src/util/spanparsing.cpp"\
" src/util/strencodings.cpp"\
+ " src/util/string.cpp"\
" src/util/syserror.cpp"\
" src/util/url.cpp"\
" -p . ${MAKEJOBS} -- -Xiwyu --cxx17ns -Xiwyu --mapping_file=${BASE_BUILD_DIR}/bitcoin-$HOST/contrib/devtools/iwyu/bitcoin.core.imp"
diff --git a/configure.ac b/configure.ac
index 1752fda344..12f8f2dcc6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -746,6 +746,16 @@ case $host in
dnl It's safe to add these paths even if the functionality is disabled by
dnl the user (--without-wallet or --without-gui for example).
+ dnl Homebrew may create symlinks in /usr/local/include for some packages.
+ dnl Because MacOS's clang internally adds "-I /usr/local/include" to its search
+ dnl paths, this will negate efforts to use -isystem for those packages, as they
+ dnl will be found first in /usr/local. Use the internal "-internal-isystem"
+ dnl option to system-ify all /usr/local/include paths without adding it to the list
+ dnl of search paths in case it's not already there.
+ if test "$suppress_external_warnings" != "no"; then
+ AX_CHECK_PREPROC_FLAG([-Xclang -internal-isystem/usr/local/include], [CORE_CPPFLAGS="$CORE_CPPFLAGS -Xclang -internal-isystem/usr/local/include"], [], [$CXXFLAG_WERROR])
+ fi
+
if test "$use_bdb" != "no" && $BREW list --versions berkeley-db@4 >/dev/null && test "$BDB_CFLAGS" = "" && test "$BDB_LIBS" = ""; then
bdb_prefix=$($BREW --prefix berkeley-db@4 2>/dev/null)
dnl This must precede the call to BITCOIN_FIND_BDB48 below.
@@ -1695,11 +1705,12 @@ AM_CONDITIONAL([BUILD_BITCOIN_UTIL], [test $build_bitcoin_util = "yes"])
AC_MSG_RESULT($build_bitcoin_util)
AC_MSG_CHECKING([whether to build experimental bitcoin-chainstate])
-if test "$build_experimental_kernel_lib" = "no"; then
-AC_MSG_ERROR([experimental bitcoin-chainstate cannot be built without the experimental bitcoinkernel library. Use --with-experimental-kernel-lib]);
-else
- AM_CONDITIONAL([BUILD_BITCOIN_CHAINSTATE], [test $build_bitcoin_chainstate = "yes"])
+if test "$build_bitcoin_chainstate" = "yes"; then
+ if test "$build_experimental_kernel_lib" = "no"; then
+ AC_MSG_ERROR([experimental bitcoin-chainstate cannot be built without the experimental bitcoinkernel library. Use --with-experimental-kernel-lib]);
+ fi
fi
+AM_CONDITIONAL([BUILD_BITCOIN_CHAINSTATE], [test $build_bitcoin_chainstate = "yes"])
AC_MSG_RESULT($build_bitcoin_chainstate)
AC_MSG_CHECKING([whether to build libraries])
diff --git a/contrib/guix/libexec/build.sh b/contrib/guix/libexec/build.sh
index 2795a90036..f39f83d443 100755
--- a/contrib/guix/libexec/build.sh
+++ b/contrib/guix/libexec/build.sh
@@ -196,7 +196,6 @@ make -C depends --jobs="$JOBS" HOST="$HOST" \
x86_64_linux_RANLIB=x86_64-linux-gnu-ranlib \
x86_64_linux_NM=x86_64-linux-gnu-nm \
x86_64_linux_STRIP=x86_64-linux-gnu-strip \
- qt_config_opts_x86_64_linux='-platform linux-g++ -xplatform bitcoin-linux-g++' \
FORCE_USE_SYSTEM_CLANG=1
diff --git a/contrib/guix/manifest.scm b/contrib/guix/manifest.scm
index 7c45a5b866..8e5c89cc5e 100644
--- a/contrib/guix/manifest.scm
+++ b/contrib/guix/manifest.scm
@@ -21,7 +21,6 @@
(gnu packages llvm)
(gnu packages mingw)
(gnu packages moreutils)
- (gnu packages perl)
(gnu packages pkg-config)
(gnu packages python)
(gnu packages python-crypto)
@@ -78,6 +77,11 @@ http://www.linuxfromscratch.org/hlfs/view/development/chapter05/gcc-pass1.html"
(("-rpath=") "-rpath-link="))
#t))))))))
+(define building-on (string-append (list-ref (string-split (%current-system) #\-) 0) "-guix-linux-gnu"))
+
+(define (explicit-cross-configure package)
+ (package-with-extra-configure-variable package "--build" building-on))
+
(define (make-cross-toolchain target
base-gcc-for-libc
base-kernel-headers
@@ -87,9 +91,9 @@ http://www.linuxfromscratch.org/hlfs/view/development/chapter05/gcc-pass1.html"
(let* ((xbinutils (cross-binutils target))
;; 1. Build a cross-compiling gcc without targeting any libc, derived
;; from BASE-GCC-FOR-LIBC
- (xgcc-sans-libc (cross-gcc target
- #:xgcc base-gcc-for-libc
- #:xbinutils xbinutils))
+ (xgcc-sans-libc (explicit-cross-configure (cross-gcc target
+ #:xgcc base-gcc-for-libc
+ #:xbinutils xbinutils)))
;; 2. Build cross-compiled kernel headers with XGCC-SANS-LIBC, derived
;; from BASE-KERNEL-HEADERS
(xkernel (cross-kernel-headers target
@@ -98,17 +102,17 @@ http://www.linuxfromscratch.org/hlfs/view/development/chapter05/gcc-pass1.html"
xbinutils))
;; 3. Build a cross-compiled libc with XGCC-SANS-LIBC and XKERNEL,
;; derived from BASE-LIBC
- (xlibc (cross-libc target
- base-libc
- xgcc-sans-libc
- xbinutils
- xkernel))
+ (xlibc (explicit-cross-configure (cross-libc target
+ base-libc
+ xgcc-sans-libc
+ xbinutils
+ xkernel)))
;; 4. Build a cross-compiling gcc targeting XLIBC, derived from
;; BASE-GCC
- (xgcc (cross-gcc target
- #:xgcc base-gcc
- #:xbinutils xbinutils
- #:libc xlibc)))
+ (xgcc (explicit-cross-configure (cross-gcc target
+ #:xgcc base-gcc
+ #:xbinutils xbinutils
+ #:libc xlibc))))
;; Define a meta-package that propagates the resulting XBINUTILS, XLIBC, and
;; XGCC
(package
@@ -610,10 +614,9 @@ inspecting signatures in Mach-O binaries.")
gcc-toolchain-10
(list gcc-toolchain-10 "static")
;; Scripting
- perl
python-3
;; Git
- git
+ git-minimal
;; Tests
(fix-ppc64-nx-default lief))
(let ((target (getenv "HOST")))
diff --git a/contrib/guix/patches/glibc-2.24-guix-prefix.patch b/contrib/guix/patches/glibc-2.24-guix-prefix.patch
index cba2f59a8d..875e8cd611 100644
--- a/contrib/guix/patches/glibc-2.24-guix-prefix.patch
+++ b/contrib/guix/patches/glibc-2.24-guix-prefix.patch
@@ -15,7 +15,7 @@ when we being using newer versions of glibc.
CFLAGS-.oS = $(CFLAGS-.o) $(PIC-ccflag)
+
+# Map Guix store paths to /usr
-+CFLAGS-.oS += `find /gnu/store -maxdepth 1 -mindepth 1 -type d -exec echo -n " -fdebug-prefix-map={}=/usr" \;`
++CFLAGS-.oS += `find /gnu/store -maxdepth 1 -mindepth 1 -type d -exec echo -n " -ffile-prefix-map={}=/usr" \;`
+
CPPFLAGS-.oS = $(CPPFLAGS-.o) -DPIC -DLIBC_NONSHARED=1
libtype.oS = lib%_nonshared.a
diff --git a/contrib/guix/patches/glibc-2.27-guix-prefix.patch b/contrib/guix/patches/glibc-2.27-guix-prefix.patch
index cdb3971f7a..d777af74f0 100644
--- a/contrib/guix/patches/glibc-2.27-guix-prefix.patch
+++ b/contrib/guix/patches/glibc-2.27-guix-prefix.patch
@@ -15,7 +15,7 @@ when we being using newer versions of glibc.
CFLAGS-.o = $(filter %frame-pointer,$(+cflags)) $(pie-default)
+
+# Map Guix store paths to /usr
-+CFLAGS-.o += `find /gnu/store -maxdepth 1 -mindepth 1 -type d -exec echo -n " -fdebug-prefix-map={}=/usr" \;`
++CFLAGS-.o += `find /gnu/store -maxdepth 1 -mindepth 1 -type d -exec echo -n " -ffile-prefix-map={}=/usr" \;`
+
libtype.o := lib%.a
object-suffixes += .o
diff --git a/contrib/message-capture/message-capture-parser.py b/contrib/message-capture/message-capture-parser.py
index eefd22a60e..33759ee713 100755
--- a/contrib/message-capture/message-capture-parser.py
+++ b/contrib/message-capture/message-capture-parser.py
@@ -79,8 +79,7 @@ def to_jsonable(obj: Any) -> Any:
val = getattr(obj, slot, None)
if slot in HASH_INTS and isinstance(val, int):
ret[slot] = ser_uint256(val).hex()
- elif slot in HASH_INT_VECTORS:
- assert all(isinstance(a, int) for a in val)
+ elif slot in HASH_INT_VECTORS and all(isinstance(a, int) for a in val):
ret[slot] = [ser_uint256(a).hex() for a in val]
else:
ret[slot] = to_jsonable(val)
diff --git a/contrib/seeds/makeseeds.py b/contrib/seeds/makeseeds.py
index 37c6f5fd7c..eda58c370f 100755
--- a/contrib/seeds/makeseeds.py
+++ b/contrib/seeds/makeseeds.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2013-2020 The Bitcoin Core developers
+# Copyright (c) 2013-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
#
@@ -7,10 +7,10 @@
#
import argparse
+import collections
import ipaddress
import re
import sys
-import collections
from typing import List, Dict, Union
from asmap import ASMap, net_to_prefix
@@ -38,7 +38,8 @@ PATTERN_AGENT = re.compile(
r"0.20.(0|1|2|99)|"
r"0.21.(0|1|2|99)|"
r"22.(0|99)|"
- r"23.99"
+ r"23.(0|99)|"
+ r"24.99"
r")")
def parseline(line: str) -> Union[dict, None]:
diff --git a/contrib/seeds/nodes_main.txt b/contrib/seeds/nodes_main.txt
index d8e34bdb60..f8572b26c7 100644
--- a/contrib/seeds/nodes_main.txt
+++ b/contrib/seeds/nodes_main.txt
@@ -1,688 +1,856 @@
-2.37.30.144:8777
-2.138.174.158:8333
-2.152.78.124:8333
-5.8.18.154:8333
-5.45.74.50:8333
-5.79.123.3:8333
-5.102.168.217:22220
-5.103.137.146:9333
-5.128.87.126:8333
-5.172.132.200:8333
-5.188.62.18:8333
-5.254.101.226:8334
-8.210.18.56:8333
-8.210.92.32:8333
-14.13.34.225:16181
-14.39.151.167:8333
-18.196.79.108:8333
-18.218.139.58:48333
-20.184.15.116:8433
-23.175.0.220:8333
-23.233.107.21:8333
-24.35.68.229:8333
-24.37.3.26:8333
-24.102.91.203:8333
-24.116.153.115:8333
-24.134.6.165:8333
-24.155.218.13:8333
-24.160.137.173:8333
-24.177.106.85:8333
-24.184.0.146:8333
-24.194.222.116:8333
-24.205.215.192:8333
-27.124.108.19:8333
-31.14.40.64:8333
-31.47.202.112:8333
-31.165.115.7:8333
-34.65.45.157:8333
-34.78.48.104:8333
-34.80.134.68:8333
-34.101.132.198:8333
-34.227.68.216:8333
-35.137.212.22:8333
-35.231.190.134:8333
-37.1.217.35:8333
-37.15.62.32:8333
-37.143.118.174:8333
-37.200.59.67:8333
-37.205.9.165:8333
-38.23.180.228:8333
-38.65.119.26:8333
-38.141.134.140:8333
-39.109.122.127:8444
-41.79.70.146:8333
-41.193.122.191:8333
-43.225.62.107:8333
-45.35.73.152:8333
-45.43.97.103:8333
-45.63.10.52:20008
-45.84.153.40:8333
-45.95.64.225:8333
-45.129.180.214:8333
-45.154.255.162:8333
-45.226.80.102:8333
-46.6.10.230:8333
-46.23.87.218:8333
-46.32.50.98:8333
-46.47.84.85:8333
-46.48.126.58:8333
-46.146.248.89:8333
-46.165.221.209:9333
-46.166.142.2:8333
-46.166.162.45:20001
-46.173.50.58:8333
-46.175.178.3:8333
-46.188.30.118:8333
-46.219.120.59:3673
-46.229.238.187:8333
-47.93.230.171:8333
-47.100.162.210:18332
-47.144.106.249:8333
-47.188.70.205:8333
-47.227.226.242:8333
-50.2.13.164:8333
-50.5.46.195:8333
-50.45.128.28:8333
-51.148.153.60:8333
-51.154.62.103:8333
-51.154.131.18:8333
-51.158.150.155:8333
-51.159.2.218:8333
-54.198.19.34:8333
-58.105.168.41:8333
-58.158.0.86:8333
-60.251.129.61:8336
-61.239.91.250:8333
-62.28.190.194:8333
-62.152.58.16:9421
-62.171.129.32:8333
-62.251.54.163:8333
-63.247.147.166:8333
-64.33.68.176:8333
-64.156.192.61:8333
-64.187.175.226:8333
-64.233.245.39:8333
-64.237.82.149:8333
-65.101.247.26:8333
-66.29.129.218:8333
-66.49.204.11:8333
-66.58.243.215:8333
-66.85.234.129:8333
-66.130.120.52:8333
-67.10.121.145:8333
-67.210.228.203:8333
-67.213.87.21:8333
-68.181.4.12:8333
-69.7.124.146:8333
-69.8.175.201:8333
-69.59.18.22:8333
-69.119.193.9:8333
-69.130.201.27:8333
-69.131.101.176:8333
-70.15.194.32:8333
-70.64.27.12:8333
-72.29.170.151:8333
-72.74.34.99:8333
-72.133.177.119:8333
-73.166.84.222:8333
-74.67.240.204:8333
-74.91.115.229:8333
-74.118.137.119:8333
-74.213.251.203:8333
-74.220.255.190:8333
-76.11.60.155:8333
-76.66.144.127:8333
-77.70.16.245:8333
-77.85.204.149:8333
-77.105.87.97:8333
-77.120.113.69:8433
-77.120.113.71:8433
-77.120.122.116:8433
-77.120.122.118:8433
-77.162.190.90:8333
-77.167.245.239:55544
-77.232.41.189:8333
-78.20.227.249:8333
-78.21.167.8:8333
-78.27.139.13:8333
-78.43.208.25:8333
-78.63.28.146:8333
-78.72.228.239:8333
-78.108.102.8:8333
-78.129.0.39:8333
-78.129.169.69:8333
-79.77.182.180:8333
-79.77.182.183:8333
-79.107.178.59:8333
-80.55.225.158:8333
-80.64.211.102:8333
-80.64.211.103:8333
-80.71.57.50:8333
-80.81.3.27:8333
-80.82.55.43:8333
-80.88.172.227:64264
-80.89.203.172:8001
-80.93.213.246:8333
-80.147.82.165:8333
-80.229.28.60:8333
-80.247.233.40:8333
-80.255.8.93:8333
-81.7.17.202:8333
-81.10.241.165:8333
-81.21.86.157:8333
-81.171.22.143:8333
-81.237.206.224:8343
-82.69.23.195:8333
-82.96.96.40:8333
-82.116.50.101:8333
-82.136.99.122:8333
-82.149.97.25:17567
-82.154.24.209:8333
-82.165.241.50:8333
-82.197.218.253:8333
-82.202.68.231:8333
-83.137.41.10:8333
-83.208.6.211:8333
-83.217.8.31:44420
-83.220.110.48:8333
-83.222.138.85:8333
-83.243.191.199:8333
-84.22.139.57:8333
-84.27.155.17:8333
-84.75.28.247:8333
-84.112.60.16:8333
-84.211.7.56:8333
-84.237.7.249:8333
-85.23.51.177:8333
-85.24.145.198:8333
-85.184.138.108:8333
-85.194.238.134:8333
-85.195.54.110:8333
-85.208.71.36:8333
-85.208.71.39:8333
-85.214.136.45:8333
-85.214.161.252:8333
-85.227.245.128:8333
-86.18.34.243:8333
-86.20.50.170:8333
-86.49.105.90:8333
-86.76.7.132:8333
-86.100.26.188:8333
-86.106.143.143:55373
-86.120.58.66:8333
-86.133.251.239:8901
-86.149.8.23:8901
-87.78.197.234:8333
-87.120.8.5:20008
-87.121.37.156:8333
-88.82.181.44:8333
-88.87.93.52:1691
-88.98.235.134:8333
-88.136.187.214:8333
-88.147.244.250:8333
-88.148.153.148:8333
-88.212.45.166:8333
-88.212.55.138:8333
-89.38.96.153:9273
-89.47.161.135:8333
-89.88.62.190:8333
-89.158.32.44:8333
-89.163.145.240:8333
-89.163.249.234:3673
-89.176.196.80:8333
-89.216.21.96:8333
-90.84.227.255:8333
-90.146.130.214:8333
-90.250.9.1:8333
-91.93.194.154:8333
-91.106.188.229:8333
-91.126.40.109:8333
-91.137.127.123:8333
-91.147.232.98:8333
-91.152.123.18:8333
-91.178.17.120:8333
-91.204.99.178:8333
-91.223.175.14:8333
-92.42.110.242:8333
-92.53.90.84:8333
-92.221.155.228:8333
-93.57.81.162:8333
-93.95.88.13:8333
-93.103.13.1:8333
-93.123.180.164:8333
-93.190.117.26:8333
-94.105.125.240:8333
-94.110.23.215:8333
-94.154.159.99:8333
-94.189.161.119:8333
-94.203.255.70:8333
-94.232.173.93:8333
-95.79.122.99:8333
-95.80.1.110:8333
-95.83.73.31:8333
-95.110.133.223:8333
-95.110.234.93:8333
-95.164.65.194:8333
-95.165.8.182:8333
-95.174.219.101:8333
-95.191.130.100:8333
-95.214.53.154:8333
-95.215.205.180:8333
-96.43.130.234:8333
-98.25.201.31:8333
-98.128.247.182:8333
-98.171.21.129:8333
-99.147.135.161:8333
-101.100.163.118:8327
-102.132.245.16:8333
-102.182.204.96:8333
-102.182.235.245:8333
-103.14.245.250:8333
-103.47.192.15:8333
-103.84.84.250:8335
-103.99.168.130:8333
-103.99.168.140:8333
-103.198.192.14:20008
-103.232.104.227:8333
-104.143.2.195:8333
-104.172.235.227:8333
-104.238.220.199:8333
-107.11.115.68:8333
-107.173.166.43:8333
-108.4.212.83:8333
-109.136.73.97:8333
-109.173.98.23:8333
-109.190.68.116:8333
-109.235.246.60:8333
-109.248.206.13:8333
-110.12.64.96:8333
-111.90.140.46:8333
-111.90.159.184:50001
-113.107.201.131:8333
-115.47.141.250:8885
-116.58.171.67:8333
-116.87.57.218:8333
-116.202.161.56:8333
-117.51.159.130:8333
-118.103.126.140:28333
-121.45.190.210:8333
-121.99.193.25:8333
-122.112.148.153:8339
-122.148.135.234:8333
-128.0.190.26:8333
-128.65.194.136:8333
-129.126.172.115:8333
-129.226.125.10:8333
-131.188.40.191:8333
-134.195.185.52:8333
-135.180.44.61:8333
-136.52.114.123:8333
-136.56.170.96:8333
-137.116.213.143:8333
-137.226.34.46:8333
-138.43.233.57:8333
-139.130.41.82:8333
-140.190.12.129:8333
-142.4.105.77:8333
-142.54.181.218:8333
-143.177.231.247:8333
-143.178.64.10:8333
-144.34.161.65:18333
-146.4.124.134:8333
-146.83.56.69:8333
-146.90.193.68:8333
-146.196.55.156:28833
-148.66.50.50:8335
-148.251.1.20:8343
-151.48.95.212:8333
-151.252.193.245:8333
-152.44.137.83:8333
-152.115.191.196:8333
-154.221.31.86:8333
-156.17.103.2:8088
-157.138.20.22:8333
-158.58.188.37:8333
-158.140.209.79:8333
-159.89.230.128:8333
-159.246.25.52:8333
-160.20.59.250:8433
-162.0.234.190:8333
-162.62.26.218:8333
-162.250.188.194:8333
-162.251.70.82:8333
-163.158.206.255:8333
-164.68.105.105:8333
-165.228.174.117:8333
-166.62.82.103:32771
-166.70.49.26:8333
-166.78.241.9:8333
-166.78.241.25:8333
-167.71.73.244:8333
-167.179.147.155:8333
-168.91.238.8:8333
-172.105.21.216:8333
-172.117.105.95:8333
-173.23.103.30:8000
-173.205.92.151:54805
-173.205.92.154:54805
-173.205.92.157:54805
-173.208.152.218:8333
-173.241.227.243:8333
-174.3.4.232:8333
-174.17.11.22:8333
-174.88.241.167:8333
-174.114.102.41:8333
-174.114.250.86:8333
-174.142.191.136:8333
-175.39.72.87:8333
-176.12.16.135:8333
-176.37.23.30:8333
-176.62.179.221:8333
-176.74.136.237:8333
-176.99.6.226:8333
-176.212.185.153:8333
-177.81.236.117:8333
-178.19.106.26:8333
-178.21.118.178:8333
-178.33.232.69:8333
-178.79.84.139:8333
-178.124.162.209:8333
-178.132.2.246:8333
-178.150.96.46:8333
-178.162.212.44:8333
-178.193.226.120:8333
-178.236.137.63:8333
-180.150.46.187:8333
-181.164.210.228:8530
-183.110.220.210:30301
-184.95.58.166:8336
-184.164.147.82:41333
-184.171.208.109:8333
-185.17.143.220:8333
-185.21.217.49:8333
-185.25.48.184:8333
-185.28.96.16:8333
-185.31.136.246:8333
-185.64.116.15:8333
-185.68.249.91:8333
-185.108.247.190:8333
-185.141.60.36:8333
-185.148.3.227:8333
-185.148.145.74:8333
-185.159.20.143:8333
-185.167.113.59:8333
-185.185.26.141:8111
-185.189.132.178:57780
-185.204.197.112:8333
-185.209.70.17:8333
-185.220.156.193:8333
-185.238.129.113:8333
-185.239.221.5:8333
-185.244.217.39:8333
-185.254.97.164:8333
-186.33.167.11:8333
-188.32.14.31:8334
-188.42.40.234:18333
-188.134.8.36:8333
-188.138.88.14:8333
-188.156.110.239:8333
-188.165.244.143:8333
-188.213.68.38:8333
-188.214.129.65:20012
-188.242.15.74:8333
-188.244.4.78:8333
-189.39.6.82:8333
-189.207.46.32:8333
-189.212.121.74:8333
-192.3.11.20:8333
-192.65.170.15:8333
-192.146.137.44:8333
-192.182.157.119:8333
-192.187.109.141:8333
-192.227.80.83:8333
-193.10.203.23:8334
-193.32.127.160:58477
-193.32.127.162:58477
-193.58.196.212:8333
-193.106.29.106:8333
-193.138.154.43:8333
-193.178.170.232:8333
-193.196.37.62:8333
-193.222.130.14:8333
-193.234.50.227:8333
-194.14.246.205:8333
-194.135.135.69:8333
-194.147.113.201:8333
-194.165.30.20:8333
-194.219.62.23:8333
-195.56.63.4:8333
-195.134.183.188:8333
-195.208.103.30:8444
-195.208.103.31:8444
-198.1.231.6:8333
-198.12.14.136:8333
-198.84.237.70:8333
-198.178.120.5:8112
-199.48.92.184:8333
-199.68.199.19:8333
-199.182.184.204:8333
-199.189.242.141:8333
-199.247.7.208:8333
-200.122.181.37:8333
-201.191.6.103:8333
-202.107.219.130:8333
-202.108.211.135:8333
-203.94.33.112:8333
-203.130.48.117:8885
-203.132.94.196:8333
-203.162.13.181:8332
-204.191.201.43:8333
-204.229.10.90:8333
-205.178.41.124:8333
-206.55.178.157:8333
-206.126.203.8:8333
-206.174.115.96:8333
-206.223.153.52:8333
-207.188.159.25:8333
-207.229.46.80:8333
-209.58.145.157:8333
-209.126.81.147:8333
-209.145.63.150:8333
-209.209.10.30:8333
-209.237.127.227:8333
-212.99.226.36:9020
-212.185.86.84:8333
-212.227.211.87:8333
-213.5.36.58:8333
-213.89.236.219:8333
-213.93.145.183:8333
-213.214.66.182:8333
-216.41.249.178:8333
-216.146.251.8:8333
-216.249.70.22:8333
-217.11.240.4:8333
-217.15.178.7:8333
-217.24.233.116:8333
-217.64.148.98:51401
-217.113.121.169:8333
-217.170.124.170:8333
-220.132.135.54:8333
-220.221.58.25:8333
-220.233.178.199:8333
-221.219.97.105:2001
-[2001:1608:1b:f9::1]:26491
-[2001:1620:510::2]:8333
-[2001:1bc0:c1::2000]:8333
-[2001:470:1f0a:89a::2]:8333
-[2001:470:de5a::ec]:9333
-[2001:4b98:dc0:45:216:3eff:fea2:95cd]:8333
-[2001:4dd0:3564:0:fd76:c1d3:1854:5bd9]:8333
-[2001:4de8:b1b2:1:0:dead:beef:7]:8333
-[2001:638:a000:4140::ffff:191]:8333
-[2001:648:2800:131:4b1f:f6fc:20f7:f99f]:8333
-[2001:678:cc8::1:10:88]:20008
-[2001:67c:26b4:ff00::44]:8333
-[2001:67c:2db8:13::92]:8333
-[2001:7c0:2310:0:f816:3eff:fe6c:4f58]:8333
-[2001:818:ea1b:7600:f053:aade:f47b:b701]:8333
-[2001:8f1:1404:3700:8e49:715a:2e09:b634]:9444
-[2001:985:55a0:1::2]:8333
-[2001:999:270:2c2c:c8b:3a20:3f2f:318f]:8333
-[2001:b07:ac9:442b:79d6:bbbe:b37c:a783]:8333
-[2002:2f5b:a5f9::2f5b:a5f9]:8885
-[2002:b6ff:3dca::b6ff:3dca]:28364
-[2400:2410:cea2:d00:41bc:c9ea:861b:51ee]:8333
-[2400:3b00:20:c:bacb:29ff:feab:8886]:8333
-[2401:d002:3902:700:d72c:5e22:4e95:389d]:8333
-[2403:6200:88a0:fb17:f5f2:d8b5:b7ba:f4d3]:8333
-[2405:9800:b910:5f8e:1830:f630:2cc6:88fb]:8333
-[2405:9800:b970:c64c:109f:74e7:ae5f:87c7]:8333
-[2405:aa00:2::40]:8333
-[2407:8800:bc61:2202:d63d:7eff:fe6c:dc36]:8333
-[2408:8248:7004:f831::83c]:8333
-[2409:10:ca20:1df0:224:e8ff:fe1f:60d9]:8333
-[240b:11:43a1:bd00:e589:f8a7:49b:3b86]:8333
-[240d:1a:791:3400:d65d:64ff:fe28:927e]:8333
-[240d:1a:791:3400:d681:d7ff:fef6:a21e]:10050
-[2600:1700:5b2b:5f::8040]:8333
-[2600:2104:1003:c5ab:dc5e:90ff:fe18:1d08]:8333
-[2600:3c00:e002:2e32::1:14]:8333
-[2600:8805:2400:14e:12dd:b1ff:fef2:3013]:8333
-[2602:ffb8::208:72:57:200]:8333
-[2603:301f:1ebf:e000:e23f:49ff:fee7:7431]:8333
-[2603:6081:1800:6600:16dd:a9ff:feee:b2f3]:8333
-[2604:1380:1000:7400::1]:8333
-[2604:4500::2e06]:8112
-[2604:5500:c134:4000:7285:c2ff:fe4a:e143]:32797
-[2604:5500:c134:4000::3fc]:32797
-[2604:7c00:120:4b::eb24]:8333
-[2605:6400:30:f220::]:8333
-[2605:6f80:0:7:fc1b:ccff:fe8a:d822]:8333
-[2605:ae00:203::203]:8333
-[2605:c000:2a0a:1::102]:8333
-[2605:f700:c0:827:225:90ff:fee3:34a6]:8333
-[2607:9280:b:73b:250:56ff:fe14:25b5]:8333
-[2607:f2f8:ad40:bc1::1]:8333
-[2607:fa18:3a01::20]:8333
-[2620:11c:5001:1118:d267:e5ff:fee9:e673]:8333
-[2620:11c:5001:2199:d267:e5ff:fee9:e673]:8333
-[2620:6:2003:105:2d8:61ff:fe0f:853]:8333
-[2620:6e:a000:1:42:42:42:42]:8333
-[2803:cf00:af8:f200:b89e:cf34:92c7:2d26]:8333
-[2804:14c:65d1:402c:bc53:bf5d:68a:2136]:8333
-[2804:7f1:e783:d401:661c:67ff:feba:5547]:8333
-[2804:d57:5537:4800:21e:67ff:fea8:d798]:8333
-[2804:d57:5537:4800:3615:9eff:fe23:d610]:8333
-[2806:2f0:2080:62a:86f:1a01:c44f:1794]:8333
-[2a00:1028:8382:bf22:5f7f:b78f:2737:7739]:8333
-[2a00:12e0:101:99:20c:29ff:fe29:d03f]:8333
-[2a00:1328:e101:c00::163]:8333
-[2a00:1630:10:1003:0:b19:b00b:babe]:8333
-[2a00:1768:2001:27::ef6a]:8333
-[2a00:1828:a004:2::666]:8333
-[2a00:1838:2a:1400:92e2:baff:fe4a:c416]:8333
-[2a00:1c10:2:709::217]:22220
-[2a00:1f40:5001:108:5d17:7703:b0f5:4133]:8333
-[2a00:6020:15dd:ee00:c8c2:2c77:1749:35db]:8333
-[2a00:6020:b482:9200:491a:358c:d8f7:1da]:8333
-[2a00:7145:c1:1:ae29:727:2b87:f64]:5141
-[2a00:8a60:e012:a00::21]:8333
-[2a00:a040:100:f3:45a5:ac0:fea3:71e1]:8333
-[2a01:488:2000:9801::d]:8333
-[2a01:490:16:301::2]:8333
-[2a01:5200:6c:6162:7a61:746b:6f2e:736b]:8333
-[2a01:6380:fffe:73:4e3:b3cc:a871:36d1]:8333
-[2a01:7a0:2:137c::3]:8333
-[2a01:7c8:aac9:c9:5054:ff:fedf:ff95]:8333
-[2a01:7c8:d001:1c1:5054:ff:feee:3e1a]:8333
-[2a01:8740:1:ffc5::8c6a]:8333
-[2a01:cb00:d3d:7700:227:eff:fe28:c565]:8333
-[2a01:d0:0:1c::253]:8333
-[2a01:d0:bef2::12]:8333
-[2a01:e0a:9fb:b0e0:54f8:1901:6e83:62c1]:8333
-[2a01:e0a:aa7:c8c0:9679:affa:b6e5:efc7]:8333
-[2a02:13b8:f000:101::a]:8333
-[2a02:168:6328:0:2a8:2cff:fe68:e32c]:8333
-[2a02:2780:9000:70::7]:8333
-[2a02:2e02:3900:5400:a099:e1ff:feb6:d0e]:8333
-[2a02:390:9000:0:aaa1:59ff:fe43:b57b]:8333
-[2a02:58:97:7d20::60]:8333
-[2a02:6d40:305e:601:dea6:32ff:fe44:4b25]:8333
-[2a02:7a01::91:228:45:130]:8333
-[2a02:7aa0:1619::adc:8de0]:8333
-[2a02:7b40:3e4d:998d::1]:8333
-[2a02:7b40:592f:a187::1]:8333
-[2a02:8388:e5c6:d380:201:2eff:fe82:b3cc]:8333
-[2a02:9a0:102::110]:8333
-[2a02:a311:8143:8c00::4]:8353
-[2a02:af8:fab0:808:85:234:145:132]:8333
-[2a02:e00:fff0:506::1]:8444
-[2a02:e00:fff0:506::a]:8444
-[2a02:e98:20:1504::1]:8333
-[2a03:4000:47:f1::1]:8333
-[2a03:6000:870:0:46:23:87:218]:8333
-[2a03:7380:3015:524:afc5:d3bc:7c66:8f94]:8333
-[2a03:ec0:0:928:8c00:93ff:fe84:a007]:8333
-[2a03:ec0:0:928::701]:8333
-[2a04:2180:0:2::aa]:8333
-[2a04:52c0:101:29e::]:8333
-[2a04:52c0:103:c455::1]:8333
-[2a04:bc40:1dc3:8d::2:1001]:8333
-[2a05:1500:702:0:1c00:40ff:fe00:c]:8333
-[2a06:dd00:10:3:225:90ff:fe32:64cc]:8333
-[2a06:dd00:1:22:225:90ff:fe0e:bd48]:8333
-[2a07:6b47:100:464::9357:ffda]:8333
-[2a07:a880:4601:1062:b4b4:bd2a:39d4:7acf]:51401
-[2a07:abc4::1:946]:8333
-[2a07:abc4::89:234:180:194]:8333
-[2a09:2681:102::210]:8333
-[2a0a:c801:1:7::183]:8333
-[2a0b:f300:2:6::2]:8333
-[2a0c:59c0:18::a20e]:57658
-[2a0d:5600:24:a8e::a91e]:55373
-[2a0d:eb00:8005:1::13]:8333
-[2a10:4740:45:1:a013:d1ff:fe85:36e3]:8333
-[2a10:8b40:1::103]:8335
-[2c0f:f8f0:da51:0:70c3:eea9:9717:9579]:8333
+2.3.25.181:8333 # AS3215
+2.152.78.124:8333 # AS12430
+5.39.74.166:8333 # AS16276
+5.45.79.81:18332 # AS50673
+5.53.16.128:8333 # AS50923
+5.95.186.78:8333 # AS30722
+5.128.87.126:8333 # AS31200
+5.133.65.82:8333 # AS15440
+5.146.20.229:8333 # AS3209
+5.180.41.119:8333 # AS18978
+5.188.62.18:8333 # AS34665
+5.199.173.66:8333 # AS16125
+5.255.97.25:8333 # AS60404
+5.255.103.180:8333 # AS60404
+8.209.70.77:8333 # AS45102
+8.209.105.138:8333 # AS45102
+18.162.208.153:48332 # AS16509
+23.175.0.200:8333 # AS395502
+23.175.0.222:8333 # AS395502
+23.233.107.21:8333 # AS5645
+23.236.25.169:8333 # AS30029
+24.35.68.229:8333 # AS11404
+24.84.164.50:8333 # AS6327
+24.116.153.115:8333 # AS11492
+24.184.0.146:8333 # AS6128
+27.33.160.196:8333 # AS7545
+27.124.108.19:8333 # AS58511
+27.148.206.140:8333 # AS4134
+31.17.64.192:8333 # AS204028
+31.18.114.135:8333 # AS204028
+31.41.23.249:8333 # AS31287
+31.42.176.138:8333 # AS43641
+31.47.202.112:8333 # AS34385
+34.65.45.157:8333 # AS15169
+34.80.134.68:8333 # AS15169
+34.126.115.35:8333 # AS396982
+37.1.204.231:8333 # AS50673
+37.120.155.34:8333 # AS9009
+37.143.118.174:8333 # AS48926
+37.193.227.16:8333 # AS31200
+37.220.135.151:8333 # AS41206
+37.235.146.236:8333 # AS41268
+38.124.126.42:8333 # AS11550
+38.141.134.140:8333 # AS174
+38.145.151.150:8333 # AS40545
+40.115.137.28:8333 # AS8075
+41.72.154.66:8333 # AS37153
+41.79.70.146:8333 # AS37349
+42.193.55.135:8333 # AS45090
+43.225.62.107:8333 # AS63953
+45.43.97.103:8333 # AS26827
+45.85.48.58:8333 # AS208016
+45.126.26.229:8333 # AS45763
+45.134.142.40:8333 # AS60068
+45.154.252.162:8333 # AS13335
+46.13.216.169:8333 # AS6855
+46.23.87.218:8333 # AS51088
+46.40.127.164:8333 # AS43205
+46.48.126.58:8333 # AS12668
+46.59.13.35:8333 # AS8473
+46.72.238.17:8333 # AS12714
+46.128.141.184:8333 # AS16097
+46.146.248.89:8333 # AS9049
+46.165.221.209:9333 # AS28753
+46.166.142.2:8333 # AS43350
+46.175.178.3:8333 # AS28725
+47.36.144.51:8333 # AS20115
+47.180.49.158:8333 # AS5650
+49.228.131.133:2210 # AS133481
+50.2.13.164:8333 # AS62904
+50.35.71.51:8333 # AS20055
+50.53.250.162:8333 # AS20055
+51.68.36.57:8333 # AS16276
+51.138.4.135:30001 # AS8075
+51.154.62.103:8333 # AS15796
+51.158.150.155:8333 # AS12876
+54.176.63.16:8333 # AS16509
+58.158.0.86:8333 # AS2519
+59.138.115.137:8333 # AS2516
+59.167.191.60:8333 # AS4739
+60.205.205.119:8333 # AS37963
+60.234.122.245:8333 # AS9790
+60.240.210.155:8333 # AS7545
+61.239.91.250:8333 # AS9269
+62.74.143.11:8333 # AS3329
+62.138.162.12:8333 # AS20773
+62.169.74.233:8333 # AS2860
+62.171.129.32:8333 # AS51167
+62.209.198.65:8333 # AS6855
+63.247.147.166:8333 # AS30221
+64.98.76.62:8333 # AS32133
+66.29.129.218:8333 # AS22612
+66.96.235.28:8333 # AS63859
+66.130.120.52:8333 # AS5769
+66.198.209.243:8333 # AS33152
+66.208.64.128:8333 # AS10352
+66.225.231.148:8333 # AS23352
+67.55.3.200:8333 # AS33139
+67.58.232.107:8333 # AS14051
+67.211.92.2:8333 # AS11711
+67.223.119.122:8333 # AS22612
+68.48.131.251:8333 # AS7922
+68.181.4.12:8333 # AS47
+69.14.185.9:8333 # AS12083
+69.54.29.193:8333 # AS12282
+69.59.18.22:8333 # AS397444
+69.131.101.176:8333 # AS4181
+69.165.205.142:8833 # AS5645
+69.228.219.124:8333 # AS7018
+70.59.123.25:8333 # AS209
+70.62.13.150:8333 # AS7843
+70.66.248.170:8333 # AS6327
+70.112.153.229:8333 # AS7843
+70.160.240.132:8333 # AS22773
+70.190.177.204:8333 # AS22773
+71.28.189.239:8333 # AS398465
+71.234.125.198:8333 # AS1351
+72.74.123.179:8333 # AS701
+72.253.236.217:8333 # AS36149
+73.219.254.120:8333 # AS1351
+74.91.115.229:8333 # AS14586
+74.118.137.119:8333 # AS20326
+74.195.166.100:8333 # AS19108
+74.220.255.190:8333 # AS23175
+76.67.211.110:8333 # AS577
+76.169.163.14:8333 # AS20001
+77.32.121.162:8333 # AS35612
+77.53.135.74:8333 # AS45011
+77.70.16.245:8333 # AS8717
+77.85.204.149:8333 # AS8866
+77.107.38.239:8333 # AS62183
+77.120.26.102:8333 # AS25229
+77.162.190.90:8333 # AS1136
+78.20.227.249:8333 # AS6848
+78.21.167.8:8333 # AS6848
+78.27.139.13:8333 # AS6723
+78.90.91.220:8333 # AS8717
+78.108.108.25:8333 # AS8251
+78.108.108.38:8333 # AS8251
+79.77.182.183:8333 # AS13285
+79.98.159.7:11333 # AS44065
+79.189.211.201:8333 # AS5617
+80.55.225.158:8333 # AS5617
+80.83.186.35:8333 # AS33891
+80.88.172.227:64264 # AS31263
+80.209.87.103:9333 # AS31027
+80.229.28.60:8333 # AS2856
+81.7.16.182:8333 # AS35366
+81.7.17.202:8333 # AS35366
+81.19.10.2:8333 # AS24641
+81.88.221.190:8333 # AS39709
+81.171.22.143:8333 # AS60781
+81.224.44.164:8333 # AS3301
+81.224.160.81:8333 # AS3301
+82.1.68.54:8333 # AS5089
+82.21.164.47:8333 # AS5089
+82.64.116.5:8333 # AS12322
+82.66.10.11:8333 # AS12322
+82.96.96.40:8333 # AS29686
+82.116.50.101:8333 # AS30936
+82.129.68.62:8333 # AS48945
+82.136.99.122:8333 # AS8821
+82.154.24.209:8333 # AS8657
+82.197.215.125:8333 # AS25596
+83.128.132.91:8333 # AS15435
+83.137.41.10:8333 # AS31394
+83.208.6.211:8333 # AS5610
+83.208.193.242:8333 # AS5610
+83.222.138.85:8333 # AS31736
+83.240.124.68:8333 # AS31246
+83.243.191.199:8333 # AS41164
+84.9.5.211:8333 # AS5378
+84.28.57.90:8333 # AS6830
+84.38.3.249:8333 # AS196691
+84.112.60.16:8333 # AS8412
+84.215.56.119:8333 # AS41164
+84.226.243.175:8333 # AS6730
+84.245.14.73:8333 # AS25596
+84.252.157.90:18333 # AS200590
+84.255.244.61:8333 # AS34779
+85.23.24.123:8333 # AS16086
+85.52.185.29:8666 # AS12479
+85.58.120.201:8333 # AS12479
+85.93.96.18:8333 # AS29208
+85.165.8.197:8333 # AS2119
+85.173.165.66:8333 # AS12389
+85.184.143.105:8333 # AS39642
+85.191.74.103:8333 # AS39642
+85.194.238.134:8333 # AS47605
+85.195.54.110:8333 # AS35706
+85.195.196.142:8333 # AS13030
+85.208.69.11:8333 # AS25091
+85.208.69.21:8333 # AS25091
+85.208.71.36:8333 # AS42275
+85.208.71.39:8333 # AS42275
+85.214.118.71:8333 # AS6724
+85.214.161.252:8333 # AS6724
+85.216.32.73:8333 # AS51185
+85.254.98.221:8333 # AS13194
+86.58.11.152:8333 # AS3212
+86.95.8.249:8333 # AS1136
+86.100.26.188:8333 # AS39007
+86.106.143.143:55373 # AS9009
+86.124.145.184:8333 # AS8708
+86.133.251.239:8901 # AS2856
+87.79.94.221:8333 # AS8422
+87.120.8.5:20008 # AS34224
+87.125.157.220:8333 # AS12430
+88.9.76.133:8333 # AS3352
+88.90.184.68:8333 # AS2119
+88.151.101.14:5000 # AS41075
+88.151.101.253:5000 # AS41075
+88.198.92.47:8333 # AS24940
+88.208.115.70:8333 # AS29208
+88.210.15.24:8333 # AS212702
+88.212.45.166:8333 # AS42841
+89.102.206.238:8333 # AS16019
+89.103.111.34:8333 # AS16019
+89.114.143.113:8333 # AS12353
+89.134.62.74:8333 # AS21334
+89.152.8.231:8333 # AS2860
+89.161.26.78:8333 # AS39375
+89.207.131.19:8333 # AS49544
+89.248.193.229:8333 # AS49505
+90.3.48.62:8333 # AS3215
+90.146.121.97:8333 # AS12605
+90.146.130.214:8333 # AS12605
+90.196.169.58:8333 # AS5607
+90.250.9.1:8333 # AS5378
+91.93.194.154:8333 # AS34984
+91.126.40.109:8333 # AS35699
+91.204.99.178:8333 # AS20485
+91.204.149.5:8333 # AS42765
+91.206.17.195:8333 # AS13259
+91.209.51.131:8333 # AS48239
+91.215.91.254:8333 # AS48078
+92.91.27.60:8333 # AS15557
+92.221.20.232:8333 # AS29695
+92.255.85.31:8333 # AS9002
+93.4.101.37:8333 # AS15557
+93.46.81.5:8333 # AS12874
+93.57.81.162:8333 # AS12874
+93.73.39.196:8333 # AS25229
+93.90.82.226:8333 # AS47626
+93.95.88.13:8333 # AS35434
+93.123.180.164:8333 # AS35539
+93.189.145.169:8333 # AS12555
+94.17.185.107:8333 # AS12709
+94.75.198.120:8333 # AS60781
+94.114.196.169:8333 # AS3209
+94.142.213.250:55544 # AS5524
+94.154.159.99:8333 # AS62240
+94.158.246.183:8333 # AS39798
+94.239.145.32:8333 # AS5410
+95.31.12.22:8333 # AS8402
+95.31.196.15:8333 # AS3216
+95.110.133.223:8333 # AS31034
+95.110.234.93:8333 # AS31034
+95.161.12.45:8333 # AS39598
+95.191.130.100:8333 # AS12389
+95.208.158.161:8333 # AS51185
+95.213.145.218:8333 # AS49505
+95.214.53.154:8333 # AS201814
+95.214.53.160:8333 # AS201814
+96.44.156.199:8333 # AS8100
+97.75.145.12:8333 # AS22709
+102.132.192.141:8333 # AS37680
+103.14.245.250:8333 # AS24482
+103.85.38.205:8333 # AS134090
+103.88.92.78:8332 # AS17547
+103.99.168.100:8333 # AS6939
+103.99.168.140:8333 # AS6939
+103.99.170.210:8333 # AS54415
+103.99.170.220:8333 # AS54415
+103.100.44.70:8333 # AS10143
+103.178.236.27:8333 # AS49981
+103.209.12.144:8333 # AS58511
+104.59.147.15:8333 # AS7018
+104.129.171.121:8333 # AS174
+104.200.65.234:8333 # AS23033
+104.238.220.199:8333 # AS23470
+104.244.73.6:8333 # AS53667
+106.71.119.230:8333 # AS4804
+107.173.166.43:8333 # AS23352
+108.161.22.78:8333 # AS54154
+108.174.63.234:8333 # AS36352
+109.99.63.159:8333 # AS9050
+109.105.40.247:8333 # AS12570
+109.107.185.130:8333 # AS48282
+109.110.239.4:8333 # AS35432
+109.173.41.43:8333 # AS42610
+109.236.90.117:8333 # AS49981
+109.248.206.13:8333 # AS203493
+109.255.106.206:8333 # AS6830
+111.90.140.23:8333 # AS45839
+111.90.140.46:8333 # AS45839
+111.90.159.246:8333 # AS34309
+112.118.188.50:8333 # AS4760
+115.47.141.250:8885 # AS4134
+116.58.171.67:8333 # AS2514
+118.92.107.108:8333 # AS9500
+119.42.55.203:8333 # AS133159
+120.79.71.72:8333 # AS37963
+121.99.240.87:8333 # AS9790
+123.60.213.192:8333 # AS55990
+124.156.158.100:8333 # AS132203
+124.222.123.238:8333 # AS45090
+125.178.6.116:8333 # AS3786
+128.0.190.26:8333 # AS30764
+128.65.194.136:8333 # AS29222
+129.13.189.212:8333 # AS34878
+129.126.172.115:8333 # AS17547
+129.146.52.174:8333 # AS31898
+130.44.168.202:8333 # AS6079
+131.161.80.166:8333 # AS263694
+131.188.40.191:8333 # AS680
+134.195.185.52:8333 # AS13536
+135.134.238.47:8333 # AS4181
+135.180.218.58:8333 # AS46375
+135.181.215.237:8333 # AS24940
+136.29.109.180:8333 # AS19165
+136.32.238.6:8333 # AS16591
+136.56.170.96:8333 # AS16591
+137.25.38.108:8333 # AS20115
+137.226.34.46:8333 # AS680
+138.207.211.106:8333 # AS11776
+139.130.41.82:8333 # AS1221
+139.153.255.107:8333 # AS786
+140.190.12.129:8333 # AS14828
+142.54.181.218:8333 # AS32097
+143.177.229.149:8333 # AS50266
+143.178.64.10:8333 # AS50266
+144.24.245.183:8333 # AS31898
+144.126.130.178:8333 # AS40021
+146.4.124.129:8333 # AS3303
+146.71.69.103:8333 # AS7782
+146.83.56.69:8333 # AS23140
+147.194.177.165:8333 # AS15128
+149.90.214.78:8333 # AS12353
+149.102.157.156:8333 # AS13768
+151.248.156.55:8333 # AS8821
+151.252.193.245:8333 # AS29582
+153.92.93.114:8333 # AS41998
+154.211.6.2:8333 # AS140224
+156.17.103.2:8088 # AS8970
+156.146.177.221:8333 # AS1448
+157.131.143.173:8333 # AS46375
+158.58.188.37:8333 # AS57497
+158.248.39.239:8333 # AS29695
+159.89.230.128:8333 # AS14061
+159.196.3.239:8333 # AS4764
+159.224.189.250:8333 # AS13188
+160.72.51.154:8333 # AS46887
+161.29.236.55:8333 # AS4826
+161.97.119.166:8333 # AS51167
+161.246.11.230:8333 # AS9486
+162.62.18.226:8333 # AS132203
+162.250.123.179:8333 # AS19318
+162.250.191.222:8333 # AS26832
+162.254.118.20:8333 # AS6130
+163.172.81.70:8333 # AS12876
+164.90.47.8:8333 # AS53449
+165.228.174.117:8333 # AS1221
+166.70.145.151:8333 # AS6315
+168.91.238.8:8333 # AS11039
+170.253.11.25:8333 # AS15704
+171.103.170.115:8333 # AS7470
+172.93.166.135:8333 # AS22653
+172.103.217.236:8333 # AS25668
+172.105.21.216:8333 # AS63949
+172.112.153.95:8333 # AS20001
+173.3.218.91:8333 # AS6128
+173.12.119.133:8333 # AS7922
+173.34.127.181:8333 # AS812
+173.76.123.173:8333 # AS701
+173.176.198.68:8333 # AS5769
+173.208.152.218:8333 # AS32097
+173.241.227.243:8333 # AS19009
+173.246.27.7:8333 # AS1403
+173.255.240.205:8333 # AS63949
+174.30.47.15:8333 # AS209
+174.114.250.86:8333 # AS812
+174.138.35.229:8333 # AS14061
+174.142.191.136:8333 # AS32613
+176.10.143.190:8333 # AS8473
+176.74.136.237:8333 # AS35613
+176.118.220.29:8333 # AS60042
+176.126.116.7:8333 # AS20473
+176.126.167.10:8333 # AS8449
+176.212.185.153:8333 # AS9049
+176.235.209.186:8333 # AS34984
+177.81.236.117:8333 # AS28573
+177.89.205.70:8333 # AS28220
+178.48.168.12:8333 # AS21334
+178.124.162.209:8333 # AS6697
+178.159.98.133:8333 # AS202390
+178.196.89.209:8333 # AS3303
+178.236.137.63:8333 # AS44843
+178.252.123.24:8333 # AS42893
+179.43.170.186:8333 # AS51852
+180.150.46.187:8333 # AS4764
+181.117.128.140:8333 # AS19037
+184.19.19.16:8333 # AS5650
+185.21.217.48:8333 # AS200052
+185.25.48.184:8333 # AS61272
+185.31.136.246:8333 # AS47605
+185.52.93.45:8333 # AS39449
+185.64.116.15:8333 # AS31736
+185.68.249.91:8333 # AS51184
+185.98.54.20:8333 # AS39572
+185.107.83.55:8333 # AS43350
+185.140.253.169:8333 # AS200735
+185.148.145.74:8333 # AS44901
+185.165.170.19:8333 # AS3223
+185.167.113.59:8333 # AS207054
+185.185.26.141:8111 # AS201206
+185.197.163.136:8333 # AS60144
+185.209.12.76:8333 # AS212323
+185.209.70.17:8333 # AS204568
+185.227.156.226:8333 # AS209846
+185.233.189.210:8333 # AS61303
+185.239.221.5:8333 # AS61282
+185.244.100.106:8333 # AS2586
+185.254.97.164:8333 # AS44486
+186.33.167.11:8333 # AS1299
+186.176.98.37:8333 # AS262197
+186.249.217.25:8333 # AS7195
+186.250.95.132:8333 # AS262967
+188.32.14.31:8334 # AS42610
+188.35.167.14:8333 # AS34123
+188.68.45.143:8333 # AS47147
+188.117.200.212:8333 # AS25447
+188.138.88.14:8333 # AS20773
+188.151.237.158:8333 # AS1257
+188.154.236.49:8333 # AS6730
+189.123.177.128:8333 # AS4230
+190.123.27.11:8333 # AS52468
+190.145.127.254:8333 # AS14080
+192.69.53.77:8333 # AS11142
+192.146.137.44:8333 # AS25376
+192.222.24.54:8333 # AS22646
+192.222.147.141:8333 # AS1403
+193.32.127.162:60969 # AS39351
+193.111.198.187:8111 # AS24961
+193.196.37.62:8333 # AS34878
+194.13.80.185:15430 # AS47147
+194.147.113.201:8333 # AS21232
+194.165.30.20:8333 # AS35162
+194.191.239.98:8333 # AS1836
+195.56.63.4:8333 # AS5483
+195.56.63.10:8333 # AS5483
+195.123.239.185:8333 # AS64010
+195.140.226.154:8333 # AS35614
+198.1.231.6:8333 # AS30236
+198.148.112.27:8333 # AS35916
+199.126.234.237:8333 # AS395570
+199.193.174.173:8333 # AS7992
+199.247.7.208:8333 # AS20473
+200.122.181.46:8333 # AS3790
+201.191.6.103:8333 # AS11830
+201.212.36.209:8333 # AS7303
+201.221.234.200:8333 # AS27928
+202.108.211.135:8333 # AS4837
+202.169.17.178:8333 # AS137549
+202.177.24.140:8333 # AS7479
+203.130.48.117:8885 # AS54994
+203.132.94.196:8333 # AS38195
+205.178.41.124:8333 # AS11039
+206.72.201.228:8333 # AS19318
+206.192.203.0:8333 # AS7029
+206.223.153.52:8333 # AS19214
+207.134.216.145:8334 # AS395570
+207.188.154.50:8333 # AS15704
+207.229.46.80:8333 # AS852
+207.255.193.47:8333 # AS11776
+208.104.92.74:8333 # AS14615
+209.58.145.157:8333 # AS394380
+209.58.158.232:8335 # AS394380
+209.141.43.243:8333 # AS53667
+209.226.142.62:8333 # AS577
+209.237.127.227:8333 # AS1299
+209.237.133.54:8333 # AS53859
+211.248.90.50:8333 # AS4766
+212.21.18.78:8333 # AS20485
+212.34.225.118:8333 # AS44395
+212.51.146.137:8333 # AS13030
+212.227.211.87:8333 # AS8560
+213.0.69.76:8333 # AS3352
+213.5.36.58:8333 # AS49974
+213.47.64.105:8333 # AS8412
+213.89.135.151:8333 # AS1257
+213.141.154.201:8333 # AS12714
+213.159.198.45:8333 # AS8359
+213.184.244.24:8333 # AS60280
+213.214.66.182:8333 # AS43205
+213.226.123.76:8333 # AS49943
+216.146.251.8:8333 # AS54579
+216.186.238.14:8333 # AS12083
+217.5.150.114:8333 # AS3320
+217.15.178.11:8333 # AS25534
+217.24.239.109:8333 # AS9063
+217.64.47.138:8333 # AS39324
+217.73.80.104:8333 # AS44291
+217.79.181.38:8333 # AS24961
+217.92.55.246:8333 # AS3320
+217.113.121.169:8333 # AS8416
+217.115.116.250:8333 # AS30900
+217.155.244.170:8333 # AS13037
+217.170.124.170:8333 # AS35401
+220.132.135.54:8333 # AS3462
+220.233.178.199:8333 # AS38195
+222.154.111.46:8333 # AS4648
+[2001:1620:510::2]:8333 # AS13030
+[2001:19f0:6001:39aa:5400:3ff:fef0:916]:8333 # AS20473
+[2001:19f0:8001:f71:5400:4ff:fe10:6a63]:8333 # AS20473
+[2001:1bc0:c1::2000]:8333 # AS29686
+[2001:1c02:11e:3500:df25:6321:8260:d9be]:8333 # AS6830
+[2001:41d0:1004:1b79::]:8339 # AS16276
+[2001:41d0:203:3739::]:8333 # AS16276
+[2001:41d0:203:aacc::]:8333 # AS16276
+[2001:41d0:203:bb0a::]:8333 # AS16276
+[2001:41d0:2:bf8f::]:8333 # AS16276
+[2001:41d0:303:6586::]:8333 # AS16276
+[2001:41d0:602:4493::]:8333 # AS16276
+[2001:41d0:8:b9d8::1]:8333 # AS16276
+[2001:41d0:a:69a2::1]:8333 # AS16276
+[2001:41f0::62:6974:636f:696e]:8333 # AS6830
+[2001:44b8:256:5d11:216:3eff:fe39:d5d4]:8333 # AS4739
+[2001:470:1b62::]:8333 # AS6939
+[2001:470:1f07:803:20c:29ff:fe2d:5879]:8333 # AS6939
+[2001:470:1f15:106:e2d5:5eff:fe42:7ae5]:8333 # AS6939
+[2001:470:1f15:c43::11]:8333 # AS6939
+[2001:470:26:472::b7c]:8333 # AS6939
+[2001:470:75e9:1::10]:8333 # AS6939
+[2001:470:de5a::ec]:9333 # AS6939
+[2001:4ba0:babe:584::1]:8333 # AS24961
+[2001:4ba0:ffff:24::1]:8333 # AS24961
+[2001:4dd0:3564:0:30b7:1d7b:6fec:4c5c]:8333 # AS8422
+[2001:4dd0:3564:0:88e:b4ff:2ad0:699b]:8333 # AS8422
+[2001:4dd0:3564:0:9c1c:cc31:9fe8:5505]:8333 # AS8422
+[2001:4dd0:3564:0:a0c4:d41f:4c4:1bb0]:8333 # AS8422
+[2001:4dd0:3564:0:fd76:c1d3:1854:5bd9]:8333 # AS8422
+[2001:4dd0:3564:1::7676:8090]:8333 # AS8422
+[2001:4dd0:3564:1:b977:bd71:4612:8e40]:8333 # AS8422
+[2001:4dd0:af0e:3564::69:1]:8333 # AS8422
+[2001:4dd0:af0e:3564::69:90]:8333 # AS8422
+[2001:4de8:b1b2:1:0:dead:beef:7]:8333 # AS29208
+[2001:638:a000:4140::ffff:191]:8333 # AS680
+[2001:678:acc:42::]:8333 # AS60404
+[2001:67c:26b4:ff00::44]:8333 # AS25376
+[2001:67c:2db8:6::36]:8333 # AS39798
+[2001:7c0:2310:0:f816:3eff:fe0d:4ab6]:8333 # AS34878
+[2001:7c0:2310:0:f816:3eff:fe6c:4f58]:8333 # AS34878
+[2001:861:3246:a10::40]:8333 # AS5410
+[2001:b07:2e6:38d7:ba27:ebff:fe60:3dc1]:8333 # AS12874
+[2001:b07:6461:7811:489:d2da:e07:1af7]:8333 # AS12874
+[2001:b07:ac9:442b:79d6:bbbe:b37c:a783]:8333 # AS12874
+[2001:bc8:1600:0:208:a2ff:fe0c:8a2e]:8333 # AS12876
+[2001:bc8:323c:ff:a634:384f:1849:f4bc]:8333 # AS12876
+[2001:bc8:323c:ff:d217:c2ff:fe07:2cd9]:8333 # AS12876
+[2001:bc8:3bec:100::1]:8333 # AS12876
+[2002:2f5b:a5f9::2f5b:a5f9]:8885 # AS6939
+[2003:cb:8713:6102:aaa1:59ff:fe57:7779]:8333 # AS3320
+[2003:e0:370e:1400::5]:8333 # AS3320
+[2003:f6:3f10:6700:4c9f:7620:8324:d4a7]:8333 # AS3320
+[2400:2410:cea2:d00:41bc:c9ea:861b:51ee]:8333 # AS17676
+[2400:2411:a3e1:4900:2568:684b:e99:7120]:8333 # AS17676
+[2400:2411:a3e1:4900:2987:b88f:61e0:84fa]:8333 # AS17676
+[2400:3b00:20:c:bacb:29ff:feab:8886]:8333 # AS18229
+[2401:b140:1::100:210]:8333 # AS54415
+[2401:b140:1::100:220]:8333 # AS54415
+[2401:b140::42:100]:8333 # AS6939
+[2401:b140::44:130]:8333 # AS6939
+[2401:d002:3902:700:d72c:5e22:4e95:389d]:8333 # AS38195
+[2404:4408:6752:c000::1999]:8333 # AS9790
+[2404:7a85:4161:2b00:49a1:427a:fac:3409]:8333 # AS2518
+[2405:9800:b972:ab58:c05:e938:267e:271]:8333 # AS45430
+[2406:da11:169:b03:32b5:f901:9f7c:3e4b]:8333 # AS16509
+[2406:da14:335:b601:ceb7:b4fc:a855:f3a5]:8333 # AS16509
+[2406:da1e:a4e:8a03:2aad:496b:768d:e497]:8333 # AS16509
+[2407:8800:bc61:2202:a0c6:107:502b:4e3b]:8333 # AS7545
+[2409:10:ca20:1df0:224:e8ff:fe1f:60d9]:8333 # AS55391
+[2600:1700:22f1:641f:e8:39c8:eb1d:a1eb]:8333 # AS7018
+[2600:1700:9c5d:ed0::38]:8333 # AS7018
+[2600:1700:9c5d:ed0:d0d6:1d9:5cc2:ab47]:8333 # AS7018
+[2600:1702:1ce0:4010::40]:8333 # AS7018
+[2600:1f14:40e:e301:d155:aa3a:77be:960e]:8333 # AS16509
+[2600:1f16:a08:b901:1afa:ef4e:4ce7:2ba4]:8333 # AS16509
+[2600:1f1c:2d3:2403:5bac:3fc6:6513:7a63]:8333 # AS16509
+[2600:2104:1003:c5ab:dc5e:90ff:fe18:1d08]:8333 # AS11404
+[2600:3c00::f03c:92ff:fe92:2745]:8333 # AS63949
+[2600:3c00::f03c:92ff:fecf:61b6]:8333 # AS63949
+[2600:3c00::f03c:93ff:feb3:1b6]:8333 # AS63949
+[2600:3c00:e002:2e32::1:14]:8333 # AS63949
+[2600:3c02::f03c:92ff:fe5d:9fb]:8333 # AS63949
+[2600:4040:2854:5e00:c6e9:84ff:fe46:ee8]:8666 # AS13786
+[2600:6c54:7100:1ad1:bddf:550e:91be:f9e1]:8333 # AS20115
+[2600:8805:2400:14e:12dd:b1ff:fef2:3013]:8333 # AS22773
+[2601:184:300:bde:3c29:8e94:1ba8:fde3]:8333 # AS7922
+[2601:18c:8080:300f:219:d1ff:fe75:dc2f]:8333 # AS7922
+[2601:18d:4600:43f1:20e7:b3ff:fecf:a99]:8333 # AS7922
+[2601:18d:8701:c290::3330]:8333 # AS7922
+[2601:246:4d7f:9e28:f321:36ca:7a71:c687]:8333 # AS7922
+[2601:640:c201:960d:86eb:f27d:66a2:f2c1]:8333 # AS7922
+[2602:241:75d1:2b90::7840]:8333 # AS46375
+[2602:ffb8::208:72:57:200]:8333 # AS2914
+[2603:3004:6a1:3800:851f:584d:7aba:affb]:8333 # AS7922
+[2603:3004:6a1:3800::4402]:8333 # AS7922
+[2603:3004:70d:1400:8532:2900:ce6f:acdf]:8333 # AS7922
+[2603:3004:745:900:f0d7:556a:a8c:ced5]:8333 # AS7922
+[2603:6080:c000:5d8a::104f]:8333 # AS7843
+[2603:8000:d100:8991:cc29:ccff:fe42:300c]:8333 # AS7843
+[2603:8080:1f07:6fdd:7de2:d969:78c9:b7ea]:8333 # AS7843
+[2603:8080:7300:531::13ea]:8333 # AS7843
+[2603:80a0:703:40f8::38]:8333 # AS7843
+[2604:180:f3::218]:8333 # AS3842
+[2604:3d08:0:5:d941:4b03:a093:131b]:8333 # AS6327
+[2604:7c00:120:4b::eb24]:8333 # AS174
+[2604:a00:21:3043:bf6a:535e:dfeb:5b7b]:8333 # AS19318
+[2604:a880:400:d0::1ce7:4001]:8333 # AS14061
+[2604:a880:400:d0::1d44:e001]:8333 # AS14061
+[2604:a880:400:d0::261f:6001]:8333 # AS14061
+[2604:a880:400:d1::7e2:e001]:8333 # AS14061
+[2604:a880:4:1d0::14:3000]:8333 # AS14061
+[2604:a880:4:1d0::e5:b000]:8333 # AS14061
+[2605:6400:30:f220::]:8333 # AS53667
+[2605:6f80:0:7:fc1b:ccff:fe8a:d822]:8333 # AS53340
+[2605:a140:2076:8253::1]:8333 # AS40021
+[2605:a140:3007:1287::1]:8333 # AS40021
+[2605:ae00:203::203]:8333 # AS7819
+[2605:c000:2a0a:1::102]:8333 # AS7393
+[2607:1a00:1:d::11:7c4d]:8333 # AS22653
+[2607:5300:203:1214::]:8333 # AS16276
+[2607:9280:b:73b:250:56ff:fe14:25b5]:8333 # AS395502
+[2607:9280:b:73b:250:56ff:fe21:9c2f]:8333 # AS395502
+[2607:9280:b:73b:250:56ff:fe21:bf32]:8333 # AS395502
+[2607:9280:b:73b:250:56ff:fe33:4d1b]:8333 # AS395502
+[2607:9280:b:73b:250:56ff:fe3d:401]:8333 # AS395502
+[2607:f2c0:e1c2:69:12c3:7bff:fe4d:9431]:8333 # AS5645
+[2607:f2c0:e1c2:69:ecb2:6e88:9f33:5057]:8333 # AS5645
+[2620:6:2003:105:2d8:61ff:fe0f:853]:8333 # AS25682
+[2620:6e:a000:1:42:42:42:42]:8333 # AS397444
+[2620:a6:2000:1::3:d570]:8333 # AS27566
+[2620:a6:2000:1::5:162a]:8333 # AS27566
+[2620:a6:2000:1::5:1631]:8333 # AS27566
+[2620:a6:2000:1::c:e634]:8333 # AS27566
+[2800:40:33:8ab:a0e7:b215:fc83:5c31]:8333 # AS16814
+[2800:bf0:149:f4b:f8df:8d7d:801b:e25e]:8333 # AS27947
+[2804:14c:198:80d5:7603:41d1:d3fc:e797]:8333 # AS28573
+[2804:14d:ae81:827b:99a8:1e3f:6db2:29db]:8333 # AS4230
+[2804:d57:5537:4800:3e7c:3fff:fe7b:80aa]:8333 # AS8167
+[2a00:12e0:101:99:20c:29ff:fe29:d03f]:8333 # AS6798
+[2a00:1328:e101:c00::163]:8333 # AS31078
+[2a00:1398:4:2a03:215:5dff:fed6:1033]:8333 # AS34878
+[2a00:1398:4:2a03::bc03]:8333 # AS34878
+[2a00:1630:10:1003:0:b19:b00b:babe]:8333 # AS49544
+[2a00:1768:2001:27::ef6a]:8333 # AS43350
+[2a00:1828:a004:2::666]:8333 # AS34240
+[2a00:1c10:2:709::217]:22220 # AS50300
+[2a00:1f40:5001:108:5d17:7703:b0f5:4133]:8333 # AS42864
+[2a00:23c5:fe80:7301:d6ae:52ff:fed5:56a5]:8333 # AS2856
+[2a00:23c6:5c91:5808:c05a:4dff:fe65:9d69]:8333 # AS2856
+[2a00:6020:1bfa:d400:20c:29ff:fe61:4a4c]:8333 # AS60294
+[2a00:6020:b482:9200:491a:358c:d8f7:1da]:8333 # AS60294
+[2a00:6020:b489:2000:5054:ff:fefc:5ed8]:8333 # AS60294
+[2a00:7c80:0:25::e37a]:8333 # AS49981
+[2a00:7c80:0:71::8]:8333 # AS49981
+[2a00:8a60:e012:a00::21]:8333 # AS680
+[2a00:ae40:240e:3200::3]:8333 # AS50923
+[2a00:bbe0:cc:0:62a4:4cff:fe23:7510]:8333 # AS47605
+[2a00:ca8:a1f:3025:f949:e442:c940:13e8]:8333 # AS30764
+[2a00:d4e0:2:d002:4467:31e0:6fa5:b3ef]:8333 # AS15600
+[2a00:ee2:1200:1900:8d3:d2ff:feb1:bc58]:8333 # AS5603
+[2a01:238:420f:9200:fa5a:1a4b:1e6a:fadf]:8333 # AS6724
+[2a01:238:4389:c400:3b26:d94e:38d5:44ef]:8333 # AS6724
+[2a01:490:16:301::2]:8333 # AS8251
+[2a01:4b00:807c:3100:cda1:c6a:2bad:2418]:8333 # AS56478
+[2a01:4f8:141:2254::2]:8333 # AS24940
+[2a01:4f8:173:230a::2]:8333 # AS24940
+[2a01:4f8:190:91c4::2]:8333 # AS24940
+[2a01:4f8:200:7222::2]:8333 # AS24940
+[2a01:4f8:202:3e6::2]:8333 # AS24940
+[2a01:4f8:221:44d7::2]:8333 # AS24940
+[2a01:4f8:231:915::2]:8333 # AS24940
+[2a01:4f9:2a:1ce0::2]:8333 # AS24940
+[2a01:4f9:2b:29a::2]:8333 # AS24940
+[2a01:4f9:4a:31de::2]:8333 # AS24940
+[2a01:5200:6c:6162:7a61:746b:6f2e:736b]:8333 # AS6855
+[2a01:6380:fffe:73:10fb:d012:8581:b4d7]:8333 # AS25540
+[2a01:7a7:2:2804:ae1f:6bff:fe9d:6c94]:8333 # AS20773
+[2a01:7c8:aaac:89:5054:ff:feb7:f5cb]:8333 # AS20857
+[2a01:7c8:aac9:c9:5054:ff:fedf:ff95]:8333 # AS20857
+[2a01:7c8:d001:1c1:5054:ff:feee:3e1a]:8333 # AS20857
+[2a01:7c8:d009:2aa:5054:ff:fe1b:a196]:11520 # AS20857
+[2a01:7c8:fffa:50e:ddfe:c924:ca0a:cbab]:8333 # AS20857
+[2a01:7e00::f03c:93ff:fe59:66dc]:8333 # AS63949
+[2a01:7e01::f03c:93ff:fe3b:bb5b]:8333 # AS63949
+[2a01:8740:1:ffc5::8c6a]:8333 # AS57344
+[2a01:9f40:a000::100]:8333 # AS42908
+[2a01:cb00:d3d:7700:227:eff:fe28:c565]:8333 # AS3215
+[2a01:e0a:20:7350:919c:b1c3:8b83:adf9]:8333 # AS12322
+[2a01:e0a:301:7010:b87d:e14b:cea9:b998]:8333 # AS12322
+[2a01:e0a:48b:2d10:94f2:4d5c:ca5f:bf49]:8333 # AS12322
+[2a01:e0a:530:a0a0:f465:af5:be1b:9075]:8333 # AS12322
+[2a01:e0a:aa7:c8c0:9679:affa:b6e5:efc7]:8333 # AS12322
+[2a01:e11:100c:70:cbc8:9e31:4b77:1626]:8333 # AS12322
+[2a01:e34:ee78:3060:230:48ff:fe81:f1c6]:8333 # AS12322
+[2a02:1210:14a9:6700:a00:27ff:fe4e:82b6]:8333 # AS3303
+[2a02:1210:4639:f00:10a7:e965:509a:7a4a]:8333 # AS3303
+[2a02:1210:7c92:5100:211:32ff:feae:152d]:8333 # AS3303
+[2a02:1210:86bf:f100:3178:d700:d44d:6bb1]:8333 # AS3303
+[2a02:1210:9487:a200:edc1:93a4:945:9a92]:8333 # AS3303
+[2a02:168:420b:a::20]:8333 # AS13030
+[2a02:168:6328:0:4a21:bff:fe26:38c3]:8333 # AS13030
+[2a02:168:676e:0:e65f:1ff:fe09:3591]:8333 # AS13030
+[2a02:1748:f39f:5872:dead:beef:b1ac:c0fe]:8333 # AS51184
+[2a02:180:1:1::517:10b6]:8333 # AS35366
+[2a02:2168:a379:d100:96de:80ff:fea3:fd00]:8333 # AS42610
+[2a02:2780:9000:70::7]:8333 # AS35434
+[2a02:2780:9000:70::f]:8333 # AS35434
+[2a02:2780::e01a]:8333 # AS35434
+[2a02:2e02:3900:5400:a099:e1ff:feb6:d0e]:8333 # AS12479
+[2a02:2f05:660e:8b00::1]:8333 # AS48571
+[2a02:58:97:7d20::60]:8333 # AS25596
+[2a02:6d40:3073:c01:dea6:32ff:fe44:4b25]:8333 # AS42652
+[2a02:7a01::91:228:45:130]:8333 # AS16019
+[2a02:7b40:5928:89::1]:8333 # AS62282
+[2a02:7b40:c3b5:f583::1]:8333 # AS62282
+[2a02:8308:8087:aa00:9ea8:1b2:ef98:56bf]:8333 # AS16019
+[2a02:842a:1df:8a01:1e1b:dff:fe0b:236d]:8333 # AS15557
+[2a02:a44d:14d6:1:2c0:8ff:fe8f:b3b2]:8333 # AS1136
+[2a02:a45a:94cd:f00d::1]:8333 # AS1136
+[2a02:a45f:3b9d:30::3]:8333 # AS1136
+[2a02:a467:7833:1:7285:c2ff:fe2c:21e9]:8333 # AS1136
+[2a02:aa14:2380:b300:4040:be88:8b01:d38]:8333 # AS6830
+[2a02:c206:2044:9826::1]:8333 # AS51167
+[2a02:c206:2082:1246::1]:8333 # AS51167
+[2a02:c206:3008:2368::1]:8333 # AS51167
+[2a02:c207:0:4971::1]:5332 # AS51167
+[2a02:c207:2014:4199::1]:8333 # AS51167
+[2a02:c207:2024:6115::1]:8333 # AS51167
+[2a02:c207:2026:6682::1]:8333 # AS51167
+[2a02:c207:3002:7468::1]:8333 # AS51167
+[2a02:e98:20:1504::1]:8333 # AS24641
+[2a03:4000:6:416c::43]:8333 # AS47147
+[2a03:4000:6:f814:548b:17ff:fe31:b64a]:8333 # AS47147
+[2a03:6000:870:0:46:23:87:218]:8333 # AS51088
+[2a03:94e0:ffff:185:243:218:0:19]:8333 # AS56655
+[2a03:b0c0:1:e0::397:6001]:8333 # AS14061
+[2a03:b0c0:2:f0::163:3001]:8333 # AS14061
+[2a03:b0c0:2:f0::18a:d001]:8333 # AS14061
+[2a03:b0c0:3:d0::f3e:2001]:8333 # AS14061
+[2a03:e2c0:1347::2]:8333 # AS50113
+[2a03:ec0:0:928::701:701]:8333 # AS199669
+[2a04:52c0:103:c455::1]:8334 # AS60404
+[2a04:52c0:3007:200::2000]:8333 # AS60404
+[2a04:bc40:1dc3:8d::2:1001]:8333 # AS35277
+[2a05:1500:702:0:1c00:40ff:fe00:c]:8333 # AS48635
+[2a05:3580:d101:3700::]:8333 # AS20764
+[2a05:3580:db0b:1600:c489:76ed:313d:b33]:8333 # AS20764
+[2a05:d014:a55:4001:8127:afa7:daf9:d91b]:8333 # AS16509
+[2a05:d014:a55:4001:f6ab:dd5e:4039:b46c]:8333 # AS16509
+[2a05:d014:a55:4003:6523:50a1:152:e88c]:8333 # AS16509
+[2a05:d01a:b7b:3c01:8bf7:ae14:afb3:33ae]:8333 # AS16509
+[2a05:f480:1800:697:5400:2ff:feb6:c36d]:8333 # AS20473
+[2a06:e040:7603:2918:c6ef:464e:9fe5:73ec]:8333 # AS198507
+[2a07:abc4::1:946]:8333 # AS62000
+[2a09:2681:102::210]:8333 # AS61282
+[2a0a:c801:1:7::183]:8333 # AS39798
+[2a0c:5a80:1210:a800:6af7:28ff:fee5:6b3a]:8333 # AS57269
+[2a0d:5600:24:a8e::a91e]:55373 # AS9009
+[2a0d:7c40:3000:b04::2]:8333 # AS54290
+[2a0d:8340:24::2]:8333 # AS50113
+[2a0f:df00:0:2010::162]:8333 # AS41281
+[2a10:3781:16b9:1:fe3f:dbff:fe04:2d4c]:8333 # AS206238
+[2a10:3781:84b:1:b123:6306:943a:f09b]:8333 # AS206238
+[2a10:d200:1:33:a6bf:1ff:fe6a:46a9]:8333 # AS212323
+[2c0f:f4c0:2202:20b0:261c:4ff:fe14:daa0]:8333 # AS327693
+[2c0f:f8f0:da51:0:70c3:eea9:9717:9579]:8333 # AS30844
-# manually added 2021-03 for minimal torv3 bootstrap support
-2g5qfdkn2vvcbqhzcyvyiitg4ceukybxklraxjnu7atlhd22gdwywaid.onion:8333
-2jmtxvyup3ijr7u6uvu7ijtnojx4g5wodvaedivbv74w4vzntxbrhvad.onion:8333
-37m62wn7dz3uqpathpc4qfmgrbupachj52nt3jbtbjugpbu54kbud7yd.onion:8333
+# manually updated 2022-08 for minimal torv3 bootstrap support
5g72ppm3krkorsfopcm2bi7wlv4ohhs4u4mlseymasn7g7zhdcyjpfid.onion:8333
-7cgwjuwi5ehvcay4tazy7ya6463bndjk6xzrttw5t3xbpq4p22q6fyid.onion:8333
-7pyrpvqdhmayxggpcyqn5l3m5vqkw3qubnmgwlpya2mdo6x7pih7r7id.onion:8333
b64xcbleqmwgq2u46bh4hegnlrzzvxntyzbmucn3zt7cssm7y4ubv3id.onion:8333
-ejxefzf5fpst4mg2rib7grksvscl7p6fvjp6agzgfc2yglxnjtxc3aid.onion:8333
fjdyxicpm4o42xmedlwl3uvk5gmqdfs5j37wir52327vncjzvtpfv7yd.onion:8333
fpz6r5ppsakkwypjcglz6gcnwt7ytfhxskkfhzu62tnylcknh3eq6pad.onion:8333
-fzhn4uoxfbfss7h7d6ffbn266ca432ekbbzvqtsdd55ylgxn4jucm5qd.onion:8333
gxo5anvfnffnftfy5frkgvplq3rpga2ie3tcblo2vl754fvnhgorn5yd.onion:8333
ifdu5qvbofrt4ekui2iyb3kbcyzcsglazhx2hn4wfskkrx2v24qxriid.onion:8333
itz3oxsihs62muvknc237xabl5f6w6rfznfhbpayrslv2j2ubels47yd.onion:8333
-lrjh6fywjqttmlifuemq3puhvmshxzzyhoqx7uoufali57eypuenzzid.onion:8333
+kpgvmscirrdqpekbqjsvw5teanhatztpp2gl6eee4zkowvwfxwenqaid.onion:8333
m7cbpjolo662uel7rpaid46as2otcj44vvwg3gccodnvaeuwbm3anbyd.onion:8333
-opnyfyeiibe5qo5a3wbxzbb4xdiagc32bbce46owmertdknta5mi7uyd.onion:8333
-owjsdxmzla6d7lrwkbmetywqym5cyswpihciesfl5qdv2vrmwsgy4uqd.onion:8333
-q7kgmd7n7h27ds4fg7wocgniuqb3oe2zxp4nfe4skd5da6wyipibqzqd.onion:8333
+mwmfluek4au6mxxpw6fy7sjhkm65bdfc7izc7lpz3trewfdghyrzsbid.onion:8333
rp7k2go3s5lyj3fnj6zn62ktarlrsft2ohlsxkyd7v3e3idqyptvread.onion:8333
-sys54sv4xv3hn3sdiv3oadmzqpgyhd4u4xphv4xqk64ckvaxzm57a7yd.onion:8333
-tddeij4qigtjr6jfnrmq6btnirmq5msgwcsdpcdjr7atftm7cxlqztid.onion:8333
-vi5bnbxkleeqi6hfccjochnn65lcxlfqs4uwgmhudph554zibiusqnad.onion:8333
-xqt25cobm5zqucac3634zfght72he6u3eagfyej5ellbhcdgos7t2had.onion:8333
-# manually added 2021-08 for minimal i2p bootstrap support
+# manually updated 2022-08 for minimal i2p bootstrap support
+255fhcp6ajvftnyo7bwz3an3t4a4brhopm3bamyh2iu5r3gnr2rq.b32.i2p:0
+27yrtht5b5bzom2w5ajb27najuqvuydtzb7bavlak25wkufec5mq.b32.i2p:0
+2el6enckmfyiwbfcwsygkwksovtynzsigmyv3bzyk7j7qqahooua.b32.i2p:0
+3gocb7wc4zvbmmebktet7gujccuux4ifk3kqilnxnj5wpdpqx2hq.b32.i2p:0
+3tns2oov4tnllntotazy6umzkq4fhkco3iu5rnkxtu3pbfzxda7q.b32.i2p:0
+4fcc23wt3hyjk3csfzcdyjz5pcwg5dzhdqgma6bch2qyiakcbboa.b32.i2p:0
+4osyqeknhx5qf3a73jeimexwclmt42cju6xdp7icja4ixxguu2hq.b32.i2p:0
+4umsi4nlmgyp4rckosg4vegd2ysljvid47zu7pqsollkaszcbpqq.b32.i2p:0
+52v6uo6crlrlhzphslyiqblirux6olgsaa45ixih7sq5np4jujaa.b32.i2p:0
+6j2ezegd3e2e2x3o3pox335f5vxfthrrigkdrbgfbdjchm5h4awa.b32.i2p:0
+6n36ljyr55szci5ygidmxqer64qr24f4qmnymnbvgehz7qinxnla.b32.i2p:0
+72yjs6mvlby3ky6mgpvvlemmwq5pfcznrzd34jkhclgrishqdxva.b32.i2p:0
+7r4ri53lby2i3xqbgpw3idvhzeku7ubhftlf72ldqkg5kde6dauq.b32.i2p:0
a5qsnv3maw77mlmmzlcglu6twje6ttctd3fhpbfwcbpmewx6fczq.b32.i2p:0
-bitcornrd36coazsbzsz4pdebyzvaplmsalq4kpoljmn6cg6x5zq.b32.i2p:0
+aovep2pco7v2k4rheofrgytbgk23eg22dczpsjqgqtxcqqvmxk6a.b32.i2p:0
+bddbsmkas3z6fakorbkfjhv77i4hv6rysyjsvrdjukxolfghc23q.b32.i2p:0
+bitcoi656nll5hu6u7ddzrmzysdtwtnzcnrjd4rfdqbeey7dmn5a.b32.i2p:0
+brifkruhlkgrj65hffybrjrjqcgdgqs2r7siizb5b2232nruik3a.b32.i2p:0
c4gfnttsuwqomiygupdqqqyy5y5emnk5c73hrfvatri67prd7vyq.b32.i2p:0
-dhtq2p76tyhi442aidb3vd2bv7yxxjuddpb2jydnnrl2ons5bhha.b32.i2p:0
+day3hgxyrtwjslt54sikevbhxxs4qzo7d6vi72ipmscqtq3qmijq.b32.i2p:0
+di2zq6fr3fegf2jdcd7hdwyql4umr462gonsns2nxz5qg5vz4bka.b32.i2p:0
+e55k6wu46rzp4pg5pk5npgbr3zz45bc3ihtzu2xcye5vwnzdy7pq.b32.i2p:0
+eciohu5nq7vsvwjjc52epskuk75d24iccgzmhbzrwonw6lx4gdva.b32.i2p:0
+ejlnngarmhqvune74ko7kk55xtgbz5i5ncs4vmnvjpy3l7y63xaa.b32.i2p:0
+g47cqoppu26pr4n2cfaioqx7lbdi7mea7yqhlrkdz3wjwxjxdh2a.b32.i2p:0
h3r6bkn46qxftwja53pxiykntegfyfjqtnzbm6iv6r5mungmqgmq.b32.i2p:0
-hnbbyjpxx54623l555sta7pocy3se4sdgmuebi5k6reesz5rjp6q.b32.i2p:0
+hhfi4yqkg2twqiwezrfksftjjofbyx3ojkmlnfmcwntgnrjjhkya.b32.i2p:0
+hpiibrflqkbrcshfhmrtwfyeb7mds7a3obzwrgarejevddzamvsq.b32.i2p:0
+i4pyhsfdq4247dunel7paatdaq5gusi2hnybp2yf5wxwdnrgxaqq.b32.i2p:0
+iw6tgpmbdykffceku5da6nzf2bmz66fvp5fpcvemfu3df6aq6pga.b32.i2p:0
+jkfuajo4ayvo2rbv5qdj443q6adqmnormbhsf2f7rlp5t24xomda.b32.i2p:0
jz3s4eurm5vzjresf4mwo7oni4bk36daolwxh4iqtewakylgkxmq.b32.i2p:0
-kokkmpquqlkptu5hkmzqlttsmtwxicldr4so7wqsufk6bwf32nma.b32.i2p:0
+liu75cvktv4icbctg72w7nxbk4eibt7wamizfdii4omz7gcke5vq.b32.i2p:0
+ljsquuu3y4xje6l32p32inn6r2y6ull6oocgup6jtjrohrqxbz6a.b32.i2p:0
+lrah7acdsgopybg43shadwwiv6igezaw64i6jb5muqdg7dmhj3la.b32.i2p:0
+lzuu6mjtu7vd55d2biphicihufipoa7vyym6xfnkmmlra3tiziia.b32.i2p:0
+m6bpynxkv2ktwxkg6p2gyudjfhdupb6kuzabeqdnckkdkf4kxjla.b32.i2p:0
+m6v454xd6p3bt5swujgmveklsp7lzbkqlqqfc2p36cjlwv5dbucq.b32.i2p:0
+mlgeizrroynuhpxbzeosajt5u4ddcvynxfmcbm6kwjpaufilxigq.b32.i2p:0
+ofubxr2ir7u2guzjwyrvujicivzmvinwa36nuzlrg7tnsmebal7a.b32.i2p:0
+okfxeoh6itu4f5f43dhbzvkqwfrvm5c66lj6lvjj4q2b35i4pk4q.b32.i2p:0
+oz2ia3flpm3du2tyusulrn7h7e2eo3juzkrmn34bvnrlcrugv7ia.b32.i2p:0
+qd6jlsevsexww3wefpqs7iglxb3f63y4e6ydulfzrvwflpicmdqa.b32.i2p:0
+qddg7myylinn4tw6kdjmmp6fsyetkosnrbp2gsjx77tmkqyqv6ua.b32.i2p:0
+rizfinyses2r3or4iubs5wx66gdy6mpf73w7uobfacm2l5cral3q.b32.i2p:0
+s5hhjtmlg53bko3nwwskas7xgsmeqzy6thtsj5aa64djyrljgqaq.b32.i2p:0
sedndhv5vpcgdmykyi5st4yqhdxl3hpdtglta4do435wupahhx6q.b32.i2p:0
+tsl4dlpu2id252b6crbdnblruct664se6f2iw35fuqwa3te7wcoq.b32.i2p:0
+tugq6wa2ls2bv27pr2iy3da3k5ow3fzefbcvjcr22uc7w5vmevja.b32.i2p:0
+usztavbib756k5vqggzgkyswoj6mttihjvp3c2pa642t2mb4pvsa.b32.i2p:0
+vgu6llqbyjphml25umd5ztvyxrxuplz2g74fzbx75g3kkaetoyiq.b32.i2p:0
+wjrul5jwwb4vqdmkkrjbmly7osj6amecdpsac5xvaoqrti4nb3ha.b32.i2p:0
+wvktcp7hy4l6immhi5cxyz2dlsbhhvtcmskjemrnqehacnoap23q.b32.i2p:0
wwbw7nqr3ahkqv62cuqfwgtneekvvpnuc4i4f6yo7tpoqjswvcwa.b32.i2p:0
+xlqndzjoe5nr2nsxo6xwibh44ghyz4jfqevu62xykvemextpmjbq.b32.i2p:0
+yc4xwin5ujenvcr6ynwkz7lnmmq3nmzxvfguele6ovqqpxgjvonq.b32.i2p:0
+zdoabsg7ugzothyawodjhq54nvlofa746rxfkxpnjzj6nukmha6a.b32.i2p:0
zsxwyo6qcn3chqzwxnseusqgsnuw3maqnztkiypyfxtya4snkoka.b32.i2p:0
+zysrlpii5ftrzivfcyhdrwpeyyqddbrdefnfu5q6otk5gtugmh2a.b32.i2p:0
# manually added 2022-01 for minimal cjdns bootstrap support
[fc32:17ea:e415:c3bf:9808:149d:b5a2:c9aa]:8333
diff --git a/contrib/seeds/nodes_main_manual.txt b/contrib/seeds/nodes_main_manual.txt
index a6e0b8763a..286448d95d 100644
--- a/contrib/seeds/nodes_main_manual.txt
+++ b/contrib/seeds/nodes_main_manual.txt
@@ -1,42 +1,77 @@
-# manually added 2021-03 for minimal torv3 bootstrap support
-2g5qfdkn2vvcbqhzcyvyiitg4ceukybxklraxjnu7atlhd22gdwywaid.onion:8333
-2jmtxvyup3ijr7u6uvu7ijtnojx4g5wodvaedivbv74w4vzntxbrhvad.onion:8333
-37m62wn7dz3uqpathpc4qfmgrbupachj52nt3jbtbjugpbu54kbud7yd.onion:8333
+# manually updated 2022-08 for minimal torv3 bootstrap support
5g72ppm3krkorsfopcm2bi7wlv4ohhs4u4mlseymasn7g7zhdcyjpfid.onion:8333
-7cgwjuwi5ehvcay4tazy7ya6463bndjk6xzrttw5t3xbpq4p22q6fyid.onion:8333
-7pyrpvqdhmayxggpcyqn5l3m5vqkw3qubnmgwlpya2mdo6x7pih7r7id.onion:8333
b64xcbleqmwgq2u46bh4hegnlrzzvxntyzbmucn3zt7cssm7y4ubv3id.onion:8333
-ejxefzf5fpst4mg2rib7grksvscl7p6fvjp6agzgfc2yglxnjtxc3aid.onion:8333
fjdyxicpm4o42xmedlwl3uvk5gmqdfs5j37wir52327vncjzvtpfv7yd.onion:8333
fpz6r5ppsakkwypjcglz6gcnwt7ytfhxskkfhzu62tnylcknh3eq6pad.onion:8333
-fzhn4uoxfbfss7h7d6ffbn266ca432ekbbzvqtsdd55ylgxn4jucm5qd.onion:8333
gxo5anvfnffnftfy5frkgvplq3rpga2ie3tcblo2vl754fvnhgorn5yd.onion:8333
ifdu5qvbofrt4ekui2iyb3kbcyzcsglazhx2hn4wfskkrx2v24qxriid.onion:8333
itz3oxsihs62muvknc237xabl5f6w6rfznfhbpayrslv2j2ubels47yd.onion:8333
-lrjh6fywjqttmlifuemq3puhvmshxzzyhoqx7uoufali57eypuenzzid.onion:8333
+kpgvmscirrdqpekbqjsvw5teanhatztpp2gl6eee4zkowvwfxwenqaid.onion:8333
m7cbpjolo662uel7rpaid46as2otcj44vvwg3gccodnvaeuwbm3anbyd.onion:8333
-opnyfyeiibe5qo5a3wbxzbb4xdiagc32bbce46owmertdknta5mi7uyd.onion:8333
-owjsdxmzla6d7lrwkbmetywqym5cyswpihciesfl5qdv2vrmwsgy4uqd.onion:8333
-q7kgmd7n7h27ds4fg7wocgniuqb3oe2zxp4nfe4skd5da6wyipibqzqd.onion:8333
+mwmfluek4au6mxxpw6fy7sjhkm65bdfc7izc7lpz3trewfdghyrzsbid.onion:8333
rp7k2go3s5lyj3fnj6zn62ktarlrsft2ohlsxkyd7v3e3idqyptvread.onion:8333
-sys54sv4xv3hn3sdiv3oadmzqpgyhd4u4xphv4xqk64ckvaxzm57a7yd.onion:8333
-tddeij4qigtjr6jfnrmq6btnirmq5msgwcsdpcdjr7atftm7cxlqztid.onion:8333
-vi5bnbxkleeqi6hfccjochnn65lcxlfqs4uwgmhudph554zibiusqnad.onion:8333
-xqt25cobm5zqucac3634zfght72he6u3eagfyej5ellbhcdgos7t2had.onion:8333
-# manually added 2021-08 for minimal i2p bootstrap support
+# manually updated 2022-08 for minimal i2p bootstrap support
+255fhcp6ajvftnyo7bwz3an3t4a4brhopm3bamyh2iu5r3gnr2rq.b32.i2p:0
+27yrtht5b5bzom2w5ajb27najuqvuydtzb7bavlak25wkufec5mq.b32.i2p:0
+2el6enckmfyiwbfcwsygkwksovtynzsigmyv3bzyk7j7qqahooua.b32.i2p:0
+3gocb7wc4zvbmmebktet7gujccuux4ifk3kqilnxnj5wpdpqx2hq.b32.i2p:0
+3tns2oov4tnllntotazy6umzkq4fhkco3iu5rnkxtu3pbfzxda7q.b32.i2p:0
+4fcc23wt3hyjk3csfzcdyjz5pcwg5dzhdqgma6bch2qyiakcbboa.b32.i2p:0
+4osyqeknhx5qf3a73jeimexwclmt42cju6xdp7icja4ixxguu2hq.b32.i2p:0
+4umsi4nlmgyp4rckosg4vegd2ysljvid47zu7pqsollkaszcbpqq.b32.i2p:0
+52v6uo6crlrlhzphslyiqblirux6olgsaa45ixih7sq5np4jujaa.b32.i2p:0
+6j2ezegd3e2e2x3o3pox335f5vxfthrrigkdrbgfbdjchm5h4awa.b32.i2p:0
+6n36ljyr55szci5ygidmxqer64qr24f4qmnymnbvgehz7qinxnla.b32.i2p:0
+72yjs6mvlby3ky6mgpvvlemmwq5pfcznrzd34jkhclgrishqdxva.b32.i2p:0
+7r4ri53lby2i3xqbgpw3idvhzeku7ubhftlf72ldqkg5kde6dauq.b32.i2p:0
a5qsnv3maw77mlmmzlcglu6twje6ttctd3fhpbfwcbpmewx6fczq.b32.i2p:0
-bitcornrd36coazsbzsz4pdebyzvaplmsalq4kpoljmn6cg6x5zq.b32.i2p:0
+aovep2pco7v2k4rheofrgytbgk23eg22dczpsjqgqtxcqqvmxk6a.b32.i2p:0
+bddbsmkas3z6fakorbkfjhv77i4hv6rysyjsvrdjukxolfghc23q.b32.i2p:0
+bitcoi656nll5hu6u7ddzrmzysdtwtnzcnrjd4rfdqbeey7dmn5a.b32.i2p:0
+brifkruhlkgrj65hffybrjrjqcgdgqs2r7siizb5b2232nruik3a.b32.i2p:0
c4gfnttsuwqomiygupdqqqyy5y5emnk5c73hrfvatri67prd7vyq.b32.i2p:0
-dhtq2p76tyhi442aidb3vd2bv7yxxjuddpb2jydnnrl2ons5bhha.b32.i2p:0
+day3hgxyrtwjslt54sikevbhxxs4qzo7d6vi72ipmscqtq3qmijq.b32.i2p:0
+di2zq6fr3fegf2jdcd7hdwyql4umr462gonsns2nxz5qg5vz4bka.b32.i2p:0
+e55k6wu46rzp4pg5pk5npgbr3zz45bc3ihtzu2xcye5vwnzdy7pq.b32.i2p:0
+eciohu5nq7vsvwjjc52epskuk75d24iccgzmhbzrwonw6lx4gdva.b32.i2p:0
+ejlnngarmhqvune74ko7kk55xtgbz5i5ncs4vmnvjpy3l7y63xaa.b32.i2p:0
+g47cqoppu26pr4n2cfaioqx7lbdi7mea7yqhlrkdz3wjwxjxdh2a.b32.i2p:0
h3r6bkn46qxftwja53pxiykntegfyfjqtnzbm6iv6r5mungmqgmq.b32.i2p:0
-hnbbyjpxx54623l555sta7pocy3se4sdgmuebi5k6reesz5rjp6q.b32.i2p:0
+hhfi4yqkg2twqiwezrfksftjjofbyx3ojkmlnfmcwntgnrjjhkya.b32.i2p:0
+hpiibrflqkbrcshfhmrtwfyeb7mds7a3obzwrgarejevddzamvsq.b32.i2p:0
+i4pyhsfdq4247dunel7paatdaq5gusi2hnybp2yf5wxwdnrgxaqq.b32.i2p:0
+iw6tgpmbdykffceku5da6nzf2bmz66fvp5fpcvemfu3df6aq6pga.b32.i2p:0
+jkfuajo4ayvo2rbv5qdj443q6adqmnormbhsf2f7rlp5t24xomda.b32.i2p:0
jz3s4eurm5vzjresf4mwo7oni4bk36daolwxh4iqtewakylgkxmq.b32.i2p:0
-kokkmpquqlkptu5hkmzqlttsmtwxicldr4so7wqsufk6bwf32nma.b32.i2p:0
+liu75cvktv4icbctg72w7nxbk4eibt7wamizfdii4omz7gcke5vq.b32.i2p:0
+ljsquuu3y4xje6l32p32inn6r2y6ull6oocgup6jtjrohrqxbz6a.b32.i2p:0
+lrah7acdsgopybg43shadwwiv6igezaw64i6jb5muqdg7dmhj3la.b32.i2p:0
+lzuu6mjtu7vd55d2biphicihufipoa7vyym6xfnkmmlra3tiziia.b32.i2p:0
+m6bpynxkv2ktwxkg6p2gyudjfhdupb6kuzabeqdnckkdkf4kxjla.b32.i2p:0
+m6v454xd6p3bt5swujgmveklsp7lzbkqlqqfc2p36cjlwv5dbucq.b32.i2p:0
+mlgeizrroynuhpxbzeosajt5u4ddcvynxfmcbm6kwjpaufilxigq.b32.i2p:0
+ofubxr2ir7u2guzjwyrvujicivzmvinwa36nuzlrg7tnsmebal7a.b32.i2p:0
+okfxeoh6itu4f5f43dhbzvkqwfrvm5c66lj6lvjj4q2b35i4pk4q.b32.i2p:0
+oz2ia3flpm3du2tyusulrn7h7e2eo3juzkrmn34bvnrlcrugv7ia.b32.i2p:0
+qd6jlsevsexww3wefpqs7iglxb3f63y4e6ydulfzrvwflpicmdqa.b32.i2p:0
+qddg7myylinn4tw6kdjmmp6fsyetkosnrbp2gsjx77tmkqyqv6ua.b32.i2p:0
+rizfinyses2r3or4iubs5wx66gdy6mpf73w7uobfacm2l5cral3q.b32.i2p:0
+s5hhjtmlg53bko3nwwskas7xgsmeqzy6thtsj5aa64djyrljgqaq.b32.i2p:0
sedndhv5vpcgdmykyi5st4yqhdxl3hpdtglta4do435wupahhx6q.b32.i2p:0
+tsl4dlpu2id252b6crbdnblruct664se6f2iw35fuqwa3te7wcoq.b32.i2p:0
+tugq6wa2ls2bv27pr2iy3da3k5ow3fzefbcvjcr22uc7w5vmevja.b32.i2p:0
+usztavbib756k5vqggzgkyswoj6mttihjvp3c2pa642t2mb4pvsa.b32.i2p:0
+vgu6llqbyjphml25umd5ztvyxrxuplz2g74fzbx75g3kkaetoyiq.b32.i2p:0
+wjrul5jwwb4vqdmkkrjbmly7osj6amecdpsac5xvaoqrti4nb3ha.b32.i2p:0
+wvktcp7hy4l6immhi5cxyz2dlsbhhvtcmskjemrnqehacnoap23q.b32.i2p:0
wwbw7nqr3ahkqv62cuqfwgtneekvvpnuc4i4f6yo7tpoqjswvcwa.b32.i2p:0
+xlqndzjoe5nr2nsxo6xwibh44ghyz4jfqevu62xykvemextpmjbq.b32.i2p:0
+yc4xwin5ujenvcr6ynwkz7lnmmq3nmzxvfguele6ovqqpxgjvonq.b32.i2p:0
+zdoabsg7ugzothyawodjhq54nvlofa746rxfkxpnjzj6nukmha6a.b32.i2p:0
zsxwyo6qcn3chqzwxnseusqgsnuw3maqnztkiypyfxtya4snkoka.b32.i2p:0
+zysrlpii5ftrzivfcyhdrwpeyyqddbrdefnfu5q6otk5gtugmh2a.b32.i2p:0
# manually added 2022-01 for minimal cjdns bootstrap support
[fc32:17ea:e415:c3bf:9808:149d:b5a2:c9aa]:8333
diff --git a/contrib/seeds/nodes_test.txt b/contrib/seeds/nodes_test.txt
index 118bec280e..5b04791d60 100644
--- a/contrib/seeds/nodes_test.txt
+++ b/contrib/seeds/nodes_test.txt
@@ -1,16 +1,89 @@
# List of fixed seed nodes for testnet
-# Onion nodes
-35k2va6vyw4oo5ly2quvcszgdqr56kcnfgcqpnpcffut4jn3mhhwgbid.onion:18333
-blo2esfvk2rr7sr4jspmu3vt2vpgr5rigflsj645fnku7v4qmljurtid.onion:18333
-fuckcswupr5rmlvx2kqqrrosxvjyong4hatmuvxsvtcwe4dsh5rus7qd.onion:18333
-gblylyacjlitd2ywdmo2qqylwtdky7kgeqfvlhiw4zdag4x62tx54hyd.onion:18333
-gzwpduv33l7yze3bcdzj3inebiyjwddjnwvnjhh5wvnv4me76mjt2kad.onion:18333
-h3rphzofxzq52tb63mg5f6kc4my3fkcrgh3m5qryeatts43iljbawiid.onion:18333
-kf4qlhek34b3kgyxyodlmvgm4bxfrjsbjtgayyaiuyhr2eoyfgtm3bad.onion:18333
+# Onion nodes, last verified 2022-08 for minimal torv3 bootstrap support
+24j74ahq6ed4wmfrghdwroyfzimlkhnrb7zh4zw3vl2allzxbjrhaqid.onion:18333
+2fy74te65gm3c3gv3u5mhwdudvbdfh6k5fdz4gduimrltjjrxftbxrqd.onion:18333
+2lsncqdflwk272dhydrxf7ikfy23ppnmm54dnynyxiym6lqf3wowrmqd.onion:18333
+33o6qaidta7s2pmltet6vynd337vamgcifhh44rehwwxqpflcjt2njid.onion:18333
+3oo6bsc5mvf6a6ypmoaikilta6ka7mbdhdwhrnqhuhjlbaxyedvfvaqd.onion:18333
+3pe3fyklipy4sppkkgnhc22kcxtt57uler5kv72t676bbrwmcseo5qad.onion:18333
+4u4mcz2sfvxs7pwcwncswgmmcdzqtzjx7ztfo332jv4pqucb22ikdhad.onion:18333
+5v3i2kfqiqwp75gznjoptss7qgrcgseceqxpzpqkd34qeqzrg726i7id.onion:18333
+5zlrxk6q24t4vz5k4ie7gtuasdjavhoelhinzimxbfhc77u7vafipsid.onion:18333
+67s3af64ehw7xnxv422axm7tns4d6kutrftc6bjq375n74q3kj4pp7ad.onion:18333
+6a4ony53julvnufo632ktgmwvhupz63wbdwx7n7qudjy32qyq6gm3bqd.onion:18333
+6ftyg3nhc6tn2hyzls6zfdsfbroczhkxtdqumqb5q4yafhy5rdpapbid.onion:18333
+7554uw5djruh34j5ddx3iprzgqgzypcjtptwoldymfbgoywqcw2wiwyd.onion:18333
+766lozlabxaqjpbqsvt6sn3c65n6gkwwhoxyvggj7nfwnmw4cpaoccad.onion:18333
+7blv5abnytdf47yvbhxmykprmvjryqob65i2jmdwq3rrajcn2iiysbqd.onion:18333
+7v2ja4igx4v5y2jr6jrr6gaxohjhlzhvgwe4avlraxchozf7ea3kruqd.onion:18333
+7zgbmtzxow2oevd5aaqtsormw7ujv4zprl3oi2355immhq4gk7cyw5ad.onion:18333
+adstabjz7ec2y3jt4w2dvummowzv7g6m2f3kajeejffuaz7ojwj6epqd.onion:18333
+aesy6tfufadkut6flu2bsqgnw2422ur2ynjalguxlzuzuktg3zehttqd.onion:18333
+alxo32b5edi3bn2e224qrgytgxxpic4knyipvpdvctfsrvcaiq5lgeyd.onion:18333
+aoeart34umoonvd2kbqr3bc4sweu6a4msh2gp4skyqvei3shzcxbgmyd.onion:18333
+aprzvj7hgctsde4mkj3ewq35gvykspjvkqiygg7bpnw5tkvse2n7rhid.onion:18333
+awpk6z3xghx6ozouhodcydaqtr6uzzbnw4creuix7mkupxoxlmhhspad.onion:18333
+ayynqazucyh2jd5rehcfggmhunqpdwzlbhzbqgy6lj4ctz2ocj7chpid.onion:18333
+b2ika53aqckv4gs7wmog3byrea2vfzm5p7ye33digcsmvvnpbyqmzoyd.onion:18333
+be7zx3hh6dlahorlvsrrgqm4oahfrgqm2tbwnbd4u53ntu5f765n6hyd.onion:18333
+bluk62wj24bsvdwh47muo54hhwsatkftiqxevt5kba7hstjoex6ueeyd.onion:18333
+bubm6fiopfzkxqrfx6vqpioe5ahlhyubz57ogsqqy4ha5pnngiqlh6id.onion:18333
+d3czabzjj57lgrsr5gawkjd7v3gznrqa7zyizqmk4lryascavmipnyad.onion:18333
+ddj4cuvb32ve5chtp6jattcdnnmxmpoofjthzi7thgxxht7yqoetj3yd.onion:18333
+dqhhlssfwmh3g6zhwxpcfbw64xz5rfikcglinbhoxv5ajv4qzicjyeid.onion:18333
+drthcyb4x4rdfekw5g7xjogxi7aqoluilgulbgwvsme3nw3oibvchbad.onion:18333
+dwb47cmqa2tjpmvjaear7gdcars2lez6niefhi4qf22qehtyta6577qd.onion:18333
+e7tkrf54ng3q5vcn5gn77zwjwm74lkfav4mwdux3pvon6yvqg3tf46qd.onion:18333
+etuymy47s3quepvdaoo72i5e5mc7uovrzu5m4jf5q6mwlwizoxy4xgid.onion:18333
+fbimesnyhzubbzqc3uaufzkbyfmnkxvypoxaveaub7rzpzh2foxrn2yd.onion:18333
+fzbrwmgwmko7quelrhfuskt3ijabac76zx7g52dfrevmhdkj6ivh7qyd.onion:18333
+gy6nih4pmp5esyvvnhlj6qvk7zkbjuoswkxffyiip3dbkvsfxwz5zcqd.onion:18333
+ha62ziqzqdogd75zg7lfh4fqrg3bim3cpqzyupo43w5pw4fen6nr2pyd.onion:18333
+hacjjgj2mbqqrthzimmi6anvin7dljjhfl3ik6ebg3w3nmgsvr3ymmqd.onion:18333
+hbkp5xwpqo4qm75kpglfrclyiuuvdgv7mtiqfys7oqks4dmpqgpeoeid.onion:18333
+hqgoy62hoqjmz37brdfvoeov3cix5fixbqjoert4ydr6herg5oc3iwyd.onion:18333
+hvbmmzvqrpgps2x5u4ip4ksf3e5m2fneac754gtnhjn2rsevni6cz3ad.onion:18333
+hw3vzp32w4h6giplue6ix445oi6wt7gmeksrznb7tdfwhkgit7gnbbad.onion:18333
+iddr66ewkhenivapgianudjkwqcp6dxtssg7ixrdot5az6uh7m5tmjqd.onion:18333
+imya36iexiiiqrkwuxxcehnv4kg5shtirwd2vg4cnjy6lfjlph3fusqd.onion:18333
+iuhhuocns7entrzlxsxktyz2ibs7hqgiggv6sauzqkzka6laslwz7oqd.onion:18333
+ji5wmshokuc63eiulzlwj2zdvnligvrwfvvc76bice3tu43wfzvpmkyd.onion:18333
+jjfuyj7krgzkmpxvn3b2j2hwlzkmze3ezy3ifwk7dnswwawgmzqhjrqd.onion:18333
+jn2p4sgfphkxpow7kjrubrbqat77kkibzqkvuwhxyalcrazwmcqeaqyd.onion:18333
+jrveyz4us6sog6e6czsvr5mvvhgzjgv4idbe4idrolmqeudvt5a2dgid.onion:18333
+jsc4frvvnl2d3bhzyofsc72xpztgm23nl4fnb4dwkzsxr6fhij2q5iyd.onion:18333
+klymxdvje7kccv3tznabo3udopsftkmjemkbi2urqxjm4hefaudejjyd.onion:18333
+kwjxlauwjtecjfsiwopbl5pvn5n6z5rz76uk6osmlurd3uyuymcw7aid.onion:18333
+lc7upz2srw2yhpcvwg4afy64ylcoo6mfwlttqj5ovuglqnhnohpi5iqd.onion:18333
+lf3mpxfyjuovcqdvinl52pvdmmda6xqyfeiarlfamdjpgy3ouzmmlbyd.onion:18333
mc7k47ndjvvhcgs54wmjzxvate4rtuybbjoryikdssjhcxlx27psbyqd.onion:18333
-mrhiniicugfo7mgrwv3wtolk3tptlcw2uq7ih6sq43fa4k4zbilut3yd.onion:18333
-uiudyws3qizgmepfoh7wwjmsoxoxut4qrmotjjhrn247xnjopr7sfcid.onion:18333
-zc2wvoqcezcrf64trji6jmhtss34a5ds5ntzdhqegzvex3ynrd7nxcad.onion:18333
-zd5m3dgdn46naj36pxvvcalfw2paecle6sdxq64ptwxtxjomkywpklqd.onion:18333
-
+mjbg3ggeuelmc7ixty3zjccyo2urg2uyherfqe7ytkm2ejkwlec7h6ad.onion:18333
+nkyqozv6kdwi423s7s2mezzguf5bafot2a3hv4ed2dbvtblisdmad4qd.onion:18333
+nvvqo4xxiwgb3y246jmcbuuveurfdq2zs3a5y7veqkeqv5jfhang7gyd.onion:18333
+o6vfovqxz3oxszfppczpjejwouobztjrgvfojc3emvhan3bkyskzhuad.onion:18333
+oaiw2lnhzgp5ry7ivzneuufmh7lfploquu2rjv5rozmlbefedsnxe5qd.onion:18333
+oln7ybci53wk4g5n42nipyixvyjxbludsbrfsmhnirb6tk7ovlikd5id.onion:18333
+otmfnhc6wrrbf2tpdy6zkisqc3r3urnsuowsnmatoto6yixaocnkseid.onion:18333
+ovc6sajbqfcbwv3wrq7ylklu6q6prvisz4jr4lyycn4kgukzjfe4mjad.onion:18333
+pm57didyzg5ljuvn5ufr5uun2iencuk3af2gzqc5zvgfh452c3rxtjyd.onion:18333
+pmismhpwug34gnqzbutranvx2wjwbshyqj4un2dyzyuvak2eh55psfyd.onion:18333
+polarisultijjhaku6z6u7jyboho5epdsg44ttebfaxmgau2z5sqolad.onion:18333
+qe2jbe447he6panfvpyqhyntf7346gmuf55bxrmdzggmgwyjsyknhxyd.onion:18333
+qz6yd5lsgdajcteoareeptwnipxsezyx5kks6ukpk5tvqinffzunqmyd.onion:18333
+rp6pn3b3oesyr2giolbysbjhqeugxntsu7crnkth4y33ok4zvcl7yrqd.onion:18333
+ujdchuw3hz5gkbouiv4p6pwbfdn7v4k6gluwvd4wiukqc7y7ow754uad.onion:18333
+vctlwaqgmu53eutz2hewuakcipfgtyljsd7czut4dd62xr3rp6fqezad.onion:18333
+vf5ur53tzmdtotvkndcgochklnuav7quqjvkc6mctqfvef6wnmn26mid.onion:18333
+wnxgjgjgplv5iu4mssyuunycvku4qnqr5t4q6cfdt47k7uwrfifuirad.onion:18333
+wpkbkdr7clw7zk3jkwiult6bf422j54u77ml4rgig2xq7icogyrcspid.onion:18333
+wzpdt24tdark26eugredddorik3tqwcj5ialtt2yim4ceiuiq7phkyqd.onion:18333
+xgapnikkbldoggjh5ewxkyauhuwnvf3xkspxroe3ojvfrk4lswkyx5yd.onion:18333
+xkvzdhcirontixbq6pjhru57bf4sgtqylvphk25csfrsy5p5ay3oc3yd.onion:18333
+xnipauenw5wnjb2zbx6v6umgvbb3g6xhf5kjo7pnyn5tdzvzaxtzicid.onion:18333
+yda7kwpii33j2qpq32ftf6lp22znknswipjwaccvsqj7l337jvfesnid.onion:18333
+z3j5foswuhpmtrg3kb56stkzmuoaesvd5jz3eztq46c4cidapglcyuad.onion:18333
+zcep44k7unwjm2wxty4ijh2e4fv5zgbrvwlctzyaqnrqhltjfzrtodad.onion:18333
+zmvizz7fd5hdue6wt3lwqumd6qwt4ijymmmotfzh75curq3mzjm53hyd.onion:18333
+zoaa3x7quyuijggii5zl4uyeioodudsgtr2uyv2qtdsslac5ukiwlxid.onion:18333
+zovauxlorl5eswumbsoxv2m5y3sm3qlk7657dcpr2uld7xf35en46sqd.onion:18333
diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk
index e854843dab..d9ae918d71 100644
--- a/depends/packages/qt.mk
+++ b/depends/packages/qt.mk
@@ -56,6 +56,7 @@ $(package)_config_opts += -no-linuxfb
$(package)_config_opts += -no-libjpeg
$(package)_config_opts += -no-libproxy
$(package)_config_opts += -no-libudev
+$(package)_config_opts += -no-mimetype-database
$(package)_config_opts += -no-mtdev
$(package)_config_opts += -no-openssl
$(package)_config_opts += -no-openvg
diff --git a/doc/README.md b/doc/README.md
index 31c95afab0..c570432aa4 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -53,7 +53,6 @@ The Bitcoin repo's [root README](/README.md) contains relevant information on th
- [Developer Notes](developer-notes.md)
- [Productivity Notes](productivity.md)
-- [Release Notes](release-notes.md)
- [Release Process](release-process.md)
- [Source Code Documentation (External Link)](https://doxygen.bitcoincore.org/)
- [Translation Process](translation_process.md)
diff --git a/doc/build-osx.md b/doc/build-osx.md
index fdf0a9d414..f11ed97e09 100644
--- a/doc/build-osx.md
+++ b/doc/build-osx.md
@@ -96,14 +96,6 @@ Skip if you don't intend to use the GUI.
brew install qt@5
```
-Ensure that the `qt@5` package is installed, not the `qt` package.
-If 'qt' is installed, the build process will fail.
-if installed, remove the `qt` package with the following command:
-
-``` bash
-brew uninstall qt
-```
-
Note: Building with Qt binaries downloaded from the Qt website is not officially supported.
See the notes in [#7714](https://github.com/bitcoin/bitcoin/issues/7714).
diff --git a/doc/descriptors.md b/doc/descriptors.md
index 60cc36db07..69a5ee2715 100644
--- a/doc/descriptors.md
+++ b/doc/descriptors.md
@@ -11,13 +11,16 @@ Supporting RPCs are:
addresses.
- `listunspent` outputs a specialized descriptor for the reported unspent outputs.
- `getaddressinfo` outputs a descriptor for solvable addresses (since v0.18).
-- `importmulti` takes as input descriptors to import into the wallet
+- `importmulti` takes as input descriptors to import into a legacy wallet
(since v0.18).
- `generatetodescriptor` takes as input a descriptor and generates coins to it
(`regtest` only, since v0.19).
- `utxoupdatepsbt` takes as input descriptors to add information to the psbt
(since v0.19).
-- `createmultisig` and `addmultisigaddress` return descriptors as well (since v0.20)
+- `createmultisig` and `addmultisigaddress` return descriptors as well (since v0.20).
+- `importdescriptors` takes as input descriptors to import into a descriptor wallet
+ (since v0.21).
+- `listdescriptors` outputs descriptors imported into a descriptor wallet (since v22).
This document describes the language. For the specifics on usage, see the RPC
documentation for the functions mentioned above.
diff --git a/doc/design/assumeutxo.md b/doc/design/assumeutxo.md
index 2726cf779b..c353c78ff8 100644
--- a/doc/design/assumeutxo.md
+++ b/doc/design/assumeutxo.md
@@ -41,7 +41,7 @@ be of use.
Chainstate within the system goes through a number of phases when UTXO snapshots are
used, as managed by `ChainstateManager`. At various points there can be multiple
-`CChainState` objects in existence to facilitate both maintaining the network tip and
+`Chainstate` objects in existence to facilitate both maintaining the network tip and
performing historical validation of the assumed-valid chain.
It is worth noting that though there are multiple separate chainstates, those
@@ -53,7 +53,7 @@ data.
### "Normal" operation via initial block download
-`ChainstateManager` manages a single CChainState object, for which
+`ChainstateManager` manages a single Chainstate object, for which
`m_snapshot_blockhash` is null. This chainstate is (maybe obviously)
considered active. This is the "traditional" mode of operation for bitcoind.
diff --git a/doc/developer-notes.md b/doc/developer-notes.md
index 1aa4e4d690..00c68911ef 100644
--- a/doc/developer-notes.md
+++ b/doc/developer-notes.md
@@ -386,8 +386,10 @@ Run configure with the `--enable-gprof` option, then make.
If the code is behaving strangely, take a look in the `debug.log` file in the data directory;
error and debugging messages are written there.
-The `-debug=...` command-line option controls debugging; running with just `-debug` or `-debug=1` will turn
-on all categories (and give you a very large `debug.log` file).
+Debug logging can be enabled on startup with the `-debug` and `-loglevel`
+configuration options and toggled while bitcoind is running with the `logging`
+RPC. For instance, launching bitcoind with `-debug` or `-debug=1` will turn on
+all log categories and `-loglevel=trace` will turn on all log severity levels.
The Qt code routes `qDebug()` output to `debug.log` under category "qt": run with `-debug=qt`
to see it.
@@ -960,7 +962,7 @@ void CTxMemPool::UpdateTransactionsFromBlock(...)
```C++
// validation.h
-class CChainState
+class Chainstate
{
protected:
...
@@ -981,7 +983,7 @@ public:
}
// validation.cpp
-bool CChainState::PreciousBlock(BlockValidationState& state, CBlockIndex* pindex)
+bool Chainstate::PreciousBlock(BlockValidationState& state, CBlockIndex* pindex)
{
AssertLockNotHeld(m_chainstate_mutex);
AssertLockNotHeld(::cs_main);
diff --git a/doc/i2p.md b/doc/i2p.md
index 39f65c4e5f..1599c2fe0f 100644
--- a/doc/i2p.md
+++ b/doc/i2p.md
@@ -47,9 +47,26 @@ In a typical situation, this suffices:
bitcoind -i2psam=127.0.0.1:7656
```
-The first time Bitcoin Core connects to the I2P router, its I2P address (and
-corresponding private key) will be automatically generated and saved in a file
-named `i2p_private_key` in the Bitcoin Core data directory.
+The first time Bitcoin Core connects to the I2P router, if
+`-i2pacceptincoming=1`, then it will automatically generate a persistent I2P
+address and its corresponding private key. The private key will be saved in a
+file named `i2p_private_key` in the Bitcoin Core data directory. The persistent
+I2P address is used for accepting incoming connections and for making outgoing
+connections if `-i2pacceptincoming=1`. If `-i2pacceptincoming=0` then only
+outbound I2P connections are made and a different transient I2P address is used
+for each connection to improve privacy.
+
+## Persistent vs transient I2P addresses
+
+In I2P connections, the connection receiver sees the I2P address of the
+connection initiator. This is unlike the Tor network where the recipient does
+not know who is connecting to them and can't tell if two connections are from
+the same peer or not.
+
+If an I2P node is not accepting incoming connections, then Bitcoin Core uses
+random, one-time, transient I2P addresses for itself for outbound connections
+to make it harder to discriminate, fingerprint or analyze it based on its I2P
+address.
## Additional configuration options related to I2P
@@ -85,7 +102,8 @@ one of the networks has issues.
## I2P-related information in Bitcoin Core
-There are several ways to see your I2P address in Bitcoin Core:
+There are several ways to see your I2P address in Bitcoin Core if accepting
+incoming I2P connections (`-i2pacceptincoming`):
- in the "Local addresses" output of CLI `-netinfo`
- in the "localaddresses" output of RPC `getnetworkinfo`
- in the debug log (grep for `AddLocal`; the I2P address ends in `.b32.i2p`)
diff --git a/doc/managing-wallets.md b/doc/managing-wallets.md
index 6c1e13c503..366d7ec54b 100644
--- a/doc/managing-wallets.md
+++ b/doc/managing-wallets.md
@@ -120,4 +120,29 @@ After that, `getwalletinfo` can be used to check if the wallet has been fully re
$ bitcoin-cli -rpcwallet="restored-wallet" getwalletinfo
```
-The restored wallet can also be loaded in the GUI via `File` ->`Open wallet`. \ No newline at end of file
+The restored wallet can also be loaded in the GUI via `File` ->`Open wallet`.
+
+## Migrating Legacy Wallets to Descriptor Wallets
+
+Legacy wallets (traditional non-descriptor wallets) can be migrated to become Descriptor wallets
+through the use of the `migratewallet` RPC. Migrated wallets will have all of their addresses and private keys added to
+a newly created Descriptor wallet that has the same name as the original wallet. Because Descriptor
+wallets do not support having private keys and watch-only scripts, there may be up to two
+additional wallets created after migration. In addition to a descriptor wallet of the same name,
+there may also be a wallet named `<name>_watchonly` and `<name>_solvables`. `<name>_watchonly`
+contains all of the watchonly scripts. `<name>_solvables` contains any scripts which the wallet
+knows but is not watching the corresponding P2(W)SH scripts.
+
+Migrated wallets will also generate new addresses differently. While the same BIP 32 seed will be
+used, the BIP 44, 49, 84, and 86 standard derivation paths will be used. After migrating, a new
+backup of the wallet(s) will need to be created.
+
+Given that there is an extremely large number of possible configurations for the scripts that
+Legacy wallets can know about, be watching for, and be able to sign for, `migratewallet` only
+makes a best effort attempt to capture all of these things into Descriptor wallets. There may be
+unforeseen configurations which result in some scripts being excluded. If a migration fails
+unexpectedly or otherwise misses any scripts, please create an issue on GitHub. A backup of the
+original wallet can be found in the wallet directory with the name `<name>-<timestamp>.legacy.bak`.
+
+The backup can be restored using the `restorewallet` command as discussed in the
+[Restoring the Wallet From a Backup](#16-restoring-the-wallet-from-a-backup) section
diff --git a/doc/release-notes-15936.md b/doc/release-notes-15936.md
deleted file mode 100644
index 90c0413b9a..0000000000
--- a/doc/release-notes-15936.md
+++ /dev/null
@@ -1,15 +0,0 @@
-GUI changes
------------
-
-Configuration changes made in the bitcoin GUI (such as the pruning setting,
-proxy settings, UPNP preferences) are now saved to `<datadir>/settings.json`
-file rather than to the Qt settings backend (windows registry or unix desktop
-config files), so these settings will now apply to bitcoind, instead of being
-ignored.
-
-Also, the interaction between GUI settings and `bitcoin.conf` settings is
-simplified. Settings from `bitcoin.conf` are now displayed normally in the GUI
-settings dialog, instead of in a separate warning message ("Options set in this
-dialog are overridden by the configuration file: -setting=value"). And these
-settings can now be edited because `settings.json` values take precedence over
-`bitcoin.conf` values.
diff --git a/doc/release-notes-24098.md b/doc/release-notes-24098.md
deleted file mode 100644
index 79e047e9a5..0000000000
--- a/doc/release-notes-24098.md
+++ /dev/null
@@ -1,22 +0,0 @@
-Notable changes
-===============
-
-Updated REST APIs
------------------
-
-- The `/headers/` and `/blockfilterheaders/` endpoints have been updated to use
- a query parameter instead of path parameter to specify the result count. The
- count parameter is now optional, and defaults to 5 for both endpoints. The old
- endpoints are still functional, and have no documented behaviour change.
-
- For `/headers`, use
- `GET /rest/headers/<BLOCK-HASH>.<bin|hex|json>?count=<COUNT=5>`
- instead of
- `GET /rest/headers/<COUNT>/<BLOCK-HASH>.<bin|hex|json>` (deprecated)
-
- For `/blockfilterheaders/`, use
- `GET /rest/blockfilterheaders/<FILTERTYPE>/<BLOCK-HASH>.<bin|hex|json>?count=<COUNT=5>`
- instead of
- `GET /rest/blockfilterheaders/<FILTERTYPE>/<COUNT>/<BLOCK-HASH>.<bin|hex|json>` (deprecated)
-
- (#24098)
diff --git a/doc/release-notes-24118.md b/doc/release-notes-24118.md
deleted file mode 100644
index 16f23c7d00..0000000000
--- a/doc/release-notes-24118.md
+++ /dev/null
@@ -1,10 +0,0 @@
-New RPCs
---------
-
-- The `sendall` RPC spends specific UTXOs to one or more recipients
- without creating change. By default, the `sendall` RPC will spend
- every UTXO in the wallet. `sendall` is useful to empty wallets or to
- create a changeless payment from select UTXOs. When creating a payment
- from a specific amount for which the recipient incurs the transaction
- fee, continue to use the `subtractfeefromamount` option via the
- `send`, `sendtoaddress`, or `sendmany` RPCs. (#24118)
diff --git a/doc/release-notes-24148.md b/doc/release-notes-24148.md
deleted file mode 100644
index f7a0fd6fa1..0000000000
--- a/doc/release-notes-24148.md
+++ /dev/null
@@ -1,23 +0,0 @@
-Notable changes
-===============
-
-Wallet
-------
-
-- The `wsh()` output descriptor was extended with Miniscript support. You can import Miniscript
- descriptors for P2WSH in a watchonly wallet to track coins, but you can't spend from them using
- the Bitcoin Core wallet yet.
- You can find more about Miniscript on the [reference website](https://bitcoin.sipa.be/miniscript/).
-
-
-Low-level changes
-=================
-
-RPC
----
-
-- The `deriveaddresses`, `getdescriptorinfo`, `importdescriptors` and `scantxoutset` commands now
- accept Miniscript expression within a `wsh()` descriptor.
-
-- The `getaddressinfo`, `decodescript`, `listdescriptors` and `listunspent` commands may now output
- a Miniscript descriptor inside a `wsh()` where a `wsh(raw())` descriptor was previously returned.
diff --git a/doc/release-notes-24198.md b/doc/release-notes-24198.md
deleted file mode 100644
index e41b2a8e26..0000000000
--- a/doc/release-notes-24198.md
+++ /dev/null
@@ -1,6 +0,0 @@
-Updated RPCs
-------------
-
-- The `listtransactions`, `gettransaction`, and `listsinceblock`
- RPC methods now include a wtxid field (hash of serialized transaction,
- including witness data) for each transaction. \ No newline at end of file
diff --git a/doc/release-notes-24494.md b/doc/release-notes-24494.md
deleted file mode 100644
index afbb926433..0000000000
--- a/doc/release-notes-24494.md
+++ /dev/null
@@ -1,2 +0,0 @@
-To help prevent fingerprinting transactions created by the Bitcoin Core wallet, change output
-amounts are now randomized. (#24494)
diff --git a/doc/release-notes-25504.md b/doc/release-notes-25504.md
deleted file mode 100644
index bf80f18031..0000000000
--- a/doc/release-notes-25504.md
+++ /dev/null
@@ -1,6 +0,0 @@
-Updated RPCs
-------------
-
-- The `listsinceblock`, `listtransactions` and `gettransaction` output now contain a new
- `parent_descs` field for every "receive" entry.
-- A new optional `include_change` parameter was added to the `listsinceblock` command.
diff --git a/doc/release-notes-25610.md b/doc/release-notes-25610.md
deleted file mode 100644
index 743a7709bf..0000000000
--- a/doc/release-notes-25610.md
+++ /dev/null
@@ -1,12 +0,0 @@
-Wallet
-------
-
-- The `-walletrbf` startup option will now default to `true`. The
- wallet will now default to opt-in RBF on transactions that it creates.
-
-Updated RPCs
-------------
-
-- The `replaceable` option for the `createrawtransaction` and
- `createpsbt` RPCs will now default to `true`. Transactions created
- with these RPCs will default to having opt-in RBF enabled.
diff --git a/doc/release-notes.md b/doc/release-notes.md
deleted file mode 100644
index 444926087b..0000000000
--- a/doc/release-notes.md
+++ /dev/null
@@ -1,124 +0,0 @@
-*The release notes draft is a temporary file that can be added to by anyone. See
-[/doc/developer-notes.md#release-notes](/doc/developer-notes.md#release-notes)
-for the process.*
-
-*version* Release Notes Draft
-===============================
-
-Bitcoin Core version *version* is now available from:
-
- <https://bitcoincore.org/bin/bitcoin-core-*version*/>
-
-This release includes new features, various bug fixes and performance
-improvements, as well as updated translations.
-
-Please report bugs using the issue tracker at GitHub:
-
- <https://github.com/bitcoin/bitcoin/issues>
-
-To receive security and update notifications, please subscribe to:
-
- <https://bitcoincore.org/en/list/announcements/join/>
-
-How to Upgrade
-==============
-
-If you are running an older version, shut it down. Wait until it has completely
-shut down (which might take a few minutes in some cases), then run the
-installer (on Windows) or just copy over `/Applications/Bitcoin-Qt` (on Mac)
-or `bitcoind`/`bitcoin-qt` (on Linux).
-
-Upgrading directly from a version of Bitcoin Core that has reached its EOL is
-possible, but it might take some time if the data directory needs to be migrated. Old
-wallet versions of Bitcoin Core are generally supported.
-
-Compatibility
-==============
-
-Bitcoin Core is supported and extensively tested on operating systems
-using the Linux kernel, macOS 10.15+, and Windows 7 and newer. Bitcoin
-Core should also work on most other Unix-like systems but is not as
-frequently tested on them. It is not recommended to use Bitcoin Core on
-unsupported systems.
-
-Notable changes
-===============
-
-P2P and network changes
------------------------
-
-Updated RPCs
-------------
-
-- The `-deprecatedrpc=softforks` configuration option has been removed. The
- RPC `getblockchaininfo` no longer returns the `softforks` field, which was
- previously deprecated in 23.0. (#23508) Information on soft fork status is
- now only available via the `getdeploymentinfo` RPC.
-
-- The `deprecatedrpc=exclude_coinbase` configuration option has been removed.
- The `receivedby` RPCs (`listreceivedbyaddress`, `listreceivedbylabel`,
- `getreceivedbyaddress` and `getreceivedbylabel`) now always return results
- accounting for received coins from coinbase outputs, without an option to
- change that behaviour. Excluding coinbases was previously deprecated in 23.0.
- (#25171)
-
-- The `deprecatedrpc=fees` configuration option has been removed. The top-level
- fee fields `fee`, `modifiedfee`, `ancestorfees` and `descendantfees` are no
- longer returned by RPCs `getmempoolentry`, `getrawmempool(verbose=true)`,
- `getmempoolancestors(verbose=true)` and `getmempooldescendants(verbose=true)`.
- The same fee fields can be accessed through the `fees` object in the result.
- The top-level fee fields were previously deprecated in 23.0. (#25204)
-
-Changes to wallet related RPCs can be found in the Wallet section below.
-
-New RPCs
---------
-
-Build System
-------------
-
-Updated settings
-----------------
-
-
-Changes to GUI or wallet related settings can be found in the GUI or Wallet section below.
-
-New settings
-------------
-
-- A new `mempoolfullrbf` option has been added, which enables the mempool to
- accept transaction replacement without enforcing BIP125 replaceability
- signaling. (#25353)
-
-Tools and Utilities
--------------------
-
-Wallet
-------
-
-- RPC `getreceivedbylabel` now returns an error, "Label not found
- in wallet" (-4), if the label is not in the address book. (#25122)
-
-GUI changes
------------
-
-Low-level changes
-=================
-
-RPC
----
-
-Tests
------
-
-*version* change log
-====================
-
-Credits
-=======
-
-Thanks to everyone who directly contributed to this release:
-
-
-As well as to everyone that helped with translations on
-[Transifex](https://www.transifex.com/bitcoin/bitcoin/).
diff --git a/doc/release-notes/release-notes-24408.md b/doc/release-notes/release-notes-24408.md
deleted file mode 100644
index 1072ec786a..0000000000
--- a/doc/release-notes/release-notes-24408.md
+++ /dev/null
@@ -1,5 +0,0 @@
-New RPCs
---------
-
-- A new `gettxspendingprevout` RPC has been added, which scans the mempool to find
- transactions spending any of the given outpoints. (#24408) \ No newline at end of file
diff --git a/doc/release-notes/release-notes-471.md b/doc/release-notes/release-notes-471.md
deleted file mode 100644
index 7cebedd8b3..0000000000
--- a/doc/release-notes/release-notes-471.md
+++ /dev/null
@@ -1,4 +0,0 @@
-GUI changes
---------
-
-- A new menu item to restore a wallet from a backup file has been added (#471). \ No newline at end of file
diff --git a/src/.clang-tidy b/src/.clang-tidy
index f59f80f8ce..9d78ccc959 100644
--- a/src/.clang-tidy
+++ b/src/.clang-tidy
@@ -1,21 +1,28 @@
Checks: '
-*,
bugprone-argument-comment,
+bugprone-use-after-move,
misc-unused-using-decls,
modernize-use-default-member-init,
modernize-use-nullptr,
performance-for-range-copy,
+performance-move-const-arg,
performance-unnecessary-copy-initialization,
readability-redundant-declaration,
readability-redundant-string-init,
'
WarningsAsErrors: '
bugprone-argument-comment,
+bugprone-use-after-move,
misc-unused-using-decls,
modernize-use-default-member-init,
modernize-use-nullptr,
performance-for-range-copy,
+performance-move-const-arg,
performance-unnecessary-copy-initialization,
readability-redundant-declaration,
readability-redundant-string-init,
'
+CheckOptions:
+ - key: performance-move-const-arg.CheckTriviallyCopyableMove
+ value: false
diff --git a/src/Makefile.am b/src/Makefile.am
index 18c6c25b96..d5500b08a2 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -23,7 +23,7 @@ noinst_PROGRAMS =
TESTS =
BENCHMARKS =
-BITCOIN_INCLUDES=-I$(builddir) -I$(srcdir)/$(MINISKETCH_INCLUDE_DIR_INT) -I$(srcdir)/secp256k1/include -I$(srcdir)/$(UNIVALUE_INCLUDE_DIR_INT) $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS)
+BITCOIN_INCLUDES=-I$(builddir) -I$(srcdir)/$(MINISKETCH_INCLUDE_DIR_INT) -I$(srcdir)/secp256k1/include -I$(srcdir)/$(UNIVALUE_INCLUDE_DIR_INT) $(LEVELDB_CPPFLAGS)
LIBBITCOIN_NODE=libbitcoin_node.a
LIBBITCOIN_COMMON=libbitcoin_common.a
@@ -151,6 +151,7 @@ BITCOIN_CORE_H = \
external_signer.h \
flatfile.h \
fs.h \
+ headerssync.h \
httprpc.h \
httpserver.h \
i2p.h \
@@ -264,6 +265,7 @@ BITCOIN_CORE_H = \
undo.h \
util/asmap.h \
util/bip32.h \
+ util/bitdeque.h \
util/bytevectorhash.h \
util/check.h \
util/epochguard.h \
@@ -347,7 +349,7 @@ libbitcoin_util_a-clientversion.$(OBJEXT): obj/build.h
# Contains code accessing mempool and chain state that is meant to be separated
# from wallet and gui code (see node/README.md). Shared code should go in
# libbitcoin_common or libbitcoin_util libraries, instead.
-libbitcoin_node_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(MINIUPNPC_CPPFLAGS) $(NATPMP_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS)
+libbitcoin_node_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BOOST_CPPFLAGS) $(MINIUPNPC_CPPFLAGS) $(NATPMP_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS)
libbitcoin_node_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_node_a_SOURCES = \
addrdb.cpp \
@@ -360,6 +362,7 @@ libbitcoin_node_a_SOURCES = \
dbwrapper.cpp \
deploymentstatus.cpp \
flatfile.cpp \
+ headerssync.cpp \
httprpc.cpp \
httpserver.cpp \
i2p.cpp \
@@ -436,7 +439,7 @@ libbitcoin_node_a_SOURCES += dummywallet.cpp
endif
if ENABLE_ZMQ
-libbitcoin_zmq_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(ZMQ_CFLAGS)
+libbitcoin_zmq_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BOOST_CPPFLAGS) $(ZMQ_CFLAGS)
libbitcoin_zmq_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_zmq_a_SOURCES = \
zmq/zmqabstractnotifier.cpp \
@@ -449,7 +452,7 @@ endif
# wallet: shared between bitcoind and bitcoin-qt, but only linked
# when wallet enabled
-libbitcoin_wallet_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BDB_CPPFLAGS) $(SQLITE_CFLAGS)
+libbitcoin_wallet_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BOOST_CPPFLAGS) $(BDB_CPPFLAGS) $(SQLITE_CFLAGS)
libbitcoin_wallet_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_wallet_a_SOURCES = \
wallet/coincontrol.cpp \
@@ -488,7 +491,7 @@ if USE_BDB
libbitcoin_wallet_a_SOURCES += wallet/bdb.cpp wallet/salvage.cpp
endif
-libbitcoin_wallet_tool_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
+libbitcoin_wallet_tool_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BOOST_CPPFLAGS)
libbitcoin_wallet_tool_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_wallet_tool_a_SOURCES = \
wallet/wallettool.cpp \
@@ -652,7 +655,7 @@ libbitcoin_common_a_SOURCES = \
$(BITCOIN_CORE_H)
# util: shared between all executables.
-libbitcoin_util_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
+libbitcoin_util_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BOOST_CPPFLAGS)
libbitcoin_util_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_util_a_SOURCES = \
support/lockedpool.cpp \
@@ -769,7 +772,7 @@ bitcoin_cli_LDADD += $(EVENT_LIBS)
# bitcoin-tx binary #
bitcoin_tx_SOURCES = bitcoin-tx.cpp
-bitcoin_tx_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
+bitcoin_tx_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BOOST_CPPFLAGS)
bitcoin_tx_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
bitcoin_tx_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS)
@@ -830,7 +833,7 @@ bitcoin_util_LDADD = \
# bitcoin-chainstate binary #
bitcoin_chainstate_SOURCES = bitcoin-chainstate.cpp
-bitcoin_chainstate_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
+bitcoin_chainstate_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BOOST_CPPFLAGS)
bitcoin_chainstate_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
# $(LIBTOOL_APP_LDFLAGS) deliberately omitted here so that we can test linking
diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include
index a23d872250..3ed643d932 100644
--- a/src/Makefile.bench.include
+++ b/src/Makefile.bench.include
@@ -51,7 +51,7 @@ bench_bench_bitcoin_SOURCES = \
nodist_bench_bench_bitcoin_SOURCES = $(GENERATED_BENCH_FILES)
-bench_bench_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS) -I$(builddir)/bench/
+bench_bench_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BOOST_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS) -I$(builddir)/bench/
bench_bench_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
bench_bench_bitcoin_LDADD = \
$(LIBTEST_UTIL) \
diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include
index b4acc47aa1..602a118259 100644
--- a/src/Makefile.qt.include
+++ b/src/Makefile.qt.include
@@ -295,7 +295,7 @@ BITCOIN_QT_RC = qt/res/bitcoin-qt-res.rc
BITCOIN_QT_INCLUDES = -DQT_NO_KEYWORDS -DQT_USE_QSTRINGBUILDER
qt_libbitcoinqt_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \
- $(QT_INCLUDES) $(QT_DBUS_INCLUDES) $(QR_CFLAGS)
+ $(QT_INCLUDES) $(QT_DBUS_INCLUDES) $(QR_CFLAGS) $(BOOST_CPPFLAGS)
qt_libbitcoinqt_a_CXXFLAGS = $(AM_CXXFLAGS) $(QT_PIE_FLAGS)
qt_libbitcoinqt_a_OBJCXXFLAGS = $(AM_OBJCXXFLAGS) $(QT_PIE_FLAGS)
diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include
index fa822f2954..89c659d4b9 100644
--- a/src/Makefile.qttest.include
+++ b/src/Makefile.qttest.include
@@ -27,7 +27,7 @@ TEST_QT_H = \
qt/test/wallettests.h
qt_test_test_bitcoin_qt_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \
- $(QT_INCLUDES) $(QT_TEST_INCLUDES)
+ $(QT_INCLUDES) $(QT_TEST_INCLUDES) $(BOOST_CPPFLAGS)
qt_test_test_bitcoin_qt_SOURCES = \
init/bitcoin-qt.cpp \
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 22a95f9682..5f2e535e85 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -93,6 +93,7 @@ BITCOIN_TESTS =\
test/fs_tests.cpp \
test/getarg_tests.cpp \
test/hash_tests.cpp \
+ test/headers_sync_chainwork_tests.cpp \
test/httpserver_tests.cpp \
test/i2p_tests.cpp \
test/interfaces_tests.cpp \
@@ -173,7 +174,8 @@ BITCOIN_TESTS += \
wallet/test/availablecoins_tests.cpp \
wallet/test/init_tests.cpp \
wallet/test/ismine_tests.cpp \
- wallet/test/scriptpubkeyman_tests.cpp
+ wallet/test/scriptpubkeyman_tests.cpp \
+ wallet/test/walletload_tests.cpp
FUZZ_SUITE_LD_COMMON +=\
$(SQLITE_LIBS) \
@@ -201,7 +203,7 @@ BITCOIN_TEST_SUITE += \
endif # ENABLE_WALLET
test_test_bitcoin_SOURCES = $(BITCOIN_TEST_SUITE) $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES)
-test_test_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(TESTDEFS) $(EVENT_CFLAGS)
+test_test_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(TESTDEFS) $(BOOST_CPPFLAGS) $(EVENT_CFLAGS)
test_test_bitcoin_LDADD = $(LIBTEST_UTIL)
if ENABLE_WALLET
test_test_bitcoin_LDADD += $(LIBBITCOIN_WALLET)
@@ -221,7 +223,7 @@ FUZZ_SUITE_LD_COMMON += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS)
endif
if ENABLE_FUZZ_BINARY
-test_fuzz_fuzz_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
+test_fuzz_fuzz_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BOOST_CPPFLAGS)
test_fuzz_fuzz_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_fuzz_LDADD = $(FUZZ_SUITE_LD_COMMON)
test_fuzz_fuzz_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS) $(RUNTIME_LDFLAGS)
@@ -235,6 +237,7 @@ test_fuzz_fuzz_SOURCES = \
test/fuzz/banman.cpp \
test/fuzz/base_encode_decode.cpp \
test/fuzz/bech32.cpp \
+ test/fuzz/bitdeque.cpp \
test/fuzz/block.cpp \
test/fuzz/block_header.cpp \
test/fuzz/blockfilter.cpp \
diff --git a/src/Makefile.test_fuzz.include b/src/Makefile.test_fuzz.include
index b43816636f..11b5c12062 100644
--- a/src/Makefile.test_fuzz.include
+++ b/src/Makefile.test_fuzz.include
@@ -13,7 +13,7 @@ TEST_FUZZ_H = \
test/fuzz/mempool_utils.h \
test/fuzz/util.h
-libtest_fuzz_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(MINIUPNPC_CPPFLAGS) $(NATPMP_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS)
+libtest_fuzz_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BOOST_CPPFLAGS)
libtest_fuzz_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libtest_fuzz_a_SOURCES = \
test/fuzz/fuzz.cpp \
diff --git a/src/Makefile.test_util.include b/src/Makefile.test_util.include
index 9306bb6fcc..ada789f1b0 100644
--- a/src/Makefile.test_util.include
+++ b/src/Makefile.test_util.include
@@ -20,7 +20,7 @@ TEST_UTIL_H = \
test/util/validation.h \
test/util/wallet.h
-libtest_util_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(MINIUPNPC_CPPFLAGS) $(NATPMP_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS)
+libtest_util_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BOOST_CPPFLAGS)
libtest_util_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libtest_util_a_SOURCES = \
test/util/blockfilter.cpp \
diff --git a/src/addrdb.cpp b/src/addrdb.cpp
index 31f8eadf98..7106d819b0 100644
--- a/src/addrdb.cpp
+++ b/src/addrdb.cpp
@@ -187,11 +187,11 @@ std::optional<bilingual_str> LoadAddrman(const NetGroupManager& netgroupman, con
auto check_addrman = std::clamp<int32_t>(args.GetIntArg("-checkaddrman", DEFAULT_ADDRMAN_CONSISTENCY_CHECKS), 0, 1000000);
addrman = std::make_unique<AddrMan>(netgroupman, /*deterministic=*/false, /*consistency_check_ratio=*/check_addrman);
- int64_t nStart = GetTimeMillis();
+ const auto start{SteadyClock::now()};
const auto path_addr{args.GetDataDirNet() / "peers.dat"};
try {
DeserializeFileDB(path_addr, *addrman, CLIENT_VERSION);
- LogPrintf("Loaded %i addresses from peers.dat %dms\n", addrman->size(), GetTimeMillis() - nStart);
+ LogPrintf("Loaded %i addresses from peers.dat %dms\n", addrman->size(), Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
} catch (const DbNotFoundError&) {
// Addrman can be in an inconsistent state after failure, reset it
addrman = std::make_unique<AddrMan>(netgroupman, /*deterministic=*/false, /*consistency_check_ratio=*/check_addrman);
diff --git a/src/banman.cpp b/src/banman.cpp
index 508383d9f2..3cd646c148 100644
--- a/src/banman.cpp
+++ b/src/banman.cpp
@@ -31,12 +31,12 @@ void BanMan::LoadBanlist()
if (m_client_interface) m_client_interface->InitMessage(_("Loading banlist…").translated);
- int64_t n_start = GetTimeMillis();
+ const auto start{SteadyClock::now()};
if (m_ban_db.Read(m_banned)) {
SweepBanned(); // sweep out unused entries
LogPrint(BCLog::NET, "Loaded %d banned node addresses/subnets %dms\n", m_banned.size(),
- GetTimeMillis() - n_start);
+ Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
} else {
LogPrintf("Recreating the banlist database\n");
m_banned = {};
@@ -58,13 +58,13 @@ void BanMan::DumpBanlist()
SetBannedSetDirty(false);
}
- int64_t n_start = GetTimeMillis();
+ const auto start{SteadyClock::now()};
if (!m_ban_db.Write(banmap)) {
SetBannedSetDirty(true);
}
LogPrint(BCLog::NET, "Flushed %d banned node addresses/subnets to disk %dms\n", banmap.size(),
- GetTimeMillis() - n_start);
+ Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
}
void BanMan::ClearBanned()
diff --git a/src/bitcoin-chainstate.cpp b/src/bitcoin-chainstate.cpp
index 7312ae45d4..d972b71a65 100644
--- a/src/bitcoin-chainstate.cpp
+++ b/src/bitcoin-chainstate.cpp
@@ -104,7 +104,7 @@ int main(int argc, char* argv[])
}
}
- for (CChainState* chainstate : WITH_LOCK(::cs_main, return chainman.GetAll())) {
+ for (Chainstate* chainstate : WITH_LOCK(::cs_main, return chainman.GetAll())) {
BlockValidationState state;
if (!chainstate->ActivateBestChain(state, nullptr)) {
std::cerr << "Failed to connect best block (" << state.ToString() << ")" << std::endl;
@@ -195,7 +195,7 @@ int main(int argc, char* argv[])
bool new_block;
auto sc = std::make_shared<submitblock_StateCatcher>(block.GetHash());
RegisterSharedValidationInterface(sc);
- bool accepted = chainman.ProcessNewBlock(blockptr, /*force_processing=*/true, /*new_block=*/&new_block);
+ bool accepted = chainman.ProcessNewBlock(blockptr, /*force_processing=*/true, /*min_pow_checked=*/true, /*new_block=*/&new_block);
UnregisterSharedValidationInterface(sc);
if (!new_block && accepted) {
std::cerr << "duplicate" << std::endl;
@@ -210,6 +210,9 @@ int main(int argc, char* argv[])
case BlockValidationResult::BLOCK_RESULT_UNSET:
std::cerr << "initial value. Block has not yet been rejected" << std::endl;
break;
+ case BlockValidationResult::BLOCK_HEADER_LOW_WORK:
+ std::cerr << "the block header may be on a too-little-work chain" << std::endl;
+ break;
case BlockValidationResult::BLOCK_CONSENSUS:
std::cerr << "invalid by consensus rules (excluding any below reasons)" << std::endl;
break;
@@ -250,7 +253,7 @@ epilogue:
GetMainSignals().FlushBackgroundCallbacks();
{
LOCK(cs_main);
- for (CChainState* chainstate : chainman.GetAll()) {
+ for (Chainstate* chainstate : chainman.GetAll()) {
if (chainstate->CanFlushToDisk()) {
chainstate->ForceFlushStateToDisk();
chainstate->ResetCoinsViews();
diff --git a/src/blockfilter.cpp b/src/blockfilter.cpp
index 43d88df720..85929747be 100644
--- a/src/blockfilter.cpp
+++ b/src/blockfilter.cpp
@@ -3,7 +3,6 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <mutex>
-#include <sstream>
#include <set>
#include <blockfilter.h>
@@ -13,6 +12,7 @@
#include <script/script.h>
#include <streams.h>
#include <util/golombrice.h>
+#include <util/string.h>
/// SerType used to serialize parameters in GCS filter encoding.
static constexpr int GCS_SER_TYPE = SER_NETWORK;
@@ -179,19 +179,7 @@ const std::set<BlockFilterType>& AllBlockFilterTypes()
const std::string& ListBlockFilterTypes()
{
- static std::string type_list;
-
- static std::once_flag flag;
- std::call_once(flag, []() {
- std::stringstream ret;
- bool first = true;
- for (const auto& entry : g_filter_types) {
- if (!first) ret << ", ";
- ret << entry.second;
- first = false;
- }
- type_list = ret.str();
- });
+ static std::string type_list{Join(g_filter_types, ", ", [](const auto& entry) { return entry.second; })};
return type_list;
}
diff --git a/src/blockfilter.h b/src/blockfilter.h
index d6a51e95c2..0cb627d9df 100644
--- a/src/blockfilter.h
+++ b/src/blockfilter.h
@@ -11,6 +11,7 @@
#include <unordered_set>
#include <vector>
+#include <attributes.h>
#include <primitives/block.h>
#include <serialize.h>
#include <uint256.h>
@@ -65,8 +66,8 @@ public:
GCSFilter(const Params& params, const ElementSet& elements);
uint32_t GetN() const { return m_N; }
- const Params& GetParams() const { return m_params; }
- const std::vector<unsigned char>& GetEncoded() const { return m_encoded; }
+ const Params& GetParams() const LIFETIMEBOUND { return m_params; }
+ const std::vector<unsigned char>& GetEncoded() const LIFETIMEBOUND { return m_encoded; }
/**
* Checks if the element may be in the set. False positives are possible
@@ -128,10 +129,10 @@ public:
BlockFilter(BlockFilterType filter_type, const CBlock& block, const CBlockUndo& block_undo);
BlockFilterType GetFilterType() const { return m_filter_type; }
- const uint256& GetBlockHash() const { return m_block_hash; }
- const GCSFilter& GetFilter() const { return m_filter; }
+ const uint256& GetBlockHash() const LIFETIMEBOUND { return m_block_hash; }
+ const GCSFilter& GetFilter() const LIFETIMEBOUND { return m_filter; }
- const std::vector<unsigned char>& GetEncodedFilter() const
+ const std::vector<unsigned char>& GetEncodedFilter() const LIFETIMEBOUND
{
return m_filter.GetEncoded();
}
diff --git a/src/chain.cpp b/src/chain.cpp
index 446bb216c2..66a0830394 100644
--- a/src/chain.cpp
+++ b/src/chain.cpp
@@ -28,32 +28,33 @@ void CChain::SetTip(CBlockIndex& block)
}
}
-CBlockLocator CChain::GetLocator(const CBlockIndex *pindex) const {
- int nStep = 1;
- std::vector<uint256> vHave;
- vHave.reserve(32);
-
- if (!pindex)
- pindex = Tip();
- while (pindex) {
- vHave.push_back(pindex->GetBlockHash());
- // Stop when we have added the genesis block.
- if (pindex->nHeight == 0)
- break;
+std::vector<uint256> LocatorEntries(const CBlockIndex* index)
+{
+ int step = 1;
+ std::vector<uint256> have;
+ if (index == nullptr) return have;
+
+ have.reserve(32);
+ while (index) {
+ have.emplace_back(index->GetBlockHash());
+ if (index->nHeight == 0) break;
// Exponentially larger steps back, plus the genesis block.
- int nHeight = std::max(pindex->nHeight - nStep, 0);
- if (Contains(pindex)) {
- // Use O(1) CChain index if possible.
- pindex = (*this)[nHeight];
- } else {
- // Otherwise, use O(log n) skiplist.
- pindex = pindex->GetAncestor(nHeight);
- }
- if (vHave.size() > 10)
- nStep *= 2;
+ int height = std::max(index->nHeight - step, 0);
+ // Use skiplist.
+ index = index->GetAncestor(height);
+ if (have.size() > 10) step *= 2;
}
+ return have;
+}
- return CBlockLocator(vHave);
+CBlockLocator GetLocator(const CBlockIndex* index)
+{
+ return CBlockLocator{LocatorEntries(index)};
+}
+
+CBlockLocator CChain::GetLocator() const
+{
+ return ::GetLocator(Tip());
}
const CBlockIndex *CChain::FindFork(const CBlockIndex *pindex) const {
diff --git a/src/chain.h b/src/chain.h
index cc1d9e2d22..2d3b084b9b 100644
--- a/src/chain.h
+++ b/src/chain.h
@@ -473,8 +473,8 @@ public:
/** Set/initialize a chain with a given tip. */
void SetTip(CBlockIndex& block);
- /** Return a CBlockLocator that refers to a block in this chain (by default the tip). */
- CBlockLocator GetLocator(const CBlockIndex* pindex = nullptr) const;
+ /** Return a CBlockLocator that refers to the tip in of this chain. */
+ CBlockLocator GetLocator() const;
/** Find the last common block between this chain and a block index entry. */
const CBlockIndex* FindFork(const CBlockIndex* pindex) const;
@@ -483,4 +483,10 @@ public:
CBlockIndex* FindEarliestAtLeast(int64_t nTime, int height) const;
};
+/** Get a locator for a block index entry. */
+CBlockLocator GetLocator(const CBlockIndex* index);
+
+/** Construct a list of hash entries to put in a locator. */
+std::vector<uint256> LocatorEntries(const CBlockIndex* index);
+
#endif // BITCOIN_CHAIN_H
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index dd7b93234d..c6d4eee7b9 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -93,8 +93,8 @@ public:
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("0x00000000000000000000000000000000000000002927cdceccbd5209e81e80db");
- consensus.defaultAssumeValid = uint256S("0x000000000000000000052d314a259755ca65944e68df6b12a067ea8f1f5a7091"); // 724466
+ consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000003404ba0801921119f903495e");
+ consensus.defaultAssumeValid = uint256S("0x00000000000000000009c97098b5295f7e5f183ac811fb5d1534040adb93cabd"); // 751565
/**
* The message start string is designed to be unlikely to occur in normal data.
@@ -107,7 +107,7 @@ public:
pchMessageStart[3] = 0xd9;
nDefaultPort = 8333;
nPruneAfterHeight = 100000;
- m_assumed_blockchain_size = 460;
+ m_assumed_blockchain_size = 496;
m_assumed_chain_state_size = 6;
genesis = CreateGenesisBlock(1231006505, 2083236893, 0x1d00ffff, 1, 50 * COIN);
@@ -168,10 +168,10 @@ public:
};
chainTxData = ChainTxData{
- // Data from RPC: getchaintxstats 4096 000000000000000000052d314a259755ca65944e68df6b12a067ea8f1f5a7091
- /* nTime */ 1645542140,
- /* nTxCount */ 712531200,
- /* dTxRate */ 2.891036496010309,
+ // Data from RPC: getchaintxstats 4096 00000000000000000009c97098b5295f7e5f183ac811fb5d1534040adb93cabd
+ .nTime = 1661697692,
+ .nTxCount = 760120522,
+ .dTxRate = 2.925802860942233,
};
}
};
@@ -213,8 +213,8 @@ public:
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("0x00000000000000000000000000000000000000000000064728c7be6fe4b2f961");
- consensus.defaultAssumeValid = uint256S("0x00000000000163cfb1f97c4e4098a3692c8053ad9cab5ad9c86b338b5c00b8b7"); // 2143398
+ consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000000000076f6e7cbd0beade5d20");
+ consensus.defaultAssumeValid = uint256S("0x0000000000000004877fa2d36316398528de4f347df2f8a96f76613a298ce060"); // 2344474
pchMessageStart[0] = 0x0b;
pchMessageStart[1] = 0x11;
@@ -222,7 +222,7 @@ public:
pchMessageStart[3] = 0x07;
nDefaultPort = 18333;
nPruneAfterHeight = 1000;
- m_assumed_blockchain_size = 40;
+ m_assumed_blockchain_size = 42;
m_assumed_chain_state_size = 2;
genesis = CreateGenesisBlock(1296688602, 414098458, 0x1d00ffff, 1, 50 * COIN);
@@ -264,10 +264,10 @@ public:
};
chainTxData = ChainTxData{
- // Data from RPC: getchaintxstats 4096 00000000d18cfe81cbeea665076807789bd8f831d557632e635bc6e3c003069e
- /* nTime */ 1645635119,
- /* nTxCount */ 62226341,
- /* dTxRate */ 0.07717997442177152,
+ // Data from RPC: getchaintxstats 4096 0000000000000004877fa2d36316398528de4f347df2f8a96f76613a298ce060
+ .nTime = 1661705221,
+ .nTxCount = 63531852,
+ .dTxRate = 0.1079119341520164,
};
}
};
@@ -289,15 +289,15 @@ public:
vSeeds.emplace_back("178.128.221.177");
vSeeds.emplace_back("v7ajjeirttkbnt32wpy3c6w3emwnfr3fkla7hpxcfokr3ysd3kqtzmqd.onion:38333");
- consensus.nMinimumChainWork = uint256S("0x000000000000000000000000000000000000000000000000000000de26b0e471");
- consensus.defaultAssumeValid = uint256S("0x00000112852484b5fe3451572368f93cfd2723279af3464e478aee35115256ef"); // 78788
+ consensus.nMinimumChainWork = uint256S("0x000000000000000000000000000000000000000000000000000001291fc22898");
+ consensus.defaultAssumeValid = uint256S("0x000000d1a0e224fa4679d2fb2187ba55431c284fa1b74cbc8cfda866fd4d2c09"); // 105495
m_assumed_blockchain_size = 1;
m_assumed_chain_state_size = 0;
chainTxData = ChainTxData{
- // Data from RPC: getchaintxstats 4096 0000003d9144c56ac110ae04a0c271a0acce2f14f426b39fdf0d938c96d2eb09
- /* nTime */ 1645631279,
- /* nTxCount */ 1257429,
- /* dTxRate */ 0.1389638742514995,
+ // Data from RPC: getchaintxstats 4096 000000d1a0e224fa4679d2fb2187ba55431c284fa1b74cbc8cfda866fd4d2c09
+ .nTime = 1661702566,
+ .nTxCount = 1903567,
+ .dTxRate = 0.02336701143027275,
};
} else {
const auto signet_challenge = args.GetArgs("-signetchallenge");
diff --git a/src/chainparamsseeds.h b/src/chainparamsseeds.h
index b9df1c61f0..f065647d49 100644
--- a/src/chainparamsseeds.h
+++ b/src/chainparamsseeds.h
@@ -7,703 +7,945 @@
* Each line contains a BIP155 serialized (networkID, addr, port) tuple.
*/
static const uint8_t chainparams_seed_main[] = {
- 0x01,0x04,0x02,0x25,0x1e,0x90,0x22,0x49,
- 0x01,0x04,0x02,0x8a,0xae,0x9e,0x20,0x8d,
+ 0x01,0x04,0x02,0x03,0x19,0xb5,0x20,0x8d,
0x01,0x04,0x02,0x98,0x4e,0x7c,0x20,0x8d,
- 0x01,0x04,0x05,0x08,0x12,0x9a,0x20,0x8d,
- 0x01,0x04,0x05,0x2d,0x4a,0x32,0x20,0x8d,
- 0x01,0x04,0x05,0x4f,0x7b,0x03,0x20,0x8d,
- 0x01,0x04,0x05,0x66,0xa8,0xd9,0x56,0xcc,
- 0x01,0x04,0x05,0x67,0x89,0x92,0x24,0x75,
+ 0x01,0x04,0x05,0x27,0x4a,0xa6,0x20,0x8d,
+ 0x01,0x04,0x05,0x2d,0x4f,0x51,0x47,0x9c,
+ 0x01,0x04,0x05,0x35,0x10,0x80,0x20,0x8d,
+ 0x01,0x04,0x05,0x5f,0xba,0x4e,0x20,0x8d,
0x01,0x04,0x05,0x80,0x57,0x7e,0x20,0x8d,
- 0x01,0x04,0x05,0xac,0x84,0xc8,0x20,0x8d,
+ 0x01,0x04,0x05,0x85,0x41,0x52,0x20,0x8d,
+ 0x01,0x04,0x05,0x92,0x14,0xe5,0x20,0x8d,
+ 0x01,0x04,0x05,0xb4,0x29,0x77,0x20,0x8d,
0x01,0x04,0x05,0xbc,0x3e,0x12,0x20,0x8d,
- 0x01,0x04,0x05,0xfe,0x65,0xe2,0x20,0x8e,
- 0x01,0x04,0x08,0xd2,0x12,0x38,0x20,0x8d,
- 0x01,0x04,0x08,0xd2,0x5c,0x20,0x20,0x8d,
- 0x01,0x04,0x0e,0x0d,0x22,0xe1,0x3f,0x35,
- 0x01,0x04,0x0e,0x27,0x97,0xa7,0x20,0x8d,
- 0x01,0x04,0x12,0xc4,0x4f,0x6c,0x20,0x8d,
- 0x01,0x04,0x12,0xda,0x8b,0x3a,0xbc,0xcd,
- 0x01,0x04,0x14,0xb8,0x0f,0x74,0x20,0xf1,
- 0x01,0x04,0x17,0xaf,0x00,0xdc,0x20,0x8d,
+ 0x01,0x04,0x05,0xc7,0xad,0x42,0x20,0x8d,
+ 0x01,0x04,0x05,0xff,0x61,0x19,0x20,0x8d,
+ 0x01,0x04,0x05,0xff,0x67,0xb4,0x20,0x8d,
+ 0x01,0x04,0x08,0xd1,0x46,0x4d,0x20,0x8d,
+ 0x01,0x04,0x08,0xd1,0x69,0x8a,0x20,0x8d,
+ 0x01,0x04,0x12,0xa2,0xd0,0x99,0xbc,0xcc,
+ 0x01,0x04,0x17,0xaf,0x00,0xc8,0x20,0x8d,
+ 0x01,0x04,0x17,0xaf,0x00,0xde,0x20,0x8d,
0x01,0x04,0x17,0xe9,0x6b,0x15,0x20,0x8d,
+ 0x01,0x04,0x17,0xec,0x19,0xa9,0x20,0x8d,
0x01,0x04,0x18,0x23,0x44,0xe5,0x20,0x8d,
- 0x01,0x04,0x18,0x25,0x03,0x1a,0x20,0x8d,
- 0x01,0x04,0x18,0x66,0x5b,0xcb,0x20,0x8d,
+ 0x01,0x04,0x18,0x54,0xa4,0x32,0x20,0x8d,
0x01,0x04,0x18,0x74,0x99,0x73,0x20,0x8d,
- 0x01,0x04,0x18,0x86,0x06,0xa5,0x20,0x8d,
- 0x01,0x04,0x18,0x9b,0xda,0x0d,0x20,0x8d,
- 0x01,0x04,0x18,0xa0,0x89,0xad,0x20,0x8d,
- 0x01,0x04,0x18,0xb1,0x6a,0x55,0x20,0x8d,
0x01,0x04,0x18,0xb8,0x00,0x92,0x20,0x8d,
- 0x01,0x04,0x18,0xc2,0xde,0x74,0x20,0x8d,
- 0x01,0x04,0x18,0xcd,0xd7,0xc0,0x20,0x8d,
+ 0x01,0x04,0x1b,0x21,0xa0,0xc4,0x20,0x8d,
0x01,0x04,0x1b,0x7c,0x6c,0x13,0x20,0x8d,
- 0x01,0x04,0x1f,0x0e,0x28,0x40,0x20,0x8d,
+ 0x01,0x04,0x1b,0x94,0xce,0x8c,0x20,0x8d,
+ 0x01,0x04,0x1f,0x11,0x40,0xc0,0x20,0x8d,
+ 0x01,0x04,0x1f,0x12,0x72,0x87,0x20,0x8d,
+ 0x01,0x04,0x1f,0x29,0x17,0xf9,0x20,0x8d,
+ 0x01,0x04,0x1f,0x2a,0xb0,0x8a,0x20,0x8d,
0x01,0x04,0x1f,0x2f,0xca,0x70,0x20,0x8d,
- 0x01,0x04,0x1f,0xa5,0x73,0x07,0x20,0x8d,
0x01,0x04,0x22,0x41,0x2d,0x9d,0x20,0x8d,
- 0x01,0x04,0x22,0x4e,0x30,0x68,0x20,0x8d,
0x01,0x04,0x22,0x50,0x86,0x44,0x20,0x8d,
- 0x01,0x04,0x22,0x65,0x84,0xc6,0x20,0x8d,
- 0x01,0x04,0x22,0xe3,0x44,0xd8,0x20,0x8d,
- 0x01,0x04,0x23,0x89,0xd4,0x16,0x20,0x8d,
- 0x01,0x04,0x23,0xe7,0xbe,0x86,0x20,0x8d,
- 0x01,0x04,0x25,0x01,0xd9,0x23,0x20,0x8d,
- 0x01,0x04,0x25,0x0f,0x3e,0x20,0x20,0x8d,
+ 0x01,0x04,0x22,0x7e,0x73,0x23,0x20,0x8d,
+ 0x01,0x04,0x25,0x01,0xcc,0xe7,0x20,0x8d,
+ 0x01,0x04,0x25,0x78,0x9b,0x22,0x20,0x8d,
0x01,0x04,0x25,0x8f,0x76,0xae,0x20,0x8d,
- 0x01,0x04,0x25,0xc8,0x3b,0x43,0x20,0x8d,
- 0x01,0x04,0x25,0xcd,0x09,0xa5,0x20,0x8d,
- 0x01,0x04,0x26,0x17,0xb4,0xe4,0x20,0x8d,
- 0x01,0x04,0x26,0x41,0x77,0x1a,0x20,0x8d,
+ 0x01,0x04,0x25,0xc1,0xe3,0x10,0x20,0x8d,
+ 0x01,0x04,0x25,0xdc,0x87,0x97,0x20,0x8d,
+ 0x01,0x04,0x25,0xeb,0x92,0xec,0x20,0x8d,
+ 0x01,0x04,0x26,0x7c,0x7e,0x2a,0x20,0x8d,
0x01,0x04,0x26,0x8d,0x86,0x8c,0x20,0x8d,
- 0x01,0x04,0x27,0x6d,0x7a,0x7f,0x20,0xfc,
+ 0x01,0x04,0x26,0x91,0x97,0x96,0x20,0x8d,
+ 0x01,0x04,0x28,0x73,0x89,0x1c,0x20,0x8d,
+ 0x01,0x04,0x29,0x48,0x9a,0x42,0x20,0x8d,
0x01,0x04,0x29,0x4f,0x46,0x92,0x20,0x8d,
- 0x01,0x04,0x29,0xc1,0x7a,0xbf,0x20,0x8d,
+ 0x01,0x04,0x2a,0xc1,0x37,0x87,0x20,0x8d,
0x01,0x04,0x2b,0xe1,0x3e,0x6b,0x20,0x8d,
- 0x01,0x04,0x2d,0x23,0x49,0x98,0x20,0x8d,
0x01,0x04,0x2d,0x2b,0x61,0x67,0x20,0x8d,
- 0x01,0x04,0x2d,0x3f,0x0a,0x34,0x4e,0x28,
- 0x01,0x04,0x2d,0x54,0x99,0x28,0x20,0x8d,
- 0x01,0x04,0x2d,0x5f,0x40,0xe1,0x20,0x8d,
- 0x01,0x04,0x2d,0x81,0xb4,0xd6,0x20,0x8d,
- 0x01,0x04,0x2d,0x9a,0xff,0xa2,0x20,0x8d,
- 0x01,0x04,0x2d,0xe2,0x50,0x66,0x20,0x8d,
- 0x01,0x04,0x2e,0x06,0x0a,0xe6,0x20,0x8d,
+ 0x01,0x04,0x2d,0x55,0x30,0x3a,0x20,0x8d,
+ 0x01,0x04,0x2d,0x7e,0x1a,0xe5,0x20,0x8d,
+ 0x01,0x04,0x2d,0x86,0x8e,0x28,0x20,0x8d,
+ 0x01,0x04,0x2d,0x9a,0xfc,0xa2,0x20,0x8d,
+ 0x01,0x04,0x2e,0x0d,0xd8,0xa9,0x20,0x8d,
0x01,0x04,0x2e,0x17,0x57,0xda,0x20,0x8d,
- 0x01,0x04,0x2e,0x20,0x32,0x62,0x20,0x8d,
- 0x01,0x04,0x2e,0x2f,0x54,0x55,0x20,0x8d,
+ 0x01,0x04,0x2e,0x28,0x7f,0xa4,0x20,0x8d,
0x01,0x04,0x2e,0x30,0x7e,0x3a,0x20,0x8d,
+ 0x01,0x04,0x2e,0x3b,0x0d,0x23,0x20,0x8d,
+ 0x01,0x04,0x2e,0x48,0xee,0x11,0x20,0x8d,
+ 0x01,0x04,0x2e,0x80,0x8d,0xb8,0x20,0x8d,
0x01,0x04,0x2e,0x92,0xf8,0x59,0x20,0x8d,
0x01,0x04,0x2e,0xa5,0xdd,0xd1,0x24,0x75,
0x01,0x04,0x2e,0xa6,0x8e,0x02,0x20,0x8d,
- 0x01,0x04,0x2e,0xa6,0xa2,0x2d,0x4e,0x21,
- 0x01,0x04,0x2e,0xad,0x32,0x3a,0x20,0x8d,
0x01,0x04,0x2e,0xaf,0xb2,0x03,0x20,0x8d,
- 0x01,0x04,0x2e,0xbc,0x1e,0x76,0x20,0x8d,
- 0x01,0x04,0x2e,0xdb,0x78,0x3b,0x0e,0x59,
- 0x01,0x04,0x2e,0xe5,0xee,0xbb,0x20,0x8d,
- 0x01,0x04,0x2f,0x5d,0xe6,0xab,0x20,0x8d,
- 0x01,0x04,0x2f,0x64,0xa2,0xd2,0x47,0x9c,
- 0x01,0x04,0x2f,0x90,0x6a,0xf9,0x20,0x8d,
- 0x01,0x04,0x2f,0xbc,0x46,0xcd,0x20,0x8d,
- 0x01,0x04,0x2f,0xe3,0xe2,0xf2,0x20,0x8d,
+ 0x01,0x04,0x2f,0x24,0x90,0x33,0x20,0x8d,
+ 0x01,0x04,0x2f,0xb4,0x31,0x9e,0x20,0x8d,
+ 0x01,0x04,0x31,0xe4,0x83,0x85,0x08,0xa2,
0x01,0x04,0x32,0x02,0x0d,0xa4,0x20,0x8d,
- 0x01,0x04,0x32,0x05,0x2e,0xc3,0x20,0x8d,
- 0x01,0x04,0x32,0x2d,0x80,0x1c,0x20,0x8d,
- 0x01,0x04,0x33,0x94,0x99,0x3c,0x20,0x8d,
+ 0x01,0x04,0x32,0x23,0x47,0x33,0x20,0x8d,
+ 0x01,0x04,0x32,0x35,0xfa,0xa2,0x20,0x8d,
+ 0x01,0x04,0x33,0x44,0x24,0x39,0x20,0x8d,
+ 0x01,0x04,0x33,0x8a,0x04,0x87,0x75,0x31,
0x01,0x04,0x33,0x9a,0x3e,0x67,0x20,0x8d,
- 0x01,0x04,0x33,0x9a,0x83,0x12,0x20,0x8d,
0x01,0x04,0x33,0x9e,0x96,0x9b,0x20,0x8d,
- 0x01,0x04,0x33,0x9f,0x02,0xda,0x20,0x8d,
- 0x01,0x04,0x36,0xc6,0x13,0x22,0x20,0x8d,
- 0x01,0x04,0x3a,0x69,0xa8,0x29,0x20,0x8d,
+ 0x01,0x04,0x36,0xb0,0x3f,0x10,0x20,0x8d,
0x01,0x04,0x3a,0x9e,0x00,0x56,0x20,0x8d,
- 0x01,0x04,0x3c,0xfb,0x81,0x3d,0x20,0x90,
+ 0x01,0x04,0x3b,0x8a,0x73,0x89,0x20,0x8d,
+ 0x01,0x04,0x3b,0xa7,0xbf,0x3c,0x20,0x8d,
+ 0x01,0x04,0x3c,0xcd,0xcd,0x77,0x20,0x8d,
+ 0x01,0x04,0x3c,0xea,0x7a,0xf5,0x20,0x8d,
+ 0x01,0x04,0x3c,0xf0,0xd2,0x9b,0x20,0x8d,
0x01,0x04,0x3d,0xef,0x5b,0xfa,0x20,0x8d,
- 0x01,0x04,0x3e,0x1c,0xbe,0xc2,0x20,0x8d,
- 0x01,0x04,0x3e,0x98,0x3a,0x10,0x24,0xcd,
+ 0x01,0x04,0x3e,0x4a,0x8f,0x0b,0x20,0x8d,
+ 0x01,0x04,0x3e,0x8a,0xa2,0x0c,0x20,0x8d,
+ 0x01,0x04,0x3e,0xa9,0x4a,0xe9,0x20,0x8d,
0x01,0x04,0x3e,0xab,0x81,0x20,0x20,0x8d,
- 0x01,0x04,0x3e,0xfb,0x36,0xa3,0x20,0x8d,
+ 0x01,0x04,0x3e,0xd1,0xc6,0x41,0x20,0x8d,
0x01,0x04,0x3f,0xf7,0x93,0xa6,0x20,0x8d,
- 0x01,0x04,0x40,0x21,0x44,0xb0,0x20,0x8d,
- 0x01,0x04,0x40,0x9c,0xc0,0x3d,0x20,0x8d,
- 0x01,0x04,0x40,0xbb,0xaf,0xe2,0x20,0x8d,
- 0x01,0x04,0x40,0xe9,0xf5,0x27,0x20,0x8d,
- 0x01,0x04,0x40,0xed,0x52,0x95,0x20,0x8d,
- 0x01,0x04,0x41,0x65,0xf7,0x1a,0x20,0x8d,
+ 0x01,0x04,0x40,0x62,0x4c,0x3e,0x20,0x8d,
0x01,0x04,0x42,0x1d,0x81,0xda,0x20,0x8d,
- 0x01,0x04,0x42,0x31,0xcc,0x0b,0x20,0x8d,
- 0x01,0x04,0x42,0x3a,0xf3,0xd7,0x20,0x8d,
- 0x01,0x04,0x42,0x55,0xea,0x81,0x20,0x8d,
+ 0x01,0x04,0x42,0x60,0xeb,0x1c,0x20,0x8d,
0x01,0x04,0x42,0x82,0x78,0x34,0x20,0x8d,
- 0x01,0x04,0x43,0x0a,0x79,0x91,0x20,0x8d,
- 0x01,0x04,0x43,0xd2,0xe4,0xcb,0x20,0x8d,
- 0x01,0x04,0x43,0xd5,0x57,0x15,0x20,0x8d,
+ 0x01,0x04,0x42,0xc6,0xd1,0xf3,0x20,0x8d,
+ 0x01,0x04,0x42,0xd0,0x40,0x80,0x20,0x8d,
+ 0x01,0x04,0x42,0xe1,0xe7,0x94,0x20,0x8d,
+ 0x01,0x04,0x43,0x37,0x03,0xc8,0x20,0x8d,
+ 0x01,0x04,0x43,0x3a,0xe8,0x6b,0x20,0x8d,
+ 0x01,0x04,0x43,0xd3,0x5c,0x02,0x20,0x8d,
+ 0x01,0x04,0x43,0xdf,0x77,0x7a,0x20,0x8d,
+ 0x01,0x04,0x44,0x30,0x83,0xfb,0x20,0x8d,
0x01,0x04,0x44,0xb5,0x04,0x0c,0x20,0x8d,
- 0x01,0x04,0x45,0x07,0x7c,0x92,0x20,0x8d,
- 0x01,0x04,0x45,0x08,0xaf,0xc9,0x20,0x8d,
+ 0x01,0x04,0x45,0x0e,0xb9,0x09,0x20,0x8d,
+ 0x01,0x04,0x45,0x36,0x1d,0xc1,0x20,0x8d,
0x01,0x04,0x45,0x3b,0x12,0x16,0x20,0x8d,
- 0x01,0x04,0x45,0x77,0xc1,0x09,0x20,0x8d,
- 0x01,0x04,0x45,0x82,0xc9,0x1b,0x20,0x8d,
0x01,0x04,0x45,0x83,0x65,0xb0,0x20,0x8d,
- 0x01,0x04,0x46,0x0f,0xc2,0x20,0x20,0x8d,
- 0x01,0x04,0x46,0x40,0x1b,0x0c,0x20,0x8d,
- 0x01,0x04,0x48,0x1d,0xaa,0x97,0x20,0x8d,
- 0x01,0x04,0x48,0x4a,0x22,0x63,0x20,0x8d,
- 0x01,0x04,0x48,0x85,0xb1,0x77,0x20,0x8d,
- 0x01,0x04,0x49,0xa6,0x54,0xde,0x20,0x8d,
- 0x01,0x04,0x4a,0x43,0xf0,0xcc,0x20,0x8d,
+ 0x01,0x04,0x45,0xa5,0xcd,0x8e,0x22,0x81,
+ 0x01,0x04,0x45,0xe4,0xdb,0x7c,0x20,0x8d,
+ 0x01,0x04,0x46,0x3b,0x7b,0x19,0x20,0x8d,
+ 0x01,0x04,0x46,0x3e,0x0d,0x96,0x20,0x8d,
+ 0x01,0x04,0x46,0x42,0xf8,0xaa,0x20,0x8d,
+ 0x01,0x04,0x46,0x70,0x99,0xe5,0x20,0x8d,
+ 0x01,0x04,0x46,0xa0,0xf0,0x84,0x20,0x8d,
+ 0x01,0x04,0x46,0xbe,0xb1,0xcc,0x20,0x8d,
+ 0x01,0x04,0x47,0x1c,0xbd,0xef,0x20,0x8d,
+ 0x01,0x04,0x47,0xea,0x7d,0xc6,0x20,0x8d,
+ 0x01,0x04,0x48,0x4a,0x7b,0xb3,0x20,0x8d,
+ 0x01,0x04,0x48,0xfd,0xec,0xd9,0x20,0x8d,
+ 0x01,0x04,0x49,0xdb,0xfe,0x78,0x20,0x8d,
0x01,0x04,0x4a,0x5b,0x73,0xe5,0x20,0x8d,
0x01,0x04,0x4a,0x76,0x89,0x77,0x20,0x8d,
- 0x01,0x04,0x4a,0xd5,0xfb,0xcb,0x20,0x8d,
+ 0x01,0x04,0x4a,0xc3,0xa6,0x64,0x20,0x8d,
0x01,0x04,0x4a,0xdc,0xff,0xbe,0x20,0x8d,
- 0x01,0x04,0x4c,0x0b,0x3c,0x9b,0x20,0x8d,
- 0x01,0x04,0x4c,0x42,0x90,0x7f,0x20,0x8d,
+ 0x01,0x04,0x4c,0x43,0xd3,0x6e,0x20,0x8d,
+ 0x01,0x04,0x4c,0xa9,0xa3,0x0e,0x20,0x8d,
+ 0x01,0x04,0x4d,0x20,0x79,0xa2,0x20,0x8d,
+ 0x01,0x04,0x4d,0x35,0x87,0x4a,0x20,0x8d,
0x01,0x04,0x4d,0x46,0x10,0xf5,0x20,0x8d,
0x01,0x04,0x4d,0x55,0xcc,0x95,0x20,0x8d,
- 0x01,0x04,0x4d,0x69,0x57,0x61,0x20,0x8d,
- 0x01,0x04,0x4d,0x78,0x71,0x45,0x20,0xf1,
- 0x01,0x04,0x4d,0x78,0x71,0x47,0x20,0xf1,
- 0x01,0x04,0x4d,0x78,0x7a,0x74,0x20,0xf1,
- 0x01,0x04,0x4d,0x78,0x7a,0x76,0x20,0xf1,
+ 0x01,0x04,0x4d,0x6b,0x26,0xef,0x20,0x8d,
+ 0x01,0x04,0x4d,0x78,0x1a,0x66,0x20,0x8d,
0x01,0x04,0x4d,0xa2,0xbe,0x5a,0x20,0x8d,
- 0x01,0x04,0x4d,0xa7,0xf5,0xef,0xd8,0xf8,
- 0x01,0x04,0x4d,0xe8,0x29,0xbd,0x20,0x8d,
0x01,0x04,0x4e,0x14,0xe3,0xf9,0x20,0x8d,
0x01,0x04,0x4e,0x15,0xa7,0x08,0x20,0x8d,
0x01,0x04,0x4e,0x1b,0x8b,0x0d,0x20,0x8d,
- 0x01,0x04,0x4e,0x2b,0xd0,0x19,0x20,0x8d,
- 0x01,0x04,0x4e,0x3f,0x1c,0x92,0x20,0x8d,
- 0x01,0x04,0x4e,0x48,0xe4,0xef,0x20,0x8d,
- 0x01,0x04,0x4e,0x6c,0x66,0x08,0x20,0x8d,
- 0x01,0x04,0x4e,0x81,0x00,0x27,0x20,0x8d,
- 0x01,0x04,0x4e,0x81,0xa9,0x45,0x20,0x8d,
- 0x01,0x04,0x4f,0x4d,0xb6,0xb4,0x20,0x8d,
+ 0x01,0x04,0x4e,0x5a,0x5b,0xdc,0x20,0x8d,
+ 0x01,0x04,0x4e,0x6c,0x6c,0x19,0x20,0x8d,
+ 0x01,0x04,0x4e,0x6c,0x6c,0x26,0x20,0x8d,
0x01,0x04,0x4f,0x4d,0xb6,0xb7,0x20,0x8d,
- 0x01,0x04,0x4f,0x6b,0xb2,0x3b,0x20,0x8d,
+ 0x01,0x04,0x4f,0x62,0x9f,0x07,0x2c,0x45,
+ 0x01,0x04,0x4f,0xbd,0xd3,0xc9,0x20,0x8d,
0x01,0x04,0x50,0x37,0xe1,0x9e,0x20,0x8d,
- 0x01,0x04,0x50,0x40,0xd3,0x66,0x20,0x8d,
- 0x01,0x04,0x50,0x40,0xd3,0x67,0x20,0x8d,
- 0x01,0x04,0x50,0x47,0x39,0x32,0x20,0x8d,
- 0x01,0x04,0x50,0x51,0x03,0x1b,0x20,0x8d,
- 0x01,0x04,0x50,0x52,0x37,0x2b,0x20,0x8d,
+ 0x01,0x04,0x50,0x53,0xba,0x23,0x20,0x8d,
0x01,0x04,0x50,0x58,0xac,0xe3,0xfb,0x08,
- 0x01,0x04,0x50,0x59,0xcb,0xac,0x1f,0x41,
- 0x01,0x04,0x50,0x5d,0xd5,0xf6,0x20,0x8d,
- 0x01,0x04,0x50,0x93,0x52,0xa5,0x20,0x8d,
+ 0x01,0x04,0x50,0xd1,0x57,0x67,0x24,0x75,
0x01,0x04,0x50,0xe5,0x1c,0x3c,0x20,0x8d,
- 0x01,0x04,0x50,0xf7,0xe9,0x28,0x20,0x8d,
- 0x01,0x04,0x50,0xff,0x08,0x5d,0x20,0x8d,
+ 0x01,0x04,0x51,0x07,0x10,0xb6,0x20,0x8d,
0x01,0x04,0x51,0x07,0x11,0xca,0x20,0x8d,
- 0x01,0x04,0x51,0x0a,0xf1,0xa5,0x20,0x8d,
- 0x01,0x04,0x51,0x15,0x56,0x9d,0x20,0x8d,
+ 0x01,0x04,0x51,0x13,0x0a,0x02,0x20,0x8d,
+ 0x01,0x04,0x51,0x58,0xdd,0xbe,0x20,0x8d,
0x01,0x04,0x51,0xab,0x16,0x8f,0x20,0x8d,
- 0x01,0x04,0x51,0xed,0xce,0xe0,0x20,0x97,
- 0x01,0x04,0x52,0x45,0x17,0xc3,0x20,0x8d,
+ 0x01,0x04,0x51,0xe0,0x2c,0xa4,0x20,0x8d,
+ 0x01,0x04,0x51,0xe0,0xa0,0x51,0x20,0x8d,
+ 0x01,0x04,0x52,0x01,0x44,0x36,0x20,0x8d,
+ 0x01,0x04,0x52,0x15,0xa4,0x2f,0x20,0x8d,
+ 0x01,0x04,0x52,0x40,0x74,0x05,0x20,0x8d,
+ 0x01,0x04,0x52,0x42,0x0a,0x0b,0x20,0x8d,
0x01,0x04,0x52,0x60,0x60,0x28,0x20,0x8d,
0x01,0x04,0x52,0x74,0x32,0x65,0x20,0x8d,
+ 0x01,0x04,0x52,0x81,0x44,0x3e,0x20,0x8d,
0x01,0x04,0x52,0x88,0x63,0x7a,0x20,0x8d,
- 0x01,0x04,0x52,0x95,0x61,0x19,0x44,0x9f,
0x01,0x04,0x52,0x9a,0x18,0xd1,0x20,0x8d,
- 0x01,0x04,0x52,0xa5,0xf1,0x32,0x20,0x8d,
- 0x01,0x04,0x52,0xc5,0xda,0xfd,0x20,0x8d,
- 0x01,0x04,0x52,0xca,0x44,0xe7,0x20,0x8d,
+ 0x01,0x04,0x52,0xc5,0xd7,0x7d,0x20,0x8d,
+ 0x01,0x04,0x53,0x80,0x84,0x5b,0x20,0x8d,
0x01,0x04,0x53,0x89,0x29,0x0a,0x20,0x8d,
0x01,0x04,0x53,0xd0,0x06,0xd3,0x20,0x8d,
- 0x01,0x04,0x53,0xd9,0x08,0x1f,0xad,0x84,
- 0x01,0x04,0x53,0xdc,0x6e,0x30,0x20,0x8d,
+ 0x01,0x04,0x53,0xd0,0xc1,0xf2,0x20,0x8d,
0x01,0x04,0x53,0xde,0x8a,0x55,0x20,0x8d,
+ 0x01,0x04,0x53,0xf0,0x7c,0x44,0x20,0x8d,
0x01,0x04,0x53,0xf3,0xbf,0xc7,0x20,0x8d,
- 0x01,0x04,0x54,0x16,0x8b,0x39,0x20,0x8d,
- 0x01,0x04,0x54,0x1b,0x9b,0x11,0x20,0x8d,
- 0x01,0x04,0x54,0x4b,0x1c,0xf7,0x20,0x8d,
+ 0x01,0x04,0x54,0x09,0x05,0xd3,0x20,0x8d,
+ 0x01,0x04,0x54,0x1c,0x39,0x5a,0x20,0x8d,
+ 0x01,0x04,0x54,0x26,0x03,0xf9,0x20,0x8d,
0x01,0x04,0x54,0x70,0x3c,0x10,0x20,0x8d,
- 0x01,0x04,0x54,0xd3,0x07,0x38,0x20,0x8d,
- 0x01,0x04,0x54,0xed,0x07,0xf9,0x20,0x8d,
- 0x01,0x04,0x55,0x17,0x33,0xb1,0x20,0x8d,
- 0x01,0x04,0x55,0x18,0x91,0xc6,0x20,0x8d,
- 0x01,0x04,0x55,0xb8,0x8a,0x6c,0x20,0x8d,
+ 0x01,0x04,0x54,0xd7,0x38,0x77,0x20,0x8d,
+ 0x01,0x04,0x54,0xe2,0xf3,0xaf,0x20,0x8d,
+ 0x01,0x04,0x54,0xf5,0x0e,0x49,0x20,0x8d,
+ 0x01,0x04,0x54,0xfc,0x9d,0x5a,0x47,0x9d,
+ 0x01,0x04,0x54,0xff,0xf4,0x3d,0x20,0x8d,
+ 0x01,0x04,0x55,0x17,0x18,0x7b,0x20,0x8d,
+ 0x01,0x04,0x55,0x34,0xb9,0x1d,0x21,0xda,
+ 0x01,0x04,0x55,0x3a,0x78,0xc9,0x20,0x8d,
+ 0x01,0x04,0x55,0x5d,0x60,0x12,0x20,0x8d,
+ 0x01,0x04,0x55,0xa5,0x08,0xc5,0x20,0x8d,
+ 0x01,0x04,0x55,0xad,0xa5,0x42,0x20,0x8d,
+ 0x01,0x04,0x55,0xb8,0x8f,0x69,0x20,0x8d,
+ 0x01,0x04,0x55,0xbf,0x4a,0x67,0x20,0x8d,
0x01,0x04,0x55,0xc2,0xee,0x86,0x20,0x8d,
0x01,0x04,0x55,0xc3,0x36,0x6e,0x20,0x8d,
+ 0x01,0x04,0x55,0xc3,0xc4,0x8e,0x20,0x8d,
+ 0x01,0x04,0x55,0xd0,0x45,0x0b,0x20,0x8d,
+ 0x01,0x04,0x55,0xd0,0x45,0x15,0x20,0x8d,
0x01,0x04,0x55,0xd0,0x47,0x24,0x20,0x8d,
0x01,0x04,0x55,0xd0,0x47,0x27,0x20,0x8d,
- 0x01,0x04,0x55,0xd6,0x88,0x2d,0x20,0x8d,
+ 0x01,0x04,0x55,0xd6,0x76,0x47,0x20,0x8d,
0x01,0x04,0x55,0xd6,0xa1,0xfc,0x20,0x8d,
- 0x01,0x04,0x55,0xe3,0xf5,0x80,0x20,0x8d,
- 0x01,0x04,0x56,0x12,0x22,0xf3,0x20,0x8d,
- 0x01,0x04,0x56,0x14,0x32,0xaa,0x20,0x8d,
- 0x01,0x04,0x56,0x31,0x69,0x5a,0x20,0x8d,
- 0x01,0x04,0x56,0x4c,0x07,0x84,0x20,0x8d,
+ 0x01,0x04,0x55,0xd8,0x20,0x49,0x20,0x8d,
+ 0x01,0x04,0x55,0xfe,0x62,0xdd,0x20,0x8d,
+ 0x01,0x04,0x56,0x3a,0x0b,0x98,0x20,0x8d,
+ 0x01,0x04,0x56,0x5f,0x08,0xf9,0x20,0x8d,
0x01,0x04,0x56,0x64,0x1a,0xbc,0x20,0x8d,
0x01,0x04,0x56,0x6a,0x8f,0x8f,0xd8,0x4d,
- 0x01,0x04,0x56,0x78,0x3a,0x42,0x20,0x8d,
+ 0x01,0x04,0x56,0x7c,0x91,0xb8,0x20,0x8d,
0x01,0x04,0x56,0x85,0xfb,0xef,0x22,0xc5,
- 0x01,0x04,0x56,0x95,0x08,0x17,0x22,0xc5,
- 0x01,0x04,0x57,0x4e,0xc5,0xea,0x20,0x8d,
+ 0x01,0x04,0x57,0x4f,0x5e,0xdd,0x20,0x8d,
0x01,0x04,0x57,0x78,0x08,0x05,0x4e,0x28,
- 0x01,0x04,0x57,0x79,0x25,0x9c,0x20,0x8d,
- 0x01,0x04,0x58,0x52,0xb5,0x2c,0x20,0x8d,
- 0x01,0x04,0x58,0x57,0x5d,0x34,0x06,0x9b,
- 0x01,0x04,0x58,0x62,0xeb,0x86,0x20,0x8d,
- 0x01,0x04,0x58,0x88,0xbb,0xd6,0x20,0x8d,
- 0x01,0x04,0x58,0x93,0xf4,0xfa,0x20,0x8d,
- 0x01,0x04,0x58,0x94,0x99,0x94,0x20,0x8d,
+ 0x01,0x04,0x57,0x7d,0x9d,0xdc,0x20,0x8d,
+ 0x01,0x04,0x58,0x09,0x4c,0x85,0x20,0x8d,
+ 0x01,0x04,0x58,0x5a,0xb8,0x44,0x20,0x8d,
+ 0x01,0x04,0x58,0x97,0x65,0x0e,0x13,0x88,
+ 0x01,0x04,0x58,0x97,0x65,0xfd,0x13,0x88,
+ 0x01,0x04,0x58,0xc6,0x5c,0x2f,0x20,0x8d,
+ 0x01,0x04,0x58,0xd0,0x73,0x46,0x20,0x8d,
+ 0x01,0x04,0x58,0xd2,0x0f,0x18,0x20,0x8d,
0x01,0x04,0x58,0xd4,0x2d,0xa6,0x20,0x8d,
- 0x01,0x04,0x58,0xd4,0x37,0x8a,0x20,0x8d,
- 0x01,0x04,0x59,0x26,0x60,0x99,0x24,0x39,
- 0x01,0x04,0x59,0x2f,0xa1,0x87,0x20,0x8d,
- 0x01,0x04,0x59,0x58,0x3e,0xbe,0x20,0x8d,
- 0x01,0x04,0x59,0x9e,0x20,0x2c,0x20,0x8d,
- 0x01,0x04,0x59,0xa3,0x91,0xf0,0x20,0x8d,
- 0x01,0x04,0x59,0xa3,0xf9,0xea,0x0e,0x59,
- 0x01,0x04,0x59,0xb0,0xc4,0x50,0x20,0x8d,
- 0x01,0x04,0x59,0xd8,0x15,0x60,0x20,0x8d,
- 0x01,0x04,0x5a,0x54,0xe3,0xff,0x20,0x8d,
+ 0x01,0x04,0x59,0x66,0xce,0xee,0x20,0x8d,
+ 0x01,0x04,0x59,0x67,0x6f,0x22,0x20,0x8d,
+ 0x01,0x04,0x59,0x72,0x8f,0x71,0x20,0x8d,
+ 0x01,0x04,0x59,0x86,0x3e,0x4a,0x20,0x8d,
+ 0x01,0x04,0x59,0x98,0x08,0xe7,0x20,0x8d,
+ 0x01,0x04,0x59,0xa1,0x1a,0x4e,0x20,0x8d,
+ 0x01,0x04,0x59,0xcf,0x83,0x13,0x20,0x8d,
+ 0x01,0x04,0x59,0xf8,0xc1,0xe5,0x20,0x8d,
+ 0x01,0x04,0x5a,0x03,0x30,0x3e,0x20,0x8d,
+ 0x01,0x04,0x5a,0x92,0x79,0x61,0x20,0x8d,
0x01,0x04,0x5a,0x92,0x82,0xd6,0x20,0x8d,
+ 0x01,0x04,0x5a,0xc4,0xa9,0x3a,0x20,0x8d,
0x01,0x04,0x5a,0xfa,0x09,0x01,0x20,0x8d,
0x01,0x04,0x5b,0x5d,0xc2,0x9a,0x20,0x8d,
- 0x01,0x04,0x5b,0x6a,0xbc,0xe5,0x20,0x8d,
0x01,0x04,0x5b,0x7e,0x28,0x6d,0x20,0x8d,
- 0x01,0x04,0x5b,0x89,0x7f,0x7b,0x20,0x8d,
- 0x01,0x04,0x5b,0x93,0xe8,0x62,0x20,0x8d,
- 0x01,0x04,0x5b,0x98,0x7b,0x12,0x20,0x8d,
- 0x01,0x04,0x5b,0xb2,0x11,0x78,0x20,0x8d,
0x01,0x04,0x5b,0xcc,0x63,0xb2,0x20,0x8d,
- 0x01,0x04,0x5b,0xdf,0xaf,0x0e,0x20,0x8d,
- 0x01,0x04,0x5c,0x2a,0x6e,0xf2,0x20,0x8d,
- 0x01,0x04,0x5c,0x35,0x5a,0x54,0x20,0x8d,
- 0x01,0x04,0x5c,0xdd,0x9b,0xe4,0x20,0x8d,
+ 0x01,0x04,0x5b,0xcc,0x95,0x05,0x20,0x8d,
+ 0x01,0x04,0x5b,0xce,0x11,0xc3,0x20,0x8d,
+ 0x01,0x04,0x5b,0xd1,0x33,0x83,0x20,0x8d,
+ 0x01,0x04,0x5b,0xd7,0x5b,0xfe,0x20,0x8d,
+ 0x01,0x04,0x5c,0x5b,0x1b,0x3c,0x20,0x8d,
+ 0x01,0x04,0x5c,0xdd,0x14,0xe8,0x20,0x8d,
+ 0x01,0x04,0x5c,0xff,0x55,0x1f,0x20,0x8d,
+ 0x01,0x04,0x5d,0x04,0x65,0x25,0x20,0x8d,
+ 0x01,0x04,0x5d,0x2e,0x51,0x05,0x20,0x8d,
0x01,0x04,0x5d,0x39,0x51,0xa2,0x20,0x8d,
+ 0x01,0x04,0x5d,0x49,0x27,0xc4,0x20,0x8d,
+ 0x01,0x04,0x5d,0x5a,0x52,0xe2,0x20,0x8d,
0x01,0x04,0x5d,0x5f,0x58,0x0d,0x20,0x8d,
- 0x01,0x04,0x5d,0x67,0x0d,0x01,0x20,0x8d,
0x01,0x04,0x5d,0x7b,0xb4,0xa4,0x20,0x8d,
- 0x01,0x04,0x5d,0xbe,0x75,0x1a,0x20,0x8d,
- 0x01,0x04,0x5e,0x69,0x7d,0xf0,0x20,0x8d,
- 0x01,0x04,0x5e,0x6e,0x17,0xd7,0x20,0x8d,
+ 0x01,0x04,0x5d,0xbd,0x91,0xa9,0x20,0x8d,
+ 0x01,0x04,0x5e,0x11,0xb9,0x6b,0x20,0x8d,
+ 0x01,0x04,0x5e,0x4b,0xc6,0x78,0x20,0x8d,
+ 0x01,0x04,0x5e,0x72,0xc4,0xa9,0x20,0x8d,
+ 0x01,0x04,0x5e,0x8e,0xd5,0xfa,0xd8,0xf8,
0x01,0x04,0x5e,0x9a,0x9f,0x63,0x20,0x8d,
- 0x01,0x04,0x5e,0xbd,0xa1,0x77,0x20,0x8d,
- 0x01,0x04,0x5e,0xcb,0xff,0x46,0x20,0x8d,
- 0x01,0x04,0x5e,0xe8,0xad,0x5d,0x20,0x8d,
- 0x01,0x04,0x5f,0x4f,0x7a,0x63,0x20,0x8d,
- 0x01,0x04,0x5f,0x50,0x01,0x6e,0x20,0x8d,
- 0x01,0x04,0x5f,0x53,0x49,0x1f,0x20,0x8d,
+ 0x01,0x04,0x5e,0x9e,0xf6,0xb7,0x20,0x8d,
+ 0x01,0x04,0x5e,0xef,0x91,0x20,0x20,0x8d,
+ 0x01,0x04,0x5f,0x1f,0x0c,0x16,0x20,0x8d,
+ 0x01,0x04,0x5f,0x1f,0xc4,0x0f,0x20,0x8d,
0x01,0x04,0x5f,0x6e,0x85,0xdf,0x20,0x8d,
0x01,0x04,0x5f,0x6e,0xea,0x5d,0x20,0x8d,
- 0x01,0x04,0x5f,0xa4,0x41,0xc2,0x20,0x8d,
- 0x01,0x04,0x5f,0xa5,0x08,0xb6,0x20,0x8d,
- 0x01,0x04,0x5f,0xae,0xdb,0x65,0x20,0x8d,
+ 0x01,0x04,0x5f,0xa1,0x0c,0x2d,0x20,0x8d,
0x01,0x04,0x5f,0xbf,0x82,0x64,0x20,0x8d,
+ 0x01,0x04,0x5f,0xd0,0x9e,0xa1,0x20,0x8d,
+ 0x01,0x04,0x5f,0xd5,0x91,0xda,0x20,0x8d,
0x01,0x04,0x5f,0xd6,0x35,0x9a,0x20,0x8d,
- 0x01,0x04,0x5f,0xd7,0xcd,0xb4,0x20,0x8d,
- 0x01,0x04,0x60,0x2b,0x82,0xea,0x20,0x8d,
- 0x01,0x04,0x62,0x19,0xc9,0x1f,0x20,0x8d,
- 0x01,0x04,0x62,0x80,0xf7,0xb6,0x20,0x8d,
- 0x01,0x04,0x62,0xab,0x15,0x81,0x20,0x8d,
- 0x01,0x04,0x63,0x93,0x87,0xa1,0x20,0x8d,
- 0x01,0x04,0x65,0x64,0xa3,0x76,0x20,0x87,
- 0x01,0x04,0x66,0x84,0xf5,0x10,0x20,0x8d,
- 0x01,0x04,0x66,0xb6,0xcc,0x60,0x20,0x8d,
- 0x01,0x04,0x66,0xb6,0xeb,0xf5,0x20,0x8d,
+ 0x01,0x04,0x5f,0xd6,0x35,0xa0,0x20,0x8d,
+ 0x01,0x04,0x60,0x2c,0x9c,0xc7,0x20,0x8d,
+ 0x01,0x04,0x61,0x4b,0x91,0x0c,0x20,0x8d,
+ 0x01,0x04,0x66,0x84,0xc0,0x8d,0x20,0x8d,
0x01,0x04,0x67,0x0e,0xf5,0xfa,0x20,0x8d,
- 0x01,0x04,0x67,0x2f,0xc0,0x0f,0x20,0x8d,
- 0x01,0x04,0x67,0x54,0x54,0xfa,0x20,0x8f,
- 0x01,0x04,0x67,0x63,0xa8,0x82,0x20,0x8d,
+ 0x01,0x04,0x67,0x55,0x26,0xcd,0x20,0x8d,
+ 0x01,0x04,0x67,0x58,0x5c,0x4e,0x20,0x8c,
+ 0x01,0x04,0x67,0x63,0xa8,0x64,0x20,0x8d,
0x01,0x04,0x67,0x63,0xa8,0x8c,0x20,0x8d,
- 0x01,0x04,0x67,0xc6,0xc0,0x0e,0x4e,0x28,
- 0x01,0x04,0x67,0xe8,0x68,0xe3,0x20,0x8d,
- 0x01,0x04,0x68,0x8f,0x02,0xc3,0x20,0x8d,
- 0x01,0x04,0x68,0xac,0xeb,0xe3,0x20,0x8d,
+ 0x01,0x04,0x67,0x63,0xaa,0xd2,0x20,0x8d,
+ 0x01,0x04,0x67,0x63,0xaa,0xdc,0x20,0x8d,
+ 0x01,0x04,0x67,0x64,0x2c,0x46,0x20,0x8d,
+ 0x01,0x04,0x67,0xb2,0xec,0x1b,0x20,0x8d,
+ 0x01,0x04,0x67,0xd1,0x0c,0x90,0x20,0x8d,
+ 0x01,0x04,0x68,0x3b,0x93,0x0f,0x20,0x8d,
+ 0x01,0x04,0x68,0x81,0xab,0x79,0x20,0x8d,
+ 0x01,0x04,0x68,0xc8,0x41,0xea,0x20,0x8d,
0x01,0x04,0x68,0xee,0xdc,0xc7,0x20,0x8d,
- 0x01,0x04,0x6b,0x0b,0x73,0x44,0x20,0x8d,
+ 0x01,0x04,0x68,0xf4,0x49,0x06,0x20,0x8d,
+ 0x01,0x04,0x6a,0x47,0x77,0xe6,0x20,0x8d,
0x01,0x04,0x6b,0xad,0xa6,0x2b,0x20,0x8d,
- 0x01,0x04,0x6c,0x04,0xd4,0x53,0x20,0x8d,
- 0x01,0x04,0x6d,0x88,0x49,0x61,0x20,0x8d,
- 0x01,0x04,0x6d,0xad,0x62,0x17,0x20,0x8d,
- 0x01,0x04,0x6d,0xbe,0x44,0x74,0x20,0x8d,
- 0x01,0x04,0x6d,0xeb,0xf6,0x3c,0x20,0x8d,
+ 0x01,0x04,0x6c,0xa1,0x16,0x4e,0x20,0x8d,
+ 0x01,0x04,0x6c,0xae,0x3f,0xea,0x20,0x8d,
+ 0x01,0x04,0x6d,0x63,0x3f,0x9f,0x20,0x8d,
+ 0x01,0x04,0x6d,0x69,0x28,0xf7,0x20,0x8d,
+ 0x01,0x04,0x6d,0x6b,0xb9,0x82,0x20,0x8d,
+ 0x01,0x04,0x6d,0x6e,0xef,0x04,0x20,0x8d,
+ 0x01,0x04,0x6d,0xad,0x29,0x2b,0x20,0x8d,
+ 0x01,0x04,0x6d,0xec,0x5a,0x75,0x20,0x8d,
0x01,0x04,0x6d,0xf8,0xce,0x0d,0x20,0x8d,
- 0x01,0x04,0x6e,0x0c,0x40,0x60,0x20,0x8d,
+ 0x01,0x04,0x6d,0xff,0x6a,0xce,0x20,0x8d,
+ 0x01,0x04,0x6f,0x5a,0x8c,0x17,0x20,0x8d,
0x01,0x04,0x6f,0x5a,0x8c,0x2e,0x20,0x8d,
- 0x01,0x04,0x6f,0x5a,0x9f,0xb8,0xc3,0x51,
- 0x01,0x04,0x71,0x6b,0xc9,0x83,0x20,0x8d,
+ 0x01,0x04,0x6f,0x5a,0x9f,0xf6,0x20,0x8d,
+ 0x01,0x04,0x70,0x76,0xbc,0x32,0x20,0x8d,
0x01,0x04,0x73,0x2f,0x8d,0xfa,0x22,0xb5,
0x01,0x04,0x74,0x3a,0xab,0x43,0x20,0x8d,
- 0x01,0x04,0x74,0x57,0x39,0xda,0x20,0x8d,
- 0x01,0x04,0x74,0xca,0xa1,0x38,0x20,0x8d,
- 0x01,0x04,0x75,0x33,0x9f,0x82,0x20,0x8d,
- 0x01,0x04,0x76,0x67,0x7e,0x8c,0x6e,0xad,
- 0x01,0x04,0x79,0x2d,0xbe,0xd2,0x20,0x8d,
- 0x01,0x04,0x79,0x63,0xc1,0x19,0x20,0x8d,
- 0x01,0x04,0x7a,0x70,0x94,0x99,0x20,0x93,
- 0x01,0x04,0x7a,0x94,0x87,0xea,0x20,0x8d,
+ 0x01,0x04,0x76,0x5c,0x6b,0x6c,0x20,0x8d,
+ 0x01,0x04,0x77,0x2a,0x37,0xcb,0x20,0x8d,
+ 0x01,0x04,0x78,0x4f,0x47,0x48,0x20,0x8d,
+ 0x01,0x04,0x79,0x63,0xf0,0x57,0x20,0x8d,
+ 0x01,0x04,0x7b,0x3c,0xd5,0xc0,0x20,0x8d,
+ 0x01,0x04,0x7c,0x9c,0x9e,0x64,0x20,0x8d,
+ 0x01,0x04,0x7c,0xde,0x7b,0xee,0x20,0x8d,
+ 0x01,0x04,0x7d,0xb2,0x06,0x74,0x20,0x8d,
0x01,0x04,0x80,0x00,0xbe,0x1a,0x20,0x8d,
0x01,0x04,0x80,0x41,0xc2,0x88,0x20,0x8d,
+ 0x01,0x04,0x81,0x0d,0xbd,0xd4,0x20,0x8d,
0x01,0x04,0x81,0x7e,0xac,0x73,0x20,0x8d,
- 0x01,0x04,0x81,0xe2,0x7d,0x0a,0x20,0x8d,
+ 0x01,0x04,0x81,0x92,0x34,0xae,0x20,0x8d,
+ 0x01,0x04,0x82,0x2c,0xa8,0xca,0x20,0x8d,
+ 0x01,0x04,0x83,0xa1,0x50,0xa6,0x20,0x8d,
0x01,0x04,0x83,0xbc,0x28,0xbf,0x20,0x8d,
0x01,0x04,0x86,0xc3,0xb9,0x34,0x20,0x8d,
- 0x01,0x04,0x87,0xb4,0x2c,0x3d,0x20,0x8d,
- 0x01,0x04,0x88,0x34,0x72,0x7b,0x20,0x8d,
+ 0x01,0x04,0x87,0x86,0xee,0x2f,0x20,0x8d,
+ 0x01,0x04,0x87,0xb4,0xda,0x3a,0x20,0x8d,
+ 0x01,0x04,0x87,0xb5,0xd7,0xed,0x20,0x8d,
+ 0x01,0x04,0x88,0x1d,0x6d,0xb4,0x20,0x8d,
+ 0x01,0x04,0x88,0x20,0xee,0x06,0x20,0x8d,
0x01,0x04,0x88,0x38,0xaa,0x60,0x20,0x8d,
- 0x01,0x04,0x89,0x74,0xd5,0x8f,0x20,0x8d,
+ 0x01,0x04,0x89,0x19,0x26,0x6c,0x20,0x8d,
0x01,0x04,0x89,0xe2,0x22,0x2e,0x20,0x8d,
- 0x01,0x04,0x8a,0x2b,0xe9,0x39,0x20,0x8d,
+ 0x01,0x04,0x8a,0xcf,0xd3,0x6a,0x20,0x8d,
0x01,0x04,0x8b,0x82,0x29,0x52,0x20,0x8d,
+ 0x01,0x04,0x8b,0x99,0xff,0x6b,0x20,0x8d,
0x01,0x04,0x8c,0xbe,0x0c,0x81,0x20,0x8d,
- 0x01,0x04,0x8e,0x04,0x69,0x4d,0x20,0x8d,
0x01,0x04,0x8e,0x36,0xb5,0xda,0x20,0x8d,
- 0x01,0x04,0x8f,0xb1,0xe7,0xf7,0x20,0x8d,
+ 0x01,0x04,0x8f,0xb1,0xe5,0x95,0x20,0x8d,
0x01,0x04,0x8f,0xb2,0x40,0x0a,0x20,0x8d,
- 0x01,0x04,0x90,0x22,0xa1,0x41,0x47,0x9d,
- 0x01,0x04,0x92,0x04,0x7c,0x86,0x20,0x8d,
+ 0x01,0x04,0x90,0x18,0xf5,0xb7,0x20,0x8d,
+ 0x01,0x04,0x90,0x7e,0x82,0xb2,0x20,0x8d,
+ 0x01,0x04,0x92,0x04,0x7c,0x81,0x20,0x8d,
+ 0x01,0x04,0x92,0x47,0x45,0x67,0x20,0x8d,
0x01,0x04,0x92,0x53,0x38,0x45,0x20,0x8d,
- 0x01,0x04,0x92,0x5a,0xc1,0x44,0x20,0x8d,
- 0x01,0x04,0x92,0xc4,0x37,0x9c,0x70,0xa1,
- 0x01,0x04,0x94,0x42,0x32,0x32,0x20,0x8f,
- 0x01,0x04,0x94,0xfb,0x01,0x14,0x20,0x97,
- 0x01,0x04,0x97,0x30,0x5f,0xd4,0x20,0x8d,
+ 0x01,0x04,0x93,0xc2,0xb1,0xa5,0x20,0x8d,
+ 0x01,0x04,0x95,0x5a,0xd6,0x4e,0x20,0x8d,
+ 0x01,0x04,0x95,0x66,0x9d,0x9c,0x20,0x8d,
+ 0x01,0x04,0x97,0xf8,0x9c,0x37,0x20,0x8d,
0x01,0x04,0x97,0xfc,0xc1,0xf5,0x20,0x8d,
- 0x01,0x04,0x98,0x2c,0x89,0x53,0x20,0x8d,
- 0x01,0x04,0x98,0x73,0xbf,0xc4,0x20,0x8d,
- 0x01,0x04,0x9a,0xdd,0x1f,0x56,0x20,0x8d,
+ 0x01,0x04,0x99,0x5c,0x5d,0x72,0x20,0x8d,
+ 0x01,0x04,0x9a,0xd3,0x06,0x02,0x20,0x8d,
0x01,0x04,0x9c,0x11,0x67,0x02,0x1f,0x98,
- 0x01,0x04,0x9d,0x8a,0x14,0x16,0x20,0x8d,
+ 0x01,0x04,0x9c,0x92,0xb1,0xdd,0x20,0x8d,
+ 0x01,0x04,0x9d,0x83,0x8f,0xad,0x20,0x8d,
0x01,0x04,0x9e,0x3a,0xbc,0x25,0x20,0x8d,
- 0x01,0x04,0x9e,0x8c,0xd1,0x4f,0x20,0x8d,
+ 0x01,0x04,0x9e,0xf8,0x27,0xef,0x20,0x8d,
0x01,0x04,0x9f,0x59,0xe6,0x80,0x20,0x8d,
- 0x01,0x04,0x9f,0xf6,0x19,0x34,0x20,0x8d,
- 0x01,0x04,0xa0,0x14,0x3b,0xfa,0x20,0xf1,
- 0x01,0x04,0xa2,0x00,0xea,0xbe,0x20,0x8d,
- 0x01,0x04,0xa2,0x3e,0x1a,0xda,0x20,0x8d,
- 0x01,0x04,0xa2,0xfa,0xbc,0xc2,0x20,0x8d,
- 0x01,0x04,0xa2,0xfb,0x46,0x52,0x20,0x8d,
- 0x01,0x04,0xa3,0x9e,0xce,0xff,0x20,0x8d,
- 0x01,0x04,0xa4,0x44,0x69,0x69,0x20,0x8d,
+ 0x01,0x04,0x9f,0xc4,0x03,0xef,0x20,0x8d,
+ 0x01,0x04,0x9f,0xe0,0xbd,0xfa,0x20,0x8d,
+ 0x01,0x04,0xa0,0x48,0x33,0x9a,0x20,0x8d,
+ 0x01,0x04,0xa1,0x1d,0xec,0x37,0x20,0x8d,
+ 0x01,0x04,0xa1,0x61,0x77,0xa6,0x20,0x8d,
+ 0x01,0x04,0xa1,0xf6,0x0b,0xe6,0x20,0x8d,
+ 0x01,0x04,0xa2,0x3e,0x12,0xe2,0x20,0x8d,
+ 0x01,0x04,0xa2,0xfa,0x7b,0xb3,0x20,0x8d,
+ 0x01,0x04,0xa2,0xfa,0xbf,0xde,0x20,0x8d,
+ 0x01,0x04,0xa2,0xfe,0x76,0x14,0x20,0x8d,
+ 0x01,0x04,0xa3,0xac,0x51,0x46,0x20,0x8d,
+ 0x01,0x04,0xa4,0x5a,0x2f,0x08,0x20,0x8d,
0x01,0x04,0xa5,0xe4,0xae,0x75,0x20,0x8d,
- 0x01,0x04,0xa6,0x3e,0x52,0x67,0x80,0x03,
- 0x01,0x04,0xa6,0x46,0x31,0x1a,0x20,0x8d,
- 0x01,0x04,0xa6,0x4e,0xf1,0x09,0x20,0x8d,
- 0x01,0x04,0xa6,0x4e,0xf1,0x19,0x20,0x8d,
- 0x01,0x04,0xa7,0x47,0x49,0xf4,0x20,0x8d,
- 0x01,0x04,0xa7,0xb3,0x93,0x9b,0x20,0x8d,
+ 0x01,0x04,0xa6,0x46,0x91,0x97,0x20,0x8d,
0x01,0x04,0xa8,0x5b,0xee,0x08,0x20,0x8d,
+ 0x01,0x04,0xaa,0xfd,0x0b,0x19,0x20,0x8d,
+ 0x01,0x04,0xab,0x67,0xaa,0x73,0x20,0x8d,
+ 0x01,0x04,0xac,0x5d,0xa6,0x87,0x20,0x8d,
+ 0x01,0x04,0xac,0x67,0xd9,0xec,0x20,0x8d,
0x01,0x04,0xac,0x69,0x15,0xd8,0x20,0x8d,
- 0x01,0x04,0xac,0x75,0x69,0x5f,0x20,0x8d,
- 0x01,0x04,0xad,0x17,0x67,0x1e,0x1f,0x40,
- 0x01,0x04,0xad,0xcd,0x5c,0x97,0xd6,0x15,
- 0x01,0x04,0xad,0xcd,0x5c,0x9a,0xd6,0x15,
- 0x01,0x04,0xad,0xcd,0x5c,0x9d,0xd6,0x15,
+ 0x01,0x04,0xac,0x70,0x99,0x5f,0x20,0x8d,
+ 0x01,0x04,0xad,0x03,0xda,0x5b,0x20,0x8d,
+ 0x01,0x04,0xad,0x0c,0x77,0x85,0x20,0x8d,
+ 0x01,0x04,0xad,0x22,0x7f,0xb5,0x20,0x8d,
+ 0x01,0x04,0xad,0x4c,0x7b,0xad,0x20,0x8d,
+ 0x01,0x04,0xad,0xb0,0xc6,0x44,0x20,0x8d,
0x01,0x04,0xad,0xd0,0x98,0xda,0x20,0x8d,
0x01,0x04,0xad,0xf1,0xe3,0xf3,0x20,0x8d,
- 0x01,0x04,0xae,0x03,0x04,0xe8,0x20,0x8d,
- 0x01,0x04,0xae,0x11,0x0b,0x16,0x20,0x8d,
- 0x01,0x04,0xae,0x58,0xf1,0xa7,0x20,0x8d,
- 0x01,0x04,0xae,0x72,0x66,0x29,0x20,0x8d,
+ 0x01,0x04,0xad,0xf6,0x1b,0x07,0x20,0x8d,
+ 0x01,0x04,0xad,0xff,0xf0,0xcd,0x20,0x8d,
+ 0x01,0x04,0xae,0x1e,0x2f,0x0f,0x20,0x8d,
0x01,0x04,0xae,0x72,0xfa,0x56,0x20,0x8d,
+ 0x01,0x04,0xae,0x8a,0x23,0xe5,0x20,0x8d,
0x01,0x04,0xae,0x8e,0xbf,0x88,0x20,0x8d,
- 0x01,0x04,0xaf,0x27,0x48,0x57,0x20,0x8d,
- 0x01,0x04,0xb0,0x0c,0x10,0x87,0x20,0x8d,
- 0x01,0x04,0xb0,0x25,0x17,0x1e,0x20,0x8d,
- 0x01,0x04,0xb0,0x3e,0xb3,0xdd,0x20,0x8d,
+ 0x01,0x04,0xb0,0x0a,0x8f,0xbe,0x20,0x8d,
0x01,0x04,0xb0,0x4a,0x88,0xed,0x20,0x8d,
- 0x01,0x04,0xb0,0x63,0x06,0xe2,0x20,0x8d,
+ 0x01,0x04,0xb0,0x76,0xdc,0x1d,0x20,0x8d,
+ 0x01,0x04,0xb0,0x7e,0x74,0x07,0x20,0x8d,
+ 0x01,0x04,0xb0,0x7e,0xa7,0x0a,0x20,0x8d,
0x01,0x04,0xb0,0xd4,0xb9,0x99,0x20,0x8d,
+ 0x01,0x04,0xb0,0xeb,0xd1,0xba,0x20,0x8d,
0x01,0x04,0xb1,0x51,0xec,0x75,0x20,0x8d,
- 0x01,0x04,0xb2,0x13,0x6a,0x1a,0x20,0x8d,
- 0x01,0x04,0xb2,0x15,0x76,0xb2,0x20,0x8d,
- 0x01,0x04,0xb2,0x21,0xe8,0x45,0x20,0x8d,
- 0x01,0x04,0xb2,0x4f,0x54,0x8b,0x20,0x8d,
+ 0x01,0x04,0xb1,0x59,0xcd,0x46,0x20,0x8d,
+ 0x01,0x04,0xb2,0x30,0xa8,0x0c,0x20,0x8d,
0x01,0x04,0xb2,0x7c,0xa2,0xd1,0x20,0x8d,
- 0x01,0x04,0xb2,0x84,0x02,0xf6,0x20,0x8d,
- 0x01,0x04,0xb2,0x96,0x60,0x2e,0x20,0x8d,
- 0x01,0x04,0xb2,0xa2,0xd4,0x2c,0x20,0x8d,
- 0x01,0x04,0xb2,0xc1,0xe2,0x78,0x20,0x8d,
+ 0x01,0x04,0xb2,0x9f,0x62,0x85,0x20,0x8d,
+ 0x01,0x04,0xb2,0xc4,0x59,0xd1,0x20,0x8d,
0x01,0x04,0xb2,0xec,0x89,0x3f,0x20,0x8d,
+ 0x01,0x04,0xb2,0xfc,0x7b,0x18,0x20,0x8d,
+ 0x01,0x04,0xb3,0x2b,0xaa,0xba,0x20,0x8d,
0x01,0x04,0xb4,0x96,0x2e,0xbb,0x20,0x8d,
- 0x01,0x04,0xb5,0xa4,0xd2,0xe4,0x21,0x52,
- 0x01,0x04,0xb7,0x6e,0xdc,0xd2,0x76,0x5d,
- 0x01,0x04,0xb8,0x5f,0x3a,0xa6,0x20,0x90,
- 0x01,0x04,0xb8,0xa4,0x93,0x52,0xa1,0x75,
- 0x01,0x04,0xb8,0xab,0xd0,0x6d,0x20,0x8d,
- 0x01,0x04,0xb9,0x11,0x8f,0xdc,0x20,0x8d,
- 0x01,0x04,0xb9,0x15,0xd9,0x31,0x20,0x8d,
+ 0x01,0x04,0xb5,0x75,0x80,0x8c,0x20,0x8d,
+ 0x01,0x04,0xb8,0x13,0x13,0x10,0x20,0x8d,
+ 0x01,0x04,0xb9,0x15,0xd9,0x30,0x20,0x8d,
0x01,0x04,0xb9,0x19,0x30,0xb8,0x20,0x8d,
- 0x01,0x04,0xb9,0x1c,0x60,0x10,0x20,0x8d,
0x01,0x04,0xb9,0x1f,0x88,0xf6,0x20,0x8d,
+ 0x01,0x04,0xb9,0x34,0x5d,0x2d,0x20,0x8d,
0x01,0x04,0xb9,0x40,0x74,0x0f,0x20,0x8d,
0x01,0x04,0xb9,0x44,0xf9,0x5b,0x20,0x8d,
- 0x01,0x04,0xb9,0x6c,0xf7,0xbe,0x20,0x8d,
- 0x01,0x04,0xb9,0x8d,0x3c,0x24,0x20,0x8d,
- 0x01,0x04,0xb9,0x94,0x03,0xe3,0x20,0x8d,
+ 0x01,0x04,0xb9,0x62,0x36,0x14,0x20,0x8d,
+ 0x01,0x04,0xb9,0x6b,0x53,0x37,0x20,0x8d,
+ 0x01,0x04,0xb9,0x8c,0xfd,0xa9,0x20,0x8d,
0x01,0x04,0xb9,0x94,0x91,0x4a,0x20,0x8d,
- 0x01,0x04,0xb9,0x9f,0x14,0x8f,0x20,0x8d,
+ 0x01,0x04,0xb9,0xa5,0xaa,0x13,0x20,0x8d,
0x01,0x04,0xb9,0xa7,0x71,0x3b,0x20,0x8d,
0x01,0x04,0xb9,0xb9,0x1a,0x8d,0x1f,0xaf,
- 0x01,0x04,0xb9,0xbd,0x84,0xb2,0xe1,0xb4,
- 0x01,0x04,0xb9,0xcc,0xc5,0x70,0x20,0x8d,
+ 0x01,0x04,0xb9,0xc5,0xa3,0x88,0x20,0x8d,
+ 0x01,0x04,0xb9,0xd1,0x0c,0x4c,0x20,0x8d,
0x01,0x04,0xb9,0xd1,0x46,0x11,0x20,0x8d,
- 0x01,0x04,0xb9,0xdc,0x9c,0xc1,0x20,0x8d,
- 0x01,0x04,0xb9,0xee,0x81,0x71,0x20,0x8d,
+ 0x01,0x04,0xb9,0xe3,0x9c,0xe2,0x20,0x8d,
+ 0x01,0x04,0xb9,0xe9,0xbd,0xd2,0x20,0x8d,
0x01,0x04,0xb9,0xef,0xdd,0x05,0x20,0x8d,
- 0x01,0x04,0xb9,0xf4,0xd9,0x27,0x20,0x8d,
+ 0x01,0x04,0xb9,0xf4,0x64,0x6a,0x20,0x8d,
0x01,0x04,0xb9,0xfe,0x61,0xa4,0x20,0x8d,
0x01,0x04,0xba,0x21,0xa7,0x0b,0x20,0x8d,
+ 0x01,0x04,0xba,0xb0,0x62,0x25,0x20,0x8d,
+ 0x01,0x04,0xba,0xf9,0xd9,0x19,0x20,0x8d,
+ 0x01,0x04,0xba,0xfa,0x5f,0x84,0x20,0x8d,
0x01,0x04,0xbc,0x20,0x0e,0x1f,0x20,0x8e,
- 0x01,0x04,0xbc,0x2a,0x28,0xea,0x47,0x9d,
- 0x01,0x04,0xbc,0x86,0x08,0x24,0x20,0x8d,
+ 0x01,0x04,0xbc,0x23,0xa7,0x0e,0x20,0x8d,
+ 0x01,0x04,0xbc,0x44,0x2d,0x8f,0x20,0x8d,
+ 0x01,0x04,0xbc,0x75,0xc8,0xd4,0x20,0x8d,
0x01,0x04,0xbc,0x8a,0x58,0x0e,0x20,0x8d,
- 0x01,0x04,0xbc,0x9c,0x6e,0xef,0x20,0x8d,
- 0x01,0x04,0xbc,0xa5,0xf4,0x8f,0x20,0x8d,
- 0x01,0x04,0xbc,0xd5,0x44,0x26,0x20,0x8d,
- 0x01,0x04,0xbc,0xd6,0x81,0x41,0x4e,0x2c,
- 0x01,0x04,0xbc,0xf2,0x0f,0x4a,0x20,0x8d,
- 0x01,0x04,0xbc,0xf4,0x04,0x4e,0x20,0x8d,
- 0x01,0x04,0xbd,0x27,0x06,0x52,0x20,0x8d,
- 0x01,0x04,0xbd,0xcf,0x2e,0x20,0x20,0x8d,
- 0x01,0x04,0xbd,0xd4,0x79,0x4a,0x20,0x8d,
- 0x01,0x04,0xc0,0x03,0x0b,0x14,0x20,0x8d,
- 0x01,0x04,0xc0,0x41,0xaa,0x0f,0x20,0x8d,
+ 0x01,0x04,0xbc,0x97,0xed,0x9e,0x20,0x8d,
+ 0x01,0x04,0xbc,0x9a,0xec,0x31,0x20,0x8d,
+ 0x01,0x04,0xbd,0x7b,0xb1,0x80,0x20,0x8d,
+ 0x01,0x04,0xbe,0x7b,0x1b,0x0b,0x20,0x8d,
+ 0x01,0x04,0xbe,0x91,0x7f,0xfe,0x20,0x8d,
+ 0x01,0x04,0xc0,0x45,0x35,0x4d,0x20,0x8d,
0x01,0x04,0xc0,0x92,0x89,0x2c,0x20,0x8d,
- 0x01,0x04,0xc0,0xb6,0x9d,0x77,0x20,0x8d,
- 0x01,0x04,0xc0,0xbb,0x6d,0x8d,0x20,0x8d,
- 0x01,0x04,0xc0,0xe3,0x50,0x53,0x20,0x8d,
- 0x01,0x04,0xc1,0x0a,0xcb,0x17,0x20,0x8e,
- 0x01,0x04,0xc1,0x20,0x7f,0xa0,0xe4,0x6d,
- 0x01,0x04,0xc1,0x20,0x7f,0xa2,0xe4,0x6d,
- 0x01,0x04,0xc1,0x3a,0xc4,0xd4,0x20,0x8d,
- 0x01,0x04,0xc1,0x6a,0x1d,0x6a,0x20,0x8d,
- 0x01,0x04,0xc1,0x8a,0x9a,0x2b,0x20,0x8d,
- 0x01,0x04,0xc1,0xb2,0xaa,0xe8,0x20,0x8d,
+ 0x01,0x04,0xc0,0xde,0x18,0x36,0x20,0x8d,
+ 0x01,0x04,0xc0,0xde,0x93,0x8d,0x20,0x8d,
+ 0x01,0x04,0xc1,0x20,0x7f,0xa2,0xee,0x29,
+ 0x01,0x04,0xc1,0x6f,0xc6,0xbb,0x1f,0xaf,
0x01,0x04,0xc1,0xc4,0x25,0x3e,0x20,0x8d,
- 0x01,0x04,0xc1,0xde,0x82,0x0e,0x20,0x8d,
- 0x01,0x04,0xc1,0xea,0x32,0xe3,0x20,0x8d,
- 0x01,0x04,0xc2,0x0e,0xf6,0xcd,0x20,0x8d,
- 0x01,0x04,0xc2,0x87,0x87,0x45,0x20,0x8d,
+ 0x01,0x04,0xc2,0x0d,0x50,0xb9,0x3c,0x46,
0x01,0x04,0xc2,0x93,0x71,0xc9,0x20,0x8d,
0x01,0x04,0xc2,0xa5,0x1e,0x14,0x20,0x8d,
- 0x01,0x04,0xc2,0xdb,0x3e,0x17,0x20,0x8d,
+ 0x01,0x04,0xc2,0xbf,0xef,0x62,0x20,0x8d,
0x01,0x04,0xc3,0x38,0x3f,0x04,0x20,0x8d,
- 0x01,0x04,0xc3,0x86,0xb7,0xbc,0x20,0x8d,
- 0x01,0x04,0xc3,0xd0,0x67,0x1e,0x20,0xfc,
- 0x01,0x04,0xc3,0xd0,0x67,0x1f,0x20,0xfc,
+ 0x01,0x04,0xc3,0x38,0x3f,0x0a,0x20,0x8d,
+ 0x01,0x04,0xc3,0x7b,0xef,0xb9,0x20,0x8d,
+ 0x01,0x04,0xc3,0x8c,0xe2,0x9a,0x20,0x8d,
0x01,0x04,0xc6,0x01,0xe7,0x06,0x20,0x8d,
- 0x01,0x04,0xc6,0x0c,0x0e,0x88,0x20,0x8d,
- 0x01,0x04,0xc6,0x54,0xed,0x46,0x20,0x8d,
- 0x01,0x04,0xc6,0xb2,0x78,0x05,0x1f,0xb0,
- 0x01,0x04,0xc7,0x30,0x5c,0xb8,0x20,0x8d,
- 0x01,0x04,0xc7,0x44,0xc7,0x13,0x20,0x8d,
- 0x01,0x04,0xc7,0xb6,0xb8,0xcc,0x20,0x8d,
- 0x01,0x04,0xc7,0xbd,0xf2,0x8d,0x20,0x8d,
+ 0x01,0x04,0xc6,0x94,0x70,0x1b,0x20,0x8d,
+ 0x01,0x04,0xc7,0x7e,0xea,0xed,0x20,0x8d,
+ 0x01,0x04,0xc7,0xc1,0xae,0xad,0x20,0x8d,
0x01,0x04,0xc7,0xf7,0x07,0xd0,0x20,0x8d,
- 0x01,0x04,0xc8,0x7a,0xb5,0x25,0x20,0x8d,
+ 0x01,0x04,0xc8,0x7a,0xb5,0x2e,0x20,0x8d,
0x01,0x04,0xc9,0xbf,0x06,0x67,0x20,0x8d,
- 0x01,0x04,0xca,0x6b,0xdb,0x82,0x20,0x8d,
+ 0x01,0x04,0xc9,0xd4,0x24,0xd1,0x20,0x8d,
+ 0x01,0x04,0xc9,0xdd,0xea,0xc8,0x20,0x8d,
0x01,0x04,0xca,0x6c,0xd3,0x87,0x20,0x8d,
- 0x01,0x04,0xcb,0x5e,0x21,0x70,0x20,0x8d,
+ 0x01,0x04,0xca,0xa9,0x11,0xb2,0x20,0x8d,
+ 0x01,0x04,0xca,0xb1,0x18,0x8c,0x20,0x8d,
0x01,0x04,0xcb,0x82,0x30,0x75,0x22,0xb5,
0x01,0x04,0xcb,0x84,0x5e,0xc4,0x20,0x8d,
- 0x01,0x04,0xcb,0xa2,0x0d,0xb5,0x20,0x8c,
- 0x01,0x04,0xcc,0xbf,0xc9,0x2b,0x20,0x8d,
- 0x01,0x04,0xcc,0xe5,0x0a,0x5a,0x20,0x8d,
0x01,0x04,0xcd,0xb2,0x29,0x7c,0x20,0x8d,
- 0x01,0x04,0xce,0x37,0xb2,0x9d,0x20,0x8d,
- 0x01,0x04,0xce,0x7e,0xcb,0x08,0x20,0x8d,
- 0x01,0x04,0xce,0xae,0x73,0x60,0x20,0x8d,
+ 0x01,0x04,0xce,0x48,0xc9,0xe4,0x20,0x8d,
+ 0x01,0x04,0xce,0xc0,0xcb,0x00,0x20,0x8d,
0x01,0x04,0xce,0xdf,0x99,0x34,0x20,0x8d,
- 0x01,0x04,0xcf,0xbc,0x9f,0x19,0x20,0x8d,
+ 0x01,0x04,0xcf,0x86,0xd8,0x91,0x20,0x8e,
+ 0x01,0x04,0xcf,0xbc,0x9a,0x32,0x20,0x8d,
0x01,0x04,0xcf,0xe5,0x2e,0x50,0x20,0x8d,
+ 0x01,0x04,0xcf,0xff,0xc1,0x2f,0x20,0x8d,
+ 0x01,0x04,0xd0,0x68,0x5c,0x4a,0x20,0x8d,
0x01,0x04,0xd1,0x3a,0x91,0x9d,0x20,0x8d,
- 0x01,0x04,0xd1,0x7e,0x51,0x93,0x20,0x8d,
- 0x01,0x04,0xd1,0x91,0x3f,0x96,0x20,0x8d,
- 0x01,0x04,0xd1,0xd1,0x0a,0x1e,0x20,0x8d,
+ 0x01,0x04,0xd1,0x3a,0x9e,0xe8,0x20,0x8f,
+ 0x01,0x04,0xd1,0x8d,0x2b,0xf3,0x20,0x8d,
+ 0x01,0x04,0xd1,0xe2,0x8e,0x3e,0x20,0x8d,
0x01,0x04,0xd1,0xed,0x7f,0xe3,0x20,0x8d,
- 0x01,0x04,0xd4,0x63,0xe2,0x24,0x23,0x3c,
- 0x01,0x04,0xd4,0xb9,0x56,0x54,0x20,0x8d,
+ 0x01,0x04,0xd1,0xed,0x85,0x36,0x20,0x8d,
+ 0x01,0x04,0xd3,0xf8,0x5a,0x32,0x20,0x8d,
+ 0x01,0x04,0xd4,0x15,0x12,0x4e,0x20,0x8d,
+ 0x01,0x04,0xd4,0x22,0xe1,0x76,0x20,0x8d,
+ 0x01,0x04,0xd4,0x33,0x92,0x89,0x20,0x8d,
0x01,0x04,0xd4,0xe3,0xd3,0x57,0x20,0x8d,
+ 0x01,0x04,0xd5,0x00,0x45,0x4c,0x20,0x8d,
0x01,0x04,0xd5,0x05,0x24,0x3a,0x20,0x8d,
- 0x01,0x04,0xd5,0x59,0xec,0xdb,0x20,0x8d,
- 0x01,0x04,0xd5,0x5d,0x91,0xb7,0x20,0x8d,
+ 0x01,0x04,0xd5,0x2f,0x40,0x69,0x20,0x8d,
+ 0x01,0x04,0xd5,0x59,0x87,0x97,0x20,0x8d,
+ 0x01,0x04,0xd5,0x8d,0x9a,0xc9,0x20,0x8d,
+ 0x01,0x04,0xd5,0x9f,0xc6,0x2d,0x20,0x8d,
+ 0x01,0x04,0xd5,0xb8,0xf4,0x18,0x20,0x8d,
0x01,0x04,0xd5,0xd6,0x42,0xb6,0x20,0x8d,
- 0x01,0x04,0xd8,0x29,0xf9,0xb2,0x20,0x8d,
+ 0x01,0x04,0xd5,0xe2,0x7b,0x4c,0x20,0x8d,
0x01,0x04,0xd8,0x92,0xfb,0x08,0x20,0x8d,
- 0x01,0x04,0xd8,0xf9,0x46,0x16,0x20,0x8d,
- 0x01,0x04,0xd9,0x0b,0xf0,0x04,0x20,0x8d,
- 0x01,0x04,0xd9,0x0f,0xb2,0x07,0x20,0x8d,
- 0x01,0x04,0xd9,0x18,0xe9,0x74,0x20,0x8d,
- 0x01,0x04,0xd9,0x40,0x94,0x62,0xc8,0xc9,
+ 0x01,0x04,0xd8,0xba,0xee,0x0e,0x20,0x8d,
+ 0x01,0x04,0xd9,0x05,0x96,0x72,0x20,0x8d,
+ 0x01,0x04,0xd9,0x0f,0xb2,0x0b,0x20,0x8d,
+ 0x01,0x04,0xd9,0x18,0xef,0x6d,0x20,0x8d,
+ 0x01,0x04,0xd9,0x40,0x2f,0x8a,0x20,0x8d,
+ 0x01,0x04,0xd9,0x49,0x50,0x68,0x20,0x8d,
+ 0x01,0x04,0xd9,0x4f,0xb5,0x26,0x20,0x8d,
+ 0x01,0x04,0xd9,0x5c,0x37,0xf6,0x20,0x8d,
0x01,0x04,0xd9,0x71,0x79,0xa9,0x20,0x8d,
+ 0x01,0x04,0xd9,0x73,0x74,0xfa,0x20,0x8d,
+ 0x01,0x04,0xd9,0x9b,0xf4,0xaa,0x20,0x8d,
0x01,0x04,0xd9,0xaa,0x7c,0xaa,0x20,0x8d,
0x01,0x04,0xdc,0x84,0x87,0x36,0x20,0x8d,
- 0x01,0x04,0xdc,0xdd,0x3a,0x19,0x20,0x8d,
0x01,0x04,0xdc,0xe9,0xb2,0xc7,0x20,0x8d,
- 0x01,0x04,0xdd,0xdb,0x61,0x69,0x07,0xd1,
- 0x02,0x10,0x20,0x01,0x16,0x08,0x00,0x1b,0x00,0xf9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x67,0x7b,
+ 0x01,0x04,0xde,0x9a,0x6f,0x2e,0x20,0x8d,
0x02,0x10,0x20,0x01,0x16,0x20,0x05,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x19,0xf0,0x60,0x01,0x39,0xaa,0x54,0x00,0x03,0xff,0xfe,0xf0,0x09,0x16,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x19,0xf0,0x80,0x01,0x0f,0x71,0x54,0x00,0x04,0xff,0xfe,0x10,0x6a,0x63,0x20,0x8d,
0x02,0x10,0x20,0x01,0x1b,0xc0,0x00,0xc1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x20,0x8d,
- 0x02,0x10,0x20,0x01,0x04,0x70,0x1f,0x0a,0x08,0x9a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x1c,0x02,0x01,0x1e,0x35,0x00,0xdf,0x25,0x63,0x21,0x82,0x60,0xd9,0xbe,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x41,0xd0,0x10,0x04,0x1b,0x79,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x93,
+ 0x02,0x10,0x20,0x01,0x41,0xd0,0x02,0x03,0x37,0x39,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x41,0xd0,0x02,0x03,0xaa,0xcc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x41,0xd0,0x02,0x03,0xbb,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x41,0xd0,0x00,0x02,0xbf,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x41,0xd0,0x03,0x03,0x65,0x86,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x41,0xd0,0x06,0x02,0x44,0x93,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x41,0xd0,0x00,0x08,0xb9,0xd8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x41,0xd0,0x00,0x0a,0x69,0xa2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x41,0xf0,0x00,0x00,0x00,0x00,0x00,0x62,0x69,0x74,0x63,0x6f,0x69,0x6e,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x44,0xb8,0x02,0x56,0x5d,0x11,0x02,0x16,0x3e,0xff,0xfe,0x39,0xd5,0xd4,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x04,0x70,0x1b,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x04,0x70,0x1f,0x07,0x08,0x03,0x02,0x0c,0x29,0xff,0xfe,0x2d,0x58,0x79,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x04,0x70,0x1f,0x15,0x01,0x06,0xe2,0xd5,0x5e,0xff,0xfe,0x42,0x7a,0xe5,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x04,0x70,0x1f,0x15,0x0c,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x04,0x70,0x00,0x26,0x04,0x72,0x00,0x00,0x00,0x00,0x00,0x00,0x0b,0x7c,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x04,0x70,0x75,0xe9,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x20,0x8d,
0x02,0x10,0x20,0x01,0x04,0x70,0xde,0x5a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xec,0x24,0x75,
- 0x02,0x10,0x20,0x01,0x4b,0x98,0x0d,0xc0,0x00,0x45,0x02,0x16,0x3e,0xff,0xfe,0xa2,0x95,0xcd,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x4b,0xa0,0xba,0xbe,0x05,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x4b,0xa0,0xff,0xff,0x00,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x4d,0xd0,0x35,0x64,0x00,0x00,0x30,0xb7,0x1d,0x7b,0x6f,0xec,0x4c,0x5c,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x4d,0xd0,0x35,0x64,0x00,0x00,0x08,0x8e,0xb4,0xff,0x2a,0xd0,0x69,0x9b,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x4d,0xd0,0x35,0x64,0x00,0x00,0x9c,0x1c,0xcc,0x31,0x9f,0xe8,0x55,0x05,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x4d,0xd0,0x35,0x64,0x00,0x00,0xa0,0xc4,0xd4,0x1f,0x04,0xc4,0x1b,0xb0,0x20,0x8d,
0x02,0x10,0x20,0x01,0x4d,0xd0,0x35,0x64,0x00,0x00,0xfd,0x76,0xc1,0xd3,0x18,0x54,0x5b,0xd9,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x4d,0xd0,0x35,0x64,0x00,0x01,0x00,0x00,0x00,0x00,0x76,0x76,0x80,0x90,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x4d,0xd0,0x35,0x64,0x00,0x01,0xb9,0x77,0xbd,0x71,0x46,0x12,0x8e,0x40,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x4d,0xd0,0xaf,0x0e,0x35,0x64,0x00,0x00,0x00,0x00,0x00,0x69,0x00,0x01,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x4d,0xd0,0xaf,0x0e,0x35,0x64,0x00,0x00,0x00,0x00,0x00,0x69,0x00,0x90,0x20,0x8d,
0x02,0x10,0x20,0x01,0x4d,0xe8,0xb1,0xb2,0x00,0x01,0x00,0x00,0xde,0xad,0xbe,0xef,0x00,0x07,0x20,0x8d,
0x02,0x10,0x20,0x01,0x06,0x38,0xa0,0x00,0x41,0x40,0x00,0x00,0x00,0x00,0xff,0xff,0x01,0x91,0x20,0x8d,
- 0x02,0x10,0x20,0x01,0x06,0x48,0x28,0x00,0x01,0x31,0x4b,0x1f,0xf6,0xfc,0x20,0xf7,0xf9,0x9f,0x20,0x8d,
- 0x02,0x10,0x20,0x01,0x06,0x78,0x0c,0xc8,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x10,0x00,0x88,0x4e,0x28,
+ 0x02,0x10,0x20,0x01,0x06,0x78,0x0a,0xcc,0x00,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d,
0x02,0x10,0x20,0x01,0x06,0x7c,0x26,0xb4,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x44,0x20,0x8d,
- 0x02,0x10,0x20,0x01,0x06,0x7c,0x2d,0xb8,0x00,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x92,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x06,0x7c,0x2d,0xb8,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x36,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x07,0xc0,0x23,0x10,0x00,0x00,0xf8,0x16,0x3e,0xff,0xfe,0x0d,0x4a,0xb6,0x20,0x8d,
0x02,0x10,0x20,0x01,0x07,0xc0,0x23,0x10,0x00,0x00,0xf8,0x16,0x3e,0xff,0xfe,0x6c,0x4f,0x58,0x20,0x8d,
- 0x02,0x10,0x20,0x01,0x08,0x18,0xea,0x1b,0x76,0x00,0xf0,0x53,0xaa,0xde,0xf4,0x7b,0xb7,0x01,0x20,0x8d,
- 0x02,0x10,0x20,0x01,0x08,0xf1,0x14,0x04,0x37,0x00,0x8e,0x49,0x71,0x5a,0x2e,0x09,0xb6,0x34,0x24,0xe4,
- 0x02,0x10,0x20,0x01,0x09,0x85,0x55,0xa0,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d,
- 0x02,0x10,0x20,0x01,0x09,0x99,0x02,0x70,0x2c,0x2c,0x0c,0x8b,0x3a,0x20,0x3f,0x2f,0x31,0x8f,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x08,0x61,0x32,0x46,0x0a,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x0b,0x07,0x02,0xe6,0x38,0xd7,0xba,0x27,0xeb,0xff,0xfe,0x60,0x3d,0xc1,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x0b,0x07,0x64,0x61,0x78,0x11,0x04,0x89,0xd2,0xda,0x0e,0x07,0x1a,0xf7,0x20,0x8d,
0x02,0x10,0x20,0x01,0x0b,0x07,0x0a,0xc9,0x44,0x2b,0x79,0xd6,0xbb,0xbe,0xb3,0x7c,0xa7,0x83,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x0b,0xc8,0x16,0x00,0x00,0x00,0x02,0x08,0xa2,0xff,0xfe,0x0c,0x8a,0x2e,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x0b,0xc8,0x32,0x3c,0x00,0xff,0xa6,0x34,0x38,0x4f,0x18,0x49,0xf4,0xbc,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x0b,0xc8,0x32,0x3c,0x00,0xff,0xd2,0x17,0xc2,0xff,0xfe,0x07,0x2c,0xd9,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x0b,0xc8,0x3b,0xec,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
0x02,0x10,0x20,0x02,0x2f,0x5b,0xa5,0xf9,0x00,0x00,0x00,0x00,0x00,0x00,0x2f,0x5b,0xa5,0xf9,0x22,0xb5,
- 0x02,0x10,0x20,0x02,0xb6,0xff,0x3d,0xca,0x00,0x00,0x00,0x00,0x00,0x00,0xb6,0xff,0x3d,0xca,0x6e,0xcc,
+ 0x02,0x10,0x20,0x03,0x00,0xcb,0x87,0x13,0x61,0x02,0xaa,0xa1,0x59,0xff,0xfe,0x57,0x77,0x79,0x20,0x8d,
+ 0x02,0x10,0x20,0x03,0x00,0xe0,0x37,0x0e,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x20,0x8d,
+ 0x02,0x10,0x20,0x03,0x00,0xf6,0x3f,0x10,0x67,0x00,0x4c,0x9f,0x76,0x20,0x83,0x24,0xd4,0xa7,0x20,0x8d,
0x02,0x10,0x24,0x00,0x24,0x10,0xce,0xa2,0x0d,0x00,0x41,0xbc,0xc9,0xea,0x86,0x1b,0x51,0xee,0x20,0x8d,
+ 0x02,0x10,0x24,0x00,0x24,0x11,0xa3,0xe1,0x49,0x00,0x25,0x68,0x68,0x4b,0x0e,0x99,0x71,0x20,0x20,0x8d,
+ 0x02,0x10,0x24,0x00,0x24,0x11,0xa3,0xe1,0x49,0x00,0x29,0x87,0xb8,0x8f,0x61,0xe0,0x84,0xfa,0x20,0x8d,
0x02,0x10,0x24,0x00,0x3b,0x00,0x00,0x20,0x00,0x0c,0xba,0xcb,0x29,0xff,0xfe,0xab,0x88,0x86,0x20,0x8d,
+ 0x02,0x10,0x24,0x01,0xb1,0x40,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x02,0x10,0x20,0x8d,
+ 0x02,0x10,0x24,0x01,0xb1,0x40,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x02,0x20,0x20,0x8d,
+ 0x02,0x10,0x24,0x01,0xb1,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x42,0x01,0x00,0x20,0x8d,
+ 0x02,0x10,0x24,0x01,0xb1,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x44,0x01,0x30,0x20,0x8d,
0x02,0x10,0x24,0x01,0xd0,0x02,0x39,0x02,0x07,0x00,0xd7,0x2c,0x5e,0x22,0x4e,0x95,0x38,0x9d,0x20,0x8d,
- 0x02,0x10,0x24,0x03,0x62,0x00,0x88,0xa0,0xfb,0x17,0xf5,0xf2,0xd8,0xb5,0xb7,0xba,0xf4,0xd3,0x20,0x8d,
- 0x02,0x10,0x24,0x05,0x98,0x00,0xb9,0x10,0x5f,0x8e,0x18,0x30,0xf6,0x30,0x2c,0xc6,0x88,0xfb,0x20,0x8d,
- 0x02,0x10,0x24,0x05,0x98,0x00,0xb9,0x70,0xc6,0x4c,0x10,0x9f,0x74,0xe7,0xae,0x5f,0x87,0xc7,0x20,0x8d,
- 0x02,0x10,0x24,0x05,0xaa,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x20,0x8d,
- 0x02,0x10,0x24,0x07,0x88,0x00,0xbc,0x61,0x22,0x02,0xd6,0x3d,0x7e,0xff,0xfe,0x6c,0xdc,0x36,0x20,0x8d,
- 0x02,0x10,0x24,0x08,0x82,0x48,0x70,0x04,0xf8,0x31,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x3c,0x20,0x8d,
+ 0x02,0x10,0x24,0x04,0x44,0x08,0x67,0x52,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x19,0x99,0x20,0x8d,
+ 0x02,0x10,0x24,0x04,0x7a,0x85,0x41,0x61,0x2b,0x00,0x49,0xa1,0x42,0x7a,0x0f,0xac,0x34,0x09,0x20,0x8d,
+ 0x02,0x10,0x24,0x05,0x98,0x00,0xb9,0x72,0xab,0x58,0x0c,0x05,0xe9,0x38,0x26,0x7e,0x02,0x71,0x20,0x8d,
+ 0x02,0x10,0x24,0x06,0xda,0x11,0x01,0x69,0x0b,0x03,0x32,0xb5,0xf9,0x01,0x9f,0x7c,0x3e,0x4b,0x20,0x8d,
+ 0x02,0x10,0x24,0x06,0xda,0x14,0x03,0x35,0xb6,0x01,0xce,0xb7,0xb4,0xfc,0xa8,0x55,0xf3,0xa5,0x20,0x8d,
+ 0x02,0x10,0x24,0x06,0xda,0x1e,0x0a,0x4e,0x8a,0x03,0x2a,0xad,0x49,0x6b,0x76,0x8d,0xe4,0x97,0x20,0x8d,
+ 0x02,0x10,0x24,0x07,0x88,0x00,0xbc,0x61,0x22,0x02,0xa0,0xc6,0x01,0x07,0x50,0x2b,0x4e,0x3b,0x20,0x8d,
0x02,0x10,0x24,0x09,0x00,0x10,0xca,0x20,0x1d,0xf0,0x02,0x24,0xe8,0xff,0xfe,0x1f,0x60,0xd9,0x20,0x8d,
- 0x02,0x10,0x24,0x0b,0x00,0x11,0x43,0xa1,0xbd,0x00,0xe5,0x89,0xf8,0xa7,0x04,0x9b,0x3b,0x86,0x20,0x8d,
- 0x02,0x10,0x24,0x0d,0x00,0x1a,0x07,0x91,0x34,0x00,0xd6,0x5d,0x64,0xff,0xfe,0x28,0x92,0x7e,0x20,0x8d,
- 0x02,0x10,0x24,0x0d,0x00,0x1a,0x07,0x91,0x34,0x00,0xd6,0x81,0xd7,0xff,0xfe,0xf6,0xa2,0x1e,0x27,0x42,
- 0x02,0x10,0x26,0x00,0x17,0x00,0x5b,0x2b,0x00,0x5f,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x40,0x20,0x8d,
+ 0x02,0x10,0x26,0x00,0x17,0x00,0x22,0xf1,0x64,0x1f,0x00,0xe8,0x39,0xc8,0xeb,0x1d,0xa1,0xeb,0x20,0x8d,
+ 0x02,0x10,0x26,0x00,0x17,0x00,0x9c,0x5d,0x0e,0xd0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x20,0x8d,
+ 0x02,0x10,0x26,0x00,0x17,0x00,0x9c,0x5d,0x0e,0xd0,0xd0,0xd6,0x01,0xd9,0x5c,0xc2,0xab,0x47,0x20,0x8d,
+ 0x02,0x10,0x26,0x00,0x17,0x02,0x1c,0xe0,0x40,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x20,0x8d,
+ 0x02,0x10,0x26,0x00,0x1f,0x14,0x04,0x0e,0xe3,0x01,0xd1,0x55,0xaa,0x3a,0x77,0xbe,0x96,0x0e,0x20,0x8d,
+ 0x02,0x10,0x26,0x00,0x1f,0x16,0x0a,0x08,0xb9,0x01,0x1a,0xfa,0xef,0x4e,0x4c,0xe7,0x2b,0xa4,0x20,0x8d,
+ 0x02,0x10,0x26,0x00,0x1f,0x1c,0x02,0xd3,0x24,0x03,0x5b,0xac,0x3f,0xc6,0x65,0x13,0x7a,0x63,0x20,0x8d,
0x02,0x10,0x26,0x00,0x21,0x04,0x10,0x03,0xc5,0xab,0xdc,0x5e,0x90,0xff,0xfe,0x18,0x1d,0x08,0x20,0x8d,
+ 0x02,0x10,0x26,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x92,0xff,0xfe,0x92,0x27,0x45,0x20,0x8d,
+ 0x02,0x10,0x26,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x92,0xff,0xfe,0xcf,0x61,0xb6,0x20,0x8d,
+ 0x02,0x10,0x26,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x93,0xff,0xfe,0xb3,0x01,0xb6,0x20,0x8d,
0x02,0x10,0x26,0x00,0x3c,0x00,0xe0,0x02,0x2e,0x32,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x14,0x20,0x8d,
+ 0x02,0x10,0x26,0x00,0x3c,0x02,0x00,0x00,0x00,0x00,0xf0,0x3c,0x92,0xff,0xfe,0x5d,0x09,0xfb,0x20,0x8d,
+ 0x02,0x10,0x26,0x00,0x40,0x40,0x28,0x54,0x5e,0x00,0xc6,0xe9,0x84,0xff,0xfe,0x46,0x0e,0xe8,0x21,0xda,
+ 0x02,0x10,0x26,0x00,0x6c,0x54,0x71,0x00,0x1a,0xd1,0xbd,0xdf,0x55,0x0e,0x91,0xbe,0xf9,0xe1,0x20,0x8d,
0x02,0x10,0x26,0x00,0x88,0x05,0x24,0x00,0x01,0x4e,0x12,0xdd,0xb1,0xff,0xfe,0xf2,0x30,0x13,0x20,0x8d,
+ 0x02,0x10,0x26,0x01,0x01,0x84,0x03,0x00,0x0b,0xde,0x3c,0x29,0x8e,0x94,0x1b,0xa8,0xfd,0xe3,0x20,0x8d,
+ 0x02,0x10,0x26,0x01,0x01,0x8c,0x80,0x80,0x30,0x0f,0x02,0x19,0xd1,0xff,0xfe,0x75,0xdc,0x2f,0x20,0x8d,
+ 0x02,0x10,0x26,0x01,0x01,0x8d,0x46,0x00,0x43,0xf1,0x20,0xe7,0xb3,0xff,0xfe,0xcf,0x0a,0x99,0x20,0x8d,
+ 0x02,0x10,0x26,0x01,0x01,0x8d,0x87,0x01,0xc2,0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x30,0x20,0x8d,
+ 0x02,0x10,0x26,0x01,0x02,0x46,0x4d,0x7f,0x9e,0x28,0xf3,0x21,0x36,0xca,0x7a,0x71,0xc6,0x87,0x20,0x8d,
+ 0x02,0x10,0x26,0x01,0x06,0x40,0xc2,0x01,0x96,0x0d,0x86,0xeb,0xf2,0x7d,0x66,0xa2,0xf2,0xc1,0x20,0x8d,
+ 0x02,0x10,0x26,0x02,0x02,0x41,0x75,0xd1,0x2b,0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x40,0x20,0x8d,
0x02,0x10,0x26,0x02,0xff,0xb8,0x00,0x00,0x00,0x00,0x02,0x08,0x00,0x72,0x00,0x57,0x02,0x00,0x20,0x8d,
- 0x02,0x10,0x26,0x03,0x30,0x1f,0x1e,0xbf,0xe0,0x00,0xe2,0x3f,0x49,0xff,0xfe,0xe7,0x74,0x31,0x20,0x8d,
- 0x02,0x10,0x26,0x03,0x60,0x81,0x18,0x00,0x66,0x00,0x16,0xdd,0xa9,0xff,0xfe,0xee,0xb2,0xf3,0x20,0x8d,
- 0x02,0x10,0x26,0x04,0x13,0x80,0x10,0x00,0x74,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
- 0x02,0x10,0x26,0x04,0x45,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2e,0x06,0x1f,0xb0,
- 0x02,0x10,0x26,0x04,0x55,0x00,0xc1,0x34,0x40,0x00,0x72,0x85,0xc2,0xff,0xfe,0x4a,0xe1,0x43,0x80,0x1d,
- 0x02,0x10,0x26,0x04,0x55,0x00,0xc1,0x34,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xfc,0x80,0x1d,
+ 0x02,0x10,0x26,0x03,0x30,0x04,0x06,0xa1,0x38,0x00,0x85,0x1f,0x58,0x4d,0x7a,0xba,0xaf,0xfb,0x20,0x8d,
+ 0x02,0x10,0x26,0x03,0x30,0x04,0x06,0xa1,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x44,0x02,0x20,0x8d,
+ 0x02,0x10,0x26,0x03,0x30,0x04,0x07,0x0d,0x14,0x00,0x85,0x32,0x29,0x00,0xce,0x6f,0xac,0xdf,0x20,0x8d,
+ 0x02,0x10,0x26,0x03,0x30,0x04,0x07,0x45,0x09,0x00,0xf0,0xd7,0x55,0x6a,0x0a,0x8c,0xce,0xd5,0x20,0x8d,
+ 0x02,0x10,0x26,0x03,0x60,0x80,0xc0,0x00,0x5d,0x8a,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x4f,0x20,0x8d,
+ 0x02,0x10,0x26,0x03,0x80,0x00,0xd1,0x00,0x89,0x91,0xcc,0x29,0xcc,0xff,0xfe,0x42,0x30,0x0c,0x20,0x8d,
+ 0x02,0x10,0x26,0x03,0x80,0x80,0x1f,0x07,0x6f,0xdd,0x7d,0xe2,0xd9,0x69,0x78,0xc9,0xb7,0xea,0x20,0x8d,
+ 0x02,0x10,0x26,0x03,0x80,0x80,0x73,0x00,0x05,0x31,0x00,0x00,0x00,0x00,0x00,0x00,0x13,0xea,0x20,0x8d,
+ 0x02,0x10,0x26,0x03,0x80,0xa0,0x07,0x03,0x40,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x20,0x8d,
+ 0x02,0x10,0x26,0x04,0x01,0x80,0x00,0xf3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x18,0x20,0x8d,
+ 0x02,0x10,0x26,0x04,0x3d,0x08,0x00,0x00,0x00,0x05,0xd9,0x41,0x4b,0x03,0xa0,0x93,0x13,0x1b,0x20,0x8d,
0x02,0x10,0x26,0x04,0x7c,0x00,0x01,0x20,0x00,0x4b,0x00,0x00,0x00,0x00,0x00,0x00,0xeb,0x24,0x20,0x8d,
+ 0x02,0x10,0x26,0x04,0x0a,0x00,0x00,0x21,0x30,0x43,0xbf,0x6a,0x53,0x5e,0xdf,0xeb,0x5b,0x7b,0x20,0x8d,
+ 0x02,0x10,0x26,0x04,0xa8,0x80,0x04,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x1c,0xe7,0x40,0x01,0x20,0x8d,
+ 0x02,0x10,0x26,0x04,0xa8,0x80,0x04,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x1d,0x44,0xe0,0x01,0x20,0x8d,
+ 0x02,0x10,0x26,0x04,0xa8,0x80,0x04,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x26,0x1f,0x60,0x01,0x20,0x8d,
+ 0x02,0x10,0x26,0x04,0xa8,0x80,0x04,0x00,0x00,0xd1,0x00,0x00,0x00,0x00,0x07,0xe2,0xe0,0x01,0x20,0x8d,
+ 0x02,0x10,0x26,0x04,0xa8,0x80,0x00,0x04,0x01,0xd0,0x00,0x00,0x00,0x00,0x00,0x14,0x30,0x00,0x20,0x8d,
+ 0x02,0x10,0x26,0x04,0xa8,0x80,0x00,0x04,0x01,0xd0,0x00,0x00,0x00,0x00,0x00,0xe5,0xb0,0x00,0x20,0x8d,
0x02,0x10,0x26,0x05,0x64,0x00,0x00,0x30,0xf2,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d,
0x02,0x10,0x26,0x05,0x6f,0x80,0x00,0x00,0x00,0x07,0xfc,0x1b,0xcc,0xff,0xfe,0x8a,0xd8,0x22,0x20,0x8d,
+ 0x02,0x10,0x26,0x05,0xa1,0x40,0x20,0x76,0x82,0x53,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
+ 0x02,0x10,0x26,0x05,0xa1,0x40,0x30,0x07,0x12,0x87,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
0x02,0x10,0x26,0x05,0xae,0x00,0x02,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x03,0x20,0x8d,
0x02,0x10,0x26,0x05,0xc0,0x00,0x2a,0x0a,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x20,0x8d,
- 0x02,0x10,0x26,0x05,0xf7,0x00,0x00,0xc0,0x08,0x27,0x02,0x25,0x90,0xff,0xfe,0xe3,0x34,0xa6,0x20,0x8d,
+ 0x02,0x10,0x26,0x07,0x1a,0x00,0x00,0x01,0x00,0x0d,0x00,0x00,0x00,0x00,0x00,0x11,0x7c,0x4d,0x20,0x8d,
+ 0x02,0x10,0x26,0x07,0x53,0x00,0x02,0x03,0x12,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d,
0x02,0x10,0x26,0x07,0x92,0x80,0x00,0x0b,0x07,0x3b,0x02,0x50,0x56,0xff,0xfe,0x14,0x25,0xb5,0x20,0x8d,
- 0x02,0x10,0x26,0x07,0xf2,0xf8,0xad,0x40,0x0b,0xc1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
- 0x02,0x10,0x26,0x07,0xfa,0x18,0x3a,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x8d,
- 0x02,0x10,0x26,0x20,0x01,0x1c,0x50,0x01,0x11,0x18,0xd2,0x67,0xe5,0xff,0xfe,0xe9,0xe6,0x73,0x20,0x8d,
- 0x02,0x10,0x26,0x20,0x01,0x1c,0x50,0x01,0x21,0x99,0xd2,0x67,0xe5,0xff,0xfe,0xe9,0xe6,0x73,0x20,0x8d,
+ 0x02,0x10,0x26,0x07,0x92,0x80,0x00,0x0b,0x07,0x3b,0x02,0x50,0x56,0xff,0xfe,0x21,0x9c,0x2f,0x20,0x8d,
+ 0x02,0x10,0x26,0x07,0x92,0x80,0x00,0x0b,0x07,0x3b,0x02,0x50,0x56,0xff,0xfe,0x21,0xbf,0x32,0x20,0x8d,
+ 0x02,0x10,0x26,0x07,0x92,0x80,0x00,0x0b,0x07,0x3b,0x02,0x50,0x56,0xff,0xfe,0x33,0x4d,0x1b,0x20,0x8d,
+ 0x02,0x10,0x26,0x07,0x92,0x80,0x00,0x0b,0x07,0x3b,0x02,0x50,0x56,0xff,0xfe,0x3d,0x04,0x01,0x20,0x8d,
+ 0x02,0x10,0x26,0x07,0xf2,0xc0,0xe1,0xc2,0x00,0x69,0x12,0xc3,0x7b,0xff,0xfe,0x4d,0x94,0x31,0x20,0x8d,
+ 0x02,0x10,0x26,0x07,0xf2,0xc0,0xe1,0xc2,0x00,0x69,0xec,0xb2,0x6e,0x88,0x9f,0x33,0x50,0x57,0x20,0x8d,
0x02,0x10,0x26,0x20,0x00,0x06,0x20,0x03,0x01,0x05,0x02,0xd8,0x61,0xff,0xfe,0x0f,0x08,0x53,0x20,0x8d,
0x02,0x10,0x26,0x20,0x00,0x6e,0xa0,0x00,0x00,0x01,0x00,0x42,0x00,0x42,0x00,0x42,0x00,0x42,0x20,0x8d,
- 0x02,0x10,0x28,0x03,0xcf,0x00,0x0a,0xf8,0xf2,0x00,0xb8,0x9e,0xcf,0x34,0x92,0xc7,0x2d,0x26,0x20,0x8d,
- 0x02,0x10,0x28,0x04,0x01,0x4c,0x65,0xd1,0x40,0x2c,0xbc,0x53,0xbf,0x5d,0x06,0x8a,0x21,0x36,0x20,0x8d,
- 0x02,0x10,0x28,0x04,0x07,0xf1,0xe7,0x83,0xd4,0x01,0x66,0x1c,0x67,0xff,0xfe,0xba,0x55,0x47,0x20,0x8d,
- 0x02,0x10,0x28,0x04,0x0d,0x57,0x55,0x37,0x48,0x00,0x02,0x1e,0x67,0xff,0xfe,0xa8,0xd7,0x98,0x20,0x8d,
- 0x02,0x10,0x28,0x04,0x0d,0x57,0x55,0x37,0x48,0x00,0x36,0x15,0x9e,0xff,0xfe,0x23,0xd6,0x10,0x20,0x8d,
- 0x02,0x10,0x28,0x06,0x02,0xf0,0x20,0x80,0x06,0x2a,0x08,0x6f,0x1a,0x01,0xc4,0x4f,0x17,0x94,0x20,0x8d,
- 0x02,0x10,0x2a,0x00,0x10,0x28,0x83,0x82,0xbf,0x22,0x5f,0x7f,0xb7,0x8f,0x27,0x37,0x77,0x39,0x20,0x8d,
+ 0x02,0x10,0x26,0x20,0x00,0xa6,0x20,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x03,0xd5,0x70,0x20,0x8d,
+ 0x02,0x10,0x26,0x20,0x00,0xa6,0x20,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x2a,0x20,0x8d,
+ 0x02,0x10,0x26,0x20,0x00,0xa6,0x20,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x31,0x20,0x8d,
+ 0x02,0x10,0x26,0x20,0x00,0xa6,0x20,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x0c,0xe6,0x34,0x20,0x8d,
+ 0x02,0x10,0x28,0x00,0x00,0x40,0x00,0x33,0x08,0xab,0xa0,0xe7,0xb2,0x15,0xfc,0x83,0x5c,0x31,0x20,0x8d,
+ 0x02,0x10,0x28,0x00,0x0b,0xf0,0x01,0x49,0x0f,0x4b,0xf8,0xdf,0x8d,0x7d,0x80,0x1b,0xe2,0x5e,0x20,0x8d,
+ 0x02,0x10,0x28,0x04,0x01,0x4c,0x01,0x98,0x80,0xd5,0x76,0x03,0x41,0xd1,0xd3,0xfc,0xe7,0x97,0x20,0x8d,
+ 0x02,0x10,0x28,0x04,0x01,0x4d,0xae,0x81,0x82,0x7b,0x99,0xa8,0x1e,0x3f,0x6d,0xb2,0x29,0xdb,0x20,0x8d,
+ 0x02,0x10,0x28,0x04,0x0d,0x57,0x55,0x37,0x48,0x00,0x3e,0x7c,0x3f,0xff,0xfe,0x7b,0x80,0xaa,0x20,0x8d,
0x02,0x10,0x2a,0x00,0x12,0xe0,0x01,0x01,0x00,0x99,0x02,0x0c,0x29,0xff,0xfe,0x29,0xd0,0x3f,0x20,0x8d,
0x02,0x10,0x2a,0x00,0x13,0x28,0xe1,0x01,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x63,0x20,0x8d,
+ 0x02,0x10,0x2a,0x00,0x13,0x98,0x00,0x04,0x2a,0x03,0x02,0x15,0x5d,0xff,0xfe,0xd6,0x10,0x33,0x20,0x8d,
+ 0x02,0x10,0x2a,0x00,0x13,0x98,0x00,0x04,0x2a,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0xbc,0x03,0x20,0x8d,
0x02,0x10,0x2a,0x00,0x16,0x30,0x00,0x10,0x10,0x03,0x00,0x00,0x0b,0x19,0xb0,0x0b,0xba,0xbe,0x20,0x8d,
0x02,0x10,0x2a,0x00,0x17,0x68,0x20,0x01,0x00,0x27,0x00,0x00,0x00,0x00,0x00,0x00,0xef,0x6a,0x20,0x8d,
0x02,0x10,0x2a,0x00,0x18,0x28,0xa0,0x04,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x66,0x20,0x8d,
- 0x02,0x10,0x2a,0x00,0x18,0x38,0x00,0x2a,0x14,0x00,0x92,0xe2,0xba,0xff,0xfe,0x4a,0xc4,0x16,0x20,0x8d,
0x02,0x10,0x2a,0x00,0x1c,0x10,0x00,0x02,0x07,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x17,0x56,0xcc,
0x02,0x10,0x2a,0x00,0x1f,0x40,0x50,0x01,0x01,0x08,0x5d,0x17,0x77,0x03,0xb0,0xf5,0x41,0x33,0x20,0x8d,
- 0x02,0x10,0x2a,0x00,0x60,0x20,0x15,0xdd,0xee,0x00,0xc8,0xc2,0x2c,0x77,0x17,0x49,0x35,0xdb,0x20,0x8d,
+ 0x02,0x10,0x2a,0x00,0x23,0xc5,0xfe,0x80,0x73,0x01,0xd6,0xae,0x52,0xff,0xfe,0xd5,0x56,0xa5,0x20,0x8d,
+ 0x02,0x10,0x2a,0x00,0x23,0xc6,0x5c,0x91,0x58,0x08,0xc0,0x5a,0x4d,0xff,0xfe,0x65,0x9d,0x69,0x20,0x8d,
+ 0x02,0x10,0x2a,0x00,0x60,0x20,0x1b,0xfa,0xd4,0x00,0x02,0x0c,0x29,0xff,0xfe,0x61,0x4a,0x4c,0x20,0x8d,
0x02,0x10,0x2a,0x00,0x60,0x20,0xb4,0x82,0x92,0x00,0x49,0x1a,0x35,0x8c,0xd8,0xf7,0x01,0xda,0x20,0x8d,
- 0x02,0x10,0x2a,0x00,0x71,0x45,0x00,0xc1,0x00,0x01,0xae,0x29,0x07,0x27,0x2b,0x87,0x0f,0x64,0x14,0x15,
+ 0x02,0x10,0x2a,0x00,0x60,0x20,0xb4,0x89,0x20,0x00,0x50,0x54,0x00,0xff,0xfe,0xfc,0x5e,0xd8,0x20,0x8d,
+ 0x02,0x10,0x2a,0x00,0x7c,0x80,0x00,0x00,0x00,0x25,0x00,0x00,0x00,0x00,0x00,0x00,0xe3,0x7a,0x20,0x8d,
+ 0x02,0x10,0x2a,0x00,0x7c,0x80,0x00,0x00,0x00,0x71,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x20,0x8d,
0x02,0x10,0x2a,0x00,0x8a,0x60,0xe0,0x12,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x21,0x20,0x8d,
- 0x02,0x10,0x2a,0x00,0xa0,0x40,0x01,0x00,0x00,0xf3,0x45,0xa5,0x0a,0xc0,0xfe,0xa3,0x71,0xe1,0x20,0x8d,
- 0x02,0x10,0x2a,0x01,0x04,0x88,0x20,0x00,0x98,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x20,0x8d,
+ 0x02,0x10,0x2a,0x00,0xae,0x40,0x24,0x0e,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x20,0x8d,
+ 0x02,0x10,0x2a,0x00,0xbb,0xe0,0x00,0xcc,0x00,0x00,0x62,0xa4,0x4c,0xff,0xfe,0x23,0x75,0x10,0x20,0x8d,
+ 0x02,0x10,0x2a,0x00,0x0c,0xa8,0x0a,0x1f,0x30,0x25,0xf9,0x49,0xe4,0x42,0xc9,0x40,0x13,0xe8,0x20,0x8d,
+ 0x02,0x10,0x2a,0x00,0xd4,0xe0,0x00,0x02,0xd0,0x02,0x44,0x67,0x31,0xe0,0x6f,0xa5,0xb3,0xef,0x20,0x8d,
+ 0x02,0x10,0x2a,0x00,0x0e,0xe2,0x12,0x00,0x19,0x00,0x08,0xd3,0xd2,0xff,0xfe,0xb1,0xbc,0x58,0x20,0x8d,
+ 0x02,0x10,0x2a,0x01,0x02,0x38,0x42,0x0f,0x92,0x00,0xfa,0x5a,0x1a,0x4b,0x1e,0x6a,0xfa,0xdf,0x20,0x8d,
+ 0x02,0x10,0x2a,0x01,0x02,0x38,0x43,0x89,0xc4,0x00,0x3b,0x26,0xd9,0x4e,0x38,0xd5,0x44,0xef,0x20,0x8d,
0x02,0x10,0x2a,0x01,0x04,0x90,0x00,0x16,0x03,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d,
+ 0x02,0x10,0x2a,0x01,0x4b,0x00,0x80,0x7c,0x31,0x00,0xcd,0xa1,0x0c,0x6a,0x2b,0xad,0x24,0x18,0x20,0x8d,
+ 0x02,0x10,0x2a,0x01,0x04,0xf8,0x01,0x41,0x22,0x54,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d,
+ 0x02,0x10,0x2a,0x01,0x04,0xf8,0x01,0x73,0x23,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d,
+ 0x02,0x10,0x2a,0x01,0x04,0xf8,0x01,0x90,0x91,0xc4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d,
+ 0x02,0x10,0x2a,0x01,0x04,0xf8,0x02,0x00,0x72,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d,
+ 0x02,0x10,0x2a,0x01,0x04,0xf8,0x02,0x02,0x03,0xe6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d,
+ 0x02,0x10,0x2a,0x01,0x04,0xf8,0x02,0x21,0x44,0xd7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d,
+ 0x02,0x10,0x2a,0x01,0x04,0xf8,0x02,0x31,0x09,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d,
+ 0x02,0x10,0x2a,0x01,0x04,0xf9,0x00,0x2a,0x1c,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d,
+ 0x02,0x10,0x2a,0x01,0x04,0xf9,0x00,0x2b,0x02,0x9a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d,
+ 0x02,0x10,0x2a,0x01,0x04,0xf9,0x00,0x4a,0x31,0xde,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d,
0x02,0x10,0x2a,0x01,0x52,0x00,0x00,0x6c,0x61,0x62,0x7a,0x61,0x74,0x6b,0x6f,0x2e,0x73,0x6b,0x20,0x8d,
- 0x02,0x10,0x2a,0x01,0x63,0x80,0xff,0xfe,0x00,0x73,0x04,0xe3,0xb3,0xcc,0xa8,0x71,0x36,0xd1,0x20,0x8d,
- 0x02,0x10,0x2a,0x01,0x07,0xa0,0x00,0x02,0x13,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x20,0x8d,
+ 0x02,0x10,0x2a,0x01,0x63,0x80,0xff,0xfe,0x00,0x73,0x10,0xfb,0xd0,0x12,0x85,0x81,0xb4,0xd7,0x20,0x8d,
+ 0x02,0x10,0x2a,0x01,0x07,0xa7,0x00,0x02,0x28,0x04,0xae,0x1f,0x6b,0xff,0xfe,0x9d,0x6c,0x94,0x20,0x8d,
+ 0x02,0x10,0x2a,0x01,0x07,0xc8,0xaa,0xac,0x00,0x89,0x50,0x54,0x00,0xff,0xfe,0xb7,0xf5,0xcb,0x20,0x8d,
0x02,0x10,0x2a,0x01,0x07,0xc8,0xaa,0xc9,0x00,0xc9,0x50,0x54,0x00,0xff,0xfe,0xdf,0xff,0x95,0x20,0x8d,
0x02,0x10,0x2a,0x01,0x07,0xc8,0xd0,0x01,0x01,0xc1,0x50,0x54,0x00,0xff,0xfe,0xee,0x3e,0x1a,0x20,0x8d,
+ 0x02,0x10,0x2a,0x01,0x07,0xc8,0xd0,0x09,0x02,0xaa,0x50,0x54,0x00,0xff,0xfe,0x1b,0xa1,0x96,0x2d,0x00,
+ 0x02,0x10,0x2a,0x01,0x07,0xc8,0xff,0xfa,0x05,0x0e,0xdd,0xfe,0xc9,0x24,0xca,0x0a,0xcb,0xab,0x20,0x8d,
+ 0x02,0x10,0x2a,0x01,0x7e,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x93,0xff,0xfe,0x59,0x66,0xdc,0x20,0x8d,
+ 0x02,0x10,0x2a,0x01,0x7e,0x01,0x00,0x00,0x00,0x00,0xf0,0x3c,0x93,0xff,0xfe,0x3b,0xbb,0x5b,0x20,0x8d,
0x02,0x10,0x2a,0x01,0x87,0x40,0x00,0x01,0xff,0xc5,0x00,0x00,0x00,0x00,0x00,0x00,0x8c,0x6a,0x20,0x8d,
+ 0x02,0x10,0x2a,0x01,0x9f,0x40,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x20,0x8d,
0x02,0x10,0x2a,0x01,0xcb,0x00,0x0d,0x3d,0x77,0x00,0x02,0x27,0x0e,0xff,0xfe,0x28,0xc5,0x65,0x20,0x8d,
- 0x02,0x10,0x2a,0x01,0x00,0xd0,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x53,0x20,0x8d,
- 0x02,0x10,0x2a,0x01,0x00,0xd0,0xbe,0xf2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x20,0x8d,
- 0x02,0x10,0x2a,0x01,0x0e,0x0a,0x09,0xfb,0xb0,0xe0,0x54,0xf8,0x19,0x01,0x6e,0x83,0x62,0xc1,0x20,0x8d,
+ 0x02,0x10,0x2a,0x01,0x0e,0x0a,0x00,0x20,0x73,0x50,0x91,0x9c,0xb1,0xc3,0x8b,0x83,0xad,0xf9,0x20,0x8d,
+ 0x02,0x10,0x2a,0x01,0x0e,0x0a,0x03,0x01,0x70,0x10,0xb8,0x7d,0xe1,0x4b,0xce,0xa9,0xb9,0x98,0x20,0x8d,
+ 0x02,0x10,0x2a,0x01,0x0e,0x0a,0x04,0x8b,0x2d,0x10,0x94,0xf2,0x4d,0x5c,0xca,0x5f,0xbf,0x49,0x20,0x8d,
+ 0x02,0x10,0x2a,0x01,0x0e,0x0a,0x05,0x30,0xa0,0xa0,0xf4,0x65,0x0a,0xf5,0xbe,0x1b,0x90,0x75,0x20,0x8d,
0x02,0x10,0x2a,0x01,0x0e,0x0a,0x0a,0xa7,0xc8,0xc0,0x96,0x79,0xaf,0xfa,0xb6,0xe5,0xef,0xc7,0x20,0x8d,
- 0x02,0x10,0x2a,0x02,0x13,0xb8,0xf0,0x00,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x20,0x8d,
- 0x02,0x10,0x2a,0x02,0x01,0x68,0x63,0x28,0x00,0x00,0x02,0xa8,0x2c,0xff,0xfe,0x68,0xe3,0x2c,0x20,0x8d,
+ 0x02,0x10,0x2a,0x01,0x0e,0x11,0x10,0x0c,0x00,0x70,0xcb,0xc8,0x9e,0x31,0x4b,0x77,0x16,0x26,0x20,0x8d,
+ 0x02,0x10,0x2a,0x01,0x0e,0x34,0xee,0x78,0x30,0x60,0x02,0x30,0x48,0xff,0xfe,0x81,0xf1,0xc6,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0x12,0x10,0x14,0xa9,0x67,0x00,0x0a,0x00,0x27,0xff,0xfe,0x4e,0x82,0xb6,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0x12,0x10,0x46,0x39,0x0f,0x00,0x10,0xa7,0xe9,0x65,0x50,0x9a,0x7a,0x4a,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0x12,0x10,0x7c,0x92,0x51,0x00,0x02,0x11,0x32,0xff,0xfe,0xae,0x15,0x2d,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0x12,0x10,0x86,0xbf,0xf1,0x00,0x31,0x78,0xd7,0x00,0xd4,0x4d,0x6b,0xb1,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0x12,0x10,0x94,0x87,0xa2,0x00,0xed,0xc1,0x93,0xa4,0x09,0x45,0x9a,0x92,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0x01,0x68,0x42,0x0b,0x00,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0x01,0x68,0x63,0x28,0x00,0x00,0x4a,0x21,0x0b,0xff,0xfe,0x26,0x38,0xc3,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0x01,0x68,0x67,0x6e,0x00,0x00,0xe6,0x5f,0x01,0xff,0xfe,0x09,0x35,0x91,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0x17,0x48,0xf3,0x9f,0x58,0x72,0xde,0xad,0xbe,0xef,0xb1,0xac,0xc0,0xfe,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0x01,0x80,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x05,0x17,0x10,0xb6,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0x21,0x68,0xa3,0x79,0xd1,0x00,0x96,0xde,0x80,0xff,0xfe,0xa3,0xfd,0x00,0x20,0x8d,
0x02,0x10,0x2a,0x02,0x27,0x80,0x90,0x00,0x00,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0x27,0x80,0x90,0x00,0x00,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0x27,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x1a,0x20,0x8d,
0x02,0x10,0x2a,0x02,0x2e,0x02,0x39,0x00,0x54,0x00,0xa0,0x99,0xe1,0xff,0xfe,0xb6,0x0d,0x0e,0x20,0x8d,
- 0x02,0x10,0x2a,0x02,0x03,0x90,0x90,0x00,0x00,0x00,0xaa,0xa1,0x59,0xff,0xfe,0x43,0xb5,0x7b,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0x2f,0x05,0x66,0x0e,0x8b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
0x02,0x10,0x2a,0x02,0x00,0x58,0x00,0x97,0x7d,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x20,0x8d,
- 0x02,0x10,0x2a,0x02,0x6d,0x40,0x30,0x5e,0x06,0x01,0xde,0xa6,0x32,0xff,0xfe,0x44,0x4b,0x25,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0x6d,0x40,0x30,0x73,0x0c,0x01,0xde,0xa6,0x32,0xff,0xfe,0x44,0x4b,0x25,0x20,0x8d,
0x02,0x10,0x2a,0x02,0x7a,0x01,0x00,0x00,0x00,0x00,0x00,0x91,0x02,0x28,0x00,0x45,0x01,0x30,0x20,0x8d,
- 0x02,0x10,0x2a,0x02,0x7a,0xa0,0x16,0x19,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0xdc,0x8d,0xe0,0x20,0x8d,
- 0x02,0x10,0x2a,0x02,0x7b,0x40,0x3e,0x4d,0x99,0x8d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
- 0x02,0x10,0x2a,0x02,0x7b,0x40,0x59,0x2f,0xa1,0x87,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
- 0x02,0x10,0x2a,0x02,0x83,0x88,0xe5,0xc6,0xd3,0x80,0x02,0x01,0x2e,0xff,0xfe,0x82,0xb3,0xcc,0x20,0x8d,
- 0x02,0x10,0x2a,0x02,0x09,0xa0,0x01,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x10,0x20,0x8d,
- 0x02,0x10,0x2a,0x02,0xa3,0x11,0x81,0x43,0x8c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x20,0xa1,
- 0x02,0x10,0x2a,0x02,0x0a,0xf8,0xfa,0xb0,0x08,0x08,0x00,0x85,0x02,0x34,0x01,0x45,0x01,0x32,0x20,0x8d,
- 0x02,0x10,0x2a,0x02,0x0e,0x00,0xff,0xf0,0x05,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0xfc,
- 0x02,0x10,0x2a,0x02,0x0e,0x00,0xff,0xf0,0x05,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x20,0xfc,
+ 0x02,0x10,0x2a,0x02,0x7b,0x40,0x59,0x28,0x00,0x89,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0x7b,0x40,0xc3,0xb5,0xf5,0x83,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0x83,0x08,0x80,0x87,0xaa,0x00,0x9e,0xa8,0x01,0xb2,0xef,0x98,0x56,0xbf,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0x84,0x2a,0x01,0xdf,0x8a,0x01,0x1e,0x1b,0x0d,0xff,0xfe,0x0b,0x23,0x6d,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0xa4,0x4d,0x14,0xd6,0x00,0x01,0x02,0xc0,0x08,0xff,0xfe,0x8f,0xb3,0xb2,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0xa4,0x5a,0x94,0xcd,0xf0,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0xa4,0x5f,0x3b,0x9d,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0xa4,0x67,0x78,0x33,0x00,0x01,0x72,0x85,0xc2,0xff,0xfe,0x2c,0x21,0xe9,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0xaa,0x14,0x23,0x80,0xb3,0x00,0x40,0x40,0xbe,0x88,0x8b,0x01,0x0d,0x38,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0xc2,0x06,0x20,0x44,0x98,0x26,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0xc2,0x06,0x20,0x82,0x12,0x46,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0xc2,0x06,0x30,0x08,0x23,0x68,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0xc2,0x07,0x00,0x00,0x49,0x71,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x14,0xd4,
+ 0x02,0x10,0x2a,0x02,0xc2,0x07,0x20,0x14,0x41,0x99,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0xc2,0x07,0x20,0x24,0x61,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0xc2,0x07,0x20,0x26,0x66,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0xc2,0x07,0x30,0x02,0x74,0x68,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
0x02,0x10,0x2a,0x02,0x0e,0x98,0x00,0x20,0x15,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
- 0x02,0x10,0x2a,0x03,0x40,0x00,0x00,0x47,0x00,0xf1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
+ 0x02,0x10,0x2a,0x03,0x40,0x00,0x00,0x06,0x41,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x43,0x20,0x8d,
+ 0x02,0x10,0x2a,0x03,0x40,0x00,0x00,0x06,0xf8,0x14,0x54,0x8b,0x17,0xff,0xfe,0x31,0xb6,0x4a,0x20,0x8d,
0x02,0x10,0x2a,0x03,0x60,0x00,0x08,0x70,0x00,0x00,0x00,0x46,0x00,0x23,0x00,0x87,0x02,0x18,0x20,0x8d,
- 0x02,0x10,0x2a,0x03,0x73,0x80,0x30,0x15,0x05,0x24,0xaf,0xc5,0xd3,0xbc,0x7c,0x66,0x8f,0x94,0x20,0x8d,
- 0x02,0x10,0x2a,0x03,0x0e,0xc0,0x00,0x00,0x09,0x28,0x8c,0x00,0x93,0xff,0xfe,0x84,0xa0,0x07,0x20,0x8d,
- 0x02,0x10,0x2a,0x03,0x0e,0xc0,0x00,0x00,0x09,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x01,0x20,0x8d,
- 0x02,0x10,0x2a,0x04,0x21,0x80,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xaa,0x20,0x8d,
- 0x02,0x10,0x2a,0x04,0x52,0xc0,0x01,0x01,0x02,0x9e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d,
- 0x02,0x10,0x2a,0x04,0x52,0xc0,0x01,0x03,0xc4,0x55,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
+ 0x02,0x10,0x2a,0x03,0x94,0xe0,0xff,0xff,0x01,0x85,0x02,0x43,0x02,0x18,0x00,0x00,0x00,0x19,0x20,0x8d,
+ 0x02,0x10,0x2a,0x03,0xb0,0xc0,0x00,0x01,0x00,0xe0,0x00,0x00,0x00,0x00,0x03,0x97,0x60,0x01,0x20,0x8d,
+ 0x02,0x10,0x2a,0x03,0xb0,0xc0,0x00,0x02,0x00,0xf0,0x00,0x00,0x00,0x00,0x01,0x63,0x30,0x01,0x20,0x8d,
+ 0x02,0x10,0x2a,0x03,0xb0,0xc0,0x00,0x02,0x00,0xf0,0x00,0x00,0x00,0x00,0x01,0x8a,0xd0,0x01,0x20,0x8d,
+ 0x02,0x10,0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x0f,0x3e,0x20,0x01,0x20,0x8d,
+ 0x02,0x10,0x2a,0x03,0xe2,0xc0,0x13,0x47,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d,
+ 0x02,0x10,0x2a,0x03,0x0e,0xc0,0x00,0x00,0x09,0x28,0x00,0x00,0x00,0x00,0x07,0x01,0x07,0x01,0x20,0x8d,
+ 0x02,0x10,0x2a,0x04,0x52,0xc0,0x01,0x03,0xc4,0x55,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8e,
+ 0x02,0x10,0x2a,0x04,0x52,0xc0,0x30,0x07,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x20,0x8d,
0x02,0x10,0x2a,0x04,0xbc,0x40,0x1d,0xc3,0x00,0x8d,0x00,0x00,0x00,0x00,0x00,0x02,0x10,0x01,0x20,0x8d,
0x02,0x10,0x2a,0x05,0x15,0x00,0x07,0x02,0x00,0x00,0x1c,0x00,0x40,0xff,0xfe,0x00,0x00,0x0c,0x20,0x8d,
- 0x02,0x10,0x2a,0x06,0xdd,0x00,0x00,0x10,0x00,0x03,0x02,0x25,0x90,0xff,0xfe,0x32,0x64,0xcc,0x20,0x8d,
- 0x02,0x10,0x2a,0x06,0xdd,0x00,0x00,0x01,0x00,0x22,0x02,0x25,0x90,0xff,0xfe,0x0e,0xbd,0x48,0x20,0x8d,
- 0x02,0x10,0x2a,0x07,0x6b,0x47,0x01,0x00,0x04,0x64,0x00,0x00,0x00,0x00,0x93,0x57,0xff,0xda,0x20,0x8d,
- 0x02,0x10,0x2a,0x07,0xa8,0x80,0x46,0x01,0x10,0x62,0xb4,0xb4,0xbd,0x2a,0x39,0xd4,0x7a,0xcf,0xc8,0xc9,
+ 0x02,0x10,0x2a,0x05,0x35,0x80,0xd1,0x01,0x37,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d,
+ 0x02,0x10,0x2a,0x05,0x35,0x80,0xdb,0x0b,0x16,0x00,0xc4,0x89,0x76,0xed,0x31,0x3d,0x0b,0x33,0x20,0x8d,
+ 0x02,0x10,0x2a,0x05,0xd0,0x14,0x0a,0x55,0x40,0x01,0x81,0x27,0xaf,0xa7,0xda,0xf9,0xd9,0x1b,0x20,0x8d,
+ 0x02,0x10,0x2a,0x05,0xd0,0x14,0x0a,0x55,0x40,0x01,0xf6,0xab,0xdd,0x5e,0x40,0x39,0xb4,0x6c,0x20,0x8d,
+ 0x02,0x10,0x2a,0x05,0xd0,0x14,0x0a,0x55,0x40,0x03,0x65,0x23,0x50,0xa1,0x01,0x52,0xe8,0x8c,0x20,0x8d,
+ 0x02,0x10,0x2a,0x05,0xd0,0x1a,0x0b,0x7b,0x3c,0x01,0x8b,0xf7,0xae,0x14,0xaf,0xb3,0x33,0xae,0x20,0x8d,
+ 0x02,0x10,0x2a,0x05,0xf4,0x80,0x18,0x00,0x06,0x97,0x54,0x00,0x02,0xff,0xfe,0xb6,0xc3,0x6d,0x20,0x8d,
+ 0x02,0x10,0x2a,0x06,0xe0,0x40,0x76,0x03,0x29,0x18,0xc6,0xef,0x46,0x4e,0x9f,0xe5,0x73,0xec,0x20,0x8d,
0x02,0x10,0x2a,0x07,0xab,0xc4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x09,0x46,0x20,0x8d,
- 0x02,0x10,0x2a,0x07,0xab,0xc4,0x00,0x00,0x00,0x00,0x00,0x89,0x02,0x34,0x01,0x80,0x01,0x94,0x20,0x8d,
0x02,0x10,0x2a,0x09,0x26,0x81,0x01,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x10,0x20,0x8d,
0x02,0x10,0x2a,0x0a,0xc8,0x01,0x00,0x01,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x83,0x20,0x8d,
- 0x02,0x10,0x2a,0x0b,0xf3,0x00,0x00,0x02,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d,
- 0x02,0x10,0x2a,0x0c,0x59,0xc0,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa2,0x0e,0xe1,0x3a,
+ 0x02,0x10,0x2a,0x0c,0x5a,0x80,0x12,0x10,0xa8,0x00,0x6a,0xf7,0x28,0xff,0xfe,0xe5,0x6b,0x3a,0x20,0x8d,
0x02,0x10,0x2a,0x0d,0x56,0x00,0x00,0x24,0x0a,0x8e,0x00,0x00,0x00,0x00,0x00,0x00,0xa9,0x1e,0xd8,0x4d,
- 0x02,0x10,0x2a,0x0d,0xeb,0x00,0x80,0x05,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x13,0x20,0x8d,
- 0x02,0x10,0x2a,0x10,0x47,0x40,0x00,0x45,0x00,0x01,0xa0,0x13,0xd1,0xff,0xfe,0x85,0x36,0xe3,0x20,0x8d,
- 0x02,0x10,0x2a,0x10,0x8b,0x40,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x03,0x20,0x8f,
+ 0x02,0x10,0x2a,0x0d,0x7c,0x40,0x30,0x00,0x0b,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d,
+ 0x02,0x10,0x2a,0x0d,0x83,0x40,0x00,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d,
+ 0x02,0x10,0x2a,0x0f,0xdf,0x00,0x00,0x00,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x62,0x20,0x8d,
+ 0x02,0x10,0x2a,0x10,0x37,0x81,0x16,0xb9,0x00,0x01,0xfe,0x3f,0xdb,0xff,0xfe,0x04,0x2d,0x4c,0x20,0x8d,
+ 0x02,0x10,0x2a,0x10,0x37,0x81,0x08,0x4b,0x00,0x01,0xb1,0x23,0x63,0x06,0x94,0x3a,0xf0,0x9b,0x20,0x8d,
+ 0x02,0x10,0x2a,0x10,0xd2,0x00,0x00,0x01,0x00,0x33,0xa6,0xbf,0x01,0xff,0xfe,0x6a,0x46,0xa9,0x20,0x8d,
+ 0x02,0x10,0x2c,0x0f,0xf4,0xc0,0x22,0x02,0x20,0xb0,0x26,0x1c,0x04,0xff,0xfe,0x14,0xda,0xa0,0x20,0x8d,
0x02,0x10,0x2c,0x0f,0xf8,0xf0,0xda,0x51,0x00,0x00,0x70,0xc3,0xee,0xa9,0x97,0x17,0x95,0x79,0x20,0x8d,
- 0x04,0x20,0xd1,0xbb,0x02,0x8d,0x4d,0xd5,0x6a,0x20,0xc0,0xf9,0x16,0x2b,0x84,0x22,0x66,0xe0,0x89,0x45,0x60,0x37,0x52,0xe2,0x0b,0xa5,0xb4,0xf8,0x26,0xb3,0x8f,0x5a,0x30,0xed,0x20,0x8d,
- 0x04,0x20,0xd2,0x59,0x3b,0xd7,0x14,0x7e,0xd0,0x98,0xfe,0x9e,0xa5,0x69,0xf4,0x26,0x6d,0x72,0x6f,0xc3,0x76,0xce,0x1d,0x40,0x41,0xa2,0xa1,0xaf,0xf9,0x6e,0x57,0x2d,0x9d,0xc3,0x20,0x8d,
- 0x04,0x20,0xdf,0xd9,0xed,0x59,0xbf,0x1e,0x77,0x48,0x3c,0x13,0x3b,0xc5,0xc8,0x15,0x86,0x88,0x68,0xf0,0x08,0xe9,0xee,0x9b,0x3d,0xa4,0x33,0x0a,0x68,0x67,0x86,0x9d,0xe2,0x83,0x20,0x8d,
0x04,0x20,0xe9,0xbf,0xa7,0xbd,0x9b,0x54,0x54,0xe8,0xc8,0xae,0x78,0x99,0xa0,0xa3,0xf6,0x5d,0x78,0xe3,0x9e,0x5c,0xa7,0x18,0xb9,0x13,0x0c,0x04,0x9b,0xf3,0x7f,0x27,0x18,0xb0,0x20,0x8d,
- 0x04,0x20,0xf8,0x8d,0x64,0xd2,0xc8,0xe9,0x0f,0x51,0x03,0x1c,0x98,0x33,0x8f,0xe0,0x1e,0xe7,0xb6,0x16,0x8d,0x2a,0xf5,0xf3,0x19,0xce,0xdd,0x9e,0xee,0x17,0xc3,0x8f,0xd6,0xa1,0x20,0x8d,
- 0x04,0x20,0xfb,0xf1,0x17,0xd6,0x03,0x3b,0x01,0x8b,0x98,0xcf,0x16,0x20,0xde,0xaf,0x6c,0xed,0x60,0xab,0x6e,0x14,0x0b,0x58,0x6b,0x2d,0xf8,0x06,0x98,0x37,0x7a,0xff,0x7a,0x0f,0x20,0x8d,
0x04,0x20,0x0f,0xb9,0x71,0x05,0x64,0x83,0x2c,0x68,0x6a,0x9c,0xf0,0x4f,0xc3,0x90,0xcd,0x5c,0x73,0x9a,0xdd,0xb3,0xc6,0x42,0xca,0x09,0xbb,0xcc,0xfe,0x29,0x49,0x9f,0xc7,0x28,0x20,0x8d,
- 0x04,0x20,0x22,0x6e,0x42,0xe4,0xbd,0x2b,0xe5,0x3e,0x30,0xda,0x8a,0x03,0xf3,0x45,0x52,0xac,0x84,0xbf,0xbf,0xc5,0xaa,0x5f,0xe0,0x1b,0x26,0x28,0xb5,0x83,0x2e,0xed,0x4c,0xee,0x20,0x8d,
0x04,0x20,0x2a,0x47,0x8b,0xa0,0x4f,0x67,0x1d,0xcd,0x5d,0x84,0x1a,0xec,0xbd,0xd2,0xaa,0xe9,0x99,0x01,0x96,0x5d,0x4e,0xff,0x64,0x47,0xba,0xde,0xbf,0x56,0x89,0x39,0xac,0xde,0x20,0x8d,
0x04,0x20,0x2b,0xf3,0xe8,0xf5,0xef,0x90,0x14,0xab,0x61,0xe9,0x11,0x97,0x9f,0x18,0x4d,0xb4,0xff,0x89,0x94,0xf7,0x92,0x94,0x53,0xe6,0x9e,0xd4,0xdb,0x85,0x89,0x4d,0x3e,0xc9,0x20,0x8d,
- 0x04,0x20,0x2e,0x4e,0xde,0x51,0xd7,0x28,0x4b,0x29,0x7c,0xff,0x1f,0x8a,0x50,0xb7,0x5e,0xf0,0x81,0xcd,0xe8,0x8a,0x08,0x73,0x58,0x4e,0x43,0x1f,0x7b,0x85,0x9a,0xed,0xe2,0x68,0x20,0x8d,
0x04,0x20,0x35,0xdd,0xd0,0x36,0xa5,0x69,0x4a,0xd2,0xcc,0xb8,0xe9,0x62,0xa3,0x55,0xeb,0x86,0xe2,0xf3,0x03,0x48,0x26,0xe6,0x20,0xad,0xda,0xaa,0xff,0xde,0x16,0xad,0x39,0x9d,0x20,0x8d,
0x04,0x20,0x41,0x47,0x4e,0xc2,0xa1,0x71,0x63,0x3e,0x11,0x54,0x46,0x91,0x80,0xed,0x41,0x16,0x32,0x29,0x19,0x60,0xc9,0xef,0xa3,0xb7,0x96,0x2c,0x94,0xa8,0xdf,0x55,0xd7,0x21,0x20,0x8d,
0x04,0x20,0x44,0xf3,0xb7,0x5e,0x48,0x3c,0xbd,0xa6,0x52,0xaa,0x68,0xb5,0xbf,0xdc,0x01,0x5f,0x4b,0xeb,0x7a,0x25,0xcb,0x4a,0x70,0xbc,0x18,0x8c,0x97,0x5d,0x27,0x54,0x09,0x17,0x20,0x8d,
- 0x04,0x20,0x5c,0x52,0x7f,0x17,0x16,0x4c,0x27,0x36,0x2d,0x05,0xa1,0x19,0x0d,0xbe,0x87,0xab,0x24,0x7b,0xe7,0x38,0x3b,0xa1,0x7f,0xd1,0xd4,0x28,0x16,0x8e,0xfc,0x98,0x7d,0x08,0x20,0x8d,
+ 0x04,0x20,0x53,0xcd,0x56,0x48,0x48,0x8c,0x47,0x07,0x91,0x41,0x82,0x65,0x5b,0x76,0x64,0x03,0x4e,0x09,0xe6,0x6f,0x7e,0x8c,0xbf,0x10,0x84,0xe6,0x54,0xeb,0x56,0xc5,0xbd,0x88,0x20,0x8d,
0x04,0x20,0x67,0xc4,0x17,0xa5,0xcb,0x77,0xbd,0xaa,0x11,0x7f,0x8b,0xc0,0x81,0xf3,0xc0,0x96,0x9d,0x31,0x27,0x9c,0xad,0x6c,0x6d,0x98,0x42,0x70,0xdb,0x50,0x12,0x96,0x0b,0x36,0x20,0x8d,
- 0x04,0x20,0x73,0xdb,0x82,0xe0,0x88,0x40,0x49,0xd8,0x3b,0xa0,0xdd,0x83,0x7c,0x84,0x3c,0xb8,0xd0,0x03,0x0b,0x7a,0x08,0x44,0x4e,0x79,0xd6,0x61,0x23,0x31,0xa9,0xb3,0x07,0x58,0x20,0x8d,
- 0x04,0x20,0x75,0x93,0x21,0xdd,0x99,0x58,0x3c,0x3f,0xae,0x36,0x50,0x58,0x49,0xe2,0xd0,0xc3,0x3a,0x2c,0x4a,0xcf,0x41,0xc4,0x82,0x48,0xab,0xec,0x07,0x5d,0x56,0x2c,0xb4,0x8d,0x20,0x8d,
- 0x04,0x20,0x87,0xd4,0x66,0x0f,0xed,0xf9,0xf5,0xf1,0xcb,0x85,0x37,0xec,0xe1,0x19,0xa8,0xa4,0x03,0xb7,0x13,0x59,0xbb,0xf8,0xd2,0x93,0x92,0x50,0xfa,0x30,0x7a,0xd8,0x43,0xd0,0x20,0x8d,
+ 0x04,0x20,0x65,0x98,0x55,0xd0,0x8a,0xe0,0x29,0xe6,0x5e,0xef,0xb7,0x8b,0x8f,0xc9,0x27,0x53,0x3d,0xd0,0x8c,0xa2,0xfa,0x32,0x2f,0xad,0xf9,0xdc,0xe2,0x4b,0x14,0x66,0x3e,0x23,0x20,0x8d,
0x04,0x20,0x8b,0xfe,0xad,0x19,0xdb,0x97,0x57,0x84,0xec,0xad,0x4f,0xb2,0xdf,0x69,0x53,0x04,0x57,0x19,0x16,0x7a,0x71,0xd7,0x2b,0xab,0x03,0xfd,0x76,0x4d,0xa0,0x70,0xc3,0xe7,0x20,0x8d,
- 0x04,0x20,0x96,0x25,0xde,0x4a,0xbc,0xbd,0x76,0x76,0xee,0x43,0x45,0x76,0xe0,0x0d,0x99,0x83,0xcd,0x83,0x8f,0x94,0xe5,0xde,0x7a,0xf2,0xf0,0x57,0xb8,0x25,0x54,0x17,0xcb,0x3b,0x20,0x8d,
- 0x04,0x20,0x98,0xc6,0x44,0x27,0x90,0x41,0xa6,0x98,0xf9,0x25,0x6c,0x59,0x0f,0x06,0x6d,0x44,0x59,0x0e,0xb2,0x46,0xb0,0xa4,0x37,0x88,0x69,0x8f,0xc1,0x32,0xcd,0x9f,0x15,0xd7,0x20,0x8d,
- 0x04,0x20,0xaa,0x3a,0x16,0x86,0xea,0x59,0x09,0x04,0x78,0xe5,0x10,0x92,0xe1,0x1d,0xad,0xf7,0x56,0x2b,0xac,0xb0,0x97,0x29,0x63,0x30,0xf4,0x1b,0xcf,0xde,0xf3,0x28,0x0a,0x29,0x20,0x8d,
- 0x04,0x20,0xbc,0x27,0xae,0x89,0xc1,0x67,0x73,0x0a,0x08,0x02,0xdf,0xb7,0xcc,0x94,0xc7,0x9f,0xf4,0x72,0x7a,0x9b,0x20,0x0c,0x5c,0x11,0x3d,0x22,0xd6,0x13,0x88,0x66,0x74,0xbf,0x20,0x8d,
+ 0x05,0x20,0xd7,0x7a,0x53,0x89,0xfe,0x02,0x6a,0x59,0xb7,0x0e,0xf8,0x6d,0x9d,0x81,0xbb,0x9f,0x01,0xc0,0xc4,0xee,0x7b,0x36,0x10,0x33,0x07,0xd2,0x29,0xd8,0xec,0xcd,0x8e,0xa3,0x00,0x00,
+ 0x05,0x20,0xd7,0xf1,0x19,0x9e,0x7d,0x0f,0x43,0x97,0x33,0x56,0xe8,0x12,0x1d,0x7d,0xa0,0x4d,0x21,0x5a,0x60,0x73,0xc8,0x7e,0x10,0x55,0x60,0x56,0xbb,0x65,0x50,0xa4,0x17,0x59,0x00,0x00,
+ 0x05,0x20,0xd1,0x17,0xe2,0x34,0x4a,0x61,0x70,0x8b,0x04,0xa2,0xb4,0xb0,0x65,0x59,0x52,0x75,0x67,0x86,0xe6,0x48,0x33,0x31,0x5d,0x87,0x38,0x57,0xd3,0xf8,0x40,0x07,0x73,0xa8,0x00,0x00,
+ 0x05,0x20,0xd9,0x9c,0x20,0xfe,0xc2,0xe6,0x6a,0x16,0x30,0x81,0x54,0xc9,0x3f,0x9a,0x89,0x10,0xa9,0x4b,0xf1,0x05,0x56,0xd5,0x04,0x2d,0xb7,0x6a,0x7b,0x67,0x8d,0xf0,0xbe,0x8f,0x00,0x00,
+ 0x05,0x20,0xdc,0xdb,0x2d,0x39,0xd5,0xe4,0xda,0xb5,0xb6,0x6e,0x98,0x33,0x8f,0x51,0x99,0x54,0x38,0x53,0xa8,0x4e,0xda,0x29,0xd8,0xb5,0x57,0x9d,0x36,0xf0,0x97,0x37,0x18,0x3f,0x00,0x00,
+ 0x05,0x20,0xe1,0x44,0x2d,0x6e,0xd3,0xd9,0xf0,0x95,0x6c,0x52,0x2e,0x44,0x3c,0x27,0x3d,0x78,0xac,0x6e,0x8f,0x27,0x1c,0x0c,0xc0,0x78,0x22,0x3e,0xa1,0x84,0x01,0x42,0x08,0x5c,0x00,0x00,
+ 0x05,0x20,0xe3,0xa5,0x88,0x11,0x4d,0x3d,0xfb,0x02,0xec,0x1f,0xda,0x48,0x86,0x12,0xf6,0x12,0xd9,0x3e,0x68,0x49,0xa7,0xae,0x37,0xfd,0x02,0x48,0x38,0x8b,0xdc,0xd4,0xa6,0x8f,0x00,0x00,
+ 0x05,0x20,0xe5,0x19,0x24,0x71,0xab,0x61,0xb0,0xfe,0x44,0x4a,0x74,0x8d,0xca,0x90,0xc3,0xd6,0x24,0xb4,0xd5,0x03,0xe7,0xf3,0x4f,0xbe,0x12,0x72,0xd6,0xa0,0x4b,0x22,0x0b,0xe1,0x00,0x00,
+ 0x05,0x20,0xee,0xab,0xea,0x3b,0xc2,0x8a,0xe2,0xb3,0xe5,0xe7,0x92,0xf0,0x88,0x05,0x68,0x8d,0x2f,0xe7,0x2c,0xd2,0x00,0x39,0xd4,0x5d,0x07,0xfc,0xa1,0xd6,0xbf,0x89,0xa2,0x40,0x00,0x00,
+ 0x05,0x20,0xf2,0x74,0x4c,0x90,0xc3,0xd9,0x34,0x4d,0x5f,0x6e,0xdb,0xdd,0x7d,0xef,0xa5,0xed,0x6e,0x59,0x9e,0x31,0x41,0x94,0x38,0x84,0xc5,0x08,0xd2,0x23,0xb3,0xa7,0xe0,0x2c,0x00,0x00,
+ 0x05,0x20,0xf3,0x77,0xe5,0xa7,0x11,0xef,0x65,0x91,0x23,0xb8,0x32,0x06,0xcb,0xc0,0x91,0xf7,0x21,0x1d,0x70,0xbc,0x83,0x1b,0x86,0x34,0x35,0x31,0x0f,0x9f,0xc1,0x0d,0xbb,0x56,0x00,0x00,
+ 0x05,0x20,0xfe,0xb0,0x99,0x79,0x95,0x58,0x71,0xb5,0x63,0xcc,0x33,0xeb,0x55,0x91,0x8c,0xb4,0x3a,0xf2,0x8b,0x2d,0x8e,0x47,0xbe,0x25,0x47,0x12,0xcd,0x14,0x48,0xf0,0x1d,0xea,0x00,0x00,
+ 0x05,0x20,0xfc,0x79,0x14,0x77,0x6b,0x0e,0x34,0x8d,0xde,0x01,0x33,0xed,0xb4,0x0e,0xa7,0xc9,0x15,0x4f,0xd0,0x27,0x2c,0xd6,0x5f,0xe9,0x63,0x82,0x8d,0xd5,0x0c,0x9e,0x18,0x29,0x00,0x00,
0x05,0x20,0x07,0x61,0x26,0xd7,0x6c,0x05,0xbf,0xf6,0x2d,0x8c,0xca,0xc4,0x65,0xd3,0xd3,0xb2,0x49,0xe9,0xcc,0x53,0x1e,0xca,0x77,0x84,0xb6,0x10,0x5e,0xc2,0x5a,0xfe,0x28,0xb3,0x00,0x00,
- 0x05,0x20,0x0a,0x26,0x27,0x45,0xb1,0x1e,0xfc,0x27,0x03,0x32,0x0e,0x65,0x9e,0x3c,0x64,0x0e,0x33,0x50,0x3d,0x6c,0x90,0x17,0x0e,0x29,0xee,0x5a,0x58,0xdf,0x08,0xde,0xbf,0x73,0x00,0x00,
+ 0x05,0x20,0x03,0xaa,0x47,0xe9,0xe2,0x77,0xeb,0xa5,0x72,0x27,0x23,0x8b,0x13,0x62,0x61,0x32,0xb5,0xb2,0x1b,0x5a,0x18,0xb2,0xf9,0x26,0x06,0x84,0xee,0x28,0x42,0xac,0xba,0xbc,0x00,0x00,
+ 0x05,0x20,0x08,0xc6,0x19,0x31,0x40,0x96,0xf3,0xe2,0x81,0x4e,0x88,0x54,0x54,0x9e,0xbf,0xfa,0x38,0x7a,0xfa,0x38,0x96,0x13,0x2a,0xc4,0x69,0xa2,0xae,0xe5,0x94,0xc7,0x16,0xb7,0x00,0x00,
+ 0x05,0x20,0x0a,0x26,0x27,0x23,0xdd,0xf3,0x56,0xbe,0x9e,0x9e,0xa7,0xc6,0x3c,0xc5,0x99,0xc4,0x87,0x3b,0x4d,0xb9,0x13,0x62,0x91,0xf2,0x25,0x1c,0x02,0x42,0x63,0xe3,0x63,0x7a,0x00,0x00,
+ 0x05,0x20,0x0c,0x50,0x55,0x46,0x87,0x5a,0x8d,0x14,0xfb,0xa7,0x29,0x70,0x18,0xa6,0x29,0x80,0x8c,0x33,0x42,0x5a,0x8f,0xe4,0x84,0x64,0x3d,0x0e,0xb5,0xbd,0x36,0x34,0x42,0xb6,0x00,0x00,
0x05,0x20,0x17,0x0c,0x56,0xce,0x72,0xa5,0xa0,0xe6,0x23,0x06,0xa3,0xc7,0x08,0x43,0x18,0xee,0x3a,0x46,0x35,0x5d,0x17,0xf6,0x78,0x96,0xa0,0x9c,0x51,0xef,0xbe,0x23,0xfd,0x71,0x00,0x00,
- 0x05,0x20,0x19,0xe7,0x0d,0x3f,0xfe,0x9e,0x0e,0x8e,0x73,0x40,0x40,0xc3,0xba,0x8f,0x41,0xaf,0xf1,0x7b,0xa6,0x83,0x1b,0xc3,0xa4,0xe0,0x6d,0x6c,0x57,0xa7,0x36,0x5d,0x09,0xce,0x00,0x00,
+ 0x05,0x20,0x18,0x31,0xb3,0x9a,0xf8,0x8c,0xec,0x99,0x2e,0x7d,0xe4,0x90,0xa2,0x54,0x27,0xbd,0xe5,0xc8,0x65,0xdf,0x1f,0xaa,0x8f,0xe9,0x0f,0x64,0x85,0x09,0xc3,0x70,0x62,0x13,0x00,0x00,
+ 0x05,0x20,0x1a,0x35,0x98,0x78,0xb1,0xd9,0x48,0x62,0xe9,0x23,0x10,0xfe,0x71,0xdb,0x10,0x5f,0x28,0xc8,0xf3,0xda,0x33,0x9b,0x26,0xcb,0x4d,0xbe,0x7b,0x03,0x76,0xb9,0xe0,0x54,0x00,0x00,
+ 0x05,0x20,0x27,0x7a,0xaf,0x5a,0x9c,0xf4,0x72,0xfe,0x3c,0xdd,0x7a,0xba,0xd7,0x98,0x31,0xde,0x73,0xce,0x84,0x5b,0x41,0xe7,0x9a,0x6a,0xe2,0xc1,0x3b,0x5b,0x37,0x23,0xc7,0xdf,0x00,0x00,
+ 0x05,0x20,0x20,0x90,0xe3,0xd3,0xad,0x87,0xeb,0x2a,0xd9,0x29,0x17,0x74,0x47,0xc9,0x54,0x57,0xfa,0x3d,0x71,0x02,0x11,0xb2,0xc3,0x87,0x31,0xb3,0x9b,0x6f,0x2e,0xfc,0x30,0xea,0x00,0x00,
+ 0x05,0x20,0x22,0x56,0xd6,0x98,0x11,0x61,0xe1,0x5a,0x34,0x9f,0xe2,0x9d,0xf5,0x2b,0xbd,0xbc,0xcc,0x1c,0xf5,0x1d,0x68,0xa5,0xca,0xb1,0xb5,0x4b,0xf1,0xb5,0xff,0x1e,0xdd,0xc0,0x00,0x00,
+ 0x05,0x20,0x37,0x3e,0x28,0x39,0xef,0xa6,0xbc,0xf8,0xf1,0xba,0x11,0x40,0x87,0x42,0xff,0x58,0x46,0x8f,0xb0,0x80,0xfe,0x20,0x75,0xc5,0x43,0xce,0xec,0x9b,0x5d,0x37,0x19,0xf4,0x00,0x00,
0x05,0x20,0x3e,0xe3,0xe0,0xa9,0xbc,0xf4,0x2e,0x59,0xd9,0x20,0xee,0xdf,0x74,0x61,0x4d,0x99,0x0c,0x5c,0x15,0x30,0x9b,0x72,0x16,0x79,0x15,0xf4,0x7a,0xca,0x34,0xcc,0x81,0x99,0x00,0x00,
- 0x05,0x20,0x3b,0x42,0x1c,0x25,0xf7,0xbf,0x79,0xed,0x6d,0x7d,0xef,0x65,0x30,0x7d,0xee,0x16,0x37,0x22,0x72,0x43,0x33,0x28,0x40,0xa3,0xaa,0xf4,0x48,0x49,0x67,0xb1,0x4b,0xfd,0x00,0x00,
+ 0x05,0x20,0x39,0xca,0x8e,0x62,0x0a,0x36,0xa7,0x68,0x22,0xc4,0xcc,0x4a,0xa9,0x16,0x69,0x4b,0x8a,0x1c,0x5f,0x6e,0x4a,0x98,0xb6,0x95,0x82,0xb3,0x66,0x66,0xc5,0x29,0x3a,0xb0,0x00,0x00,
+ 0x05,0x20,0x3b,0xd0,0x80,0xc4,0xab,0x82,0x83,0x11,0x48,0xe5,0x3b,0x23,0x3b,0x17,0x04,0x0f,0xd8,0x39,0x7c,0x1b,0x70,0x73,0x68,0x98,0x11,0x22,0x49,0x51,0x8f,0x20,0x65,0x65,0x00,0x00,
+ 0x05,0x20,0x47,0x1f,0x83,0xc8,0xa3,0x87,0x35,0xcf,0x8e,0x8d,0x22,0xfe,0xf0,0x02,0x63,0x04,0x3a,0x6a,0x49,0x1a,0x3b,0x70,0x17,0xeb,0x05,0xed,0xaf,0x61,0xb6,0x26,0xb8,0x21,0x00,0x00,
+ 0x05,0x20,0x45,0xbd,0x33,0x3d,0x81,0x1e,0x14,0x52,0x88,0x8a,0xa7,0x46,0x0f,0x37,0x25,0xd0,0x59,0x9f,0x78,0xb5,0x7f,0x4a,0xf1,0x54,0x8c,0x2d,0x36,0x32,0xf8,0x10,0xf3,0xcc,0x00,0x00,
+ 0x05,0x20,0x4a,0x8b,0x40,0x25,0xdc,0x06,0x2a,0xed,0x44,0x35,0xec,0x06,0x9e,0x73,0x70,0xf0,0x07,0x06,0x35,0xd1,0x60,0x4f,0x22,0xe8,0xbf,0x8a,0xdf,0xd9,0xeb,0x97,0x73,0x06,0x00,0x00,
0x05,0x20,0x4e,0x77,0x2e,0x12,0x91,0x67,0x6b,0x94,0xc4,0x92,0x2f,0x19,0x67,0x7d,0xcd,0x47,0x02,0xad,0xf8,0x60,0x72,0xed,0x73,0xf1,0x10,0x99,0x2c,0x05,0x61,0x66,0x55,0xd9,0x00,0x00,
- 0x05,0x20,0x53,0x94,0xa6,0x3e,0x14,0x82,0xd4,0xf9,0xd3,0xa7,0x53,0x33,0x05,0xce,0x72,0x64,0xed,0x74,0x09,0x63,0x8f,0x24,0xef,0xda,0x12,0xa1,0x55,0xe0,0xd8,0xbb,0xd3,0x58,0x00,0x00,
+ 0x05,0x20,0x5a,0x29,0xfe,0x8a,0xaa,0x9d,0x78,0x81,0x04,0x53,0x37,0xf5,0x6f,0xb6,0xe1,0x57,0x08,0x80,0xcf,0xf6,0x03,0x11,0x92,0x8d,0x08,0xe3,0x99,0x9f,0x98,0x4a,0x27,0x6b,0x00,0x00,
+ 0x05,0x20,0x5a,0x65,0x0a,0x52,0x9b,0xc7,0x2e,0x92,0x79,0x7b,0xd3,0xf7,0xa4,0x35,0xbe,0x8e,0xb1,0xea,0x2d,0x7e,0x73,0x84,0x6a,0x3f,0xc9,0x9a,0x62,0xe3,0xc6,0x17,0x0e,0x7c,0x00,0x00,
+ 0x05,0x20,0x5c,0x40,0x7f,0x80,0x43,0x91,0x9c,0xfc,0x04,0xdc,0xdc,0x8e,0x01,0xda,0xc8,0xaf,0x90,0x62,0x64,0x16,0xf7,0x11,0xe4,0x87,0xac,0xa4,0x06,0x6f,0x8d,0x87,0x4e,0xd6,0x00,0x00,
+ 0x05,0x20,0x5e,0x69,0x4f,0x31,0x33,0xa7,0xea,0x3e,0xf4,0x7a,0x0a,0x1e,0x74,0x09,0x07,0xa1,0x50,0xf7,0x03,0xf5,0xc6,0x19,0xeb,0x95,0xaa,0x63,0x17,0x10,0x6e,0x68,0xca,0x10,0x00,0x00,
+ 0x05,0x20,0x67,0x82,0xfc,0x36,0xea,0xae,0x95,0x3b,0x5d,0x46,0xf3,0xf4,0x6c,0x50,0x69,0x29,0xc7,0x47,0x87,0xca,0xa6,0x40,0x12,0x40,0x6d,0x12,0x94,0x35,0x17,0x8a,0xba,0x56,0x00,0x00,
+ 0x05,0x20,0x67,0xab,0xce,0xf2,0xe3,0xf3,0xf6,0x19,0xf6,0x56,0xa2,0x4c,0xca,0x91,0x4b,0x93,0xfe,0xbc,0x85,0x50,0x5c,0x20,0x51,0x69,0xfb,0xf0,0x92,0xbb,0x57,0xa3,0x0d,0x05,0x00,0x00,
+ 0x05,0x20,0x62,0xcc,0x44,0x66,0x31,0x76,0x1b,0x43,0xbe,0xe1,0xc9,0x1d,0x20,0x26,0x7d,0xa7,0x06,0x31,0x57,0x0d,0xb9,0x58,0x20,0xb3,0xca,0xb2,0x5e,0x0a,0x15,0x0b,0xba,0x0d,0x00,0x00,
+ 0x05,0x20,0x71,0x68,0x1b,0xc7,0x48,0x8f,0xe9,0xa3,0x53,0x29,0xb6,0x23,0x5a,0x25,0x02,0x45,0x72,0xca,0xa1,0xb6,0x06,0xfc,0xda,0x65,0x71,0x37,0xe6,0xd9,0x30,0x81,0x02,0xfe,0x00,0x00,
+ 0x05,0x20,0x72,0x8b,0x72,0x38,0xfe,0x44,0xe9,0xc2,0xf4,0xbc,0xd8,0xce,0x1c,0xd5,0x50,0xb1,0x63,0x56,0x74,0x5e,0xf2,0xd3,0xe5,0xd5,0x29,0xe4,0x34,0x1d,0xf5,0x1c,0x7a,0xb9,0x00,0x00,
+ 0x05,0x20,0x76,0x74,0x80,0x6c,0xab,0x7b,0x36,0x3a,0x6a,0x78,0xa4,0xa8,0xb8,0xb7,0xe7,0xf9,0x34,0x47,0x6d,0x34,0xca,0xa2,0xc6,0xef,0x81,0xab,0x62,0xb1,0x46,0x86,0xaf,0xd0,0x00,0x00,
+ 0x05,0x20,0x80,0xfc,0x95,0xc8,0x95,0x91,0x2f,0x6b,0x6e,0xc4,0x2b,0xe1,0x2f,0xa0,0xcb,0xb8,0x76,0x5f,0x6f,0x1c,0x27,0xb0,0x3a,0x2c,0xb9,0x8d,0x6c,0x55,0xbd,0x02,0x60,0xe0,0x00,0x00,
+ 0x05,0x20,0x80,0xc6,0x6f,0xb3,0x18,0x5a,0x1a,0xde,0x4e,0xde,0x50,0xd2,0xc6,0x3f,0xc5,0x96,0x09,0x35,0x3a,0x4d,0x88,0x5f,0xa3,0x49,0x37,0xff,0xe6,0xc5,0x43,0x10,0xaf,0xa8,0x00,0x00,
+ 0x05,0x20,0x8a,0x32,0x54,0x37,0x12,0x24,0xb5,0x1d,0xba,0x3c,0x45,0x03,0x2e,0xda,0xfe,0xf1,0x87,0x8f,0x31,0xe5,0xfe,0xed,0xfa,0x38,0x25,0x00,0x99,0xa5,0xf4,0x51,0x02,0xf7,0x00,0x00,
+ 0x05,0x20,0x97,0x4e,0x74,0xcd,0x8b,0x37,0x76,0x15,0x3b,0x6d,0xb5,0xa4,0xa0,0x4b,0xf7,0x34,0x98,0x48,0x67,0x1e,0x99,0xe7,0x24,0xf4,0x00,0xf7,0x06,0x9c,0x45,0x69,0x34,0x01,0x00,0x00,
0x05,0x20,0x91,0x06,0xd1,0x9e,0xbd,0xab,0xc4,0x61,0xb3,0x0a,0xc2,0x3b,0x29,0xf3,0x10,0x38,0xee,0xbd,0x9d,0xe3,0x99,0x97,0x30,0x70,0x6e,0xe6,0xfb,0x6a,0x3c,0x07,0x3d,0xfd,0x00,0x00,
+ 0x05,0x20,0x9c,0x97,0xc1,0xad,0xf4,0xd2,0x07,0xae,0xe8,0x3e,0x14,0x42,0x36,0x85,0x71,0xa0,0xa7,0xef,0x72,0x44,0xf1,0x74,0x8b,0x6f,0xa5,0xa4,0x2c,0x0d,0xcc,0x9f,0xb0,0x9d,0x00,0x00,
+ 0x05,0x20,0x9d,0x0d,0x0f,0x58,0x1a,0x5c,0xb4,0x1a,0xeb,0xef,0x8e,0x91,0x8d,0x8c,0x1b,0x57,0x5d,0x6d,0x97,0x24,0x28,0x45,0x54,0x8a,0x3a,0xd5,0x05,0xfb,0x76,0xac,0x25,0x52,0x00,0x00,
+ 0x05,0x20,0xa4,0xb3,0x30,0x54,0x28,0x0f,0xfb,0xe5,0x76,0xb0,0x31,0xb2,0x65,0x62,0x56,0x72,0x7c,0xc9,0xcd,0x07,0x4d,0x5f,0xb1,0x69,0xe0,0xf7,0x35,0x3d,0x30,0x3c,0x7d,0x64,0x00,0x00,
+ 0x05,0x20,0xa9,0xa9,0xe5,0xae,0x01,0xc2,0x5e,0x76,0x2f,0x5d,0xa3,0x07,0xdc,0xce,0xb8,0xbc,0x6f,0x47,0xaf,0x3a,0x37,0xf8,0x5c,0x86,0xff,0xe9,0xb6,0xa5,0x00,0x93,0x76,0x11,0x00,0x00,
+ 0x05,0x20,0xb2,0x63,0x45,0xf5,0x36,0xb0,0x79,0x58,0x0d,0x8a,0x54,0x52,0x16,0x2f,0x1f,0x74,0x93,0xe0,0x30,0x82,0x1b,0xe4,0x01,0x76,0xf5,0x03,0xa1,0x19,0xa3,0x8d,0x0e,0xce,0x00,0x00,
+ 0x05,0x20,0xb5,0x55,0x31,0x3f,0xe7,0xc7,0x17,0xe4,0x31,0x87,0x47,0x45,0x7c,0x67,0x43,0x5c,0x82,0x73,0xd6,0x62,0x64,0x94,0x92,0x32,0x2d,0x81,0x0e,0x01,0x35,0xc0,0x7e,0xb7,0x00,0x00,
0x05,0x20,0xb5,0x83,0x6f,0xb6,0x11,0xd8,0x0e,0xa8,0x57,0xda,0x15,0x20,0x5b,0x1a,0x6d,0x21,0x15,0x5a,0xbd,0xb4,0x17,0x11,0xc2,0xfb,0x0e,0xfc,0xde,0xe8,0x26,0x56,0xa8,0xac,0x00,0x00,
+ 0x05,0x20,0xba,0xe0,0xd1,0xe5,0x2e,0x27,0x5b,0x1d,0x36,0x57,0x77,0xaf,0x64,0x04,0xfc,0xe1,0x8f,0x8c,0xf1,0x25,0x81,0x2b,0x4f,0x6a,0xf8,0x55,0x48,0xc2,0x5e,0x6f,0x62,0x43,0x00,0x00,
+ 0x05,0x20,0xc0,0xb9,0x7b,0x21,0xbd,0xa2,0x48,0xda,0x8a,0x3e,0xc3,0x6c,0xac,0xfd,0x6d,0x63,0x21,0xb6,0xb3,0x37,0xa9,0x4d,0x42,0x2c,0x9e,0x75,0x61,0x07,0xdc,0xc9,0xab,0x9b,0x00,0x00,
+ 0x05,0x20,0xc8,0xdc,0x00,0xc8,0xdf,0xa1,0xb2,0xe9,0x9f,0x00,0xb3,0x86,0x93,0xc3,0xbc,0x6d,0x56,0xe2,0x83,0xfc,0xf4,0x6e,0x55,0x5d,0xed,0x4e,0x53,0xe6,0xd1,0x4c,0x38,0x3c,0x00,0x00,
0x05,0x20,0xcc,0xaf,0x6c,0x3b,0xd0,0x13,0x76,0x23,0xc3,0x36,0xbb,0x64,0x4a,0x4a,0x06,0x93,0x69,0x6d,0xb0,0x10,0x6e,0x66,0xa4,0x61,0xf8,0x2d,0xe7,0x80,0x72,0x4d,0x53,0x94,0x00,0x00,
+ 0x05,0x20,0xce,0x25,0x15,0xbd,0x08,0xe9,0x67,0x1c,0xa2,0xa5,0x16,0x0e,0x38,0xd9,0xe4,0xc6,0x20,0x31,0x86,0x23,0x21,0x5a,0x5a,0x76,0x1e,0x74,0xd5,0xd3,0x4e,0x86,0x61,0xf4,0x00,0x00,
0x06,0x10,0xfc,0x32,0x17,0xea,0xe4,0x15,0xc3,0xbf,0x98,0x08,0x14,0x9d,0xb5,0xa2,0xc9,0xaa,0x20,0x8d,
0x06,0x10,0xfc,0xc7,0xbe,0x49,0xcc,0xd1,0xdc,0x91,0x31,0x25,0xf0,0xda,0x45,0x7d,0x08,0xce,0x20,0x8d,
};
static const uint8_t chainparams_seed_test[] = {
- 0x04,0x20,0xdf,0x55,0xaa,0x83,0xd5,0xc5,0xb8,0xe7,0x75,0x78,0xd4,0x29,0x51,0x4b,0x26,0x1c,0x23,0xdf,0x28,0x4d,0x29,0x85,0x07,0xb5,0xe2,0x29,0x69,0x3e,0x25,0xbb,0x61,0xcf,0x47,0x9d,
- 0x04,0x20,0x0a,0xdd,0xa2,0x48,0xb5,0x56,0xa3,0x1f,0xca,0x3c,0x4c,0x9e,0xca,0x6e,0xb3,0xd5,0x5e,0x68,0xf6,0x28,0x31,0x57,0x24,0xfb,0x9d,0x2b,0x55,0x4f,0xd7,0x90,0x62,0xd3,0x47,0x9d,
- 0x04,0x20,0x2d,0x04,0xa1,0x4a,0xd4,0x7c,0x7b,0x16,0x2e,0xb7,0xd2,0xa1,0x08,0xc5,0xd2,0xbd,0x53,0x87,0x34,0xdc,0x38,0x26,0xca,0x56,0xf2,0xac,0xc5,0x62,0x70,0x72,0x3f,0x63,0x47,0x9d,
- 0x04,0x20,0x30,0x57,0x85,0xe0,0x02,0x4a,0xd1,0x31,0xeb,0x16,0x1b,0x1d,0xa8,0x43,0x0b,0xb4,0xc6,0xac,0x7d,0x46,0x24,0x0b,0x55,0x9d,0x16,0xe6,0x46,0x03,0x72,0xfe,0xd4,0xef,0x47,0x9d,
- 0x04,0x20,0x36,0x6c,0xf1,0xd2,0xbb,0xda,0xff,0x8c,0x93,0x61,0x10,0xf2,0x9d,0xa1,0xa4,0x0a,0x30,0x9b,0x0c,0x69,0x6d,0xaa,0xd4,0x9c,0xfd,0xb5,0x5b,0x5e,0x30,0x9f,0xf3,0x13,0x47,0x9d,
- 0x04,0x20,0x3e,0xe2,0xf3,0xe5,0xc5,0xbe,0x61,0xdd,0x4c,0x3e,0xdb,0x0d,0xd2,0xf9,0x42,0xe3,0x31,0xb2,0xa8,0x51,0x31,0xf6,0xce,0xc2,0x38,0x20,0x27,0x39,0x73,0x68,0x5a,0x42,0x47,0x9d,
- 0x04,0x20,0x51,0x79,0x05,0x9c,0x8a,0xdf,0x03,0xb5,0x1b,0x17,0xc3,0x86,0xb6,0x54,0xcc,0xe0,0x6e,0x58,0xa6,0x41,0x4c,0xcc,0x0c,0x60,0x08,0xa6,0x0f,0x1d,0x11,0xd8,0x29,0xa6,0x47,0x9d,
+ 0x04,0x20,0xd7,0x13,0xfe,0x00,0xf0,0xf1,0x07,0xcb,0x30,0xb1,0x31,0xc7,0x68,0xbb,0x05,0xca,0x18,0xb5,0x1d,0xb1,0x0f,0xf2,0x7e,0x66,0xdb,0xaa,0xf4,0x05,0xaf,0x37,0x0a,0x62,0x47,0x9d,
+ 0x04,0x20,0xd1,0x71,0xfe,0x4c,0x9e,0xe9,0x99,0xb1,0x6c,0xd5,0xdd,0x3a,0xc3,0xd8,0x74,0x1d,0x42,0x32,0x9f,0xca,0xe9,0x47,0x9e,0x18,0x74,0x43,0x22,0xb9,0xa5,0x31,0xb9,0x66,0x47,0x9d,
+ 0x04,0x20,0xd2,0xe4,0xd1,0x40,0x65,0x5d,0x95,0xaf,0xe8,0x67,0xc0,0xe3,0x72,0xfd,0x0a,0x2e,0x35,0xb7,0xbd,0xac,0x67,0x78,0x36,0xe1,0xb8,0xba,0x30,0xcf,0x2e,0x05,0xdd,0x9d,0x47,0x9d,
+ 0x04,0x20,0xde,0xdd,0xe8,0x01,0x03,0x98,0x3f,0x2d,0x3d,0x8b,0x99,0x27,0xea,0xe1,0xa3,0xde,0xff,0x50,0x30,0xc2,0x41,0x4e,0x7e,0x72,0x24,0x3d,0xad,0x78,0x3c,0xab,0x12,0x67,0x47,0x9d,
+ 0x04,0x20,0xdb,0x9d,0xe0,0xc8,0x5d,0x65,0x4b,0xe0,0x7b,0x0f,0x63,0x80,0x85,0x21,0x73,0x07,0x94,0x0f,0xb0,0x23,0x38,0xec,0x78,0xb6,0x07,0xa1,0xd2,0xb0,0x82,0xf8,0x20,0xea,0x47,0x9d,
+ 0x04,0x20,0xdb,0xc9,0xb2,0xe1,0x4b,0x43,0xf1,0xc9,0x3d,0xea,0x51,0x9a,0x71,0x6b,0x4a,0x15,0xe7,0x3e,0xfe,0x8b,0x24,0x7a,0xaa,0xff,0x53,0xf7,0xfc,0x10,0xc6,0xcc,0x14,0x88,0x47,0x9d,
+ 0x04,0x20,0xe5,0x38,0xc1,0x67,0x52,0x2d,0x6f,0x2f,0xbe,0xc2,0xb3,0x45,0x2b,0x19,0x8c,0x10,0xf3,0x09,0xe5,0x37,0xfe,0x66,0x57,0x6f,0x7a,0x4d,0x78,0xf8,0x50,0x41,0xd6,0x90,0x47,0x9d,
+ 0x04,0x20,0xed,0x76,0x8d,0x28,0xb0,0x44,0x2c,0xff,0xf4,0xd9,0x6a,0x5c,0xf9,0xca,0x5f,0x81,0xa2,0x23,0x48,0x82,0x24,0x2e,0xfc,0xbe,0x0a,0x1e,0xf9,0x02,0x43,0x31,0x37,0xf5,0x47,0x9d,
+ 0x04,0x20,0xee,0x57,0x1b,0xab,0xd0,0xd7,0x27,0xca,0xe7,0xaa,0xe2,0x09,0xf3,0x4e,0x80,0x90,0xd2,0x0a,0x9d,0xc4,0x59,0xd0,0xdc,0xa1,0x97,0x09,0x4e,0x2f,0xfe,0x9f,0xa8,0x0a,0x47,0x9d,
+ 0x04,0x20,0xf7,0xe5,0xb0,0x17,0xdc,0x21,0xed,0xfb,0xb6,0xf5,0xe6,0xb4,0x0b,0xb3,0xf3,0x6c,0xb8,0x3f,0x2a,0x93,0x89,0x66,0x2f,0x05,0x30,0xdf,0xfa,0xdf,0xf2,0x1b,0x52,0x78,0x47,0x9d,
+ 0x04,0x20,0xf0,0x38,0xe6,0xe3,0xbb,0x4d,0x17,0x56,0xd0,0xae,0xf6,0xf4,0xa9,0x99,0x96,0xa9,0xe8,0xfc,0xfb,0x76,0x08,0xed,0x7f,0xb7,0xf0,0xa0,0xd3,0x8d,0xea,0x18,0x87,0x8c,0x47,0x9d,
+ 0x04,0x20,0xf1,0x67,0x83,0x6d,0xa7,0x17,0xa6,0xdd,0x1f,0x19,0x5c,0xbd,0x92,0x8e,0x45,0x0c,0x5c,0x2c,0x9d,0x57,0x98,0xe1,0x46,0x40,0x3d,0x87,0x30,0x02,0x9f,0x1d,0x88,0xde,0x47,0x9d,
+ 0x04,0x20,0xff,0x7b,0xca,0x5b,0xa3,0x4c,0x68,0x7d,0xf1,0x3d,0x18,0xef,0xb4,0x3e,0x39,0x34,0x0d,0x9c,0x3c,0x49,0x9b,0xe7,0x67,0x2c,0x78,0x61,0x42,0x67,0x62,0xd0,0x15,0xb5,0x47,0x9d,
+ 0x04,0x20,0xff,0xbc,0xb7,0x65,0x60,0x0d,0xc1,0x04,0xbc,0x30,0x95,0x67,0xe9,0x37,0x62,0xf7,0x5b,0xe3,0x2a,0xd6,0x3b,0xaf,0x8a,0x98,0xc9,0xfb,0x4b,0x66,0xb2,0xdc,0x13,0xc0,0x47,0x9d,
+ 0x04,0x20,0xf8,0x57,0x5e,0x80,0x2d,0xc4,0xc6,0x5e,0x7f,0x15,0x09,0xee,0xcc,0x29,0xf1,0x65,0x53,0x1c,0x41,0xc1,0xf7,0x51,0xa4,0xb0,0x76,0x86,0xe3,0x10,0x24,0x4d,0xd2,0x11,0x47,0x9d,
+ 0x04,0x20,0xfd,0x74,0x90,0x71,0x06,0xbf,0x2b,0xdc,0x69,0x31,0xf2,0x63,0x1f,0x18,0x17,0x71,0xd2,0x75,0xe4,0xf5,0x35,0x89,0xc0,0x55,0x71,0x05,0xc4,0x77,0x64,0xbf,0x20,0x36,0x47,0x9d,
+ 0x04,0x20,0xfe,0x4c,0x16,0x4f,0x37,0x75,0xb4,0xe2,0x54,0x7d,0x00,0x21,0x39,0x3a,0x2c,0xb7,0xe8,0x9a,0xf3,0x2f,0x8a,0xf6,0xe4,0x6b,0x7d,0xea,0x18,0xc3,0xc3,0x86,0x57,0xc5,0x47,0x9d,
+ 0x04,0x20,0x00,0xe5,0x30,0x05,0x39,0xf9,0x05,0xac,0x6d,0x33,0xe5,0xb4,0x3a,0xd1,0x8c,0x75,0xb3,0x5f,0x9b,0xcc,0xd1,0x76,0xa0,0x24,0x84,0x49,0x4b,0x40,0x67,0xee,0x4d,0x93,0x47,0x9d,
+ 0x04,0x20,0x01,0x25,0x8f,0x4c,0xb4,0x28,0x06,0xaa,0x4f,0xc5,0x5d,0x34,0x19,0x40,0xcd,0xb6,0xb9,0xad,0x52,0x3a,0xc3,0x52,0x05,0x9a,0x97,0x5e,0x69,0x9a,0x2a,0x66,0xde,0x48,0x47,0x9d,
+ 0x04,0x20,0x02,0xee,0xed,0xe8,0x3d,0x20,0xd1,0xb0,0xb7,0x44,0xd6,0xb9,0x08,0x9b,0x13,0x35,0xee,0xf4,0x0b,0x8a,0x6e,0x10,0xfa,0xbc,0x75,0x14,0xcb,0x28,0xd4,0x40,0x44,0x3a,0x47,0x9d,
+ 0x04,0x20,0x03,0x88,0x08,0xcf,0x7c,0xa3,0x1c,0xe6,0xd4,0x7a,0x50,0x61,0x1d,0x84,0x5c,0x95,0x89,0x4f,0x03,0x8c,0x91,0xf4,0x67,0xf2,0x4a,0xc4,0x2a,0x44,0x6e,0x47,0xc8,0xae,0x47,0x9d,
+ 0x04,0x20,0x03,0xe3,0x9a,0xa7,0xe7,0x30,0xa7,0x21,0x93,0x8c,0x52,0x76,0x4b,0x43,0x7d,0x35,0x70,0xa9,0x3d,0x35,0x54,0x11,0x83,0x1b,0xe1,0x7b,0x6d,0xd9,0xaa,0xb2,0x26,0x9b,0x47,0x9d,
+ 0x04,0x20,0x05,0x9e,0xaf,0x67,0x77,0x31,0xef,0xe7,0x65,0xd4,0x3b,0x86,0x2c,0x0c,0x10,0x9c,0x7d,0x4c,0xe4,0x2d,0xb7,0x05,0x12,0x51,0x17,0xfb,0x15,0x47,0xdd,0xd7,0x5b,0x0e,0x47,0x9d,
+ 0x04,0x20,0x06,0x30,0xd8,0x03,0x34,0x16,0x0f,0xa4,0x8f,0xb1,0x21,0xc4,0x53,0x19,0x87,0xa3,0x60,0xf1,0xdb,0x2b,0x09,0xf2,0x18,0x1b,0x1e,0x5a,0x78,0x29,0xe7,0x4e,0x12,0x7e,0x47,0x9d,
+ 0x04,0x20,0x0e,0x90,0xa0,0x77,0x60,0x80,0x95,0x5e,0x1a,0x5f,0xb3,0x1c,0x6d,0x87,0x11,0x20,0x35,0x52,0xe5,0x9d,0x7f,0xf0,0x4d,0xec,0x68,0x30,0xa4,0xca,0xd5,0xaf,0x0e,0x20,0x47,0x9d,
+ 0x04,0x20,0x09,0x3f,0x9b,0xec,0xe7,0xf0,0xd6,0x03,0xba,0x2b,0xac,0xa3,0x13,0x41,0x9c,0x70,0x0e,0x58,0x9a,0x0c,0xd4,0xc3,0x66,0x84,0x7c,0xa7,0x76,0xd9,0xd3,0xa5,0xff,0xba,0x47,0x9d,
+ 0x04,0x20,0x0a,0xe8,0xaf,0x6a,0xc9,0xd7,0x03,0x2a,0x8e,0xc7,0xe7,0xd9,0x47,0x77,0x87,0x3d,0xa4,0x09,0xa8,0xb3,0x44,0x2e,0x4a,0xcf,0xaa,0x08,0x3e,0x79,0x4d,0x2e,0x25,0xfd,0x47,0x9d,
+ 0x04,0x20,0x0d,0x02,0xcf,0x15,0x0e,0x79,0x72,0xab,0xc2,0x25,0xbf,0xab,0x07,0xa1,0xc4,0xe8,0x0e,0xb3,0xe2,0x81,0xcf,0x7e,0xe3,0x4a,0x10,0xc7,0x0e,0x0e,0xbd,0xad,0x32,0x20,0x47,0x9d,
+ 0x04,0x20,0x1e,0xc5,0x90,0x07,0x29,0x4f,0x7e,0xb3,0x46,0x51,0xe9,0x81,0x65,0x24,0x7f,0xae,0xcd,0x96,0xc6,0x00,0xfe,0x70,0x8c,0xc1,0x8a,0xe2,0xe3,0x80,0x48,0x40,0xab,0x10,0x47,0x9d,
+ 0x04,0x20,0x18,0xd3,0xc1,0x52,0xa1,0xde,0xaa,0x4e,0x88,0xf3,0x7f,0x92,0x09,0xcc,0x43,0x6b,0x59,0x76,0x3d,0xce,0x2a,0x66,0x7c,0xa3,0xf3,0x39,0xaf,0x73,0xcf,0xf8,0x83,0x89,0x47,0x9d,
+ 0x04,0x20,0x1c,0x0e,0x75,0xca,0x45,0xb3,0x0f,0xb3,0x7b,0x27,0xb5,0xde,0x22,0x86,0xde,0xe5,0xf3,0xd8,0x95,0x0a,0x11,0x96,0x86,0x84,0xee,0xbd,0x7a,0x04,0xd7,0x90,0xca,0x04,0x47,0x9d,
+ 0x04,0x20,0x1c,0x66,0x71,0x60,0x3c,0xbf,0x22,0x32,0x91,0x56,0xe9,0xbf,0x74,0xb8,0xd7,0x47,0xc1,0x07,0x2e,0x88,0x59,0xa8,0xb0,0x9a,0xd5,0x93,0x09,0xb6,0xdb,0x6e,0x40,0x6a,0x47,0x9d,
+ 0x04,0x20,0x1d,0x83,0xcf,0x89,0x90,0x06,0xa6,0x97,0xb2,0xa9,0x01,0x01,0x1f,0x98,0x62,0x04,0x65,0xa5,0x93,0x3e,0x6a,0x08,0x53,0xa3,0x90,0x2e,0xb5,0x02,0x1e,0x78,0x98,0x3d,0x47,0x9d,
+ 0x04,0x20,0x27,0xe6,0xa8,0x97,0xbc,0x69,0xb7,0x0e,0xd4,0x4d,0xe9,0x9b,0xff,0xe6,0xc9,0xb3,0x3f,0xc5,0xa8,0xa0,0xaf,0x19,0x61,0xd2,0xfb,0x7d,0x5c,0xdf,0x62,0xb0,0x36,0xe6,0x47,0x9d,
+ 0x04,0x20,0x24,0xe9,0x86,0x63,0x9f,0x96,0xe1,0x42,0x3e,0xa3,0x03,0x9d,0xfd,0x23,0xa4,0xeb,0x05,0xfa,0x3a,0xb1,0xcd,0x3a,0xce,0x24,0xbd,0x87,0x99,0x65,0xd9,0x19,0x75,0xf1,0x47,0x9d,
+ 0x04,0x20,0x28,0x50,0xc2,0x49,0xb8,0x3e,0x68,0x10,0xe6,0x02,0xdd,0x01,0x42,0xe5,0x41,0xc1,0x58,0xd5,0x5e,0xb8,0x7b,0xae,0x0a,0x90,0x14,0x0f,0xe3,0x97,0xe4,0xfa,0x2b,0xaf,0x47,0x9d,
+ 0x04,0x20,0x2e,0x43,0x1b,0x30,0xd6,0x62,0x9d,0xf8,0x50,0x8b,0x89,0xcb,0x49,0x2a,0x7b,0x42,0x40,0x10,0x0b,0xfe,0xcd,0xfe,0x6e,0xe8,0x65,0x89,0x2a,0xc3,0x8d,0x49,0xf2,0x2a,0x47,0x9d,
+ 0x04,0x20,0x36,0x3c,0xd4,0x1f,0x8f,0x63,0xfa,0x49,0x62,0xb5,0x69,0xd6,0x9f,0x42,0xaa,0xfe,0x54,0x14,0xd1,0xd2,0xb2,0xae,0x52,0xe1,0x08,0x7e,0xc6,0x15,0x56,0x45,0xbd,0xb3,0x47,0x9d,
+ 0x04,0x20,0x38,0x3d,0xac,0xa2,0x19,0x80,0xdc,0x61,0xff,0xb9,0x37,0xd6,0x53,0xf0,0xb0,0x89,0xb6,0x14,0x33,0x62,0x7c,0x33,0x8a,0x3d,0xdc,0xdd,0xba,0xfb,0x70,0xa4,0x6f,0x9b,0x47,0x9d,
+ 0x04,0x20,0x38,0x04,0x94,0x99,0x3a,0x60,0x61,0x08,0xcc,0xf9,0x43,0x18,0x8f,0x01,0xb5,0x43,0x7e,0x35,0xa5,0x27,0x2a,0xf6,0x85,0x78,0x81,0x36,0xed,0xb6,0xb0,0xd2,0xac,0x77,0x47,0x9d,
+ 0x04,0x20,0x38,0x54,0xfe,0xde,0xcf,0x83,0xb9,0x06,0x7f,0xaa,0x79,0x96,0x58,0x89,0x78,0x45,0x29,0x51,0x9a,0xbf,0x64,0xd1,0x02,0xe2,0x5f,0x74,0x15,0x2e,0x0d,0x8f,0x81,0x9e,0x47,0x9d,
+ 0x04,0x20,0x3c,0x0c,0xec,0x7b,0x47,0x74,0x12,0xcc,0xef,0xe1,0x88,0xcb,0x57,0x11,0xd5,0xd8,0x91,0x7e,0x95,0x17,0x0c,0x12,0xe2,0x46,0x7c,0xc0,0xe3,0xe3,0x92,0x26,0xeb,0x85,0x47,0x9d,
+ 0x04,0x20,0x3d,0x42,0xc6,0x66,0xb0,0x8b,0xcc,0xf9,0x6a,0xfd,0xa7,0x10,0xfe,0x2a,0x45,0xd9,0x3a,0xcd,0x15,0xa4,0x00,0xbf,0xde,0x1a,0x6d,0x3a,0x5b,0xa8,0xc8,0x95,0x6a,0x3c,0x47,0x9d,
+ 0x04,0x20,0x3d,0xb7,0x5c,0xbf,0x7a,0xb7,0x0f,0xe3,0x21,0xeb,0xa1,0x3c,0x8b,0xf3,0x9d,0x72,0x3d,0x69,0xfc,0xcc,0x22,0xa5,0x1c,0xb4,0x3f,0x98,0xcb,0x63,0xa8,0xc8,0x9f,0xcc,0x47,0x9d,
+ 0x04,0x20,0x40,0xc7,0x1f,0x78,0x96,0x51,0xc8,0xd4,0x54,0x0f,0x32,0x00,0xda,0x0d,0x2a,0xb4,0x04,0xff,0x0e,0xf3,0x94,0x8d,0xf4,0x5e,0x23,0x74,0xfa,0x0c,0xfa,0x87,0xfb,0x3b,0x47,0x9d,
+ 0x04,0x20,0x43,0x30,0x0d,0xf9,0x04,0xba,0x10,0x88,0x45,0x56,0xa5,0xee,0x22,0x1d,0xb5,0xe2,0x8d,0xd9,0x1e,0x68,0x8d,0x87,0xaa,0x9b,0x82,0x6a,0x71,0xe5,0x95,0x2b,0x79,0xf6,0x47,0x9d,
+ 0x04,0x20,0x45,0x0e,0x7a,0x38,0x4d,0x97,0xc8,0xd9,0xc7,0x2b,0xbc,0xae,0xa9,0xe3,0x3a,0x40,0x65,0xf3,0xc0,0xc8,0x31,0xab,0xe9,0x02,0x99,0x82,0xb2,0xa0,0x79,0x60,0x92,0xed,0x47,0x9d,
+ 0x04,0x20,0x4a,0x3b,0x66,0x48,0xee,0x55,0x05,0xed,0x91,0x14,0x5e,0x57,0x64,0xeb,0x23,0xab,0x56,0x83,0x56,0x36,0x2d,0x6a,0x2f,0xf8,0x28,0x11,0x37,0x3a,0x73,0x76,0x2e,0x6a,0x47,0x9d,
+ 0x04,0x20,0x4a,0x4b,0x4c,0x27,0xea,0x89,0xb2,0xa6,0x3e,0xf5,0x6e,0xc3,0xa4,0xe8,0xf6,0x5e,0x54,0xcc,0x93,0x64,0xce,0x36,0x82,0xd9,0x5f,0x1b,0x65,0x6b,0x02,0xc6,0x66,0x60,0x47,0x9d,
+ 0x04,0x20,0x4b,0x74,0xfe,0x48,0xc5,0x79,0xd5,0x77,0xba,0xdf,0x52,0x63,0x40,0xc4,0x30,0x04,0xff,0xf5,0x29,0x01,0xcc,0x15,0x5a,0x58,0xf7,0xc0,0x16,0x28,0x83,0x36,0x60,0xa0,0x47,0x9d,
+ 0x04,0x20,0x4c,0x6a,0x4c,0x67,0x94,0x97,0xa4,0xe3,0x78,0x9e,0x16,0x65,0x58,0xf5,0x95,0xa9,0xcd,0x94,0x9a,0xbc,0x40,0xc2,0x4e,0x20,0x71,0x72,0xd9,0x02,0x50,0x75,0x9f,0x41,0x47,0x9d,
+ 0x04,0x20,0x4c,0x85,0xc2,0xc6,0xb5,0x6a,0xf4,0x3d,0x84,0xf9,0xc3,0x8b,0x21,0x7f,0x57,0x7e,0x66,0x66,0x6b,0x6d,0x5f,0x0a,0xd0,0xf0,0x76,0x56,0x65,0x78,0xf8,0xa7,0x42,0x75,0x47,0x9d,
+ 0x04,0x20,0x52,0xf0,0xcb,0x8e,0xa9,0x27,0xd4,0x21,0x57,0x73,0xcb,0x40,0x17,0x6e,0x83,0x73,0xe4,0x59,0xa9,0x89,0x23,0x14,0x14,0x6a,0x91,0x85,0xd2,0xce,0x1c,0x85,0x05,0x06,0x47,0x9d,
+ 0x04,0x20,0x55,0x93,0x75,0x82,0x96,0x4c,0xc8,0x24,0x96,0x48,0xb3,0x9e,0x15,0xf5,0xf5,0x6f,0x5b,0xec,0xf6,0x39,0xff,0xa8,0xaf,0x3a,0x4c,0x5d,0x22,0x3d,0xd3,0x14,0xc3,0x05,0x47,0x9d,
+ 0x04,0x20,0x58,0xbf,0x47,0xe7,0x52,0x8d,0xb5,0x83,0xbc,0x55,0xb1,0xb8,0x02,0xe3,0xdc,0xc2,0xc4,0xe7,0x79,0x85,0xb2,0xe7,0x38,0x27,0xae,0xad,0x0c,0xb8,0x34,0xed,0x71,0xde,0x47,0x9d,
+ 0x04,0x20,0x59,0x76,0xc7,0xdc,0xb8,0x4d,0x1d,0x51,0x40,0x75,0x43,0x57,0xdd,0x3e,0xa3,0x63,0x06,0x0f,0x5e,0x18,0x29,0x10,0x08,0xac,0xa0,0x60,0xd2,0xf3,0x63,0x6e,0xa6,0x58,0x47,0x9d,
0x04,0x20,0x60,0xbe,0xae,0x7d,0xa3,0x4d,0x6a,0x71,0x1a,0x5d,0xe5,0x98,0x9c,0xde,0xa0,0x99,0x39,0x19,0xd3,0x01,0x0a,0x5d,0x1c,0x21,0x43,0x94,0x92,0x71,0x5d,0x77,0xd7,0xdf,0x47,0x9d,
- 0x04,0x20,0x64,0x4e,0x86,0xa1,0x02,0xa1,0x8a,0xef,0xb0,0xd1,0xb5,0x77,0x69,0xb9,0x6a,0xdc,0xdf,0x35,0x8a,0xda,0xa4,0x3e,0x83,0xfa,0x50,0xe6,0xca,0x0e,0x2b,0x99,0x0a,0x17,0x47,0x9d,
- 0x04,0x20,0xa2,0x28,0x3c,0x5a,0x5b,0x82,0x32,0x66,0x11,0xe5,0x71,0xff,0x6b,0x25,0x92,0x75,0xdd,0x7a,0x4f,0x90,0x8b,0x1d,0x34,0xa4,0xf1,0x6e,0xb9,0xfb,0xb5,0x2e,0x7c,0x7f,0x47,0x9d,
- 0x04,0x20,0xc8,0xb5,0x6a,0xba,0x02,0x26,0x45,0x12,0xfb,0x93,0x8a,0x51,0xe4,0xb0,0xf3,0x94,0xb7,0xc0,0x74,0x72,0xeb,0x67,0x91,0x9e,0x04,0x36,0x6a,0x4b,0xef,0x0d,0x88,0xfe,0x47,0x9d,
- 0x04,0x20,0xc8,0xfa,0xcd,0x8c,0xc3,0x6f,0x3c,0xd0,0x27,0x7e,0x7d,0xeb,0x51,0x01,0x65,0xb6,0x9e,0x02,0x09,0x64,0xf4,0x87,0x78,0x7b,0x8f,0x9d,0xaf,0x3b,0xa5,0xcc,0x56,0x2c,0x47,0x9d,
+ 0x04,0x20,0x62,0x42,0x6d,0x98,0xc4,0xa1,0x16,0xc1,0x7d,0x17,0x9e,0x37,0x94,0x88,0x58,0x76,0xa9,0x13,0x6a,0x98,0x39,0x22,0x58,0x13,0xf8,0x9a,0x99,0xa2,0x25,0x56,0x59,0x05,0x47,0x9d,
+ 0x04,0x20,0x6a,0xb1,0x07,0x66,0xbe,0x50,0xec,0x8e,0x6b,0x72,0xfc,0xb4,0xc2,0x67,0x26,0xa1,0x7a,0x10,0x15,0xd3,0xd0,0x36,0x7a,0xf0,0x83,0xd0,0xc3,0x59,0x85,0x68,0x90,0xd8,0x47,0x9d,
+ 0x04,0x20,0x6d,0x6b,0x07,0x72,0xf7,0x45,0x8c,0x1d,0xe3,0x5c,0xf2,0x58,0x20,0xd2,0x95,0x25,0x22,0x51,0xc3,0x59,0x96,0xc1,0xdc,0x7e,0xa4,0x82,0x89,0x0a,0xf5,0x25,0x38,0x1a,0x47,0x9d,
+ 0x04,0x20,0x77,0xaa,0x57,0x56,0x17,0xce,0xdd,0x79,0x64,0xaf,0x78,0xb2,0xf4,0x91,0x36,0x75,0x1c,0x1c,0xcd,0x31,0x35,0x4a,0xe4,0x8b,0x64,0x65,0x4e,0x06,0xec,0x2a,0xc4,0x95,0x47,0x9d,
+ 0x04,0x20,0x70,0x11,0x6d,0x2d,0xa7,0xc9,0x9f,0xd8,0xe3,0xe8,0xae,0x5a,0x4a,0x50,0xac,0x3f,0xd6,0x57,0xad,0xd0,0xa5,0x35,0x14,0xd7,0xb1,0x76,0x58,0xb0,0x90,0xa4,0x1c,0x9b,0x47,0x9d,
+ 0x04,0x20,0x72,0xdb,0xfc,0x04,0x48,0xee,0xec,0xae,0x1b,0xad,0xe6,0x9a,0x87,0xe1,0x17,0xae,0x13,0x70,0xae,0x83,0x90,0x62,0x59,0x30,0xed,0x44,0x43,0xe9,0xab,0xee,0xaa,0xd0,0x47,0x9d,
+ 0x04,0x20,0x74,0xd8,0x56,0x9c,0x5e,0xb4,0x62,0x12,0xea,0x6f,0x1e,0x3d,0x95,0x22,0x50,0x16,0xe3,0xba,0x45,0xb2,0xa3,0xad,0x26,0xb0,0x13,0x74,0xdd,0xec,0x22,0xe0,0x70,0x9a,0x47,0x9d,
+ 0x04,0x20,0x75,0x45,0xe9,0x01,0x21,0x81,0x44,0x1b,0x57,0x76,0x8c,0x3f,0x85,0xa9,0x74,0xf4,0x3c,0xf8,0xd5,0x12,0xcf,0x13,0x1e,0x2f,0x18,0x13,0x78,0xa3,0x51,0x59,0x49,0x49,0x47,0x9d,
+ 0x04,0x20,0x7b,0x3b,0xf1,0xa0,0x78,0xc9,0xba,0xb4,0xd2,0xad,0xed,0x0b,0x1e,0xd2,0x8d,0xd2,0x08,0xd1,0x51,0x5b,0x01,0x74,0x6c,0xc0,0x5d,0xcd,0x4c,0x53,0xf3,0xba,0x16,0xe3,0x47,0x9d,
+ 0x04,0x20,0x7b,0x11,0x26,0x1d,0xf6,0xa1,0xb7,0xc3,0x36,0x19,0x0d,0x27,0x10,0x36,0xb7,0xd5,0x93,0x60,0xc8,0xf8,0x82,0x79,0x46,0xe8,0x78,0xce,0x29,0x50,0x2b,0x44,0x3f,0x7a,0x47,0x9d,
+ 0x04,0x20,0x7b,0x96,0x08,0xa2,0x54,0x5c,0xd0,0x94,0x9c,0x0a,0xa7,0xb3,0xea,0x7d,0x38,0x0b,0x8e,0xee,0x91,0xe3,0x91,0xb9,0xc9,0xcc,0x81,0x28,0x2e,0xc3,0x02,0x9a,0xcf,0x65,0x47,0x9d,
+ 0x04,0x20,0x81,0x34,0x90,0x93,0x9c,0xf9,0xc9,0xe7,0x81,0xa5,0xab,0xf1,0x03,0xe1,0xb3,0x2f,0xf7,0xcf,0x19,0x94,0x2f,0x7a,0x1b,0xc5,0x83,0xc9,0x8c,0xc3,0x5b,0x09,0x96,0x14,0x47,0x9d,
+ 0x04,0x20,0x86,0x7d,0x81,0xf5,0x72,0x30,0xc0,0x91,0x4c,0x8e,0x04,0x48,0x47,0xce,0xcd,0x43,0xef,0x22,0x67,0x17,0xea,0x95,0x2f,0x51,0x4f,0x57,0x67,0x58,0x21,0xa5,0x2e,0x68,0x47,0x9d,
+ 0x04,0x20,0x8b,0xfc,0xf6,0xec,0x3b,0x71,0x25,0x88,0xe8,0xc8,0x72,0xc3,0x89,0x05,0x27,0x81,0x28,0x6b,0xb6,0x72,0xa7,0xc5,0x16,0xaa,0x67,0xe6,0x37,0xb7,0x2b,0x99,0xa8,0x97,0x47,0x9d,
+ 0x04,0x20,0xa2,0x46,0x23,0xd2,0xdb,0x3e,0x7a,0x65,0x05,0xd4,0x45,0x78,0xff,0x3e,0xc1,0x28,0xdb,0xfa,0xf1,0x5e,0x32,0xe9,0x6a,0x8f,0x96,0x45,0x15,0x01,0x7f,0x1f,0x75,0xbf,0x47,0x9d,
+ 0x04,0x20,0xa8,0xa6,0xbb,0x02,0x06,0x65,0x3b,0xb2,0x52,0x79,0xd1,0xc9,0x6a,0x01,0x42,0x43,0xca,0x69,0xe1,0x69,0x90,0xfe,0x2c,0xd2,0x7c,0x18,0xfd,0xab,0xc7,0x71,0x7f,0x8b,0x47,0x9d,
+ 0x04,0x20,0xa9,0x7b,0x48,0xf7,0x73,0xcb,0x07,0x37,0x4e,0xaa,0x68,0xc4,0x67,0x08,0xea,0x5b,0x68,0x0a,0xfe,0x14,0x82,0x6a,0xa1,0x79,0x82,0x9c,0x0b,0x52,0x17,0xd6,0x6b,0x1b,0x47,0x9d,
+ 0x04,0x20,0xb3,0x6e,0x64,0x99,0x26,0x7a,0xeb,0xd4,0x53,0x8c,0x94,0xb1,0x4a,0x37,0x02,0xaa,0xa9,0xc8,0x36,0x11,0xec,0xf9,0x0f,0x08,0xa3,0x9f,0x3e,0xaf,0xd2,0xd1,0x2a,0x0b,0x47,0x9d,
+ 0x04,0x20,0xb3,0xd4,0x15,0x0e,0x3f,0x12,0xed,0xfc,0xab,0x69,0x55,0x91,0x45,0xcf,0xc1,0x2f,0x35,0xa4,0xf7,0x94,0xff,0xd8,0xbe,0x44,0xc8,0x36,0xaf,0x0f,0xa0,0x4e,0x36,0x22,0x47,0x9d,
+ 0x04,0x20,0xb6,0x5e,0x39,0xeb,0x93,0x18,0x22,0xad,0x78,0x94,0x34,0x48,0x31,0x8d,0xd1,0x42,0xb7,0x38,0x58,0x49,0xea,0x00,0xb9,0xcf,0x58,0x43,0x38,0x22,0x22,0x88,0x87,0xde,0x47,0x9d,
+ 0x04,0x20,0xb9,0x80,0xf6,0xa1,0x4a,0x0a,0xc6,0xe3,0x19,0x27,0xe9,0x2d,0x75,0x60,0x14,0x3d,0x2c,0xda,0x97,0x77,0x54,0x9f,0x78,0xb8,0x9b,0x72,0x6a,0x58,0xab,0x8b,0x95,0x95,0x47,0x9d,
+ 0x04,0x20,0xba,0xab,0x91,0x9c,0x48,0x8b,0x9b,0x34,0x5c,0x30,0xf3,0xd2,0x78,0xd3,0xbf,0x09,0x79,0x23,0x4e,0x18,0x5d,0x5e,0x75,0x6b,0xa2,0x91,0x63,0x2c,0x75,0xfd,0x06,0x36,0x47,0x9d,
+ 0x04,0x20,0xbb,0x50,0xf0,0x50,0x8d,0xb7,0x6c,0xd4,0x87,0x59,0x0d,0xfd,0x5f,0x51,0x86,0xa8,0x43,0xb3,0x7a,0xe7,0x2f,0x54,0x97,0x7d,0xed,0xc3,0x7b,0x31,0xe6,0xb9,0x05,0xe7,0x47,0x9d,
+ 0x04,0x20,0xc0,0xc1,0xf5,0x59,0xe8,0x46,0xf6,0x9d,0x41,0xf0,0xde,0x8b,0x32,0xf9,0x6f,0xd6,0xb2,0xd5,0x36,0x56,0x43,0xd3,0x60,0x08,0x55,0x94,0x13,0xf5,0xef,0x7f,0x4d,0x4a,0x47,0x9d,
+ 0x04,0x20,0xce,0xd3,0xd2,0xba,0x56,0xa1,0xde,0xc9,0xc4,0xdb,0x50,0x7b,0xe9,0x4d,0x59,0x65,0x1c,0x02,0x4a,0xa3,0xea,0x73,0xb2,0x66,0x70,0xe7,0x85,0xc1,0x20,0x60,0x79,0x96,0x47,0x9d,
+ 0x04,0x20,0xc8,0x88,0xfe,0x71,0x5f,0xa3,0x6c,0x96,0x6a,0xd7,0x9e,0x38,0x84,0x9f,0x44,0xe1,0x6b,0xdc,0x98,0x31,0xad,0x96,0x29,0xe7,0x00,0x83,0x63,0x03,0xae,0x69,0x2e,0x63,0x47,0x9d,
+ 0x04,0x20,0xcb,0x2a,0x8c,0xe7,0xe5,0x1f,0x4e,0x3a,0x13,0xd6,0x9e,0xd7,0x68,0x51,0x83,0xf4,0x2d,0x3e,0x21,0x38,0x63,0x18,0xe9,0x97,0x27,0xff,0x45,0x48,0xc3,0x6c,0xca,0x59,0x47,0x9d,
+ 0x04,0x20,0xcb,0x80,0x0d,0xdf,0xf0,0xa6,0x28,0x84,0x98,0xc8,0x47,0x72,0xbe,0x53,0x04,0x43,0x9c,0x3a,0x0e,0x46,0x9c,0x75,0x4c,0x57,0x50,0x98,0xe5,0x25,0x80,0x5d,0xa2,0x91,0x47,0x9d,
+ 0x04,0x20,0xcb,0xaa,0x0a,0x5d,0x6e,0x8a,0xfa,0x49,0x5a,0x8c,0x0c,0x9d,0x7a,0xe9,0x9d,0xc6,0xe4,0xcd,0xc1,0x6a,0xff,0xbb,0xf1,0x89,0xf1,0xd5,0x16,0x3f,0xdc,0xbb,0xe9,0x1b,0x47,0x9d,
};
#endif // BITCOIN_CHAINPARAMSSEEDS_H
diff --git a/src/consensus/validation.h b/src/consensus/validation.h
index 6027bb9aeb..9c0aa09356 100644
--- a/src/consensus/validation.h
+++ b/src/consensus/validation.h
@@ -79,6 +79,7 @@ enum class BlockValidationResult {
BLOCK_INVALID_PREV, //!< A block this one builds on is invalid
BLOCK_TIME_FUTURE, //!< block timestamp was > 2 hours in the future (or our clock is bad)
BLOCK_CHECKPOINT, //!< the block failed to meet one of our checkpoints
+ BLOCK_HEADER_LOW_WORK //!< the block header may be on a too-little-work chain
};
diff --git a/src/fs.cpp b/src/fs.cpp
index 74b167e313..07cce269ed 100644
--- a/src/fs.cpp
+++ b/src/fs.cpp
@@ -126,7 +126,7 @@ bool FileLock::TryLock()
if (hFile == INVALID_HANDLE_VALUE) {
return false;
}
- _OVERLAPPED overlapped = {0};
+ _OVERLAPPED overlapped = {};
if (!LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY, 0, std::numeric_limits<DWORD>::max(), std::numeric_limits<DWORD>::max(), &overlapped)) {
reason = GetErrorReason();
return false;
diff --git a/src/hash.cpp b/src/hash.cpp
index 111b707964..06caaac6ee 100644
--- a/src/hash.cpp
+++ b/src/hash.cpp
@@ -16,7 +16,7 @@ inline uint32_t ROTL32(uint32_t x, int8_t r)
unsigned int MurmurHash3(unsigned int nHashSeed, Span<const unsigned char> vDataToHash)
{
- // The following is MurmurHash3 (x86_32), see https://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp
+ // The following is MurmurHash3 (x86_32), see https://github.com/aappleby/smhasher/blob/master/src/MurmurHash3.cpp
uint32_t h1 = nHashSeed;
const uint32_t c1 = 0xcc9e2d51;
const uint32_t c2 = 0x1b873593;
diff --git a/src/headerssync.cpp b/src/headerssync.cpp
new file mode 100644
index 0000000000..757b942cd9
--- /dev/null
+++ b/src/headerssync.cpp
@@ -0,0 +1,317 @@
+// Copyright (c) 2022 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 <headerssync.h>
+#include <logging.h>
+#include <pow.h>
+#include <timedata.h>
+#include <util/check.h>
+
+// The two constants below are computed using the simulation script on
+// https://gist.github.com/sipa/016ae445c132cdf65a2791534dfb7ae1
+
+//! Store a commitment to a header every HEADER_COMMITMENT_PERIOD blocks.
+constexpr size_t HEADER_COMMITMENT_PERIOD{584};
+
+//! Only feed headers to validation once this many headers on top have been
+//! received and validated against commitments.
+constexpr size_t REDOWNLOAD_BUFFER_SIZE{13959}; // 13959/584 = ~23.9 commitments
+
+// Our memory analysis assumes 48 bytes for a CompressedHeader (so we should
+// re-calculate parameters if we compress further)
+static_assert(sizeof(CompressedHeader) == 48);
+
+HeadersSyncState::HeadersSyncState(NodeId id, const Consensus::Params& consensus_params,
+ const CBlockIndex* chain_start, const arith_uint256& minimum_required_work) :
+ m_id(id), m_consensus_params(consensus_params),
+ m_chain_start(chain_start),
+ m_minimum_required_work(minimum_required_work),
+ m_current_chain_work(chain_start->nChainWork),
+ m_commit_offset(GetRand<unsigned>(HEADER_COMMITMENT_PERIOD)),
+ m_last_header_received(m_chain_start->GetBlockHeader()),
+ m_current_height(chain_start->nHeight)
+{
+ // Estimate the number of blocks that could possibly exist on the peer's
+ // chain *right now* using 6 blocks/second (fastest blockrate given the MTP
+ // rule) times the number of seconds from the last allowed block until
+ // today. This serves as a memory bound on how many commitments we might
+ // store from this peer, and we can safely give up syncing if the peer
+ // exceeds this bound, because it's not possible for a consensus-valid
+ // chain to be longer than this (at the current time -- in the future we
+ // could try again, if necessary, to sync a longer chain).
+ m_max_commitments = 6*(Ticks<std::chrono::seconds>(GetAdjustedTime() - NodeSeconds{std::chrono::seconds{chain_start->GetMedianTimePast()}}) + MAX_FUTURE_BLOCK_TIME) / HEADER_COMMITMENT_PERIOD;
+
+ LogPrint(BCLog::NET, "Initial headers sync started with peer=%d: height=%i, max_commitments=%i, min_work=%s\n", m_id, m_current_height, m_max_commitments, m_minimum_required_work.ToString());
+}
+
+/** Free any memory in use, and mark this object as no longer usable. This is
+ * required to guarantee that we won't reuse this object with the same
+ * SaltedTxidHasher for another sync. */
+void HeadersSyncState::Finalize()
+{
+ Assume(m_download_state != State::FINAL);
+ m_header_commitments = {};
+ m_last_header_received.SetNull();
+ m_redownloaded_headers = {};
+ m_redownload_buffer_last_hash.SetNull();
+ m_redownload_buffer_first_prev_hash.SetNull();
+ m_process_all_remaining_headers = false;
+ m_current_height = 0;
+
+ m_download_state = State::FINAL;
+}
+
+/** Process the next batch of headers received from our peer.
+ * Validate and store commitments, and compare total chainwork to our target to
+ * see if we can switch to REDOWNLOAD mode. */
+HeadersSyncState::ProcessingResult HeadersSyncState::ProcessNextHeaders(const
+ std::vector<CBlockHeader>& received_headers, const bool full_headers_message)
+{
+ ProcessingResult ret;
+
+ Assume(!received_headers.empty());
+ if (received_headers.empty()) return ret;
+
+ Assume(m_download_state != State::FINAL);
+ if (m_download_state == State::FINAL) return ret;
+
+ if (m_download_state == State::PRESYNC) {
+ // During PRESYNC, we minimally validate block headers and
+ // occasionally add commitments to them, until we reach our work
+ // threshold (at which point m_download_state is updated to REDOWNLOAD).
+ ret.success = ValidateAndStoreHeadersCommitments(received_headers);
+ if (ret.success) {
+ if (full_headers_message || m_download_state == State::REDOWNLOAD) {
+ // A full headers message means the peer may have more to give us;
+ // also if we just switched to REDOWNLOAD then we need to re-request
+ // headers from the beginning.
+ ret.request_more = true;
+ } else {
+ Assume(m_download_state == State::PRESYNC);
+ // If we're in PRESYNC and we get a non-full headers
+ // message, then the peer's chain has ended and definitely doesn't
+ // have enough work, so we can stop our sync.
+ LogPrint(BCLog::NET, "Initial headers sync aborted with peer=%d: incomplete headers message at height=%i (presync phase)\n", m_id, m_current_height);
+ }
+ }
+ } else if (m_download_state == State::REDOWNLOAD) {
+ // During REDOWNLOAD, we compare our stored commitments to what we
+ // receive, and add headers to our redownload buffer. When the buffer
+ // gets big enough (meaning that we've checked enough commitments),
+ // we'll return a batch of headers to the caller for processing.
+ ret.success = true;
+ for (const auto& hdr : received_headers) {
+ if (!ValidateAndStoreRedownloadedHeader(hdr)) {
+ // Something went wrong -- the peer gave us an unexpected chain.
+ // We could consider looking at the reason for failure and
+ // punishing the peer, but for now just give up on sync.
+ ret.success = false;
+ break;
+ }
+ }
+
+ if (ret.success) {
+ // Return any headers that are ready for acceptance.
+ ret.pow_validated_headers = PopHeadersReadyForAcceptance();
+
+ // If we hit our target blockhash, then all remaining headers will be
+ // returned and we can clear any leftover internal state.
+ if (m_redownloaded_headers.empty() && m_process_all_remaining_headers) {
+ LogPrint(BCLog::NET, "Initial headers sync complete with peer=%d: releasing all at height=%i (redownload phase)\n", m_id, m_redownload_buffer_last_height);
+ } else if (full_headers_message) {
+ // If the headers message is full, we need to request more.
+ ret.request_more = true;
+ } else {
+ // For some reason our peer gave us a high-work chain, but is now
+ // declining to serve us that full chain again. Give up.
+ // Note that there's no more processing to be done with these
+ // headers, so we can still return success.
+ LogPrint(BCLog::NET, "Initial headers sync aborted with peer=%d: incomplete headers message at height=%i (redownload phase)\n", m_id, m_redownload_buffer_last_height);
+ }
+ }
+ }
+
+ if (!(ret.success && ret.request_more)) Finalize();
+ return ret;
+}
+
+bool HeadersSyncState::ValidateAndStoreHeadersCommitments(const std::vector<CBlockHeader>& headers)
+{
+ // The caller should not give us an empty set of headers.
+ Assume(headers.size() > 0);
+ if (headers.size() == 0) return true;
+
+ Assume(m_download_state == State::PRESYNC);
+ if (m_download_state != State::PRESYNC) return false;
+
+ if (headers[0].hashPrevBlock != m_last_header_received.GetHash()) {
+ // Somehow our peer gave us a header that doesn't connect.
+ // This might be benign -- perhaps our peer reorged away from the chain
+ // they were on. Give up on this sync for now (likely we will start a
+ // new sync with a new starting point).
+ LogPrint(BCLog::NET, "Initial headers sync aborted with peer=%d: non-continuous headers at height=%i (presync phase)\n", m_id, m_current_height);
+ return false;
+ }
+
+ // If it does connect, (minimally) validate and occasionally store
+ // commitments.
+ for (const auto& hdr : headers) {
+ if (!ValidateAndProcessSingleHeader(hdr)) {
+ return false;
+ }
+ }
+
+ if (m_current_chain_work >= m_minimum_required_work) {
+ m_redownloaded_headers.clear();
+ m_redownload_buffer_last_height = m_chain_start->nHeight;
+ m_redownload_buffer_first_prev_hash = m_chain_start->GetBlockHash();
+ m_redownload_buffer_last_hash = m_chain_start->GetBlockHash();
+ m_redownload_chain_work = m_chain_start->nChainWork;
+ m_download_state = State::REDOWNLOAD;
+ LogPrint(BCLog::NET, "Initial headers sync transition with peer=%d: reached sufficient work at height=%i, redownloading from height=%i\n", m_id, m_current_height, m_redownload_buffer_last_height);
+ }
+ return true;
+}
+
+bool HeadersSyncState::ValidateAndProcessSingleHeader(const CBlockHeader& current)
+{
+ Assume(m_download_state == State::PRESYNC);
+ if (m_download_state != State::PRESYNC) return false;
+
+ int next_height = m_current_height + 1;
+
+ // Verify that the difficulty isn't growing too fast; an adversary with
+ // limited hashing capability has a greater chance of producing a high
+ // work chain if they compress the work into as few blocks as possible,
+ // so don't let anyone give a chain that would violate the difficulty
+ // adjustment maximum.
+ if (!PermittedDifficultyTransition(m_consensus_params, next_height,
+ m_last_header_received.nBits, current.nBits)) {
+ LogPrint(BCLog::NET, "Initial headers sync aborted with peer=%d: invalid difficulty transition at height=%i (presync phase)\n", m_id, next_height);
+ return false;
+ }
+
+ if (next_height % HEADER_COMMITMENT_PERIOD == m_commit_offset) {
+ // Add a commitment.
+ m_header_commitments.push_back(m_hasher(current.GetHash()) & 1);
+ if (m_header_commitments.size() > m_max_commitments) {
+ // The peer's chain is too long; give up.
+ // It's possible the chain grew since we started the sync; so
+ // potentially we could succeed in syncing the peer's chain if we
+ // try again later.
+ LogPrint(BCLog::NET, "Initial headers sync aborted with peer=%d: exceeded max commitments at height=%i (presync phase)\n", m_id, next_height);
+ return false;
+ }
+ }
+
+ m_current_chain_work += GetBlockProof(CBlockIndex(current));
+ m_last_header_received = current;
+ m_current_height = next_height;
+
+ return true;
+}
+
+bool HeadersSyncState::ValidateAndStoreRedownloadedHeader(const CBlockHeader& header)
+{
+ Assume(m_download_state == State::REDOWNLOAD);
+ if (m_download_state != State::REDOWNLOAD) return false;
+
+ int64_t next_height = m_redownload_buffer_last_height + 1;
+
+ // Ensure that we're working on a header that connects to the chain we're
+ // downloading.
+ if (header.hashPrevBlock != m_redownload_buffer_last_hash) {
+ LogPrint(BCLog::NET, "Initial headers sync aborted with peer=%d: non-continuous headers at height=%i (redownload phase)\n", m_id, next_height);
+ return false;
+ }
+
+ // Check that the difficulty adjustments are within our tolerance:
+ uint32_t previous_nBits{0};
+ if (!m_redownloaded_headers.empty()) {
+ previous_nBits = m_redownloaded_headers.back().nBits;
+ } else {
+ previous_nBits = m_chain_start->nBits;
+ }
+
+ if (!PermittedDifficultyTransition(m_consensus_params, next_height,
+ previous_nBits, header.nBits)) {
+ LogPrint(BCLog::NET, "Initial headers sync aborted with peer=%d: invalid difficulty transition at height=%i (redownload phase)\n", m_id, next_height);
+ return false;
+ }
+
+ // Track work on the redownloaded chain
+ m_redownload_chain_work += GetBlockProof(CBlockIndex(header));
+
+ if (m_redownload_chain_work >= m_minimum_required_work) {
+ m_process_all_remaining_headers = true;
+ }
+
+ // If we're at a header for which we previously stored a commitment, verify
+ // it is correct. Failure will result in aborting download.
+ // Also, don't check commitments once we've gotten to our target blockhash;
+ // it's possible our peer has extended its chain between our first sync and
+ // our second, and we don't want to return failure after we've seen our
+ // target blockhash just because we ran out of commitments.
+ if (!m_process_all_remaining_headers && next_height % HEADER_COMMITMENT_PERIOD == m_commit_offset) {
+ if (m_header_commitments.size() == 0) {
+ LogPrint(BCLog::NET, "Initial headers sync aborted with peer=%d: commitment overrun at height=%i (redownload phase)\n", m_id, next_height);
+ // Somehow our peer managed to feed us a different chain and
+ // we've run out of commitments.
+ return false;
+ }
+ bool commitment = m_hasher(header.GetHash()) & 1;
+ bool expected_commitment = m_header_commitments.front();
+ m_header_commitments.pop_front();
+ if (commitment != expected_commitment) {
+ LogPrint(BCLog::NET, "Initial headers sync aborted with peer=%d: commitment mismatch at height=%i (redownload phase)\n", m_id, next_height);
+ return false;
+ }
+ }
+
+ // Store this header for later processing.
+ m_redownloaded_headers.push_back(header);
+ m_redownload_buffer_last_height = next_height;
+ m_redownload_buffer_last_hash = header.GetHash();
+
+ return true;
+}
+
+std::vector<CBlockHeader> HeadersSyncState::PopHeadersReadyForAcceptance()
+{
+ std::vector<CBlockHeader> ret;
+
+ Assume(m_download_state == State::REDOWNLOAD);
+ if (m_download_state != State::REDOWNLOAD) return ret;
+
+ while (m_redownloaded_headers.size() > REDOWNLOAD_BUFFER_SIZE ||
+ (m_redownloaded_headers.size() > 0 && m_process_all_remaining_headers)) {
+ ret.emplace_back(m_redownloaded_headers.front().GetFullHeader(m_redownload_buffer_first_prev_hash));
+ m_redownloaded_headers.pop_front();
+ m_redownload_buffer_first_prev_hash = ret.back().GetHash();
+ }
+ return ret;
+}
+
+CBlockLocator HeadersSyncState::NextHeadersRequestLocator() const
+{
+ Assume(m_download_state != State::FINAL);
+ if (m_download_state == State::FINAL) return {};
+
+ auto chain_start_locator = LocatorEntries(m_chain_start);
+ std::vector<uint256> locator;
+
+ if (m_download_state == State::PRESYNC) {
+ // During pre-synchronization, we continue from the last header received.
+ locator.push_back(m_last_header_received.GetHash());
+ }
+
+ if (m_download_state == State::REDOWNLOAD) {
+ // During redownload, we will download from the last received header that we stored.
+ locator.push_back(m_redownload_buffer_last_hash);
+ }
+
+ locator.insert(locator.end(), chain_start_locator.begin(), chain_start_locator.end());
+
+ return CBlockLocator{std::move(locator)};
+}
diff --git a/src/headerssync.h b/src/headerssync.h
new file mode 100644
index 0000000000..16da964246
--- /dev/null
+++ b/src/headerssync.h
@@ -0,0 +1,277 @@
+// Copyright (c) 2022 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_HEADERSSYNC_H
+#define BITCOIN_HEADERSSYNC_H
+
+#include <arith_uint256.h>
+#include <chain.h>
+#include <consensus/params.h>
+#include <net.h> // For NodeId
+#include <primitives/block.h>
+#include <uint256.h>
+#include <util/bitdeque.h>
+#include <util/hasher.h>
+
+#include <deque>
+#include <vector>
+
+// A compressed CBlockHeader, which leaves out the prevhash
+struct CompressedHeader {
+ // header
+ int32_t nVersion{0};
+ uint256 hashMerkleRoot;
+ uint32_t nTime{0};
+ uint32_t nBits{0};
+ uint32_t nNonce{0};
+
+ CompressedHeader()
+ {
+ hashMerkleRoot.SetNull();
+ }
+
+ CompressedHeader(const CBlockHeader& header)
+ {
+ nVersion = header.nVersion;
+ hashMerkleRoot = header.hashMerkleRoot;
+ nTime = header.nTime;
+ nBits = header.nBits;
+ nNonce = header.nNonce;
+ }
+
+ CBlockHeader GetFullHeader(const uint256& hash_prev_block) {
+ CBlockHeader ret;
+ ret.nVersion = nVersion;
+ ret.hashPrevBlock = hash_prev_block;
+ ret.hashMerkleRoot = hashMerkleRoot;
+ ret.nTime = nTime;
+ ret.nBits = nBits;
+ ret.nNonce = nNonce;
+ return ret;
+ };
+};
+
+/** HeadersSyncState:
+ *
+ * We wish to download a peer's headers chain in a DoS-resistant way.
+ *
+ * The Bitcoin protocol does not offer an easy way to determine the work on a
+ * peer's chain. Currently, we can query a peer's headers by using a GETHEADERS
+ * message, and our peer can return a set of up to 2000 headers that connect to
+ * something we know. If a peer's chain has more than 2000 blocks, then we need
+ * a way to verify that the chain actually has enough work on it to be useful to
+ * us -- by being above our anti-DoS minimum-chain-work threshold -- before we
+ * commit to storing those headers in memory. Otherwise, it would be cheap for
+ * an attacker to waste all our memory by serving us low-work headers
+ * (particularly for a new node coming online for the first time).
+ *
+ * To prevent memory-DoS with low-work headers, while still always being
+ * able to reorg to whatever the most-work chain is, we require that a chain
+ * meet a work threshold before committing it to memory. We can do this by
+ * downloading a peer's headers twice, whenever we are not sure that the chain
+ * has sufficient work:
+ *
+ * - In the first download phase, called pre-synchronization, we can calculate
+ * the work on the chain as we go (just by checking the nBits value on each
+ * header, and validating the proof-of-work).
+ *
+ * - Once we have reached a header where the cumulative chain work is
+ * sufficient, we switch to downloading the headers a second time, this time
+ * processing them fully, and possibly storing them in memory.
+ *
+ * To prevent an attacker from using (eg) the honest chain to convince us that
+ * they have a high-work chain, but then feeding us an alternate set of
+ * low-difficulty headers in the second phase, we store commitments to the
+ * chain we see in the first download phase that we check in the second phase,
+ * as follows:
+ *
+ * - In phase 1 (presync), store 1 bit (using a salted hash function) for every
+ * N headers that we see. With a reasonable choice of N, this uses relatively
+ * little memory even for a very long chain.
+ *
+ * - In phase 2 (redownload), keep a lookahead buffer and only accept headers
+ * from that buffer into the block index (permanent memory usage) once they
+ * have some target number of verified commitments on top of them. With this
+ * parametrization, we can achieve a given security target for potential
+ * permanent memory usage, while choosing N to minimize memory use during the
+ * sync (temporary, per-peer storage).
+ */
+
+class HeadersSyncState {
+public:
+ ~HeadersSyncState() {}
+
+ enum class State {
+ /** PRESYNC means the peer has not yet demonstrated their chain has
+ * sufficient work and we're only building commitments to the chain they
+ * serve us. */
+ PRESYNC,
+ /** REDOWNLOAD means the peer has given us a high-enough-work chain,
+ * and now we're redownloading the headers we saw before and trying to
+ * accept them */
+ REDOWNLOAD,
+ /** We're done syncing with this peer and can discard any remaining state */
+ FINAL
+ };
+
+ /** Return the current state of our download */
+ State GetState() const { return m_download_state; }
+
+ /** Return the height reached during the PRESYNC phase */
+ int64_t GetPresyncHeight() const { return m_current_height; }
+
+ /** Return the block timestamp of the last header received during the PRESYNC phase. */
+ uint32_t GetPresyncTime() const { return m_last_header_received.nTime; }
+
+ /** Return the amount of work in the chain received during the PRESYNC phase. */
+ arith_uint256 GetPresyncWork() const { return m_current_chain_work; }
+
+ /** Construct a HeadersSyncState object representing a headers sync via this
+ * download-twice mechanism).
+ *
+ * id: node id (for logging)
+ * consensus_params: parameters needed for difficulty adjustment validation
+ * chain_start: best known fork point that the peer's headers branch from
+ * minimum_required_work: amount of chain work required to accept the chain
+ */
+ HeadersSyncState(NodeId id, const Consensus::Params& consensus_params,
+ const CBlockIndex* chain_start, const arith_uint256& minimum_required_work);
+
+ /** Result data structure for ProcessNextHeaders. */
+ struct ProcessingResult {
+ std::vector<CBlockHeader> pow_validated_headers;
+ bool success{false};
+ bool request_more{false};
+ };
+
+ /** Process a batch of headers, once a sync via this mechanism has started
+ *
+ * received_headers: headers that were received over the network for processing.
+ * Assumes the caller has already verified the headers
+ * are continuous, and has checked that each header
+ * satisfies the proof-of-work target included in the
+ * header (but not necessarily verified that the
+ * proof-of-work target is correct and passes consensus
+ * rules).
+ * full_headers_message: true if the message was at max capacity,
+ * indicating more headers may be available
+ * ProcessingResult.pow_validated_headers: will be filled in with any
+ * headers that the caller can fully process and
+ * validate now (because these returned headers are
+ * on a chain with sufficient work)
+ * ProcessingResult.success: set to false if an error is detected and the sync is
+ * aborted; true otherwise.
+ * ProcessingResult.request_more: if true, the caller is suggested to call
+ * NextHeadersRequestLocator and send a getheaders message using it.
+ */
+ ProcessingResult ProcessNextHeaders(const std::vector<CBlockHeader>&
+ received_headers, bool full_headers_message);
+
+ /** Issue the next GETHEADERS message to our peer.
+ *
+ * This will return a locator appropriate for the current sync object, to continue the
+ * synchronization phase it is in.
+ */
+ CBlockLocator NextHeadersRequestLocator() const;
+
+private:
+ /** Clear out all download state that might be in progress (freeing any used
+ * memory), and mark this object as no longer usable.
+ */
+ void Finalize();
+
+ /**
+ * Only called in PRESYNC.
+ * Validate the work on the headers we received from the network, and
+ * store commitments for later. Update overall state with successfully
+ * processed headers.
+ * On failure, this invokes Finalize() and returns false.
+ */
+ bool ValidateAndStoreHeadersCommitments(const std::vector<CBlockHeader>& headers);
+
+ /** In PRESYNC, process and update state for a single header */
+ bool ValidateAndProcessSingleHeader(const CBlockHeader& current);
+
+ /** In REDOWNLOAD, check a header's commitment (if applicable) and add to
+ * buffer for later processing */
+ bool ValidateAndStoreRedownloadedHeader(const CBlockHeader& header);
+
+ /** Return a set of headers that satisfy our proof-of-work threshold */
+ std::vector<CBlockHeader> PopHeadersReadyForAcceptance();
+
+private:
+ /** NodeId of the peer (used for log messages) **/
+ const NodeId m_id;
+
+ /** We use the consensus params in our anti-DoS calculations */
+ const Consensus::Params& m_consensus_params;
+
+ /** Store the last block in our block index that the peer's chain builds from */
+ const CBlockIndex* m_chain_start{nullptr};
+
+ /** Minimum work that we're looking for on this chain. */
+ const arith_uint256 m_minimum_required_work;
+
+ /** Work that we've seen so far on the peer's chain */
+ arith_uint256 m_current_chain_work;
+
+ /** m_hasher is a salted hasher for making our 1-bit commitments to headers we've seen. */
+ const SaltedTxidHasher m_hasher;
+
+ /** A queue of commitment bits, created during the 1st phase, and verified during the 2nd. */
+ bitdeque<> m_header_commitments;
+
+ /** The (secret) offset on the heights for which to create commitments.
+ *
+ * m_header_commitments entries are created at any height h for which
+ * (h % HEADER_COMMITMENT_PERIOD) == m_commit_offset. */
+ const unsigned m_commit_offset;
+
+ /** m_max_commitments is a bound we calculate on how long an honest peer's chain could be,
+ * given the MTP rule.
+ *
+ * Any peer giving us more headers than this will have its sync aborted. This serves as a
+ * memory bound on m_header_commitments. */
+ uint64_t m_max_commitments{0};
+
+ /** Store the latest header received while in PRESYNC (initialized to m_chain_start) */
+ CBlockHeader m_last_header_received;
+
+ /** Height of m_last_header_received */
+ int64_t m_current_height{0};
+
+ /** During phase 2 (REDOWNLOAD), we buffer redownloaded headers in memory
+ * until enough commitments have been verified; those are stored in
+ * m_redownloaded_headers */
+ std::deque<CompressedHeader> m_redownloaded_headers;
+
+ /** Height of last header in m_redownloaded_headers */
+ int64_t m_redownload_buffer_last_height{0};
+
+ /** Hash of last header in m_redownloaded_headers (initialized to
+ * m_chain_start). We have to cache it because we don't have hashPrevBlock
+ * available in a CompressedHeader.
+ */
+ uint256 m_redownload_buffer_last_hash;
+
+ /** The hashPrevBlock entry for the first header in m_redownloaded_headers
+ * We need this to reconstruct the full header when it's time for
+ * processing.
+ */
+ uint256 m_redownload_buffer_first_prev_hash;
+
+ /** The accumulated work on the redownloaded chain. */
+ arith_uint256 m_redownload_chain_work;
+
+ /** Set this to true once we encounter the target blockheader during phase
+ * 2 (REDOWNLOAD). At this point, we can process and store all remaining
+ * headers still in m_redownloaded_headers.
+ */
+ bool m_process_all_remaining_headers{false};
+
+ /** Current state of our headers sync. */
+ State m_download_state{State::PRESYNC};
+};
+
+#endif // BITCOIN_HEADERSSYNC_H
diff --git a/src/httpserver.cpp b/src/httpserver.cpp
index 8e00a6278f..e68436cc2c 100644
--- a/src/httpserver.cpp
+++ b/src/httpserver.cpp
@@ -142,7 +142,8 @@ static std::vector<CSubNet> rpc_allow_subnets;
//! Work queue for handling longer requests off the event loop thread
static std::unique_ptr<WorkQueue<HTTPClosure>> g_work_queue{nullptr};
//! Handlers for (sub)paths
-static std::vector<HTTPPathHandler> pathHandlers;
+static GlobalMutex g_httppathhandlers_mutex;
+static std::vector<HTTPPathHandler> pathHandlers GUARDED_BY(g_httppathhandlers_mutex);
//! Bound listening sockets
static std::vector<evhttp_bound_socket *> boundSockets;
@@ -243,6 +244,7 @@ static void http_request_cb(struct evhttp_request* req, void* arg)
// Find registered handler for prefix
std::string strURI = hreq->GetURI();
std::string path;
+ LOCK(g_httppathhandlers_mutex);
std::vector<HTTPPathHandler>::const_iterator i = pathHandlers.begin();
std::vector<HTTPPathHandler>::const_iterator iend = pathHandlers.end();
for (; i != iend; ++i) {
@@ -674,11 +676,13 @@ std::optional<std::string> GetQueryParameterFromUri(const char* uri, const std::
void RegisterHTTPHandler(const std::string &prefix, bool exactMatch, const HTTPRequestHandler &handler)
{
LogPrint(BCLog::HTTP, "Registering HTTP handler for %s (exactmatch %d)\n", prefix, exactMatch);
+ LOCK(g_httppathhandlers_mutex);
pathHandlers.push_back(HTTPPathHandler(prefix, exactMatch, handler));
}
void UnregisterHTTPHandler(const std::string &prefix, bool exactMatch)
{
+ LOCK(g_httppathhandlers_mutex);
std::vector<HTTPPathHandler>::iterator i = pathHandlers.begin();
std::vector<HTTPPathHandler>::iterator iend = pathHandlers.end();
for (; i != iend; ++i)
diff --git a/src/i2p.cpp b/src/i2p.cpp
index c45bcc15d2..28be8009dc 100644
--- a/src/i2p.cpp
+++ b/src/i2p.cpp
@@ -12,11 +12,11 @@
#include <netaddress.h>
#include <netbase.h>
#include <random.h>
-#include <util/strencodings.h>
#include <tinyformat.h>
#include <util/readwritefile.h>
#include <util/sock.h>
#include <util/spanparsing.h>
+#include <util/strencodings.h>
#include <util/system.h>
#include <chrono>
@@ -115,8 +115,19 @@ namespace sam {
Session::Session(const fs::path& private_key_file,
const CService& control_host,
CThreadInterrupt* interrupt)
- : m_private_key_file(private_key_file), m_control_host(control_host), m_interrupt(interrupt),
- m_control_sock(std::make_unique<Sock>(INVALID_SOCKET))
+ : m_private_key_file{private_key_file},
+ m_control_host{control_host},
+ m_interrupt{interrupt},
+ m_control_sock{std::make_unique<Sock>(INVALID_SOCKET)},
+ m_transient{false}
+{
+}
+
+Session::Session(const CService& control_host, CThreadInterrupt* interrupt)
+ : m_control_host{control_host},
+ m_interrupt{interrupt},
+ m_control_sock{std::make_unique<Sock>(INVALID_SOCKET)},
+ m_transient{true}
{
}
@@ -314,6 +325,7 @@ void Session::DestGenerate(const Sock& sock)
// https://geti2p.net/spec/common-structures#key-certificates
// "7" or "EdDSA_SHA512_Ed25519" - "Recent Router Identities and Destinations".
// Use "7" because i2pd <2.24.0 does not recognize the textual form.
+ // If SIGNATURE_TYPE is not specified, then the default one is DSA_SHA1.
const Reply& reply = SendRequestAndGetReply(sock, "DEST GENERATE SIGNATURE_TYPE=7", false);
m_private_key = DecodeI2PBase64(reply.Get("PRIV"));
@@ -355,29 +367,47 @@ void Session::CreateIfNotCreatedAlready()
return;
}
- Log("Creating SAM session with %s", m_control_host.ToString());
+ const auto session_type = m_transient ? "transient" : "persistent";
+ const auto session_id = GetRandHash().GetHex().substr(0, 10); // full is overkill, too verbose in the logs
+
+ Log("Creating %s SAM session %s with %s", session_type, session_id, m_control_host.ToString());
auto sock = Hello();
- const auto& [read_ok, data] = ReadBinaryFile(m_private_key_file);
- if (read_ok) {
- m_private_key.assign(data.begin(), data.end());
+ if (m_transient) {
+ // The destination (private key) is generated upon session creation and returned
+ // in the reply in DESTINATION=.
+ const Reply& reply = SendRequestAndGetReply(
+ *sock,
+ strprintf("SESSION CREATE STYLE=STREAM ID=%s DESTINATION=TRANSIENT SIGNATURE_TYPE=7", session_id));
+
+ m_private_key = DecodeI2PBase64(reply.Get("DESTINATION"));
} else {
- GenerateAndSavePrivateKey(*sock);
- }
+ // Read our persistent destination (private key) from disk or generate
+ // one and save it to disk. Then use it when creating the session.
+ const auto& [read_ok, data] = ReadBinaryFile(m_private_key_file);
+ if (read_ok) {
+ m_private_key.assign(data.begin(), data.end());
+ } else {
+ GenerateAndSavePrivateKey(*sock);
+ }
- const std::string& session_id = GetRandHash().GetHex().substr(0, 10); // full is an overkill, too verbose in the logs
- const std::string& private_key_b64 = SwapBase64(EncodeBase64(m_private_key));
+ const std::string& private_key_b64 = SwapBase64(EncodeBase64(m_private_key));
- SendRequestAndGetReply(*sock, strprintf("SESSION CREATE STYLE=STREAM ID=%s DESTINATION=%s",
- session_id, private_key_b64));
+ SendRequestAndGetReply(*sock,
+ strprintf("SESSION CREATE STYLE=STREAM ID=%s DESTINATION=%s",
+ session_id,
+ private_key_b64));
+ }
m_my_addr = CService(DestBinToAddr(MyDestination()), I2P_SAM31_PORT);
m_session_id = session_id;
m_control_sock = std::move(sock);
- LogPrintfCategory(BCLog::I2P, "SAM session created: session id=%s, my address=%s\n",
- m_session_id, m_my_addr.ToString());
+ Log("%s SAM session %s created, my address=%s",
+ Capitalize(session_type),
+ m_session_id,
+ m_my_addr.ToString());
}
std::unique_ptr<Sock> Session::StreamAccept()
@@ -405,9 +435,9 @@ void Session::Disconnect()
{
if (m_control_sock->Get() != INVALID_SOCKET) {
if (m_session_id.empty()) {
- Log("Destroying incomplete session");
+ Log("Destroying incomplete SAM session");
} else {
- Log("Destroying session %s", m_session_id);
+ Log("Destroying SAM session %s", m_session_id);
}
}
m_control_sock = std::make_unique<Sock>(INVALID_SOCKET);
diff --git a/src/i2p.h b/src/i2p.h
index eb0a10103d..ebbcb437da 100644
--- a/src/i2p.h
+++ b/src/i2p.h
@@ -71,6 +71,19 @@ public:
CThreadInterrupt* interrupt);
/**
+ * Construct a transient session which will generate its own I2P private key
+ * rather than read the one from disk (it will not be saved on disk either and
+ * will be lost once this object is destroyed). This will not initiate any IO,
+ * the session will be lazily created later when first used.
+ * @param[in] control_host Location of the SAM proxy.
+ * @param[in,out] interrupt If this is signaled then all operations are canceled as soon as
+ * possible and executing methods throw an exception. Notice: only a pointer to the
+ * `CThreadInterrupt` object is saved, so it must not be destroyed earlier than this
+ * `Session` object.
+ */
+ Session(const CService& control_host, CThreadInterrupt* interrupt);
+
+ /**
* Destroy the session, closing the internally used sockets. The sockets that have been
* returned by `Accept()` or `Connect()` will not be closed, but they will be closed by
* the SAM proxy because the session is destroyed. So they will return an error next time
@@ -262,6 +275,12 @@ private:
* SAM session id.
*/
std::string m_session_id GUARDED_BY(m_mutex);
+
+ /**
+ * Whether this is a transient session (the I2P private key will not be
+ * read or written to disk).
+ */
+ const bool m_transient;
};
} // namespace sam
diff --git a/src/index/base.cpp b/src/index/base.cpp
index 1ebe89ef7c..88c2ce98fa 100644
--- a/src/index/base.cpp
+++ b/src/index/base.cpp
@@ -18,6 +18,9 @@
#include <validation.h> // For g_chainman
#include <warnings.h>
+#include <string>
+#include <utility>
+
using node::ReadBlockFromDisk;
constexpr uint8_t DB_BEST_BLOCK{'B'};
@@ -62,8 +65,8 @@ void BaseIndex::DB::WriteBestBlock(CDBBatch& batch, const CBlockLocator& locator
batch.Write(DB_BEST_BLOCK, locator);
}
-BaseIndex::BaseIndex(std::unique_ptr<interfaces::Chain> chain)
- : m_chain{std::move(chain)} {}
+BaseIndex::BaseIndex(std::unique_ptr<interfaces::Chain> chain, std::string name)
+ : m_chain{std::move(chain)}, m_name{std::move(name)} {}
BaseIndex::~BaseIndex()
{
diff --git a/src/index/base.h b/src/index/base.h
index 5a484377e7..349178a535 100644
--- a/src/index/base.h
+++ b/src/index/base.h
@@ -10,9 +10,11 @@
#include <threadinterrupt.h>
#include <validationinterface.h>
+#include <string>
+
class CBlock;
class CBlockIndex;
-class CChainState;
+class Chainstate;
namespace interfaces {
class Chain;
} // namespace interfaces
@@ -94,7 +96,8 @@ private:
protected:
std::unique_ptr<interfaces::Chain> m_chain;
- CChainState* m_chainstate{nullptr};
+ Chainstate* m_chainstate{nullptr};
+ const std::string m_name;
void BlockConnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* pindex) override;
@@ -117,13 +120,13 @@ protected:
virtual DB& GetDB() const = 0;
/// Get the name of the index for display in logs.
- virtual const char* GetName() const = 0;
+ const std::string& GetName() const LIFETIMEBOUND { return m_name; }
/// Update the internal best block index as well as the prune lock.
void SetBestBlockIndex(const CBlockIndex* block);
public:
- BaseIndex(std::unique_ptr<interfaces::Chain> chain);
+ BaseIndex(std::unique_ptr<interfaces::Chain> chain, std::string name);
/// Destructor interrupts sync thread if running and blocks until it exits.
virtual ~BaseIndex();
diff --git a/src/index/blockfilterindex.cpp b/src/index/blockfilterindex.cpp
index f4837f3456..292e11c874 100644
--- a/src/index/blockfilterindex.cpp
+++ b/src/index/blockfilterindex.cpp
@@ -97,7 +97,8 @@ static std::map<BlockFilterType, BlockFilterIndex> g_filter_indexes;
BlockFilterIndex::BlockFilterIndex(std::unique_ptr<interfaces::Chain> chain, BlockFilterType filter_type,
size_t n_cache_size, bool f_memory, bool f_wipe)
- : BaseIndex(std::move(chain)), m_filter_type(filter_type)
+ : BaseIndex(std::move(chain), BlockFilterTypeName(filter_type) + " block filter index")
+ , m_filter_type(filter_type)
{
const std::string& filter_name = BlockFilterTypeName(filter_type);
if (filter_name.empty()) throw std::invalid_argument("unknown filter_type");
@@ -105,7 +106,6 @@ BlockFilterIndex::BlockFilterIndex(std::unique_ptr<interfaces::Chain> chain, Blo
fs::path path = gArgs.GetDataDirNet() / "indexes" / "blockfilter" / fs::u8path(filter_name);
fs::create_directories(path);
- m_name = filter_name + " block filter index";
m_db = std::make_unique<BaseIndex::DB>(path / "db", n_cache_size, f_memory, f_wipe);
m_filter_fileseq = std::make_unique<FlatFileSeq>(std::move(path), "fltr", FLTR_FILE_CHUNK_SIZE);
}
diff --git a/src/index/blockfilterindex.h b/src/index/blockfilterindex.h
index 968eccb6b3..5af4671091 100644
--- a/src/index/blockfilterindex.h
+++ b/src/index/blockfilterindex.h
@@ -5,6 +5,7 @@
#ifndef BITCOIN_INDEX_BLOCKFILTERINDEX_H
#define BITCOIN_INDEX_BLOCKFILTERINDEX_H
+#include <attributes.h>
#include <blockfilter.h>
#include <chain.h>
#include <flatfile.h>
@@ -25,7 +26,6 @@ class BlockFilterIndex final : public BaseIndex
{
private:
BlockFilterType m_filter_type;
- std::string m_name;
std::unique_ptr<BaseIndex::DB> m_db;
FlatFilePos m_next_filter_pos;
@@ -49,9 +49,7 @@ protected:
bool CustomRewind(const interfaces::BlockKey& current_tip, const interfaces::BlockKey& new_tip) override;
- BaseIndex::DB& GetDB() const override { return *m_db; }
-
- const char* GetName() const override { return m_name.c_str(); }
+ BaseIndex::DB& GetDB() const LIFETIMEBOUND override { return *m_db; }
public:
/** Constructs the index, which becomes available to be queried. */
diff --git a/src/index/coinstatsindex.cpp b/src/index/coinstatsindex.cpp
index b9029e946a..d3559b1b75 100644
--- a/src/index/coinstatsindex.cpp
+++ b/src/index/coinstatsindex.cpp
@@ -6,6 +6,7 @@
#include <coins.h>
#include <crypto/muhash.h>
#include <index/coinstatsindex.h>
+#include <kernel/coinstats.h>
#include <node/blockstorage.h>
#include <serialize.h>
#include <txdb.h>
@@ -104,7 +105,7 @@ struct DBHashKey {
std::unique_ptr<CoinStatsIndex> g_coin_stats_index;
CoinStatsIndex::CoinStatsIndex(std::unique_ptr<interfaces::Chain> chain, size_t n_cache_size, bool f_memory, bool f_wipe)
- : BaseIndex(std::move(chain))
+ : BaseIndex(std::move(chain), "coinstatsindex")
{
fs::path path{gArgs.GetDataDirNet() / "indexes" / "coinstats"};
fs::create_directories(path);
@@ -322,13 +323,13 @@ static bool LookUpOne(const CDBWrapper& db, const interfaces::BlockKey& block, D
return db.Read(DBHashKey(block.hash), result);
}
-std::optional<CCoinsStats> CoinStatsIndex::LookUpStats(const CBlockIndex* block_index) const
+std::optional<CCoinsStats> CoinStatsIndex::LookUpStats(const CBlockIndex& block_index) const
{
- CCoinsStats stats{Assert(block_index)->nHeight, block_index->GetBlockHash()};
+ CCoinsStats stats{block_index.nHeight, block_index.GetBlockHash()};
stats.index_used = true;
DBVal entry;
- if (!LookUpOne(*m_db, {block_index->GetBlockHash(), block_index->nHeight}, entry)) {
+ if (!LookUpOne(*m_db, {block_index.GetBlockHash(), block_index.nHeight}, entry)) {
return std::nullopt;
}
diff --git a/src/index/coinstatsindex.h b/src/index/coinstatsindex.h
index c4af223388..fa59cb1ab1 100644
--- a/src/index/coinstatsindex.h
+++ b/src/index/coinstatsindex.h
@@ -5,11 +5,14 @@
#ifndef BITCOIN_INDEX_COINSTATSINDEX_H
#define BITCOIN_INDEX_COINSTATSINDEX_H
-#include <chain.h>
#include <crypto/muhash.h>
-#include <flatfile.h>
#include <index/base.h>
-#include <kernel/coinstats.h>
+
+class CBlockIndex;
+class CDBBatch;
+namespace kernel {
+struct CCoinsStats;
+}
/**
* CoinStatsIndex maintains statistics on the UTXO set.
@@ -17,7 +20,6 @@
class CoinStatsIndex final : public BaseIndex
{
private:
- std::string m_name;
std::unique_ptr<BaseIndex::DB> m_db;
MuHash3072 m_muhash;
@@ -49,14 +51,12 @@ protected:
BaseIndex::DB& GetDB() const override { return *m_db; }
- const char* GetName() const override { return "coinstatsindex"; }
-
public:
// Constructs the index, which becomes available to be queried.
explicit CoinStatsIndex(std::unique_ptr<interfaces::Chain> chain, size_t n_cache_size, bool f_memory = false, bool f_wipe = false);
// Look up stats for a specific block using CBlockIndex
- std::optional<kernel::CCoinsStats> LookUpStats(const CBlockIndex* block_index) const;
+ std::optional<kernel::CCoinsStats> LookUpStats(const CBlockIndex& block_index) const;
};
/// The global UTXO set hash object.
diff --git a/src/index/txindex.cpp b/src/index/txindex.cpp
index b719aface8..a4fe1b611e 100644
--- a/src/index/txindex.cpp
+++ b/src/index/txindex.cpp
@@ -49,7 +49,7 @@ bool TxIndex::DB::WriteTxs(const std::vector<std::pair<uint256, CDiskTxPos>>& v_
}
TxIndex::TxIndex(std::unique_ptr<interfaces::Chain> chain, size_t n_cache_size, bool f_memory, bool f_wipe)
- : BaseIndex(std::move(chain)), m_db(std::make_unique<TxIndex::DB>(n_cache_size, f_memory, f_wipe))
+ : BaseIndex(std::move(chain), "txindex"), m_db(std::make_unique<TxIndex::DB>(n_cache_size, f_memory, f_wipe))
{}
TxIndex::~TxIndex() = default;
diff --git a/src/index/txindex.h b/src/index/txindex.h
index be240c4582..8c1aa00033 100644
--- a/src/index/txindex.h
+++ b/src/index/txindex.h
@@ -27,8 +27,6 @@ protected:
BaseIndex::DB& GetDB() const override;
- const char* GetName() const override { return "txindex"; }
-
public:
/// Constructs the index, which becomes available to be queried.
explicit TxIndex(std::unique_ptr<interfaces::Chain> chain, size_t n_cache_size, bool f_memory = false, bool f_wipe = false);
diff --git a/src/init.cpp b/src/init.cpp
index 137d98026e..20cb483a3a 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -263,7 +263,7 @@ void Shutdown(NodeContext& node)
// FlushStateToDisk generates a ChainStateFlushed callback, which we should avoid missing
if (node.chainman) {
LOCK(cs_main);
- for (CChainState* chainstate : node.chainman->GetAll()) {
+ for (Chainstate* chainstate : node.chainman->GetAll()) {
if (chainstate->CanFlushToDisk()) {
chainstate->ForceFlushStateToDisk();
}
@@ -294,7 +294,7 @@ void Shutdown(NodeContext& node)
if (node.chainman) {
LOCK(cs_main);
- for (CChainState* chainstate : node.chainman->GetAll()) {
+ for (Chainstate* chainstate : node.chainman->GetAll()) {
if (chainstate->CanFlushToDisk()) {
chainstate->ForceFlushStateToDisk();
chainstate->ResetCoinsViews();
@@ -723,6 +723,16 @@ void InitParameterInteraction(ArgsManager& args)
if (args.SoftSetBoolArg("-whitelistrelay", true))
LogPrintf("%s: parameter interaction: -whitelistforcerelay=1 -> setting -whitelistrelay=1\n", __func__);
}
+ if (args.IsArgSet("-onlynet")) {
+ const auto onlynets = args.GetArgs("-onlynet");
+ bool clearnet_reachable = std::any_of(onlynets.begin(), onlynets.end(), [](const auto& net) {
+ const auto n = ParseNetwork(net);
+ return n == NET_IPV4 || n == NET_IPV6;
+ });
+ if (!clearnet_reachable && args.SoftSetBoolArg("-dnsseed", false)) {
+ LogPrintf("%s: parameter interaction: -onlynet excludes IPv4 and IPv6 -> setting -dnsseed=0\n", __func__);
+ }
+ }
}
/**
@@ -742,7 +752,7 @@ namespace { // Variables internal to initialization process only
int nMaxConnections;
int nUserMaxConnections;
int nFD;
-ServiceFlags nLocalServices = ServiceFlags(NODE_NETWORK | NODE_NETWORK_LIMITED | NODE_WITNESS);
+ServiceFlags nLocalServices = ServiceFlags(NODE_NETWORK_LIMITED | NODE_WITNESS);
int64_t peer_connect_timeout;
std::set<BlockFilterType> g_enabled_filter_types;
@@ -915,15 +925,12 @@ bool AppInitParameterInteraction(const ArgsManager& args, bool use_syscall_sandb
// ********************************************************* Step 3: parameter-to-internal-flags
init::SetLoggingCategories(args);
+ init::SetLoggingLevel(args);
fCheckBlockIndex = args.GetBoolArg("-checkblockindex", chainparams.DefaultConsistencyChecks());
fCheckpointsEnabled = args.GetBoolArg("-checkpoints", DEFAULT_CHECKPOINTS_ENABLED);
hashAssumeValid = uint256S(args.GetArg("-assumevalid", chainparams.GetConsensus().defaultAssumeValid.GetHex()));
- if (!hashAssumeValid.IsNull())
- LogPrintf("Assuming ancestors of block %s have valid signatures.\n", hashAssumeValid.GetHex());
- else
- LogPrintf("Validating signatures for all blocks.\n");
if (args.IsArgSet("-minimumchainwork")) {
const std::string minChainWorkStr = args.GetArg("-minimumchainwork", "");
@@ -934,10 +941,6 @@ bool AppInitParameterInteraction(const ArgsManager& args, bool use_syscall_sandb
} else {
nMinimumChainWork = UintToArith256(chainparams.GetConsensus().nMinimumChainWork);
}
- LogPrintf("Setting nMinimumChainWork=%s\n", nMinimumChainWork.GetHex());
- if (nMinimumChainWork < UintToArith256(chainparams.GetConsensus().nMinimumChainWork)) {
- LogPrintf("Warning: nMinimumChainWork set below default value of %s\n", chainparams.GetConsensus().nMinimumChainWork.GetHex());
- }
// block pruning; get the amount of disk space (in MiB) to allot for block & undo files
int64_t nPruneArg = args.GetIntArg("-prune", 0);
@@ -946,14 +949,12 @@ bool AppInitParameterInteraction(const ArgsManager& args, bool use_syscall_sandb
}
nPruneTarget = (uint64_t) nPruneArg * 1024 * 1024;
if (nPruneArg == 1) { // manual pruning: -prune=1
- LogPrintf("Block pruning enabled. Use RPC call pruneblockchain(height) to manually prune block and undo files.\n");
nPruneTarget = std::numeric_limits<uint64_t>::max();
fPruneMode = true;
} else if (nPruneTarget) {
if (nPruneTarget < MIN_DISK_SPACE_FOR_BLOCK_FILES) {
return InitError(strprintf(_("Prune configured below the minimum of %d MiB. Please use a higher number."), MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024));
}
- LogPrintf("Prune configured to target %u MiB on disk for block and undo files.\n", nPruneTarget / 1024 / 1024);
fPruneMode = true;
}
@@ -1290,6 +1291,13 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
// 2.1. -onlynet is not given or
// 2.2. -onlynet=cjdns is given
+ // Requesting DNS seeds entails connecting to IPv4/IPv6, which -onlynet options may prohibit:
+ // If -dnsseed=1 is explicitly specified, abort. If it's left unspecified by the user, we skip
+ // the DNS seeds by adjusting -dnsseed in InitParameterInteraction.
+ if (args.GetBoolArg("-dnsseed") == true && !IsReachable(NET_IPV4) && !IsReachable(NET_IPV6)) {
+ return InitError(strprintf(_("Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6")));
+ };
+
// Check for host lookup allowed before parsing any network related parameters
fNameLookup = args.GetBoolArg("-dns", DEFAULT_NAME_LOOKUP);
@@ -1316,6 +1324,8 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
onion_proxy = addrProxy;
}
+ const bool onlynet_used_with_onion{args.IsArgSet("-onlynet") && IsReachable(NET_ONION)};
+
// -onion can be used to set only a proxy for .onion, or override normal proxy for .onion addresses
// -noonion (or -onion=0) disables connecting to .onion entirely
// An empty string is used to not override the onion proxy (in which case it defaults to -proxy set above, or none)
@@ -1323,6 +1333,11 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
if (onionArg != "") {
if (onionArg == "0") { // Handle -noonion/-onion=0
onion_proxy = Proxy{};
+ if (onlynet_used_with_onion) {
+ return InitError(
+ _("Outbound connections restricted to Tor (-onlynet=onion) but the proxy for "
+ "reaching the Tor network is explicitly forbidden: -onion=0"));
+ }
} else {
CService addr;
if (!Lookup(onionArg, addr, 9050, fNameLookup) || !addr.IsValid()) {
@@ -1335,11 +1350,14 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
if (onion_proxy.IsValid()) {
SetProxy(NET_ONION, onion_proxy);
} else {
- if (args.IsArgSet("-onlynet") && IsReachable(NET_ONION)) {
+ // If -listenonion is set, then we will (try to) connect to the Tor control port
+ // later from the torcontrol thread and may retrieve the onion proxy from there.
+ const bool listenonion_disabled{!args.GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION)};
+ if (onlynet_used_with_onion && listenonion_disabled) {
return InitError(
_("Outbound connections restricted to Tor (-onlynet=onion) but the proxy for "
- "reaching the Tor network is not provided (no -proxy= and no -onion= given) or "
- "it is explicitly forbidden (-onion=0)"));
+ "reaching the Tor network is not provided: none of -proxy, -onion or "
+ "-listenonion is given"));
}
SetReachable(NET_ONION, false);
}
@@ -1422,7 +1440,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
};
uiInterface.InitMessage(_("Loading block index…").translated);
- const int64_t load_block_index_start_time = GetTimeMillis();
+ const auto load_block_index_start_time{SteadyClock::now()};
auto catch_exceptions = [](auto&& f) {
try {
return f();
@@ -1441,7 +1459,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
std::tie(status, error) = catch_exceptions([&]{ return VerifyLoadedChainstate(chainman, options);});
if (status == node::ChainstateLoadStatus::SUCCESS) {
fLoaded = true;
- LogPrintf(" block index %15dms\n", GetTimeMillis() - load_block_index_start_time);
+ LogPrintf(" block index %15dms\n", Ticks<std::chrono::milliseconds>(SteadyClock::now() - load_block_index_start_time));
}
}
@@ -1519,18 +1537,19 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
// ********************************************************* Step 10: data directory maintenance
- // if pruning, unset the service bit and perform the initial blockstore prune
+ // if pruning, perform the initial blockstore prune
// after any wallet rescanning has taken place.
if (fPruneMode) {
- LogPrintf("Unsetting NODE_NETWORK on prune mode\n");
- nLocalServices = ServiceFlags(nLocalServices & ~NODE_NETWORK);
if (!fReindex) {
LOCK(cs_main);
- for (CChainState* chainstate : chainman.GetAll()) {
+ for (Chainstate* chainstate : chainman.GetAll()) {
uiInterface.InitMessage(_("Pruning blockstore…").translated);
chainstate->PruneAndFlush();
}
}
+ } else {
+ LogPrintf("Setting NODE_NETWORK on non-prune mode\n");
+ nLocalServices = ServiceFlags(nLocalServices | NODE_NETWORK);
}
// ********************************************************* Step 11: import blocks
diff --git a/src/init/common.cpp b/src/init/common.cpp
index bdd7f16307..f2d2c5640a 100644
--- a/src/init/common.cpp
+++ b/src/init/common.cpp
@@ -11,6 +11,7 @@
#include <logging.h>
#include <node/interface_ui.h>
#include <tinyformat.h>
+#include <util/string.h>
#include <util/system.h>
#include <util/time.h>
#include <util/translation.h>
@@ -23,11 +24,12 @@ namespace init {
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.",
+ argsman.AddArg("-debug=<category>", "Output debug and trace logging (default: -nodebug, supplying <category> is optional). "
+ "If <category> is not supplied or if <category> = 1, output all debug and trace logging. <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>", "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("-debugexclude=<category>", "Exclude debug and trace logging for a category. Can be used in conjunction with -debug=1 to output debug and trace logging 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("-loglevel=<level>|<category>:<level>", strprintf("Set the global or per-category severity level for logging categories enabled with the -debug configuration option or the logging RPC: %s (default=%s); warning and error levels are always logged. If <category>:<level> is supplied, the setting will override the global one and may be specified multiple times to set multiple category-specific levels. <category> can be: %s.", LogInstance().LogLevelsString(), LogInstance().LogLevelToStr(BCLog::DEFAULT_LOG_LEVEL), LogInstance().LogCategoriesString()), ArgsManager::DISALLOW_NEGATION | ArgsManager::DISALLOW_ELISION | ArgsManager::DEBUG_ONLY, 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);
@@ -55,6 +57,26 @@ void SetLoggingOptions(const ArgsManager& args)
fLogIPs = args.GetBoolArg("-logips", DEFAULT_LOGIPS);
}
+void SetLoggingLevel(const ArgsManager& args)
+{
+ if (args.IsArgSet("-loglevel")) {
+ for (const std::string& level_str : args.GetArgs("-loglevel")) {
+ if (level_str.find_first_of(':', 3) == std::string::npos) {
+ // user passed a global log level, i.e. -loglevel=<level>
+ if (!LogInstance().SetLogLevel(level_str)) {
+ InitWarning(strprintf(_("Unsupported global logging level -loglevel=%s. Valid values: %s."), level_str, LogInstance().LogLevelsString()));
+ }
+ } else {
+ // user passed a category-specific log level, i.e. -loglevel=<category>:<level>
+ const auto& toks = SplitString(level_str, ':');
+ if (!(toks.size() == 2 && LogInstance().SetCategoryLogLevel(toks[0], toks[1]))) {
+ InitWarning(strprintf(_("Unsupported category-specific logging level -loglevel=%s. Expected -loglevel=<category>:<loglevel>. Valid categories: %s. Valid loglevels: %s."), level_str, LogInstance().LogCategoriesString(), LogInstance().LogLevelsString()));
+ }
+ }
+ }
+ }
+}
+
void SetLoggingCategories(const ArgsManager& args)
{
if (args.IsArgSet("-debug")) {
diff --git a/src/init/common.h b/src/init/common.h
index 2c7f485908..53c860c297 100644
--- a/src/init/common.h
+++ b/src/init/common.h
@@ -14,6 +14,7 @@ namespace init {
void AddLoggingArgs(ArgsManager& args);
void SetLoggingOptions(const ArgsManager& args);
void SetLoggingCategories(const ArgsManager& args);
+void SetLoggingLevel(const ArgsManager& args);
bool StartLogging(const ArgsManager& args);
void LogPackageVersion();
} // namespace init
diff --git a/src/interfaces/node.h b/src/interfaces/node.h
index 2c31e12ada..dbdb21eb91 100644
--- a/src/interfaces/node.h
+++ b/src/interfaces/node.h
@@ -260,7 +260,7 @@ public:
//! Register handler for header tip messages.
using NotifyHeaderTipFn =
- std::function<void(SynchronizationState, interfaces::BlockTip tip, double verification_progress)>;
+ std::function<void(SynchronizationState, interfaces::BlockTip tip, bool presync)>;
virtual std::unique_ptr<Handler> handleNotifyHeaderTip(NotifyHeaderTipFn fn) = 0;
//! Get and set internal node context. Useful for testing, but not
diff --git a/src/kernel/mempool_persist.cpp b/src/kernel/mempool_persist.cpp
index 1a1cf2bbdc..a14b2e6163 100644
--- a/src/kernel/mempool_persist.cpp
+++ b/src/kernel/mempool_persist.cpp
@@ -37,7 +37,7 @@ namespace kernel {
static const uint64_t MEMPOOL_DUMP_VERSION = 1;
-bool LoadMempool(CTxMemPool& pool, const fs::path& load_path, CChainState& active_chainstate, FopenFn mockable_fopen_function)
+bool LoadMempool(CTxMemPool& pool, const fs::path& load_path, Chainstate& active_chainstate, FopenFn mockable_fopen_function)
{
if (load_path.empty()) return false;
diff --git a/src/kernel/mempool_persist.h b/src/kernel/mempool_persist.h
index 9a15ec6dca..ca4917e38b 100644
--- a/src/kernel/mempool_persist.h
+++ b/src/kernel/mempool_persist.h
@@ -7,7 +7,7 @@
#include <fs.h>
-class CChainState;
+class Chainstate;
class CTxMemPool;
namespace kernel {
@@ -19,7 +19,7 @@ bool DumpMempool(const CTxMemPool& pool, const fs::path& dump_path,
/** Load the mempool from disk. */
bool LoadMempool(CTxMemPool& pool, const fs::path& load_path,
- CChainState& active_chainstate,
+ Chainstate& active_chainstate,
fsbridge::FopenFn mockable_fopen_function = fsbridge::fopen);
} // namespace kernel
diff --git a/src/logging.cpp b/src/logging.cpp
index 73c4e458bd..a3f1d39be5 100644
--- a/src/logging.cpp
+++ b/src/logging.cpp
@@ -5,15 +5,17 @@
#include <fs.h>
#include <logging.h>
-#include <util/threadnames.h>
#include <util/string.h>
+#include <util/threadnames.h>
#include <util/time.h>
#include <algorithm>
#include <array>
#include <mutex>
+#include <optional>
const char * const DEFAULT_DEBUGLOGFILE = "debug.log";
+constexpr auto MAX_USER_SETABLE_SEVERITY_LEVEL{BCLog::Level::Info};
BCLog::Logger& LogInstance()
{
@@ -122,6 +124,19 @@ bool BCLog::Logger::WillLogCategory(BCLog::LogFlags category) const
return (m_categories.load(std::memory_order_relaxed) & category) != 0;
}
+bool BCLog::Logger::WillLogCategoryLevel(BCLog::LogFlags category, BCLog::Level level) const
+{
+ // Log messages at Warning and Error level unconditionally, so that
+ // important troubleshooting information doesn't get lost.
+ if (level >= BCLog::Level::Warning) return true;
+
+ if (!WillLogCategory(category)) return false;
+
+ StdLockGuard scoped_lock(m_cs);
+ const auto it{m_category_log_levels.find(category)};
+ return level >= (it == m_category_log_levels.end() ? LogLevel() : it->second);
+}
+
bool BCLog::Logger::DefaultShrinkDebugFile() const
{
return m_categories == BCLog::NONE;
@@ -135,7 +150,7 @@ struct CLogCategoryDesc {
const CLogCategoryDesc LogCategories[] =
{
{BCLog::NONE, "0"},
- {BCLog::NONE, "none"},
+ {BCLog::NONE, ""},
{BCLog::NET, "net"},
{BCLog::TOR, "tor"},
{BCLog::MEMPOOL, "mempool"},
@@ -184,11 +199,11 @@ bool GetLogCategory(BCLog::LogFlags& flag, const std::string& str)
return false;
}
-std::string LogLevelToStr(BCLog::Level level)
+std::string BCLog::Logger::LogLevelToStr(BCLog::Level level) const
{
switch (level) {
- case BCLog::Level::None:
- return "none";
+ case BCLog::Level::Trace:
+ return "trace";
case BCLog::Level::Debug:
return "debug";
case BCLog::Level::Info:
@@ -197,6 +212,8 @@ std::string LogLevelToStr(BCLog::Level level)
return "warning";
case BCLog::Level::Error:
return "error";
+ case BCLog::Level::None:
+ return "";
}
assert(false);
}
@@ -206,7 +223,7 @@ std::string LogCategoryToStr(BCLog::LogFlags category)
// Each log category string representation should sync with LogCategories
switch (category) {
case BCLog::LogFlags::NONE:
- return "none";
+ return "";
case BCLog::LogFlags::NET:
return "net";
case BCLog::LogFlags::TOR:
@@ -269,6 +286,25 @@ std::string LogCategoryToStr(BCLog::LogFlags category)
assert(false);
}
+static std::optional<BCLog::Level> GetLogLevel(const std::string& level_str)
+{
+ if (level_str == "trace") {
+ return BCLog::Level::Trace;
+ } else if (level_str == "debug") {
+ return BCLog::Level::Debug;
+ } else if (level_str == "info") {
+ return BCLog::Level::Info;
+ } else if (level_str == "warning") {
+ return BCLog::Level::Warning;
+ } else if (level_str == "error") {
+ return BCLog::Level::Error;
+ } else if (level_str == "none") {
+ return BCLog::Level::None;
+ } else {
+ return std::nullopt;
+ }
+}
+
std::vector<LogCategory> BCLog::Logger::LogCategoriesList() const
{
// Sort log categories by alphabetical order.
@@ -287,6 +323,18 @@ std::vector<LogCategory> BCLog::Logger::LogCategoriesList() const
return ret;
}
+/** Log severity levels that can be selected by the user. */
+static constexpr std::array<BCLog::Level, 3> LogLevelsList()
+{
+ return {BCLog::Level::Info, BCLog::Level::Debug, BCLog::Level::Trace};
+}
+
+std::string BCLog::Logger::LogLevelsString() const
+{
+ const auto& levels = LogLevelsList();
+ return Join(std::vector<BCLog::Level>{levels.begin(), levels.end()}, ", ", [this](BCLog::Level level) { return LogLevelToStr(level); });
+}
+
std::string BCLog::Logger::LogTimestampStr(const std::string& str)
{
std::string strStamped;
@@ -334,7 +382,7 @@ namespace BCLog {
}
} // namespace BCLog
-void BCLog::Logger::LogPrintStr(const std::string& str, const std::string& logging_function, const std::string& source_file, const int source_line, const BCLog::LogFlags category, const BCLog::Level level)
+void BCLog::Logger::LogPrintStr(const std::string& str, const std::string& logging_function, const std::string& source_file, int source_line, BCLog::LogFlags category, BCLog::Level level)
{
StdLockGuard scoped_lock(m_cs);
std::string str_prefixed = LogEscapeMessage(str);
@@ -443,3 +491,24 @@ void BCLog::Logger::ShrinkDebugFile()
else if (file != nullptr)
fclose(file);
}
+
+bool BCLog::Logger::SetLogLevel(const std::string& level_str)
+{
+ const auto level = GetLogLevel(level_str);
+ if (!level.has_value() || level.value() > MAX_USER_SETABLE_SEVERITY_LEVEL) return false;
+ m_log_level = level.value();
+ return true;
+}
+
+bool BCLog::Logger::SetCategoryLogLevel(const std::string& category_str, const std::string& level_str)
+{
+ BCLog::LogFlags flag;
+ if (!GetLogCategory(flag, category_str)) return false;
+
+ const auto level = GetLogLevel(level_str);
+ if (!level.has_value() || level.value() > MAX_USER_SETABLE_SEVERITY_LEVEL) return false;
+
+ StdLockGuard scoped_lock(m_cs);
+ m_category_log_levels[flag] = level.value();
+ return true;
+}
diff --git a/src/logging.h b/src/logging.h
index 50869ad89a..fe91ee43a5 100644
--- a/src/logging.h
+++ b/src/logging.h
@@ -7,8 +7,8 @@
#define BITCOIN_LOGGING_H
#include <fs.h>
-#include <tinyformat.h>
#include <threadsafety.h>
+#include <tinyformat.h>
#include <util/string.h>
#include <atomic>
@@ -17,6 +17,7 @@
#include <list>
#include <mutex>
#include <string>
+#include <unordered_map>
#include <vector>
static const bool DEFAULT_LOGTIMEMICROS = false;
@@ -68,12 +69,14 @@ namespace BCLog {
ALL = ~(uint32_t)0,
};
enum class Level {
- Debug = 0,
- None = 1,
- Info = 2,
- Warning = 3,
- Error = 4,
+ Trace = 0, // High-volume or detailed logging for development/debugging
+ Debug, // Reasonably noisy logging, but still usable in production
+ Info, // Default
+ Warning,
+ Error,
+ None, // Internal use only
};
+ constexpr auto DEFAULT_LOG_LEVEL{Level::Debug};
class Logger
{
@@ -91,6 +94,13 @@ namespace BCLog {
*/
std::atomic_bool m_started_new_line{true};
+ //! Category-specific log level. Overrides `m_log_level`.
+ std::unordered_map<LogFlags, Level> m_category_log_levels GUARDED_BY(m_cs);
+
+ //! If there is no category-specific log level, all logs with a severity
+ //! level lower than `m_log_level` will be ignored.
+ std::atomic<Level> m_log_level{DEFAULT_LOG_LEVEL};
+
/** Log categories bitfield. */
std::atomic<uint32_t> m_categories{0};
@@ -112,7 +122,7 @@ namespace BCLog {
std::atomic<bool> m_reopen_file{false};
/** Send a string to the log output */
- void LogPrintStr(const std::string& str, const std::string& logging_function, const std::string& source_file, const int source_line, const BCLog::LogFlags category, const BCLog::Level level);
+ void LogPrintStr(const std::string& str, const std::string& logging_function, const std::string& source_file, int source_line, BCLog::LogFlags category, BCLog::Level level);
/** Returns whether logs will be written to any output */
bool Enabled() const
@@ -143,6 +153,22 @@ namespace BCLog {
void ShrinkDebugFile();
+ std::unordered_map<LogFlags, Level> CategoryLevels() const
+ {
+ StdLockGuard scoped_lock(m_cs);
+ return m_category_log_levels;
+ }
+ void SetCategoryLogLevel(const std::unordered_map<LogFlags, Level>& levels)
+ {
+ StdLockGuard scoped_lock(m_cs);
+ m_category_log_levels = levels;
+ }
+ bool SetCategoryLogLevel(const std::string& category_str, const std::string& level_str);
+
+ Level LogLevel() const { return m_log_level.load(); }
+ void SetLogLevel(Level level) { m_log_level = level; }
+ bool SetLogLevel(const std::string& level);
+
uint32_t GetCategoryMask() const { return m_categories.load(); }
void EnableCategory(LogFlags flag);
@@ -151,6 +177,8 @@ namespace BCLog {
bool DisableCategory(const std::string& str);
bool WillLogCategory(LogFlags category) const;
+ bool WillLogCategoryLevel(LogFlags category, Level level) const;
+
/** Returns a vector of the log categories in alphabetical order. */
std::vector<LogCategory> LogCategoriesList() const;
/** Returns a string with the log categories in alphabetical order. */
@@ -159,6 +187,12 @@ namespace BCLog {
return Join(LogCategoriesList(), ", ", [&](const LogCategory& i) { return i.category; });
};
+ //! Returns a string with all user-selectable log levels.
+ std::string LogLevelsString() const;
+
+ //! Returns the string representation of a log level.
+ std::string LogLevelToStr(BCLog::Level level) const;
+
bool DefaultShrinkDebugFile() const;
};
@@ -169,12 +203,7 @@ BCLog::Logger& LogInstance();
/** Return true if log accepts specified category, at the specified level. */
static inline bool LogAcceptCategory(BCLog::LogFlags category, BCLog::Level level)
{
- // Log messages at Warning and Error level unconditionally, so that
- // important troubleshooting information doesn't get lost.
- if (level >= BCLog::Level::Warning) {
- return true;
- }
- return LogInstance().WillLogCategory(category);
+ return LogInstance().WillLogCategoryLevel(category, level);
}
/** Return true if str parses as a log category and set the flag */
diff --git a/src/net.cpp b/src/net.cpp
index 865ce2ea97..0cc14b1d2a 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -484,18 +484,27 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
Proxy proxy;
CAddress addr_bind;
assert(!addr_bind.IsValid());
+ std::unique_ptr<i2p::sam::Session> i2p_transient_session;
if (addrConnect.IsValid()) {
+ const bool use_proxy{GetProxy(addrConnect.GetNetwork(), proxy)};
bool proxyConnectionFailed = false;
- if (addrConnect.GetNetwork() == NET_I2P && m_i2p_sam_session.get() != nullptr) {
+ if (addrConnect.GetNetwork() == NET_I2P && use_proxy) {
i2p::Connection conn;
- if (m_i2p_sam_session->Connect(addrConnect, conn, proxyConnectionFailed)) {
- connected = true;
+
+ if (m_i2p_sam_session) {
+ connected = m_i2p_sam_session->Connect(addrConnect, conn, proxyConnectionFailed);
+ } else {
+ i2p_transient_session = std::make_unique<i2p::sam::Session>(proxy.proxy, &interruptNet);
+ connected = i2p_transient_session->Connect(addrConnect, conn, proxyConnectionFailed);
+ }
+
+ if (connected) {
sock = std::move(conn.sock);
addr_bind = CAddress{conn.me, NODE_NONE};
}
- } else if (GetProxy(addrConnect.GetNetwork(), proxy)) {
+ } else if (use_proxy) {
sock = CreateSock(proxy.proxy);
if (!sock) {
return nullptr;
@@ -546,7 +555,8 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
addr_bind,
pszDest ? pszDest : "",
conn_type,
- /*inbound_onion=*/false);
+ /*inbound_onion=*/false,
+ CNodeOptions{ .i2p_sam_session = std::move(i2p_transient_session) });
pnode->AddRef();
// We're making a new connection, harvest entropy from the time (and our peer count)
@@ -563,6 +573,7 @@ void CNode::CloseSocketDisconnect()
LogPrint(BCLog::NET, "disconnecting peer=%d\n", id);
m_sock.reset();
}
+ m_i2p_sam_session.reset();
}
void CConnman::AddWhitelistPermissionFlags(NetPermissionFlags& flags, const CNetAddr &addr) const {
@@ -626,7 +637,7 @@ void CNode::CopyStats(CNodeStats& stats)
X(mapRecvBytesPerMsgType);
X(nRecvBytes);
}
- X(m_permissionFlags);
+ X(m_permission_flags);
X(m_last_ping_time);
X(m_min_ping_time);
@@ -786,7 +797,8 @@ CNetMessage V1TransportDeserializer::GetMessage(const std::chrono::microseconds
return msg;
}
-void V1TransportSerializer::prepareForTransport(CSerializedNetMsg& msg, std::vector<unsigned char>& header) {
+void V1TransportSerializer::prepareForTransport(CSerializedNetMsg& msg, std::vector<unsigned char>& header) const
+{
// create dbl-sha256 checksum
uint256 hash = Hash(msg.data);
@@ -924,27 +936,27 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
const CAddress addr_bind{MaybeFlipIPv6toCJDNS(GetBindAddress(*sock)), NODE_NONE};
- NetPermissionFlags permissionFlags = NetPermissionFlags::None;
- hListenSocket.AddSocketPermissionFlags(permissionFlags);
+ NetPermissionFlags permission_flags = NetPermissionFlags::None;
+ hListenSocket.AddSocketPermissionFlags(permission_flags);
- CreateNodeFromAcceptedSocket(std::move(sock), permissionFlags, addr_bind, addr);
+ CreateNodeFromAcceptedSocket(std::move(sock), permission_flags, addr_bind, addr);
}
void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,
- NetPermissionFlags permissionFlags,
+ NetPermissionFlags permission_flags,
const CAddress& addr_bind,
const CAddress& addr)
{
int nInbound = 0;
int nMaxInbound = nMaxConnections - m_max_outbound;
- AddWhitelistPermissionFlags(permissionFlags, addr);
- if (NetPermissions::HasFlag(permissionFlags, NetPermissionFlags::Implicit)) {
- NetPermissions::ClearFlag(permissionFlags, NetPermissionFlags::Implicit);
- if (gArgs.GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY)) NetPermissions::AddFlag(permissionFlags, NetPermissionFlags::ForceRelay);
- if (gArgs.GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY)) NetPermissions::AddFlag(permissionFlags, NetPermissionFlags::Relay);
- NetPermissions::AddFlag(permissionFlags, NetPermissionFlags::Mempool);
- NetPermissions::AddFlag(permissionFlags, NetPermissionFlags::NoBan);
+ AddWhitelistPermissionFlags(permission_flags, addr);
+ if (NetPermissions::HasFlag(permission_flags, NetPermissionFlags::Implicit)) {
+ NetPermissions::ClearFlag(permission_flags, NetPermissionFlags::Implicit);
+ if (gArgs.GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY)) NetPermissions::AddFlag(permission_flags, NetPermissionFlags::ForceRelay);
+ if (gArgs.GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY)) NetPermissions::AddFlag(permission_flags, NetPermissionFlags::Relay);
+ NetPermissions::AddFlag(permission_flags, NetPermissionFlags::Mempool);
+ NetPermissions::AddFlag(permission_flags, NetPermissionFlags::NoBan);
}
{
@@ -975,7 +987,7 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,
// Don't accept connections from banned peers.
bool banned = m_banman && m_banman->IsBanned(addr);
- if (!NetPermissions::HasFlag(permissionFlags, NetPermissionFlags::NoBan) && banned)
+ if (!NetPermissions::HasFlag(permission_flags, NetPermissionFlags::NoBan) && banned)
{
LogPrint(BCLog::NET, "connection from %s dropped (banned)\n", addr.ToString());
return;
@@ -983,7 +995,7 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,
// Only accept connections from discouraged peers if our inbound slots aren't (almost) full.
bool discouraged = m_banman && m_banman->IsDiscouraged(addr);
- if (!NetPermissions::HasFlag(permissionFlags, NetPermissionFlags::NoBan) && nInbound + 1 >= nMaxInbound && discouraged)
+ if (!NetPermissions::HasFlag(permission_flags, NetPermissionFlags::NoBan) && nInbound + 1 >= nMaxInbound && discouraged)
{
LogPrint(BCLog::NET, "connection from %s dropped (discouraged)\n", addr.ToString());
return;
@@ -1002,7 +1014,7 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,
uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize();
ServiceFlags nodeServices = nLocalServices;
- if (NetPermissions::HasFlag(permissionFlags, NetPermissionFlags::BloomFilter)) {
+ if (NetPermissions::HasFlag(permission_flags, NetPermissionFlags::BloomFilter)) {
nodeServices = static_cast<ServiceFlags>(nodeServices | NODE_BLOOM);
}
@@ -1015,10 +1027,12 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,
addr_bind,
/*addrNameIn=*/"",
ConnectionType::INBOUND,
- inbound_onion);
+ inbound_onion,
+ CNodeOptions{
+ .permission_flags = permission_flags,
+ .prefer_evict = discouraged,
+ });
pnode->AddRef();
- pnode->m_permissionFlags = permissionFlags;
- pnode->m_prefer_evict = discouraged;
m_msgproc->InitializeNode(*pnode, nodeServices);
LogPrint(BCLog::NET, "connection from %s accepted\n", addr.ToString());
@@ -1486,12 +1500,12 @@ void CConnman::ThreadDNSAddressSeed()
void CConnman::DumpAddresses()
{
- int64_t nStart = GetTimeMillis();
+ const auto start{SteadyClock::now()};
DumpPeerAddresses(::gArgs, addrman);
LogPrint(BCLog::NET, "Flushed %d addresses to peers.dat %dms\n",
- addrman.size(), GetTimeMillis() - nStart);
+ addrman.size(), Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
}
void CConnman::ProcessAddrFetch()
@@ -1628,15 +1642,28 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
LOCK2(m_addr_fetches_mutex, m_added_nodes_mutex);
if (m_addr_fetches.empty() && m_added_nodes.empty()) {
add_fixed_seeds_now = true;
- LogPrintf("Adding fixed seeds as -dnsseed=0, -addnode is not provided and all -seednode(s) attempted\n");
+ LogPrintf("Adding fixed seeds as -dnsseed=0 (or IPv4/IPv6 connections are disabled via -onlynet), -addnode is not provided and all -seednode(s) attempted\n");
}
}
if (add_fixed_seeds_now) {
+ std::vector<CAddress> seed_addrs{ConvertSeeds(Params().FixedSeeds())};
+ // We will not make outgoing connections to peers that are unreachable
+ // (e.g. because of -onlynet configuration).
+ // Therefore, we do not add them to addrman in the first place.
+ // Note that if you change -onlynet setting from one network to another,
+ // peers.dat will contain only peers of unreachable networks and
+ // manual intervention will be needed (either delete peers.dat after
+ // configuration change or manually add some reachable peer using addnode),
+ // see <https://github.com/bitcoin/bitcoin/issues/26035> for details.
+ seed_addrs.erase(std::remove_if(seed_addrs.begin(), seed_addrs.end(),
+ [](const CAddress& addr) { return !IsReachable(addr); }),
+ seed_addrs.end());
CNetAddr local;
local.SetInternal("fixedseeds");
- addrman.Add(ConvertSeeds(Params().FixedSeeds()), local);
+ addrman.Add(seed_addrs, local);
add_fixed_seeds = false;
+ LogPrintf("Added %d fixed seeds from reachable networks.\n", seed_addrs.size());
}
}
@@ -2258,7 +2285,7 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions)
}
Proxy i2p_sam;
- if (GetProxy(NET_I2P, i2p_sam)) {
+ if (GetProxy(NET_I2P, i2p_sam) && connOptions.m_i2p_accept_incoming) {
m_i2p_sam_session = std::make_unique<i2p::sam::Session>(gArgs.GetDataDirNet() / "i2p_private_key",
i2p_sam.proxy, &interruptNet);
}
@@ -2332,7 +2359,7 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions)
// Process messages
threadMessageHandler = std::thread(&util::TraceThread, "msghand", [this] { ThreadMessageHandler(); });
- if (connOptions.m_i2p_accept_incoming && m_i2p_sam_session.get() != nullptr) {
+ if (m_i2p_sam_session) {
threadI2PAcceptIncoming =
std::thread(&util::TraceThread, "i2paccept", [this] { ThreadI2PAcceptIncoming(); });
}
@@ -2701,20 +2728,31 @@ ServiceFlags CConnman::GetLocalServices() const
unsigned int CConnman::GetReceiveFloodSize() const { return nReceiveFloodSize; }
-CNode::CNode(NodeId idIn, std::shared_ptr<Sock> sock, const CAddress& addrIn,
- uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn,
- const CAddress& addrBindIn, const std::string& addrNameIn,
- ConnectionType conn_type_in, bool inbound_onion)
- : m_sock{sock},
+CNode::CNode(NodeId idIn,
+ std::shared_ptr<Sock> sock,
+ const CAddress& addrIn,
+ uint64_t nKeyedNetGroupIn,
+ uint64_t nLocalHostNonceIn,
+ const CAddress& addrBindIn,
+ const std::string& addrNameIn,
+ ConnectionType conn_type_in,
+ bool inbound_onion,
+ CNodeOptions&& node_opts)
+ : m_deserializer{std::make_unique<V1TransportDeserializer>(V1TransportDeserializer(Params(), idIn, SER_NETWORK, INIT_PROTO_VERSION))},
+ m_serializer{std::make_unique<V1TransportSerializer>(V1TransportSerializer())},
+ m_permission_flags{node_opts.permission_flags},
+ m_sock{sock},
m_connected{GetTime<std::chrono::seconds>()},
- addr(addrIn),
- addrBind(addrBindIn),
+ addr{addrIn},
+ addrBind{addrBindIn},
m_addr_name{addrNameIn.empty() ? addr.ToStringIPPort() : addrNameIn},
- m_inbound_onion(inbound_onion),
- nKeyedNetGroup(nKeyedNetGroupIn),
- id(idIn),
- nLocalHostNonce(nLocalHostNonceIn),
- m_conn_type(conn_type_in)
+ m_inbound_onion{inbound_onion},
+ m_prefer_evict{node_opts.prefer_evict},
+ nKeyedNetGroup{nKeyedNetGroupIn},
+ id{idIn},
+ nLocalHostNonce{nLocalHostNonceIn},
+ m_conn_type{conn_type_in},
+ m_i2p_sam_session{std::move(node_opts.i2p_sam_session)}
{
if (inbound_onion) assert(conn_type_in == ConnectionType::INBOUND);
@@ -2727,9 +2765,6 @@ CNode::CNode(NodeId idIn, std::shared_ptr<Sock> sock, const CAddress& addrIn,
} else {
LogPrint(BCLog::NET, "Added connection peer=%d\n", id);
}
-
- m_deserializer = std::make_unique<V1TransportDeserializer>(V1TransportDeserializer(Params(), id, SER_NETWORK, INIT_PROTO_VERSION));
- m_serializer = std::make_unique<V1TransportSerializer>(V1TransportSerializer());
}
bool CConnman::NodeFullyConnected(const CNode* pnode)
diff --git a/src/net.h b/src/net.h
index 2036e9078c..66a228b3ec 100644
--- a/src/net.h
+++ b/src/net.h
@@ -204,7 +204,7 @@ public:
mapMsgTypeSize mapSendBytesPerMsgType;
uint64_t nRecvBytes;
mapMsgTypeSize mapRecvBytesPerMsgType;
- NetPermissionFlags m_permissionFlags;
+ NetPermissionFlags m_permission_flags;
std::chrono::microseconds m_last_ping_time;
std::chrono::microseconds m_min_ping_time;
// Our address, as reported by the peer
@@ -325,13 +325,20 @@ public:
class TransportSerializer {
public:
// prepare message for transport (header construction, error-correction computation, payload encryption, etc.)
- virtual void prepareForTransport(CSerializedNetMsg& msg, std::vector<unsigned char>& header) = 0;
+ virtual void prepareForTransport(CSerializedNetMsg& msg, std::vector<unsigned char>& header) const = 0;
virtual ~TransportSerializer() {}
};
-class V1TransportSerializer : public TransportSerializer {
+class V1TransportSerializer : public TransportSerializer {
public:
- void prepareForTransport(CSerializedNetMsg& msg, std::vector<unsigned char>& header) override;
+ void prepareForTransport(CSerializedNetMsg& msg, std::vector<unsigned char>& header) const override;
+};
+
+struct CNodeOptions
+{
+ NetPermissionFlags permission_flags = NetPermissionFlags::None;
+ std::unique_ptr<i2p::sam::Session> i2p_sam_session = nullptr;
+ bool prefer_evict = false;
};
/** Information about a peer */
@@ -341,10 +348,10 @@ class CNode
friend struct ConnmanTestMsg;
public:
- std::unique_ptr<TransportDeserializer> m_deserializer;
- std::unique_ptr<TransportSerializer> m_serializer;
+ const std::unique_ptr<TransportDeserializer> m_deserializer; // Used only by SocketHandler thread
+ const std::unique_ptr<const TransportSerializer> m_serializer;
- NetPermissionFlags m_permissionFlags{NetPermissionFlags::None};
+ const NetPermissionFlags m_permission_flags;
/**
* Socket used for communication with the node.
@@ -368,7 +375,7 @@ public:
RecursiveMutex cs_vProcessMsg;
std::list<CNetMessage> vProcessMsg GUARDED_BY(cs_vProcessMsg);
- size_t nProcessQueueSize{0};
+ size_t nProcessQueueSize GUARDED_BY(cs_vProcessMsg){0};
RecursiveMutex cs_sendProcessing;
@@ -393,9 +400,9 @@ public:
* from the wire. This cleaned string can safely be logged or displayed.
*/
std::string cleanSubVer GUARDED_BY(m_subver_mutex){};
- bool m_prefer_evict{false}; // This peer is preferred for eviction.
+ const bool m_prefer_evict{false}; // This peer is preferred for eviction.
bool HasPermission(NetPermissionFlags permission) const {
- return NetPermissions::HasFlag(m_permissionFlags, permission);
+ return NetPermissions::HasFlag(m_permission_flags, permission);
}
/** fSuccessfullyConnected is set to true on receiving VERACK from the peer. */
std::atomic_bool fSuccessfullyConnected{false};
@@ -513,10 +520,16 @@ public:
* criterium in CConnman::AttemptToEvictConnection. */
std::atomic<std::chrono::microseconds> m_min_ping_time{std::chrono::microseconds::max()};
- CNode(NodeId id, std::shared_ptr<Sock> sock, const CAddress& addrIn,
- uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn,
- const CAddress& addrBindIn, const std::string& addrNameIn,
- ConnectionType conn_type_in, bool inbound_onion);
+ CNode(NodeId id,
+ std::shared_ptr<Sock> sock,
+ const CAddress& addrIn,
+ uint64_t nKeyedNetGroupIn,
+ uint64_t nLocalHostNonceIn,
+ const CAddress& addrBindIn,
+ const std::string& addrNameIn,
+ ConnectionType conn_type_in,
+ bool inbound_onion,
+ CNodeOptions&& node_opts = {});
CNode(const CNode&) = delete;
CNode& operator=(const CNode&) = delete;
@@ -596,6 +609,18 @@ private:
mapMsgTypeSize mapSendBytesPerMsgType GUARDED_BY(cs_vSend);
mapMsgTypeSize mapRecvBytesPerMsgType GUARDED_BY(cs_vRecv);
+
+ /**
+ * If an I2P session is created per connection (for outbound transient I2P
+ * connections) then it is stored here so that it can be destroyed when the
+ * socket is closed. I2P sessions involve a data/transport socket (in `m_sock`)
+ * and a control socket (in `m_i2p_sam_session`). For transient sessions, once
+ * the data socket is closed, the control socket is not going to be used anymore
+ * and is just taking up resources. So better close it as soon as `m_sock` is
+ * closed.
+ * Otherwise this unique_ptr is empty.
+ */
+ std::unique_ptr<i2p::sam::Session> m_i2p_sam_session GUARDED_BY(m_sock_mutex);
};
/**
@@ -872,12 +897,12 @@ private:
* Create a `CNode` object from a socket that has just been accepted and add the node to
* the `m_nodes` member.
* @param[in] sock Connected socket to communicate with the peer.
- * @param[in] permissionFlags The peer's permissions.
+ * @param[in] permission_flags The peer's permissions.
* @param[in] addr_bind The address and port at our side of the connection.
* @param[in] addr The address and port at the peer's side of the connection.
*/
void CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,
- NetPermissionFlags permissionFlags,
+ NetPermissionFlags permission_flags,
const CAddress& addr_bind,
const CAddress& addr);
@@ -1072,7 +1097,8 @@ private:
/**
* I2P SAM session.
- * Used to accept incoming and make outgoing I2P connections.
+ * Used to accept incoming and make outgoing I2P connections from a persistent
+ * address.
*/
std::unique_ptr<i2p::sam::Session> m_i2p_sam_session;
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index b83034463d..74700580ad 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -14,6 +14,7 @@
#include <consensus/validation.h>
#include <deploymentstatus.h>
#include <hash.h>
+#include <headerssync.h>
#include <index/blockfilterindex.h>
#include <merkleblock.h>
#include <netbase.h>
@@ -289,7 +290,7 @@ struct Peer {
* non-wtxid-relay peers, wtxid for wtxid-relay peers). We use the
* mempool to sort transactions in dependency order before relay, so
* this does not have to be sorted. */
- std::set<uint256> m_tx_inventory_to_send;
+ std::set<uint256> m_tx_inventory_to_send GUARDED_BY(m_tx_inventory_mutex);
/** Whether the peer has requested us to send our complete mempool. Only
* permitted if the peer has NetPermissionFlags::Mempool. See BIP35. */
bool m_send_mempool GUARDED_BY(m_tx_inventory_mutex){false};
@@ -381,6 +382,15 @@ struct Peer {
/** Time of the last getheaders message to this peer */
NodeClock::time_point m_last_getheaders_timestamp{};
+ /** Protects m_headers_sync **/
+ Mutex m_headers_sync_mutex;
+ /** Headers-sync state for this peer (eg for initial sync, or syncing large
+ * reorgs) **/
+ std::unique_ptr<HeadersSyncState> m_headers_sync PT_GUARDED_BY(m_headers_sync_mutex) GUARDED_BY(m_headers_sync_mutex) {};
+
+ /** Whether we've sent our peer a sendheaders message. **/
+ std::atomic<bool> m_sent_sendheaders{false};
+
explicit Peer(NodeId id, ServiceFlags our_services)
: m_id{id}
, m_our_services{our_services}
@@ -503,9 +513,9 @@ public:
/** Implement NetEventsInterface */
void InitializeNode(CNode& node, ServiceFlags our_services) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
- void FinalizeNode(const CNode& node) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
+ void FinalizeNode(const CNode& node) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_headers_presync_mutex);
bool ProcessMessages(CNode* pfrom, std::atomic<bool>& interrupt) override
- EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_recent_confirmed_transactions_mutex, !m_most_recent_block_mutex);
+ EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_recent_confirmed_transactions_mutex, !m_most_recent_block_mutex, !m_headers_presync_mutex);
bool SendMessages(CNode* pto) override EXCLUSIVE_LOCKS_REQUIRED(pto->cs_sendProcessing)
EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_recent_confirmed_transactions_mutex, !m_most_recent_block_mutex);
@@ -522,7 +532,7 @@ public:
void UnitTestMisbehaving(NodeId peer_id, int howmuch) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex) { Misbehaving(*Assert(GetPeerRef(peer_id)), howmuch, ""); };
void ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv,
const std::chrono::microseconds time_received, const std::atomic<bool>& interruptMsgProc) override
- EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_recent_confirmed_transactions_mutex, !m_most_recent_block_mutex);
+ EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_recent_confirmed_transactions_mutex, !m_most_recent_block_mutex, !m_headers_presync_mutex);
void UpdateLastBlockAnnounceTime(NodeId node, int64_t time_in_seconds) override;
private:
@@ -581,18 +591,70 @@ private:
void ProcessOrphanTx(std::set<uint256>& orphan_work_set) EXCLUSIVE_LOCKS_REQUIRED(cs_main, g_cs_orphans)
EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
- /** Process a single headers message from a peer. */
+ /** Process a single headers message from a peer.
+ *
+ * @param[in] pfrom CNode of the peer
+ * @param[in] peer The peer sending us the headers
+ * @param[in] headers The headers received. Note that this may be modified within ProcessHeadersMessage.
+ * @param[in] via_compact_block Whether this header came in via compact block handling.
+ */
void ProcessHeadersMessage(CNode& pfrom, Peer& peer,
- const std::vector<CBlockHeader>& headers,
+ std::vector<CBlockHeader>&& headers,
bool via_compact_block)
- EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
+ EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_headers_presync_mutex);
/** Various helpers for headers processing, invoked by ProcessHeadersMessage() */
+ /** Return true if headers are continuous and have valid proof-of-work (DoS points assigned on failure) */
+ bool CheckHeadersPoW(const std::vector<CBlockHeader>& headers, const Consensus::Params& consensusParams, Peer& peer);
+ /** Calculate an anti-DoS work threshold for headers chains */
+ arith_uint256 GetAntiDoSWorkThreshold();
/** Deal with state tracking and headers sync for peers that send the
* occasional non-connecting header (this can happen due to BIP 130 headers
* announcements for blocks interacting with the 2hr (MAX_FUTURE_BLOCK_TIME) rule). */
void HandleFewUnconnectingHeaders(CNode& pfrom, Peer& peer, const std::vector<CBlockHeader>& headers);
/** Return true if the headers connect to each other, false otherwise */
bool CheckHeadersAreContinuous(const std::vector<CBlockHeader>& headers) const;
+ /** Try to continue a low-work headers sync that has already begun.
+ * Assumes the caller has already verified the headers connect, and has
+ * checked that each header satisfies the proof-of-work target included in
+ * the header.
+ * @param[in] peer The peer we're syncing with.
+ * @param[in] pfrom CNode of the peer
+ * @param[in,out] headers The headers to be processed.
+ * @return True if the passed in headers were successfully processed
+ * as the continuation of a low-work headers sync in progress;
+ * false otherwise.
+ * If false, the passed in headers will be returned back to
+ * the caller.
+ * If true, the returned headers may be empty, indicating
+ * there is no more work for the caller to do; or the headers
+ * may be populated with entries that have passed anti-DoS
+ * checks (and therefore may be validated for block index
+ * acceptance by the caller).
+ */
+ bool IsContinuationOfLowWorkHeadersSync(Peer& peer, CNode& pfrom,
+ std::vector<CBlockHeader>& headers)
+ EXCLUSIVE_LOCKS_REQUIRED(peer.m_headers_sync_mutex, !m_headers_presync_mutex);
+ /** Check work on a headers chain to be processed, and if insufficient,
+ * initiate our anti-DoS headers sync mechanism.
+ *
+ * @param[in] peer The peer whose headers we're processing.
+ * @param[in] pfrom CNode of the peer
+ * @param[in] chain_start_header Where these headers connect in our index.
+ * @param[in,out] headers The headers to be processed.
+ *
+ * @return True if chain was low work and a headers sync was
+ * initiated (and headers will be empty after calling); false
+ * otherwise.
+ */
+ bool TryLowWorkHeadersSync(Peer& peer, CNode& pfrom,
+ const CBlockIndex* chain_start_header,
+ std::vector<CBlockHeader>& headers)
+ EXCLUSIVE_LOCKS_REQUIRED(!peer.m_headers_sync_mutex, !m_peer_mutex, !m_headers_presync_mutex);
+
+ /** Return true if the given header is an ancestor of
+ * m_chainman.m_best_header or our current tip */
+ bool IsAncestorOfBestHeaderOrTip(const CBlockIndex* header) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+
/** Request further headers from this peer with a given locator.
* We don't issue a getheaders message if we have a recent one outstanding.
* This returns true if a getheaders is actually sent, and false otherwise.
@@ -623,6 +685,9 @@ private:
/** Send `addr` messages on a regular schedule. */
void MaybeSendAddr(CNode& node, Peer& peer, std::chrono::microseconds current_time);
+ /** Send a single `sendheaders` message, after we have completed headers sync with a peer. */
+ void MaybeSendSendHeaders(CNode& node, Peer& peer);
+
/** Relay (gossip) an address to a few randomly chosen nodes.
*
* @param[in] originator The id of the peer that sent us the address. We don't want to relay it back.
@@ -648,7 +713,7 @@ private:
std::atomic<int> m_best_height{-1};
/** Next time to check for stale tip */
- std::chrono::seconds m_stale_tip_check_time{0s};
+ std::chrono::seconds m_stale_tip_check_time GUARDED_BY(cs_main){0s};
/** Whether this node is running in -blocksonly mode */
const bool m_ignore_incoming_txs;
@@ -657,7 +722,7 @@ private:
/** Whether we've completed initial sync yet, for determining when to turn
* on extra block-relay-only peers. */
- bool m_initial_sync_finished{false};
+ bool m_initial_sync_finished GUARDED_BY(cs_main){false};
/** Protects m_peer_map. This mutex must not be locked while holding a lock
* on any of the mutexes inside a Peer object. */
@@ -779,6 +844,24 @@ private:
std::shared_ptr<const CBlockHeaderAndShortTxIDs> m_most_recent_compact_block GUARDED_BY(m_most_recent_block_mutex);
uint256 m_most_recent_block_hash GUARDED_BY(m_most_recent_block_mutex);
+ // Data about the low-work headers synchronization, aggregated from all peers' HeadersSyncStates.
+ /** Mutex guarding the other m_headers_presync_* variables. */
+ Mutex m_headers_presync_mutex;
+ /** A type to represent statistics about a peer's low-work headers sync.
+ *
+ * - The first field is the total verified amount of work in that synchronization.
+ * - The second is:
+ * - nullopt: the sync is in REDOWNLOAD phase (phase 2).
+ * - {height, timestamp}: the sync has the specified tip height and block timestamp (phase 1).
+ */
+ using HeadersPresyncStats = std::pair<arith_uint256, std::optional<std::pair<int64_t, uint32_t>>>;
+ /** Statistics for all peers in low-work headers sync. */
+ std::map<NodeId, HeadersPresyncStats> m_headers_presync_stats GUARDED_BY(m_headers_presync_mutex) {};
+ /** The peer with the most-work entry in m_headers_presync_stats. */
+ NodeId m_headers_presync_bestpeer GUARDED_BY(m_headers_presync_mutex) {-1};
+ /** The m_headers_presync_stats improved, and needs signalling. */
+ std::atomic_bool m_headers_presync_should_signal{false};
+
/** Height of the highest block announced using BIP 152 high-bandwidth mode. */
int m_highest_fast_announce{0};
@@ -816,7 +899,7 @@ private:
EXCLUSIVE_LOCKS_REQUIRED(!m_most_recent_block_mutex, peer.m_getdata_requests_mutex) LOCKS_EXCLUDED(::cs_main);
/** Process a new block. Perform any post-processing housekeeping */
- void ProcessBlock(CNode& node, const std::shared_ptr<const CBlock>& block, bool force_processing);
+ void ProcessBlock(CNode& node, const std::shared_ptr<const CBlock>& block, bool force_processing, bool min_pow_checked);
/** Relay map (txid or wtxid -> CTransactionRef) */
typedef std::map<uint256, CTransactionRef> MapRelay;
@@ -1437,6 +1520,10 @@ void PeerManagerImpl::FinalizeNode(const CNode& node)
// fSuccessfullyConnected set.
m_addrman.Connected(node.addr);
}
+ {
+ LOCK(m_headers_presync_mutex);
+ m_headers_presync_stats.erase(nodeid);
+ }
LogPrint(BCLog::NET, "Cleared nodestate for peer=%d\n", nodeid);
}
@@ -1501,6 +1588,12 @@ bool PeerManagerImpl::GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) c
stats.m_addr_processed = peer->m_addr_processed.load();
stats.m_addr_rate_limited = peer->m_addr_rate_limited.load();
stats.m_addr_relay_enabled = peer->m_addr_relay_enabled.load();
+ {
+ LOCK(peer->m_headers_sync_mutex);
+ if (peer->m_headers_sync) {
+ stats.presync_height = peer->m_headers_sync->GetPresyncHeight();
+ }
+ }
return true;
}
@@ -1544,6 +1637,10 @@ bool PeerManagerImpl::MaybePunishNodeForBlock(NodeId nodeid, const BlockValidati
switch (state.GetResult()) {
case BlockValidationResult::BLOCK_RESULT_UNSET:
break;
+ case BlockValidationResult::BLOCK_HEADER_LOW_WORK:
+ // We didn't try to process the block because the header chain may have
+ // too little work.
+ break;
// The node is providing invalid data:
case BlockValidationResult::BLOCK_CONSENSUS:
case BlockValidationResult::BLOCK_MUTATED:
@@ -2263,6 +2360,35 @@ void PeerManagerImpl::SendBlockTransactions(CNode& pfrom, Peer& peer, const CBlo
m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::BLOCKTXN, resp));
}
+bool PeerManagerImpl::CheckHeadersPoW(const std::vector<CBlockHeader>& headers, const Consensus::Params& consensusParams, Peer& peer)
+{
+ // Do these headers have proof-of-work matching what's claimed?
+ if (!HasValidProofOfWork(headers, consensusParams)) {
+ Misbehaving(peer, 100, "header with invalid proof of work");
+ return false;
+ }
+
+ // Are these headers connected to each other?
+ if (!CheckHeadersAreContinuous(headers)) {
+ Misbehaving(peer, 20, "non-continuous headers sequence");
+ return false;
+ }
+ return true;
+}
+
+arith_uint256 PeerManagerImpl::GetAntiDoSWorkThreshold()
+{
+ arith_uint256 near_chaintip_work = 0;
+ LOCK(cs_main);
+ if (m_chainman.ActiveChain().Tip() != nullptr) {
+ const CBlockIndex *tip = m_chainman.ActiveChain().Tip();
+ // Use a 144 block buffer, so that we'll accept headers that fork from
+ // near our tip.
+ near_chaintip_work = tip->nChainWork - std::min<arith_uint256>(144*GetBlockProof(*tip), tip->nChainWork);
+ }
+ return std::max(near_chaintip_work, arith_uint256(nMinimumChainWork));
+}
+
/**
* Special handling for unconnecting headers that might be part of a block
* announcement.
@@ -2285,7 +2411,7 @@ void PeerManagerImpl::HandleFewUnconnectingHeaders(CNode& pfrom, Peer& peer,
nodestate->nUnconnectingHeaders++;
// Try to fill in the missing headers.
- if (MaybeSendGetHeaders(pfrom, m_chainman.ActiveChain().GetLocator(m_chainman.m_best_header), peer)) {
+ if (MaybeSendGetHeaders(pfrom, GetLocator(m_chainman.m_best_header), peer)) {
LogPrint(BCLog::NET, "received header %s: missing prev block %s, sending getheaders (%d) to end (peer=%d, nUnconnectingHeaders=%d)\n",
headers[0].GetHash().ToString(),
headers[0].hashPrevBlock.ToString(),
@@ -2316,6 +2442,146 @@ bool PeerManagerImpl::CheckHeadersAreContinuous(const std::vector<CBlockHeader>&
return true;
}
+bool PeerManagerImpl::IsContinuationOfLowWorkHeadersSync(Peer& peer, CNode& pfrom, std::vector<CBlockHeader>& headers)
+{
+ if (peer.m_headers_sync) {
+ auto result = peer.m_headers_sync->ProcessNextHeaders(headers, headers.size() == MAX_HEADERS_RESULTS);
+ if (result.request_more) {
+ auto locator = peer.m_headers_sync->NextHeadersRequestLocator();
+ // If we were instructed to ask for a locator, it should not be empty.
+ Assume(!locator.vHave.empty());
+ if (!locator.vHave.empty()) {
+ // It should be impossible for the getheaders request to fail,
+ // because we should have cleared the last getheaders timestamp
+ // when processing the headers that triggered this call. But
+ // it may be possible to bypass this via compactblock
+ // processing, so check the result before logging just to be
+ // safe.
+ bool sent_getheaders = MaybeSendGetHeaders(pfrom, locator, peer);
+ if (sent_getheaders) {
+ LogPrint(BCLog::NET, "more getheaders (from %s) to peer=%d\n",
+ locator.vHave.front().ToString(), pfrom.GetId());
+ } else {
+ LogPrint(BCLog::NET, "error sending next getheaders (from %s) to continue sync with peer=%d\n",
+ locator.vHave.front().ToString(), pfrom.GetId());
+ }
+ }
+ }
+
+ if (peer.m_headers_sync->GetState() == HeadersSyncState::State::FINAL) {
+ peer.m_headers_sync.reset(nullptr);
+
+ // Delete this peer's entry in m_headers_presync_stats.
+ // If this is m_headers_presync_bestpeer, it will be replaced later
+ // by the next peer that triggers the else{} branch below.
+ LOCK(m_headers_presync_mutex);
+ m_headers_presync_stats.erase(pfrom.GetId());
+ } else {
+ // Build statistics for this peer's sync.
+ HeadersPresyncStats stats;
+ stats.first = peer.m_headers_sync->GetPresyncWork();
+ if (peer.m_headers_sync->GetState() == HeadersSyncState::State::PRESYNC) {
+ stats.second = {peer.m_headers_sync->GetPresyncHeight(),
+ peer.m_headers_sync->GetPresyncTime()};
+ }
+
+ // Update statistics in stats.
+ LOCK(m_headers_presync_mutex);
+ m_headers_presync_stats[pfrom.GetId()] = stats;
+ auto best_it = m_headers_presync_stats.find(m_headers_presync_bestpeer);
+ bool best_updated = false;
+ if (best_it == m_headers_presync_stats.end()) {
+ // If the cached best peer is outdated, iterate over all remaining ones (including
+ // newly updated one) to find the best one.
+ NodeId peer_best{-1};
+ const HeadersPresyncStats* stat_best{nullptr};
+ for (const auto& [peer, stat] : m_headers_presync_stats) {
+ if (!stat_best || stat > *stat_best) {
+ peer_best = peer;
+ stat_best = &stat;
+ }
+ }
+ m_headers_presync_bestpeer = peer_best;
+ best_updated = (peer_best == pfrom.GetId());
+ } else if (best_it->first == pfrom.GetId() || stats > best_it->second) {
+ // pfrom was and remains the best peer, or pfrom just became best.
+ m_headers_presync_bestpeer = pfrom.GetId();
+ best_updated = true;
+ }
+ if (best_updated && stats.second.has_value()) {
+ // If the best peer updated, and it is in its first phase, signal.
+ m_headers_presync_should_signal = true;
+ }
+ }
+
+ if (result.success) {
+ // We only overwrite the headers passed in if processing was
+ // successful.
+ headers.swap(result.pow_validated_headers);
+ }
+
+ return result.success;
+ }
+ // Either we didn't have a sync in progress, or something went wrong
+ // processing these headers, or we are returning headers to the caller to
+ // process.
+ return false;
+}
+
+bool PeerManagerImpl::TryLowWorkHeadersSync(Peer& peer, CNode& pfrom, const CBlockIndex* chain_start_header, std::vector<CBlockHeader>& headers)
+{
+ // Calculate the total work on this chain.
+ arith_uint256 total_work = chain_start_header->nChainWork + CalculateHeadersWork(headers);
+
+ // Our dynamic anti-DoS threshold (minimum work required on a headers chain
+ // before we'll store it)
+ arith_uint256 minimum_chain_work = GetAntiDoSWorkThreshold();
+
+ // Avoid DoS via low-difficulty-headers by only processing if the headers
+ // are part of a chain with sufficient work.
+ if (total_work < minimum_chain_work) {
+ // Only try to sync with this peer if their headers message was full;
+ // otherwise they don't have more headers after this so no point in
+ // trying to sync their too-little-work chain.
+ if (headers.size() == MAX_HEADERS_RESULTS) {
+ // Note: we could advance to the last header in this set that is
+ // known to us, rather than starting at the first header (which we
+ // may already have); however this is unlikely to matter much since
+ // ProcessHeadersMessage() already handles the case where all
+ // headers in a received message are already known and are
+ // ancestors of m_best_header or chainActive.Tip(), by skipping
+ // this logic in that case. So even if the first header in this set
+ // of headers is known, some header in this set must be new, so
+ // advancing to the first unknown header would be a small effect.
+ LOCK(peer.m_headers_sync_mutex);
+ peer.m_headers_sync.reset(new HeadersSyncState(peer.m_id, m_chainparams.GetConsensus(),
+ chain_start_header, minimum_chain_work));
+
+ // Now a HeadersSyncState object for tracking this synchronization is created,
+ // process the headers using it as normal.
+ return IsContinuationOfLowWorkHeadersSync(peer, pfrom, headers);
+ } else {
+ LogPrint(BCLog::NET, "Ignoring low-work chain (height=%u) from peer=%d\n", chain_start_header->nHeight + headers.size(), pfrom.GetId());
+ // Since this is a low-work headers chain, no further processing is required.
+ headers = {};
+ return true;
+ }
+ }
+ return false;
+}
+
+bool PeerManagerImpl::IsAncestorOfBestHeaderOrTip(const CBlockIndex* header)
+{
+ if (header == nullptr) {
+ return false;
+ } else if (m_chainman.m_best_header != nullptr && header == m_chainman.m_best_header->GetAncestor(header->nHeight)) {
+ return true;
+ } else if (m_chainman.ActiveChain().Contains(header)) {
+ return true;
+ }
+ return false;
+}
+
bool PeerManagerImpl::MaybeSendGetHeaders(CNode& pfrom, const CBlockLocator& locator, Peer& peer)
{
const CNetMsgMaker msgMaker(pfrom.GetCommonVersion());
@@ -2461,21 +2727,73 @@ void PeerManagerImpl::UpdatePeerStateForReceivedHeaders(CNode& pfrom,
}
void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, Peer& peer,
- const std::vector<CBlockHeader>& headers,
+ std::vector<CBlockHeader>&& headers,
bool via_compact_block)
{
- const CNetMsgMaker msgMaker(pfrom.GetCommonVersion());
size_t nCount = headers.size();
if (nCount == 0) {
// Nothing interesting. Stop asking this peers for more headers.
+ // If we were in the middle of headers sync, receiving an empty headers
+ // message suggests that the peer suddenly has nothing to give us
+ // (perhaps it reorged to our chain). Clear download state for this peer.
+ LOCK(peer.m_headers_sync_mutex);
+ if (peer.m_headers_sync) {
+ peer.m_headers_sync.reset(nullptr);
+ LOCK(m_headers_presync_mutex);
+ m_headers_presync_stats.erase(pfrom.GetId());
+ }
+ return;
+ }
+
+ // Before we do any processing, make sure these pass basic sanity checks.
+ // We'll rely on headers having valid proof-of-work further down, as an
+ // anti-DoS criteria (note: this check is required before passing any
+ // headers into HeadersSyncState).
+ if (!CheckHeadersPoW(headers, m_chainparams.GetConsensus(), peer)) {
+ // Misbehaving() calls are handled within CheckHeadersPoW(), so we can
+ // just return. (Note that even if a header is announced via compact
+ // block, the header itself should be valid, so this type of error can
+ // always be punished.)
return;
}
const CBlockIndex *pindexLast = nullptr;
+ // We'll set already_validated_work to true if these headers are
+ // successfully processed as part of a low-work headers sync in progress
+ // (either in PRESYNC or REDOWNLOAD phase).
+ // If true, this will mean that any headers returned to us (ie during
+ // REDOWNLOAD) can be validated without further anti-DoS checks.
+ bool already_validated_work = false;
+
+ // If we're in the middle of headers sync, let it do its magic.
+ bool have_headers_sync = false;
+ {
+ LOCK(peer.m_headers_sync_mutex);
+
+ already_validated_work = IsContinuationOfLowWorkHeadersSync(peer, pfrom, headers);
+
+ // The headers we passed in may have been:
+ // - untouched, perhaps if no headers-sync was in progress, or some
+ // failure occurred
+ // - erased, such as if the headers were successfully processed and no
+ // additional headers processing needs to take place (such as if we
+ // are still in PRESYNC)
+ // - replaced with headers that are now ready for validation, such as
+ // during the REDOWNLOAD phase of a low-work headers sync.
+ // So just check whether we still have headers that we need to process,
+ // or not.
+ if (headers.empty()) {
+ return;
+ }
+
+ have_headers_sync = !!peer.m_headers_sync;
+ }
+
// Do these headers connect to something in our block index?
- bool headers_connect_blockindex{WITH_LOCK(::cs_main, return m_chainman.m_blockman.LookupBlockIndex(headers[0].hashPrevBlock) != nullptr)};
+ const CBlockIndex *chain_start_header{WITH_LOCK(::cs_main, return m_chainman.m_blockman.LookupBlockIndex(headers[0].hashPrevBlock))};
+ bool headers_connect_blockindex{chain_start_header != nullptr};
if (!headers_connect_blockindex) {
if (nCount <= MAX_BLOCKS_TO_ANNOUNCE) {
@@ -2489,28 +2807,58 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, Peer& peer,
return;
}
+ // If the headers we received are already in memory and an ancestor of
+ // m_best_header or our tip, skip anti-DoS checks. These headers will not
+ // use any more memory (and we are not leaking information that could be
+ // used to fingerprint us).
+ const CBlockIndex *last_received_header{nullptr};
+ {
+ LOCK(cs_main);
+ last_received_header = m_chainman.m_blockman.LookupBlockIndex(headers.back().GetHash());
+ if (IsAncestorOfBestHeaderOrTip(last_received_header)) {
+ already_validated_work = true;
+ }
+ }
+
+ // If our peer has NetPermissionFlags::NoBan privileges, then bypass our
+ // anti-DoS logic (this saves bandwidth when we connect to a trusted peer
+ // on startup).
+ if (pfrom.HasPermission(NetPermissionFlags::NoBan)) {
+ already_validated_work = true;
+ }
+
// At this point, the headers connect to something in our block index.
- if (!CheckHeadersAreContinuous(headers)) {
- Misbehaving(peer, 20, "non-continuous headers sequence");
+ // Do anti-DoS checks to determine if we should process or store for later
+ // processing.
+ if (!already_validated_work && TryLowWorkHeadersSync(peer, pfrom,
+ chain_start_header, headers)) {
+ // If we successfully started a low-work headers sync, then there
+ // should be no headers to process any further.
+ Assume(headers.empty());
return;
}
+ // At this point, we have a set of headers with sufficient work on them
+ // which can be processed.
+
// If we don't have the last header, then this peer will have given us
// something new (if these headers are valid).
- bool received_new_header{WITH_LOCK(::cs_main, return m_chainman.m_blockman.LookupBlockIndex(headers.back().GetHash()) == nullptr)};
+ bool received_new_header{last_received_header != nullptr};
+ // Now process all the headers.
BlockValidationState state;
- if (!m_chainman.ProcessNewBlockHeaders(headers, state, &pindexLast)) {
+ if (!m_chainman.ProcessNewBlockHeaders(headers, /*min_pow_checked=*/true, state, &pindexLast)) {
if (state.IsInvalid()) {
MaybePunishNodeForBlock(pfrom.GetId(), state, via_compact_block, "invalid header received");
return;
}
}
+ Assume(pindexLast);
- // Consider fetching more headers.
- if (nCount == MAX_HEADERS_RESULTS) {
+ // Consider fetching more headers if we are not using our headers-sync mechanism.
+ if (nCount == MAX_HEADERS_RESULTS && !have_headers_sync) {
// Headers message had its maximum size; the peer may have more headers.
- if (MaybeSendGetHeaders(pfrom, WITH_LOCK(m_chainman.GetMutex(), return m_chainman.ActiveChain().GetLocator(pindexLast)), peer)) {
+ if (MaybeSendGetHeaders(pfrom, GetLocator(pindexLast), peer)) {
LogPrint(BCLog::NET, "more getheaders (%d) to end to peer=%d (startheight:%d)\n",
pindexLast->nHeight, pfrom.GetId(), peer.m_starting_height);
}
@@ -2771,10 +3119,10 @@ void PeerManagerImpl::ProcessGetCFCheckPt(CNode& node, Peer& peer, CDataStream&
m_connman.PushMessage(&node, std::move(msg));
}
-void PeerManagerImpl::ProcessBlock(CNode& node, const std::shared_ptr<const CBlock>& block, bool force_processing)
+void PeerManagerImpl::ProcessBlock(CNode& node, const std::shared_ptr<const CBlock>& block, bool force_processing, bool min_pow_checked)
{
bool new_block{false};
- m_chainman.ProcessNewBlock(block, force_processing, &new_block);
+ m_chainman.ProcessNewBlock(block, force_processing, min_pow_checked, &new_block);
if (new_block) {
node.m_last_block_time = GetTime<std::chrono::seconds>();
} else {
@@ -3032,13 +3380,6 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
pfrom.ConnectionTypeAsString());
}
- if (pfrom.GetCommonVersion() >= SENDHEADERS_VERSION) {
- // Tell our peer we prefer to receive headers rather than inv's
- // We send this to non-NODE NETWORK peers as well, because even
- // non-NODE NETWORK peers can announce blocks (such as pruning
- // nodes)
- m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::SENDHEADERS));
- }
if (pfrom.GetCommonVersion() >= SHORT_IDS_BLOCKS_VERSION) {
// Tell our peer we are willing to provide version 2 cmpctblocks.
// However, we do not request new block announcements using
@@ -3285,7 +3626,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// use if we turned on sync with all peers).
CNodeState& state{*Assert(State(pfrom.GetId()))};
if (state.fSyncStarted || (!peer->m_inv_triggered_getheaders_before_sync && *best_block != m_last_block_inv_triggering_headers_sync)) {
- if (MaybeSendGetHeaders(pfrom, m_chainman.ActiveChain().GetLocator(m_chainman.m_best_header), *peer)) {
+ if (MaybeSendGetHeaders(pfrom, GetLocator(m_chainman.m_best_header), *peer)) {
LogPrint(BCLog::NET, "getheaders (%d) %s to peer=%d\n",
m_chainman.m_best_header->nHeight, best_block->ToString(),
pfrom.GetId());
@@ -3749,12 +4090,17 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
{
LOCK(cs_main);
- if (!m_chainman.m_blockman.LookupBlockIndex(cmpctblock.header.hashPrevBlock)) {
+ const CBlockIndex* prev_block = m_chainman.m_blockman.LookupBlockIndex(cmpctblock.header.hashPrevBlock);
+ if (!prev_block) {
// Doesn't connect (or is genesis), instead of DoSing in AcceptBlockHeader, request deeper headers
if (!m_chainman.ActiveChainstate().IsInitialBlockDownload()) {
- MaybeSendGetHeaders(pfrom, m_chainman.ActiveChain().GetLocator(m_chainman.m_best_header), *peer);
+ MaybeSendGetHeaders(pfrom, GetLocator(m_chainman.m_best_header), *peer);
}
return;
+ } else if (prev_block->nChainWork + CalculateHeadersWork({cmpctblock.header}) < GetAntiDoSWorkThreshold()) {
+ // If we get a low-work header in a compact block, we can ignore it.
+ LogPrint(BCLog::NET, "Ignoring low-work compact block from peer %d\n", pfrom.GetId());
+ return;
}
if (!m_chainman.m_blockman.LookupBlockIndex(cmpctblock.header.GetHash())) {
@@ -3764,7 +4110,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
const CBlockIndex *pindex = nullptr;
BlockValidationState state;
- if (!m_chainman.ProcessNewBlockHeaders({cmpctblock.header}, state, &pindex)) {
+ if (!m_chainman.ProcessNewBlockHeaders({cmpctblock.header}, /*min_pow_checked=*/true, state, &pindex)) {
if (state.IsInvalid()) {
MaybePunishNodeForBlock(pfrom.GetId(), state, /*via_compact_block=*/true, "invalid header via cmpctblock");
return;
@@ -3931,7 +4277,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.
- ProcessBlock(pfrom, pblock, /*force_processing=*/true);
+ ProcessBlock(pfrom, pblock, /*force_processing=*/true, /*min_pow_checked=*/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
@@ -4014,7 +4360,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// 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.
- ProcessBlock(pfrom, pblock, /*force_processing=*/true);
+ ProcessBlock(pfrom, pblock, /*force_processing=*/true, /*min_pow_checked=*/true);
}
return;
}
@@ -4045,7 +4391,23 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
ReadCompactSize(vRecv); // ignore tx count; assume it is 0.
}
- return ProcessHeadersMessage(pfrom, *peer, headers, /*via_compact_block=*/false);
+ ProcessHeadersMessage(pfrom, *peer, std::move(headers), /*via_compact_block=*/false);
+
+ // Check if the headers presync progress needs to be reported to validation.
+ // This needs to be done without holding the m_headers_presync_mutex lock.
+ if (m_headers_presync_should_signal.exchange(false)) {
+ HeadersPresyncStats stats;
+ {
+ LOCK(m_headers_presync_mutex);
+ auto it = m_headers_presync_stats.find(m_headers_presync_bestpeer);
+ if (it != m_headers_presync_stats.end()) stats = it->second;
+ }
+ if (stats.second) {
+ m_chainman.ReportHeadersPresync(stats.first, stats.second->first, stats.second->second);
+ }
+ }
+
+ return;
}
if (msg_type == NetMsgType::BLOCK)
@@ -4063,6 +4425,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
bool forceProcessing = false;
const uint256 hash(pblock->GetHash());
+ bool min_pow_checked = false;
{
LOCK(cs_main);
// Always process the block if we requested it, since we may
@@ -4073,8 +4436,14 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// which peers send us compact blocks, so the race between here and
// cs_main in ProcessNewBlock is fine.
mapBlockSource.emplace(hash, std::make_pair(pfrom.GetId(), true));
+
+ // Check work on this block against our anti-dos thresholds.
+ const CBlockIndex* prev_block = m_chainman.m_blockman.LookupBlockIndex(pblock->hashPrevBlock);
+ if (prev_block && prev_block->nChainWork + CalculateHeadersWork({pblock->GetBlockHeader()}) >= GetAntiDoSWorkThreshold()) {
+ min_pow_checked = true;
+ }
}
- ProcessBlock(pfrom, pblock, forceProcessing);
+ ProcessBlock(pfrom, pblock, forceProcessing, min_pow_checked);
return;
}
@@ -4502,7 +4871,7 @@ void PeerManagerImpl::ConsiderEviction(CNode& pto, Peer& peer, std::chrono::seco
// getheaders in-flight already, in which case the peer should
// still respond to us with a sufficiently high work chain tip.
MaybeSendGetHeaders(pto,
- m_chainman.ActiveChain().GetLocator(state.m_chain_sync.m_work_header->pprev),
+ GetLocator(state.m_chain_sync.m_work_header->pprev),
peer);
LogPrint(BCLog::NET, "sending getheaders to outbound peer=%d to verify chain work (current best known block:%s, benchmark blockhash: %s)\n", pto.GetId(), state.pindexBestKnownBlock != nullptr ? state.pindexBestKnownBlock->GetBlockHash().ToString() : "<none>", state.m_chain_sync.m_work_header->GetBlockHash().ToString());
state.m_chain_sync.m_sent_getheaders = true;
@@ -4759,6 +5128,27 @@ void PeerManagerImpl::MaybeSendAddr(CNode& node, Peer& peer, std::chrono::micros
}
}
+void PeerManagerImpl::MaybeSendSendHeaders(CNode& node, Peer& peer)
+{
+ // Delay sending SENDHEADERS (BIP 130) until we're done with an
+ // initial-headers-sync with this peer. Receiving headers announcements for
+ // new blocks while trying to sync their headers chain is problematic,
+ // because of the state tracking done.
+ if (!peer.m_sent_sendheaders && node.GetCommonVersion() >= SENDHEADERS_VERSION) {
+ LOCK(cs_main);
+ CNodeState &state = *State(node.GetId());
+ if (state.pindexBestKnownBlock != nullptr &&
+ state.pindexBestKnownBlock->nChainWork > nMinimumChainWork) {
+ // Tell our peer we prefer to receive headers rather than inv's
+ // We send this to non-NODE NETWORK peers as well, because even
+ // non-NODE NETWORK peers can announce blocks (such as pruning
+ // nodes)
+ m_connman.PushMessage(&node, CNetMsgMaker(node.GetCommonVersion()).Make(NetMsgType::SENDHEADERS));
+ peer.m_sent_sendheaders = true;
+ }
+ }
+}
+
void PeerManagerImpl::MaybeSendFeefilter(CNode& pto, Peer& peer, std::chrono::microseconds current_time)
{
if (m_ignore_incoming_txs) return;
@@ -4880,6 +5270,8 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
MaybeSendAddr(*pto, *peer, current_time);
+ MaybeSendSendHeaders(*pto, *peer);
+
{
LOCK(cs_main);
@@ -4924,7 +5316,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
got back an empty response. */
if (pindexStart->pprev)
pindexStart = pindexStart->pprev;
- if (MaybeSendGetHeaders(*pto, m_chainman.ActiveChain().GetLocator(pindexStart), *peer)) {
+ if (MaybeSendGetHeaders(*pto, GetLocator(pindexStart), *peer)) {
LogPrint(BCLog::NET, "initial getheaders (%d) to peer=%d (startheight:%d)\n", pindexStart->nHeight, pto->GetId(), peer->m_starting_height);
state.fSyncStarted = true;
diff --git a/src/net_processing.h b/src/net_processing.h
index bcda9614d4..0a882b1e53 100644
--- a/src/net_processing.h
+++ b/src/net_processing.h
@@ -35,6 +35,7 @@ struct CNodeStateStats {
uint64_t m_addr_rate_limited = 0;
bool m_addr_relay_enabled{false};
ServiceFlags their_services;
+ int64_t presync_height{-1};
};
class PeerManager : public CValidationInterface, public NetEventsInterface
diff --git a/src/node/blockstorage.cpp b/src/node/blockstorage.cpp
index 42b6b017fe..57f81e6bb6 100644
--- a/src/node/blockstorage.cpp
+++ b/src/node/blockstorage.cpp
@@ -882,7 +882,7 @@ void ThreadImport(ChainstateManager& chainman, std::vector<fs::path> vImportFile
// 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())) {
+ for (Chainstate* chainstate : WITH_LOCK(::cs_main, return chainman.GetAll())) {
BlockValidationState state;
if (!chainstate->ActivateBestChain(state, nullptr)) {
LogPrintf("Failed to connect best block (%s)\n", state.ToString());
diff --git a/src/node/blockstorage.h b/src/node/blockstorage.h
index 9b76371aae..37d74ed102 100644
--- a/src/node/blockstorage.h
+++ b/src/node/blockstorage.h
@@ -26,7 +26,7 @@ class CBlockFileInfo;
class CBlockUndo;
class CChain;
class CChainParams;
-class CChainState;
+class Chainstate;
class ChainstateManager;
struct CCheckpointData;
struct FlatFilePos;
@@ -75,12 +75,12 @@ struct PruneLockInfo {
* Maintains a tree of blocks (stored in `m_block_index`) which is consulted
* to determine where the most-work tip is.
*
- * This data is used mostly in `CChainState` - information about, e.g.,
+ * This data is used mostly in `Chainstate` - information about, e.g.,
* candidate tips is not maintained here.
*/
class BlockManager
{
- friend CChainState;
+ friend Chainstate;
friend ChainstateManager;
private:
diff --git a/src/node/chainstate.cpp b/src/node/chainstate.cpp
index ad9293f172..3f1d6dd743 100644
--- a/src/node/chainstate.cpp
+++ b/src/node/chainstate.cpp
@@ -28,10 +28,25 @@ namespace node {
ChainstateLoadResult LoadChainstate(ChainstateManager& chainman, const CacheSizes& cache_sizes,
const ChainstateLoadOptions& options)
{
- auto is_coinsview_empty = [&](CChainState* chainstate) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
+ auto is_coinsview_empty = [&](Chainstate* chainstate) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
return options.reindex || options.reindex_chainstate || chainstate->CoinsTip().GetBestBlock().IsNull();
};
+ if (!hashAssumeValid.IsNull()) {
+ LogPrintf("Assuming ancestors of block %s have valid signatures.\n", hashAssumeValid.GetHex());
+ } else {
+ LogPrintf("Validating signatures for all blocks.\n");
+ }
+ LogPrintf("Setting nMinimumChainWork=%s\n", nMinimumChainWork.GetHex());
+ if (nMinimumChainWork < UintToArith256(chainman.GetConsensus().nMinimumChainWork)) {
+ LogPrintf("Warning: nMinimumChainWork set below default value of %s\n", chainman.GetConsensus().nMinimumChainWork.GetHex());
+ }
+ if (nPruneTarget == std::numeric_limits<uint64_t>::max()) {
+ LogPrintf("Block pruning enabled. Use RPC call pruneblockchain(height) to manually prune block and undo files.\n");
+ } else if (nPruneTarget) {
+ LogPrintf("Prune configured to target %u MiB on disk for block and undo files.\n", nPruneTarget / 1024 / 1024);
+ }
+
LOCK(cs_main);
chainman.InitializeChainstate(options.mempool);
chainman.m_total_coinstip_cache = cache_sizes.coins;
@@ -86,7 +101,7 @@ ChainstateLoadResult LoadChainstate(ChainstateManager& chainman, const CacheSize
// At this point we're either in reindex or we've loaded a useful
// block tree into BlockIndex()!
- for (CChainState* chainstate : chainman.GetAll()) {
+ for (Chainstate* chainstate : chainman.GetAll()) {
chainstate->InitCoinsDB(
/*cache_size_bytes=*/cache_sizes.coins_db,
/*in_memory=*/options.coins_db_in_memory,
@@ -125,7 +140,7 @@ ChainstateLoadResult LoadChainstate(ChainstateManager& chainman, const CacheSize
if (!options.reindex) {
auto chainstates{chainman.GetAll()};
if (std::any_of(chainstates.begin(), chainstates.end(),
- [](const CChainState* cs) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { return cs->NeedsRedownload(); })) {
+ [](const Chainstate* cs) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { return cs->NeedsRedownload(); })) {
return {ChainstateLoadStatus::FAILURE, strprintf(_("Witness data for blocks after height %d requires validation. Please restart with -reindex."),
chainman.GetConsensus().SegwitHeight)};
};
@@ -136,13 +151,13 @@ ChainstateLoadResult LoadChainstate(ChainstateManager& chainman, const CacheSize
ChainstateLoadResult VerifyLoadedChainstate(ChainstateManager& chainman, const ChainstateLoadOptions& options)
{
- auto is_coinsview_empty = [&](CChainState* chainstate) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
+ auto is_coinsview_empty = [&](Chainstate* chainstate) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
return options.reindex || options.reindex_chainstate || chainstate->CoinsTip().GetBestBlock().IsNull();
};
LOCK(cs_main);
- for (CChainState* chainstate : chainman.GetAll()) {
+ for (Chainstate* chainstate : chainman.GetAll()) {
if (!is_coinsview_empty(chainstate)) {
const CBlockIndex* tip = chainstate->m_chain.Tip();
if (tip && tip->nTime > GetTime() + MAX_FUTURE_BLOCK_TIME) {
diff --git a/src/node/interface_ui.cpp b/src/node/interface_ui.cpp
index 370cde84f8..fa90d6fda7 100644
--- a/src/node/interface_ui.cpp
+++ b/src/node/interface_ui.cpp
@@ -53,7 +53,7 @@ void CClientUIInterface::NotifyNetworkActiveChanged(bool networkActive) { return
void CClientUIInterface::NotifyAlertChanged() { return g_ui_signals.NotifyAlertChanged(); }
void CClientUIInterface::ShowProgress(const std::string& title, int nProgress, bool resume_possible) { return g_ui_signals.ShowProgress(title, nProgress, resume_possible); }
void CClientUIInterface::NotifyBlockTip(SynchronizationState s, const CBlockIndex* i) { return g_ui_signals.NotifyBlockTip(s, i); }
-void CClientUIInterface::NotifyHeaderTip(SynchronizationState s, const CBlockIndex* i) { return g_ui_signals.NotifyHeaderTip(s, i); }
+void CClientUIInterface::NotifyHeaderTip(SynchronizationState s, int64_t height, int64_t timestamp, bool presync) { return g_ui_signals.NotifyHeaderTip(s, height, timestamp, presync); }
void CClientUIInterface::BannedListChanged() { return g_ui_signals.BannedListChanged(); }
bool InitError(const bilingual_str& str)
diff --git a/src/node/interface_ui.h b/src/node/interface_ui.h
index 37c0f6392b..316d75167e 100644
--- a/src/node/interface_ui.h
+++ b/src/node/interface_ui.h
@@ -105,7 +105,7 @@ public:
ADD_SIGNALS_DECL_WRAPPER(NotifyBlockTip, void, SynchronizationState, const CBlockIndex*);
/** Best header has changed */
- ADD_SIGNALS_DECL_WRAPPER(NotifyHeaderTip, void, SynchronizationState, const CBlockIndex*);
+ ADD_SIGNALS_DECL_WRAPPER(NotifyHeaderTip, void, SynchronizationState, int64_t height, int64_t timestamp, bool presync);
/** Banlist did change. */
ADD_SIGNALS_DECL_WRAPPER(BannedListChanged, void, void);
diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp
index 2c845d0127..aa7ddec770 100644
--- a/src/node/interfaces.cpp
+++ b/src/node/interfaces.cpp
@@ -377,9 +377,8 @@ public:
std::unique_ptr<Handler> handleNotifyHeaderTip(NotifyHeaderTipFn fn) override
{
return MakeHandler(
- ::uiInterface.NotifyHeaderTip_connect([fn](SynchronizationState sync_state, const CBlockIndex* block) {
- fn(sync_state, BlockTip{block->nHeight, block->GetBlockTime(), block->GetBlockHash()},
- /* verification progress is unused when a header was received */ 0);
+ ::uiInterface.NotifyHeaderTip_connect([fn](SynchronizationState sync_state, int64_t height, int64_t timestamp, bool presync) {
+ fn(sync_state, BlockTip{(int)height, timestamp, uint256{}}, presync);
}));
}
NodeContext* context() override { return m_context; }
@@ -400,7 +399,7 @@ bool FillBlock(const CBlockIndex* index, const FoundBlock& block, UniqueLock<Rec
if (block.m_max_time) *block.m_max_time = index->GetBlockTimeMax();
if (block.m_mtp_time) *block.m_mtp_time = index->GetMedianTimePast();
if (block.m_in_active_chain) *block.m_in_active_chain = active[index->nHeight] == index;
- if (block.m_locator) { *block.m_locator = active.GetLocator(index); }
+ if (block.m_locator) { *block.m_locator = GetLocator(index); }
if (block.m_next_block) FillBlock(active[index->nHeight] == index ? active[index->nHeight + 1] : nullptr, *block.m_next_block, lock, active);
if (block.m_data) {
REVERSE_LOCK(lock);
@@ -527,8 +526,7 @@ public:
{
LOCK(::cs_main);
const CBlockIndex* index = chainman().m_blockman.LookupBlockIndex(block_hash);
- if (!index) return {};
- return chainman().ActiveChain().GetLocator(index);
+ return GetLocator(index);
}
std::optional<int> findLocatorFork(const CBlockLocator& locator) override
{
diff --git a/src/node/mempool_args.cpp b/src/node/mempool_args.cpp
index cb2466804a..8c929e5e0d 100644
--- a/src/node/mempool_args.cpp
+++ b/src/node/mempool_args.cpp
@@ -12,6 +12,7 @@
#include <logging.h>
#include <policy/feerate.h>
#include <policy/policy.h>
+#include <script/standard.h>
#include <tinyformat.h>
#include <util/error.h>
#include <util/moneystr.h>
diff --git a/src/node/miner.cpp b/src/node/miner.cpp
index f04742deeb..b277188c1f 100644
--- a/src/node/miner.cpp
+++ b/src/node/miner.cpp
@@ -62,7 +62,7 @@ BlockAssembler::Options::Options()
nBlockMaxWeight = DEFAULT_BLOCK_MAX_WEIGHT;
}
-BlockAssembler::BlockAssembler(CChainState& chainstate, const CTxMemPool* mempool, const Options& options)
+BlockAssembler::BlockAssembler(Chainstate& chainstate, const CTxMemPool* mempool, const Options& options)
: chainparams{chainstate.m_chainman.GetParams()},
m_mempool(mempool),
m_chainstate(chainstate)
@@ -87,7 +87,7 @@ static BlockAssembler::Options DefaultOptions()
return options;
}
-BlockAssembler::BlockAssembler(CChainState& chainstate, const CTxMemPool* mempool)
+BlockAssembler::BlockAssembler(Chainstate& chainstate, const CTxMemPool* mempool)
: BlockAssembler(chainstate, mempool, DefaultOptions()) {}
void BlockAssembler::resetBlock()
diff --git a/src/node/miner.h b/src/node/miner.h
index 26454df3df..7269ce1186 100644
--- a/src/node/miner.h
+++ b/src/node/miner.h
@@ -148,7 +148,7 @@ private:
const CChainParams& chainparams;
const CTxMemPool* const m_mempool;
- CChainState& m_chainstate;
+ Chainstate& m_chainstate;
public:
struct Options {
@@ -157,8 +157,8 @@ public:
CFeeRate blockMinFeeRate;
};
- explicit BlockAssembler(CChainState& chainstate, const CTxMemPool* mempool);
- explicit BlockAssembler(CChainState& chainstate, const CTxMemPool* mempool, const Options& options);
+ explicit BlockAssembler(Chainstate& chainstate, const CTxMemPool* mempool);
+ explicit BlockAssembler(Chainstate& chainstate, const CTxMemPool* mempool, const Options& options);
/** Construct a new block template with coinbase to scriptPubKeyIn */
std::unique_ptr<CBlockTemplate> CreateNewBlock(const CScript& scriptPubKeyIn);
diff --git a/src/node/utxo_snapshot.h b/src/node/utxo_snapshot.h
index 401d4baaeb..9dd6f06997 100644
--- a/src/node/utxo_snapshot.h
+++ b/src/node/utxo_snapshot.h
@@ -11,7 +11,7 @@
namespace node {
//! Metadata describing a serialized version of a UTXO set from which an
-//! assumeutxo CChainState can be constructed.
+//! assumeutxo Chainstate can be constructed.
class SnapshotMetadata
{
public:
diff --git a/src/pow.cpp b/src/pow.cpp
index 1414d37564..c0449cac74 100644
--- a/src/pow.cpp
+++ b/src/pow.cpp
@@ -71,6 +71,57 @@ unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nF
return bnNew.GetCompact();
}
+// Check that on difficulty adjustments, the new difficulty does not increase
+// or decrease beyond the permitted limits.
+bool PermittedDifficultyTransition(const Consensus::Params& params, int64_t height, uint32_t old_nbits, uint32_t new_nbits)
+{
+ if (params.fPowAllowMinDifficultyBlocks) return true;
+
+ if (height % params.DifficultyAdjustmentInterval() == 0) {
+ int64_t smallest_timespan = params.nPowTargetTimespan/4;
+ int64_t largest_timespan = params.nPowTargetTimespan*4;
+
+ const arith_uint256 pow_limit = UintToArith256(params.powLimit);
+ arith_uint256 observed_new_target;
+ observed_new_target.SetCompact(new_nbits);
+
+ // Calculate the largest difficulty value possible:
+ arith_uint256 largest_difficulty_target;
+ largest_difficulty_target.SetCompact(old_nbits);
+ largest_difficulty_target *= largest_timespan;
+ largest_difficulty_target /= params.nPowTargetTimespan;
+
+ if (largest_difficulty_target > pow_limit) {
+ largest_difficulty_target = pow_limit;
+ }
+
+ // Round and then compare this new calculated value to what is
+ // observed.
+ arith_uint256 maximum_new_target;
+ maximum_new_target.SetCompact(largest_difficulty_target.GetCompact());
+ if (maximum_new_target < observed_new_target) return false;
+
+ // Calculate the smallest difficulty value possible:
+ arith_uint256 smallest_difficulty_target;
+ smallest_difficulty_target.SetCompact(old_nbits);
+ smallest_difficulty_target *= smallest_timespan;
+ smallest_difficulty_target /= params.nPowTargetTimespan;
+
+ if (smallest_difficulty_target > pow_limit) {
+ smallest_difficulty_target = pow_limit;
+ }
+
+ // Round and then compare this new calculated value to what is
+ // observed.
+ arith_uint256 minimum_new_target;
+ minimum_new_target.SetCompact(smallest_difficulty_target.GetCompact());
+ if (minimum_new_target > observed_new_target) return false;
+ } else if (old_nbits != new_nbits) {
+ return false;
+ }
+ return true;
+}
+
bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params& params)
{
bool fNegative;
diff --git a/src/pow.h b/src/pow.h
index 1d802cd01e..44b9d673ef 100644
--- a/src/pow.h
+++ b/src/pow.h
@@ -20,4 +20,18 @@ unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nF
/** Check whether a block hash satisfies the proof-of-work requirement specified by nBits */
bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params&);
+/**
+ * Return false if the proof-of-work requirement specified by new_nbits at a
+ * given height is not possible, given the proof-of-work on the prior block as
+ * specified by old_nbits.
+ *
+ * This function only checks that the new value is within a factor of 4 of the
+ * old value for blocks at the difficulty adjustment interval, and otherwise
+ * requires the values to be the same.
+ *
+ * Always returns true on networks where min difficulty blocks are allowed,
+ * such as regtest/testnet.
+ */
+bool PermittedDifficultyTransition(const Consensus::Params& params, int64_t height, uint32_t old_nbits, uint32_t new_nbits);
+
#endif // BITCOIN_POW_H
diff --git a/src/primitives/block.h b/src/primitives/block.h
index 76aba6c899..2e26e6c426 100644
--- a/src/primitives/block.h
+++ b/src/primitives/block.h
@@ -123,7 +123,7 @@ struct CBlockLocator
CBlockLocator() {}
- explicit CBlockLocator(const std::vector<uint256>& vHaveIn) : vHave(vHaveIn) {}
+ explicit CBlockLocator(std::vector<uint256>&& have) : vHave(std::move(have)) {}
SERIALIZE_METHODS(CBlockLocator, obj)
{
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 33c60deafb..cc01e4d54a 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -75,6 +75,7 @@ Q_IMPORT_PLUGIN(QAndroidPlatformIntegrationPlugin)
Q_DECLARE_METATYPE(bool*)
Q_DECLARE_METATYPE(CAmount)
Q_DECLARE_METATYPE(SynchronizationState)
+Q_DECLARE_METATYPE(SyncType)
Q_DECLARE_METATYPE(uint256)
static void RegisterMetaTypes()
@@ -82,6 +83,7 @@ static void RegisterMetaTypes()
// Register meta types used for QMetaObject::invokeMethod and Qt::QueuedConnection
qRegisterMetaType<bool*>();
qRegisterMetaType<SynchronizationState>();
+ qRegisterMetaType<SyncType>();
#ifdef ENABLE_WALLET
qRegisterMetaType<WalletModel*>();
#endif
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index 90f228803c..894a401e56 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -431,7 +431,7 @@ void BitcoinGUI::createActions()
bool wallet_name_ok;
/*: Title of pop-up window shown when the user is attempting to
-+ restore a wallet. */
+ restore a wallet. */
QString title = tr("Restore Wallet");
//: Label of the input field where the name of the wallet is entered.
QString label = tr("Wallet Name");
@@ -615,8 +615,8 @@ void BitcoinGUI::setClientModel(ClientModel *_clientModel, interfaces::BlockAndH
connect(_clientModel, &ClientModel::numConnectionsChanged, this, &BitcoinGUI::setNumConnections);
connect(_clientModel, &ClientModel::networkActiveChanged, this, &BitcoinGUI::setNetworkActive);
- modalOverlay->setKnownBestHeight(tip_info->header_height, QDateTime::fromSecsSinceEpoch(tip_info->header_time));
- setNumBlocks(tip_info->block_height, QDateTime::fromSecsSinceEpoch(tip_info->block_time), tip_info->verification_progress, false, SynchronizationState::INIT_DOWNLOAD);
+ modalOverlay->setKnownBestHeight(tip_info->header_height, QDateTime::fromSecsSinceEpoch(tip_info->header_time), /*presync=*/false);
+ setNumBlocks(tip_info->block_height, QDateTime::fromSecsSinceEpoch(tip_info->block_time), tip_info->verification_progress, SyncType::BLOCK_SYNC, SynchronizationState::INIT_DOWNLOAD);
connect(_clientModel, &ClientModel::numBlocksChanged, this, &BitcoinGUI::setNumBlocks);
// Receive and report messages from client model
@@ -1026,6 +1026,13 @@ void BitcoinGUI::updateHeadersSyncProgressLabel()
progressBarLabel->setText(tr("Syncing Headers (%1%)…").arg(QString::number(100.0 / (headersTipHeight+estHeadersLeft)*headersTipHeight, 'f', 1)));
}
+void BitcoinGUI::updateHeadersPresyncProgressLabel(int64_t height, const QDateTime& blockDate)
+{
+ int estHeadersLeft = blockDate.secsTo(QDateTime::currentDateTime()) / Params().GetConsensus().nPowTargetSpacing;
+ if (estHeadersLeft > HEADER_HEIGHT_DELTA_SYNC)
+ progressBarLabel->setText(tr("Pre-syncing Headers (%1%)…").arg(QString::number(100.0 / (height+estHeadersLeft)*height, 'f', 1)));
+}
+
void BitcoinGUI::openOptionsDialogWithTab(OptionsDialog::Tab tab)
{
if (!clientModel || !clientModel->getOptionsModel())
@@ -1039,7 +1046,7 @@ void BitcoinGUI::openOptionsDialogWithTab(OptionsDialog::Tab tab)
GUIUtil::ShowModalDialogAsynchronously(dlg);
}
-void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, bool header, SynchronizationState sync_state)
+void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, SyncType synctype, SynchronizationState sync_state)
{
// Disabling macOS App Nap on initial sync, disk and reindex operations.
#ifdef Q_OS_MACOS
@@ -1052,8 +1059,8 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVer
if (modalOverlay)
{
- if (header)
- modalOverlay->setKnownBestHeight(count, blockDate);
+ if (synctype != SyncType::BLOCK_SYNC)
+ modalOverlay->setKnownBestHeight(count, blockDate, synctype == SyncType::HEADER_PRESYNC);
else
modalOverlay->tipUpdate(count, blockDate, nVerificationProgress);
}
@@ -1067,7 +1074,10 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVer
enum BlockSource blockSource = clientModel->getBlockSource();
switch (blockSource) {
case BlockSource::NETWORK:
- if (header) {
+ if (synctype == SyncType::HEADER_PRESYNC) {
+ updateHeadersPresyncProgressLabel(count, blockDate);
+ return;
+ } else if (synctype == SyncType::HEADER_SYNC) {
updateHeadersSyncProgressLabel();
return;
}
@@ -1075,7 +1085,7 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVer
updateHeadersSyncProgressLabel();
break;
case BlockSource::DISK:
- if (header) {
+ if (synctype != SyncType::BLOCK_SYNC) {
progressBarLabel->setText(tr("Indexing blocks on disk…"));
} else {
progressBarLabel->setText(tr("Processing blocks on disk…"));
@@ -1085,7 +1095,7 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVer
progressBarLabel->setText(tr("Reindexing blocks on disk…"));
break;
case BlockSource::NONE:
- if (header) {
+ if (synctype != SyncType::BLOCK_SYNC) {
return;
}
progressBarLabel->setText(tr("Connecting to peers…"));
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index b2e13245e1..912e9b95aa 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -10,6 +10,7 @@
#endif
#include <qt/bitcoinunits.h>
+#include <qt/clientmodel.h>
#include <qt/guiutil.h>
#include <qt/optionsdialog.h>
@@ -28,7 +29,6 @@
#include <memory>
-class ClientModel;
class NetworkStyle;
class Notificator;
class OptionsModel;
@@ -208,6 +208,7 @@ private:
void updateNetworkState();
void updateHeadersSyncProgressLabel();
+ void updateHeadersPresyncProgressLabel(int64_t height, const QDateTime& blockDate);
/** Open the OptionsDialog on the specified tab index */
void openOptionsDialogWithTab(OptionsDialog::Tab tab);
@@ -226,7 +227,7 @@ public Q_SLOTS:
/** Set network state shown in the UI */
void setNetworkActive(bool network_active);
/** Set number of blocks and last block date shown in the UI */
- void setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, bool headers, SynchronizationState sync_state);
+ void setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, SyncType synctype, SynchronizationState sync_state);
/** Notify the user of an event from the core network or transaction handling code.
@param[in] title the message box / notification title
diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp
index 13694c638d..3df4d4d921 100644
--- a/src/qt/bitcoinstrings.cpp
+++ b/src/qt/bitcoinstrings.cpp
@@ -60,6 +60,9 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"Error reading %s! Transaction data may be missing or incorrect. Rescanning "
"wallet."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
+"Error: Address book data in wallet cannot be identified to belong to "
+"migrated wallets"),
+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\"."),
@@ -67,9 +70,18 @@ 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: Duplicate descriptors created during migration. Your wallet may be "
+"corrupted."),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
"Error: Legacy wallets only support the \"legacy\", \"p2sh-segwit\", and "
"\"bech32\" address types"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
+"Error: Transaction %s in wallet cannot be identified to belong to migrated "
+"wallets"),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
+"Error: Unable to produce descriptors for this legacy wallet. Make sure the "
+"wallet is unlocked first"),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
"Failed to rename invalid peers.dat file. Please move or delete it and try "
"again."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
@@ -79,6 +91,9 @@ 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", ""
+"Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet "
+"forbids connections to IPv4/IPv6"),
+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", ""
@@ -98,8 +113,11 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"be provided."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Outbound connections restricted to Tor (-onlynet=onion) but the proxy for "
-"reaching the Tor network is not provided (no -proxy= and no -onion= given) "
-"or it is explicitly forbidden (-onion=0)"),
+"reaching the Tor network is explicitly forbidden: -onion=0"),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
+"Outbound connections restricted to Tor (-onlynet=onion) but the proxy for "
+"reaching the Tor network is not provided: none of -proxy, -onion or -"
+"listenonion is given"),
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."),
@@ -156,6 +174,14 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"Unknown wallet file format \"%s\" provided. Please provide one of \"bdb\" or "
"\"sqlite\"."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
+"Unrecognized descriptor found. Loading wallet %s\n"
+"\n"
+"The wallet might had been created on a newer version.\n"
+"Please try running the latest software version.\n"),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
+"Unsupported category-specific logging level -loglevel=%s. Expected -"
+"loglevel=<category>:<loglevel>. Valid categories: %s. Valid loglevels: %s."),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
"Unsupported chainstate database format found. Please restart with -reindex-"
"chainstate. This will rebuild the chainstate database."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
@@ -176,6 +202,12 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
QT_TRANSLATE_NOOP("bitcoin-core", ""
"You need to rebuild the database using -reindex to go back to unpruned "
"mode. This will redownload the entire blockchain"),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
+"\n"
+"Unable to cleanup failed migration"),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
+"\n"
+"Unable to restore backup of wallet."),
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"),
@@ -203,15 +235,25 @@ 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: Could not add watchonly tx to watchonly wallet"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Error: Could not delete watchonly transactions"),
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: Failed to create new watchonly wallet"),
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: No %s addresses available."),
+QT_TRANSLATE_NOOP("bitcoin-core", "Error: Not all watchonly txs could be deleted"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Error: This wallet already uses SQLite"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Error: This wallet is already a descriptor wallet"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Error: Unable to begin reading all records in the database"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Error: Unable to make a backup of your wallet"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error: Unable to parse version %u as a uint32_t"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Error: Unable to read all records in the database"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Error: Unable to remove watchonly address book data"),
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"),
@@ -277,16 +319,19 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Unable to allocate memory for -maxsigcachesiz
QT_TRANSLATE_NOOP("bitcoin-core", "Unable to bind to %s on this computer (bind returned error %s)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Unable to bind to %s on this computer. %s is probably already running."),
QT_TRANSLATE_NOOP("bitcoin-core", "Unable to create the PID file '%s': %s"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Unable to find UTXO for external input"),
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 parse -maxuploadtarget: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Unable to start HTTP server. See debug log for details."),
+QT_TRANSLATE_NOOP("bitcoin-core", "Unable to unload the wallet before migrating"),
QT_TRANSLATE_NOOP("bitcoin-core", "Unknown -blockfilterindex value %s."),
QT_TRANSLATE_NOOP("bitcoin-core", "Unknown address type '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Unknown change type '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Unknown network specified in -onlynet: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Unknown new rules activated (versionbit %i)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Unsupported global logging level -loglevel=%s. Valid values: %s."),
QT_TRANSLATE_NOOP("bitcoin-core", "Unsupported logging category %s=%s."),
QT_TRANSLATE_NOOP("bitcoin-core", "User Agent comment (%s) contains unsafe characters."),
QT_TRANSLATE_NOOP("bitcoin-core", "Verifying blocks…"),
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index f41da519df..092ffe7e5b 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -215,26 +215,26 @@ QString ClientModel::blocksDir() const
return GUIUtil::PathToQString(gArgs.GetBlocksDirPath());
}
-void ClientModel::TipChanged(SynchronizationState sync_state, interfaces::BlockTip tip, double verification_progress, bool header)
+void ClientModel::TipChanged(SynchronizationState sync_state, interfaces::BlockTip tip, double verification_progress, SyncType synctype)
{
- if (header) {
+ if (synctype == SyncType::HEADER_SYNC) {
// cache best headers time and height to reduce future cs_main locks
cachedBestHeaderHeight = tip.block_height;
cachedBestHeaderTime = tip.block_time;
- } else {
+ } else if (synctype == SyncType::BLOCK_SYNC) {
m_cached_num_blocks = tip.block_height;
WITH_LOCK(m_cached_tip_mutex, m_cached_tip_blocks = tip.block_hash;);
}
// Throttle GUI notifications about (a) blocks during initial sync, and (b) both blocks and headers during reindex.
- const bool throttle = (sync_state != SynchronizationState::POST_INIT && !header) || sync_state == SynchronizationState::INIT_REINDEX;
+ const bool throttle = (sync_state != SynchronizationState::POST_INIT && synctype == SyncType::BLOCK_SYNC) || sync_state == SynchronizationState::INIT_REINDEX;
const int64_t now = throttle ? GetTimeMillis() : 0;
- int64_t& nLastUpdateNotification = header ? nLastHeaderTipUpdateNotification : nLastBlockTipUpdateNotification;
+ int64_t& nLastUpdateNotification = synctype != SyncType::BLOCK_SYNC ? nLastHeaderTipUpdateNotification : nLastBlockTipUpdateNotification;
if (throttle && now < nLastUpdateNotification + count_milliseconds(MODEL_UPDATE_DELAY)) {
return;
}
- Q_EMIT numBlocksChanged(tip.block_height, QDateTime::fromSecsSinceEpoch(tip.block_time), verification_progress, header, sync_state);
+ Q_EMIT numBlocksChanged(tip.block_height, QDateTime::fromSecsSinceEpoch(tip.block_time), verification_progress, synctype, sync_state);
nLastUpdateNotification = now;
}
@@ -264,11 +264,11 @@ void ClientModel::subscribeToCoreSignals()
});
m_handler_notify_block_tip = m_node.handleNotifyBlockTip(
[this](SynchronizationState sync_state, interfaces::BlockTip tip, double verification_progress) {
- TipChanged(sync_state, tip, verification_progress, /*header=*/false);
+ TipChanged(sync_state, tip, verification_progress, SyncType::BLOCK_SYNC);
});
m_handler_notify_header_tip = m_node.handleNotifyHeaderTip(
- [this](SynchronizationState sync_state, interfaces::BlockTip tip, double verification_progress) {
- TipChanged(sync_state, tip, verification_progress, /*header=*/true);
+ [this](SynchronizationState sync_state, interfaces::BlockTip tip, bool presync) {
+ TipChanged(sync_state, tip, /*verification_progress=*/0.0, presync ? SyncType::HEADER_PRESYNC : SyncType::HEADER_SYNC);
});
}
diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h
index 81f03a58ec..4a6abd6a76 100644
--- a/src/qt/clientmodel.h
+++ b/src/qt/clientmodel.h
@@ -37,6 +37,12 @@ enum class BlockSource {
NETWORK
};
+enum class SyncType {
+ HEADER_PRESYNC,
+ HEADER_SYNC,
+ BLOCK_SYNC
+};
+
enum NumConnections {
CONNECTIONS_NONE = 0,
CONNECTIONS_IN = (1U << 0),
@@ -105,13 +111,13 @@ private:
//! A thread to interact with m_node asynchronously
QThread* const m_thread;
- void TipChanged(SynchronizationState sync_state, interfaces::BlockTip tip, double verification_progress, bool header) EXCLUSIVE_LOCKS_REQUIRED(!m_cached_tip_mutex);
+ void TipChanged(SynchronizationState sync_state, interfaces::BlockTip tip, double verification_progress, SyncType synctype) EXCLUSIVE_LOCKS_REQUIRED(!m_cached_tip_mutex);
void subscribeToCoreSignals();
void unsubscribeFromCoreSignals();
Q_SIGNALS:
void numConnectionsChanged(int count);
- void numBlocksChanged(int count, const QDateTime& blockDate, double nVerificationProgress, bool header, SynchronizationState sync_state);
+ void numBlocksChanged(int count, const QDateTime& blockDate, double nVerificationProgress, SyncType header, SynchronizationState sync_state);
void mempoolSizeChanged(long count, size_t mempoolSizeInBytes);
void networkActiveChanged(bool networkActive);
void alertsChanged(const QString &warnings);
diff --git a/src/qt/forms/intro.ui b/src/qt/forms/intro.ui
index a1e94f99e6..9ab91f6aa9 100644
--- a/src/qt/forms/intro.ui
+++ b/src/qt/forms/intro.ui
@@ -203,7 +203,7 @@
<item>
<widget class="QLabel" name="lblExplanation1">
<property name="text">
- <string>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.</string>
+ <string>When you click OK, %1 will begin to download and process the full %4 block chain (%2 GB) starting with the earliest transactions in %3 when %4 initially launched.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index 5cc21dd40b..b9f0be41e3 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -982,7 +982,7 @@ void PrintSlotException(
std::string description = sender->metaObject()->className();
description += "->";
description += receiver->metaObject()->className();
- PrintExceptionContinue(exception, description.c_str());
+ PrintExceptionContinue(exception, description);
}
void ShowModalDialogAsynchronously(QDialog* dialog)
diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts
index 0fe69051a4..586240445e 100644
--- a/src/qt/locale/bitcoin_en.ts
+++ b/src/qt/locale/bitcoin_en.ts
@@ -313,7 +313,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<context>
<name>BitcoinApplication</name>
<message>
- <location filename="../bitcoin.cpp" line="+286"/>
+ <location filename="../bitcoin.cpp" line="+288"/>
<source>Settings file %1 might be corrupt or invalid.</source>
<translation type="unfinished"></translation>
</message>
@@ -417,12 +417,12 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+429"/>
+ <location line="+439"/>
<source>Proxy is &lt;b&gt;enabled&lt;/b&gt;: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-1150"/>
+ <location line="-1160"/>
<source>Send coins to a Bitcoin address</source>
<translation>Send coins to a Bitcoin address</translation>
</message>
@@ -542,7 +542,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+48"/>
+ <location line="+58"/>
<source>Synchronizing with network…</source>
<translation type="unfinished"></translation>
</message>
@@ -567,7 +567,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-823"/>
+ <location line="-833"/>
<source>Request payments (generates QR codes and bitcoin: URIs)</source>
<translation type="unfinished"></translation>
</message>
@@ -587,7 +587,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
- <location line="+739"/>
+ <location line="+749"/>
<source>Processed %n block(s) of transaction history.</source>
<translation>
<numerusform>Processed %n block of transaction history.</numerusform>
@@ -635,7 +635,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation>Up to date</translation>
</message>
<message>
- <location line="-808"/>
+ <location line="-818"/>
<source>Ctrl+Q</source>
<translation type="unfinished"></translation>
</message>
@@ -751,7 +751,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<message>
<location line="+8"/>
<source>Restore Wallet</source>
- <extracomment>Title of pop-up window shown when the user is attempting to + restore a wallet.</extracomment>
+ <extracomment>Title of pop-up window shown when the user is attempting to restore a wallet.</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
@@ -829,7 +829,12 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+159"/>
+ <location line="+17"/>
+ <source>Pre-syncing Headers (%1%)…</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+152"/>
<source>Error: %1</source>
<translation type="unfinished"></translation>
</message>
@@ -1365,12 +1370,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+157"/>
- <source>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>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+32"/>
+ <location line="+189"/>
<source>Limit block chain storage to</source>
<translation type="unfinished"></translation>
</message>
@@ -1390,7 +1390,12 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+10"/>
+ <location line="-10"/>
+ <source>When you click OK, %1 will begin to download and process the full %4 block chain (%2 GB) starting with the earliest transactions in %3 when %4 initially launched.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+20"/>
<source>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>
<translation type="unfinished"></translation>
</message>
@@ -1513,7 +1518,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<message>
<location line="+7"/>
<location line="+26"/>
- <location filename="../modaloverlay.cpp" line="+152"/>
+ <location filename="../modaloverlay.cpp" line="+155"/>
<source>Unknown…</source>
<translation type="unfinished"></translation>
</message>
@@ -1554,15 +1559,20 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../modaloverlay.cpp" line="-118"/>
+ <location filename="../modaloverlay.cpp" line="-121"/>
<source>%1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+124"/>
+ <location line="+127"/>
<source>Unknown. Syncing Headers (%1, %2%)…</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <location line="+5"/>
+ <source>Unknown. Pre-syncing Headers (%1, %2%)…</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>OpenURIDialog</name>
@@ -2181,7 +2191,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../overviewpage.cpp" line="+186"/>
+ <location filename="../overviewpage.cpp" line="+185"/>
<source>Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings-&gt;Mask values.</source>
<translation type="unfinished"></translation>
</message>
@@ -2685,7 +2695,7 @@ If you are receiving this error you should request the merchant provide a BIP21
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../modaloverlay.cpp" line="-35"/>
+ <location filename="../modaloverlay.cpp" line="-40"/>
<source>unknown</source>
<translation type="unfinished"></translation>
</message>
@@ -3623,7 +3633,7 @@ For more information on using this console, type %6.
<name>SendCoinsDialog</name>
<message>
<location filename="../forms/sendcoinsdialog.ui" line="+14"/>
- <location filename="../sendcoinsdialog.cpp" line="+759"/>
+ <location filename="../sendcoinsdialog.cpp" line="+757"/>
<source>Send Coins</source>
<translation>Send Coins</translation>
</message>
@@ -3810,7 +3820,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
<translation>S&amp;end</translation>
</message>
<message>
- <location filename="../sendcoinsdialog.cpp" line="-660"/>
+ <location filename="../sendcoinsdialog.cpp" line="-658"/>
<source>Copy quantity</source>
<translation type="unfinished"></translation>
</message>
@@ -3845,7 +3855,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+76"/>
+ <location line="+74"/>
<source>%1 (%2 blocks)</source>
<translation type="unfinished"></translation>
</message>
@@ -5042,7 +5052,7 @@ Go to File &gt; Open Wallet to load a wallet.
<context>
<name>WalletModel</name>
<message>
- <location filename="../walletmodel.cpp" line="+221"/>
+ <location filename="../walletmodel.cpp" line="+232"/>
<source>Send Coins</source>
<translation type="unfinished">Send Coins</translation>
</message>
@@ -5218,7 +5228,7 @@ Go to File &gt; Open Wallet to load a wallet.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+3"/>
+ <location line="+6"/>
<source>Error: Dumpfile format record is incorrect. Got &quot;%s&quot;, expected &quot;format&quot;.</source>
<translation type="unfinished"></translation>
</message>
@@ -5233,12 +5243,12 @@ Go to File &gt; Open Wallet to load a wallet.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+3"/>
+ <location line="+6"/>
<source>Error: Legacy wallets only support the &quot;legacy&quot;, &quot;p2sh-segwit&quot;, and &quot;bech32&quot; address types</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+6"/>
+ <location line="+12"/>
<source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
<translation type="unfinished"></translation>
</message>
@@ -5248,7 +5258,7 @@ Go to File &gt; Open Wallet to load a wallet.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+3"/>
+ <location line="+6"/>
<source>Invalid amount for -maxtxfee=&lt;amount&gt;: &apos;%s&apos; (must be at least the minrelay fee of %s to prevent stuck transactions)</source>
<translation type="unfinished"></translation>
</message>
@@ -5278,12 +5288,7 @@ Go to File &gt; Open Wallet to load a wallet.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+3"/>
- <source>Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is not provided (no -proxy= and no -onion= given) or it is explicitly forbidden (-onion=0)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+4"/>
+ <location line="+10"/>
<source>Please check that your computer&apos;s date and time are correct! If your clock is wrong, %s will not work properly.</source>
<translation type="unfinished"></translation>
</message>
@@ -5368,7 +5373,7 @@ Go to File &gt; Open Wallet to load a wallet.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+3"/>
+ <location line="+11"/>
<source>Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database.</source>
<translation type="unfinished"></translation>
</message>
@@ -5403,7 +5408,7 @@ Go to File &gt; Open Wallet to load a wallet.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+3"/>
+ <location line="+9"/>
<source>%s is set very high!</source>
<translation type="unfinished"></translation>
</message>
@@ -5438,12 +5443,12 @@ Go to File &gt; Open Wallet to load a wallet.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-65"/>
+ <location line="-79"/>
<source>The -txindex upgrade started by a previous version cannot be completed. Restart with the previous version or run a full -reindex.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-104"/>
+ <location line="-122"/>
<source>%s request to listen on port %u. This port is considered &quot;bad&quot; and thus it is unlikely that any Bitcoin Core peers connect to it. See doc/p2p-bad-ports.md for details and a full list.</source>
<translation type="unfinished"></translation>
</message>
@@ -5478,12 +5483,73 @@ Go to File &gt; Open Wallet to load a wallet.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+19"/>
+ <location line="+9"/>
+ <source>Error: Address book data in wallet cannot be identified to belong to migrated wallets</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+10"/>
+ <source>Error: Duplicate descriptors created during migration. Your wallet may be corrupted.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+6"/>
+ <source>Error: Transaction %s in wallet cannot be identified to belong to migrated wallets</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>Error: Unable to produce descriptors for this legacy wallet. Make sure the wallet is unlocked first</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
<source>Failed to rename invalid peers.dat file. Please move or delete it and try again.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+114"/>
+ <location line="+9"/>
+ <source>Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+21"/>
+ <source>Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is explicitly forbidden: -onion=0</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is not provided: none of -proxy, -onion or -listenonion is given</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+59"/>
+ <source>Unrecognized descriptor found. Loading wallet %s
+
+The wallet might had been created on a newer version.
+Please try running the latest software version.
+</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+5"/>
+ <source>Unsupported category-specific logging level -loglevel=%s. Expected -loglevel=&lt;category&gt;:&lt;loglevel&gt;. Valid categories: %s. Valid loglevels: %s.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+24"/>
+ <source>
+Unable to cleanup failed migration</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>
+Unable to restore backup of wallet.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+10"/>
<source>Config setting for %s only applied on %s network when in [%s] section.</source>
<translation type="unfinished"></translation>
</message>
@@ -5584,6 +5650,16 @@ Go to File &gt; Open Wallet to load a wallet.
</message>
<message>
<location line="+1"/>
+ <source>Error: Could not add watchonly tx to watchonly wallet</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Error: Could not delete watchonly transactions</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
<source>Error: Couldn&apos;t create cursor into database</source>
<translation type="unfinished"></translation>
</message>
@@ -5599,6 +5675,11 @@ Go to File &gt; Open Wallet to load a wallet.
</message>
<message>
<location line="+1"/>
+ <source>Error: Failed to create new watchonly wallet</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>
@@ -5624,11 +5705,46 @@ Go to File &gt; Open Wallet to load a wallet.
</message>
<message>
<location line="+1"/>
+ <source>Error: Not all watchonly txs could be deleted</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Error: This wallet already uses SQLite</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Error: This wallet is already a descriptor wallet</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Error: Unable to begin reading all records in the database</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Error: Unable to make a backup of your wallet</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 read all records in the database</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Error: Unable to remove watchonly address book data</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>
@@ -5954,6 +6070,11 @@ Go to File &gt; Open Wallet to load a wallet.
</message>
<message>
<location line="+1"/>
+ <source>Unable to find UTXO for external input</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
<source>Unable to generate initial keys</source>
<translation type="unfinished"></translation>
</message>
@@ -5979,6 +6100,11 @@ Go to File &gt; Open Wallet to load a wallet.
</message>
<message>
<location line="+1"/>
+ <source>Unable to unload the wallet before migrating</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
<source>Unknown -blockfilterindex value %s.</source>
<translation type="unfinished"></translation>
</message>
@@ -6004,6 +6130,11 @@ Go to File &gt; Open Wallet to load a wallet.
</message>
<message>
<location line="+1"/>
+ <source>Unsupported global logging level -loglevel=%s. Valid values: %s.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
<source>Unsupported logging category %s=%s.</source>
<translation type="unfinished"></translation>
</message>
diff --git a/src/qt/locale/bitcoin_en.xlf b/src/qt/locale/bitcoin_en.xlf
index c5f0c933f4..a25ccfca72 100644
--- a/src/qt/locale/bitcoin_en.xlf
+++ b/src/qt/locale/bitcoin_en.xlf
@@ -268,61 +268,61 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<group restype="x-trolltech-linguist-context" resname="BitcoinApplication">
<trans-unit id="_msg58">
<source xml:space="preserve">Settings file %1 might be corrupt or invalid.</source>
- <context-group purpose="location"><context context-type="linenumber">286</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">288</context></context-group>
</trans-unit>
<trans-unit id="_msg59">
<source xml:space="preserve">Runaway exception</source>
- <context-group purpose="location"><context context-type="linenumber">464</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">466</context></context-group>
</trans-unit>
<trans-unit id="_msg60">
<source xml:space="preserve">A fatal error occurred. %1 can no longer continue safely and will quit.</source>
- <context-group purpose="location"><context context-type="linenumber">465</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">467</context></context-group>
</trans-unit>
<trans-unit id="_msg61">
<source xml:space="preserve">Internal error</source>
- <context-group purpose="location"><context context-type="linenumber">474</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">476</context></context-group>
</trans-unit>
<trans-unit id="_msg62">
<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>
- <context-group purpose="location"><context context-type="linenumber">475</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">477</context></context-group>
</trans-unit>
</group>
<group restype="x-trolltech-linguist-context" resname="QObject">
<trans-unit id="_msg63">
<source xml:space="preserve">Do you want to reset settings to default values, or to abort without making changes?</source>
- <context-group purpose="location"><context context-type="linenumber">181</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">183</context></context-group>
<note annotates="source" from="developer">Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting.</note>
</trans-unit>
<trans-unit id="_msg64">
<source xml:space="preserve">A fatal error occurred. Check that settings file is writable, or try running with -nosettings.</source>
- <context-group purpose="location"><context context-type="linenumber">205</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">207</context></context-group>
<note annotates="source" from="developer">Explanatory text shown on startup when the settings file could not be written. Prompts user to check that we have the ability to write to the file. Explains that the user has the option of running without a settings file.</note>
</trans-unit>
<trans-unit id="_msg65">
<source xml:space="preserve">Error: Specified data directory &quot;%1&quot; does not exist.</source>
- <context-group purpose="location"><context context-type="linenumber">598</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">600</context></context-group>
</trans-unit>
<trans-unit id="_msg66">
<source xml:space="preserve">Error: Cannot parse configuration file: %1.</source>
- <context-group purpose="location"><context context-type="linenumber">604</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">606</context></context-group>
</trans-unit>
<trans-unit id="_msg67">
<source xml:space="preserve">Error: %1</source>
- <context-group purpose="location"><context context-type="linenumber">619</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">621</context></context-group>
</trans-unit>
<trans-unit id="_msg68">
<source xml:space="preserve">%1 didn&apos;t yet exit safely…</source>
- <context-group purpose="location"><context context-type="linenumber">693</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">695</context></context-group>
</trans-unit>
</group>
<group restype="x-trolltech-linguist-context" resname="bitcoin-core">
<trans-unit id="_msg69">
<source xml:space="preserve">Settings file could not be read</source>
- <context-group purpose="location"><context context-type="linenumber">174</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">176</context></context-group>
</trans-unit>
<trans-unit id="_msg70">
<source xml:space="preserve">Settings file could not be written</source>
- <context-group purpose="location"><context context-type="linenumber">197</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">199</context></context-group>
</trans-unit>
</group>
</body></file>
@@ -391,7 +391,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</trans-unit>
<trans-unit id="_msg86">
<source xml:space="preserve">Proxy is &lt;b&gt;enabled&lt;/b&gt;: %1</source>
- <context-group purpose="location"><context context-type="linenumber">1411</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1421</context></context-group>
</trans-unit>
<trans-unit id="_msg87">
<source xml:space="preserve">Send coins to a Bitcoin address</source>
@@ -491,23 +491,23 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</trans-unit>
<trans-unit id="_msg111">
<source xml:space="preserve">Synchronizing with network…</source>
- <context-group purpose="location"><context context-type="linenumber">1074</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1084</context></context-group>
</trans-unit>
<trans-unit id="_msg112">
<source xml:space="preserve">Indexing blocks on disk…</source>
- <context-group purpose="location"><context context-type="linenumber">1079</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1089</context></context-group>
</trans-unit>
<trans-unit id="_msg113">
<source xml:space="preserve">Processing blocks on disk…</source>
- <context-group purpose="location"><context context-type="linenumber">1081</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1091</context></context-group>
</trans-unit>
<trans-unit id="_msg114">
<source xml:space="preserve">Reindexing blocks on disk…</source>
- <context-group purpose="location"><context context-type="linenumber">1085</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1095</context></context-group>
</trans-unit>
<trans-unit id="_msg115">
<source xml:space="preserve">Connecting to peers…</source>
- <context-group purpose="location"><context context-type="linenumber">1091</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1101</context></context-group>
</trans-unit>
<trans-unit id="_msg116">
<source xml:space="preserve">Request payments (generates QR codes and bitcoin: URIs)</source>
@@ -526,7 +526,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<context-group purpose="location"><context context-type="linenumber">361</context></context-group>
</trans-unit>
<group restype="x-gettext-plurals">
- <context-group purpose="location"><context context-type="linenumber">1100</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1110</context></context-group>
<trans-unit id="_msg120[0]">
<source xml:space="preserve">Processed %n block(s) of transaction history.</source>
</trans-unit>
@@ -536,35 +536,35 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</group>
<trans-unit id="_msg121">
<source xml:space="preserve">%1 behind</source>
- <context-group purpose="location"><context context-type="linenumber">1123</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1133</context></context-group>
</trans-unit>
<trans-unit id="_msg122">
<source xml:space="preserve">Catching up…</source>
- <context-group purpose="location"><context context-type="linenumber">1128</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1138</context></context-group>
</trans-unit>
<trans-unit id="_msg123">
<source xml:space="preserve">Last received block was generated %1 ago.</source>
- <context-group purpose="location"><context context-type="linenumber">1147</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1157</context></context-group>
</trans-unit>
<trans-unit id="_msg124">
<source xml:space="preserve">Transactions after this will not yet be visible.</source>
- <context-group purpose="location"><context context-type="linenumber">1149</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1159</context></context-group>
</trans-unit>
<trans-unit id="_msg125">
<source xml:space="preserve">Error</source>
- <context-group purpose="location"><context context-type="linenumber">1174</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1184</context></context-group>
</trans-unit>
<trans-unit id="_msg126">
<source xml:space="preserve">Warning</source>
- <context-group purpose="location"><context context-type="linenumber">1178</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1188</context></context-group>
</trans-unit>
<trans-unit id="_msg127">
<source xml:space="preserve">Information</source>
- <context-group purpose="location"><context context-type="linenumber">1182</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1192</context></context-group>
</trans-unit>
<trans-unit id="_msg128">
<source xml:space="preserve">Up to date</source>
- <context-group purpose="location"><context context-type="linenumber">1104</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1114</context></context-group>
</trans-unit>
<trans-unit id="_msg129">
<source xml:space="preserve">Ctrl+Q</source>
@@ -661,7 +661,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<trans-unit id="_msg151">
<source xml:space="preserve">Restore Wallet</source>
<context-group purpose="location"><context context-type="linenumber">435</context></context-group>
- <note annotates="source" from="developer">Title of pop-up window shown when the user is attempting to + restore a wallet.</note>
+ <note annotates="source" from="developer">Title of pop-up window shown when the user is attempting to restore a wallet.</note>
</trans-unit>
<trans-unit id="_msg152">
<source xml:space="preserve">Wallet Name</source>
@@ -727,150 +727,154 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<note annotates="source" from="developer">A context menu item. The network activity was disabled previously.</note>
</trans-unit>
<trans-unit id="_msg165">
- <source xml:space="preserve">Error: %1</source>
- <context-group purpose="location"><context context-type="linenumber">1175</context></context-group>
+ <source xml:space="preserve">Pre-syncing Headers (%1%)…</source>
+ <context-group purpose="location"><context context-type="linenumber">1033</context></context-group>
</trans-unit>
<trans-unit id="_msg166">
- <source xml:space="preserve">Warning: %1</source>
- <context-group purpose="location"><context context-type="linenumber">1179</context></context-group>
+ <source xml:space="preserve">Error: %1</source>
+ <context-group purpose="location"><context context-type="linenumber">1185</context></context-group>
</trans-unit>
<trans-unit id="_msg167">
+ <source xml:space="preserve">Warning: %1</source>
+ <context-group purpose="location"><context context-type="linenumber">1189</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg168">
<source xml:space="preserve">Date: %1
</source>
- <context-group purpose="location"><context context-type="linenumber">1287</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1297</context></context-group>
</trans-unit>
- <trans-unit id="_msg168">
+ <trans-unit id="_msg169">
<source xml:space="preserve">Amount: %1
</source>
- <context-group purpose="location"><context context-type="linenumber">1288</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1298</context></context-group>
</trans-unit>
- <trans-unit id="_msg169">
+ <trans-unit id="_msg170">
<source xml:space="preserve">Wallet: %1
</source>
- <context-group purpose="location"><context context-type="linenumber">1290</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1300</context></context-group>
</trans-unit>
- <trans-unit id="_msg170">
+ <trans-unit id="_msg171">
<source xml:space="preserve">Type: %1
</source>
- <context-group purpose="location"><context context-type="linenumber">1292</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1302</context></context-group>
</trans-unit>
- <trans-unit id="_msg171">
+ <trans-unit id="_msg172">
<source xml:space="preserve">Label: %1
</source>
- <context-group purpose="location"><context context-type="linenumber">1294</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1304</context></context-group>
</trans-unit>
- <trans-unit id="_msg172">
+ <trans-unit id="_msg173">
<source xml:space="preserve">Address: %1
</source>
- <context-group purpose="location"><context context-type="linenumber">1296</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1306</context></context-group>
</trans-unit>
- <trans-unit id="_msg173">
+ <trans-unit id="_msg174">
<source xml:space="preserve">Sent transaction</source>
- <context-group purpose="location"><context context-type="linenumber">1297</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1307</context></context-group>
</trans-unit>
- <trans-unit id="_msg174">
+ <trans-unit id="_msg175">
<source xml:space="preserve">Incoming transaction</source>
- <context-group purpose="location"><context context-type="linenumber">1297</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1307</context></context-group>
</trans-unit>
- <trans-unit id="_msg175">
+ <trans-unit id="_msg176">
<source xml:space="preserve">HD key generation is &lt;b&gt;enabled&lt;/b&gt;</source>
- <context-group purpose="location"><context context-type="linenumber">1349</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1359</context></context-group>
</trans-unit>
- <trans-unit id="_msg176">
+ <trans-unit id="_msg177">
<source xml:space="preserve">HD key generation is &lt;b&gt;disabled&lt;/b&gt;</source>
- <context-group purpose="location"><context context-type="linenumber">1349</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1359</context></context-group>
</trans-unit>
- <trans-unit id="_msg177">
+ <trans-unit id="_msg178">
<source xml:space="preserve">Private key &lt;b&gt;disabled&lt;/b&gt;</source>
- <context-group purpose="location"><context context-type="linenumber">1349</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1359</context></context-group>
</trans-unit>
- <trans-unit id="_msg178">
+ <trans-unit id="_msg179">
<source xml:space="preserve">Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;unlocked&lt;/b&gt;</source>
- <context-group purpose="location"><context context-type="linenumber">1372</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1382</context></context-group>
</trans-unit>
- <trans-unit id="_msg179">
+ <trans-unit id="_msg180">
<source xml:space="preserve">Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
- <context-group purpose="location"><context context-type="linenumber">1380</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1390</context></context-group>
</trans-unit>
- <trans-unit id="_msg180">
+ <trans-unit id="_msg181">
<source xml:space="preserve">Original message:</source>
- <context-group purpose="location"><context context-type="linenumber">1499</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1509</context></context-group>
</trans-unit>
</group>
<group restype="x-trolltech-linguist-context" resname="UnitDisplayStatusBarControl">
- <trans-unit id="_msg181">
+ <trans-unit id="_msg182">
<source xml:space="preserve">Unit to show amounts in. Click to select another unit.</source>
- <context-group purpose="location"><context context-type="linenumber">1540</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1550</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../forms/coincontroldialog.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="CoinControlDialog">
- <trans-unit id="_msg182">
+ <trans-unit id="_msg183">
<source xml:space="preserve">Coin Selection</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
</trans-unit>
- <trans-unit id="_msg183">
+ <trans-unit id="_msg184">
<source xml:space="preserve">Quantity:</source>
<context-group purpose="location"><context context-type="linenumber">48</context></context-group>
</trans-unit>
- <trans-unit id="_msg184">
+ <trans-unit id="_msg185">
<source xml:space="preserve">Bytes:</source>
<context-group purpose="location"><context context-type="linenumber">77</context></context-group>
</trans-unit>
- <trans-unit id="_msg185">
+ <trans-unit id="_msg186">
<source xml:space="preserve">Amount:</source>
<context-group purpose="location"><context context-type="linenumber">122</context></context-group>
</trans-unit>
- <trans-unit id="_msg186">
+ <trans-unit id="_msg187">
<source xml:space="preserve">Fee:</source>
<context-group purpose="location"><context context-type="linenumber">202</context></context-group>
</trans-unit>
- <trans-unit id="_msg187">
+ <trans-unit id="_msg188">
<source xml:space="preserve">Dust:</source>
<context-group purpose="location"><context context-type="linenumber">154</context></context-group>
</trans-unit>
- <trans-unit id="_msg188">
+ <trans-unit id="_msg189">
<source xml:space="preserve">After Fee:</source>
<context-group purpose="location"><context context-type="linenumber">247</context></context-group>
</trans-unit>
- <trans-unit id="_msg189">
+ <trans-unit id="_msg190">
<source xml:space="preserve">Change:</source>
<context-group purpose="location"><context context-type="linenumber">279</context></context-group>
</trans-unit>
- <trans-unit id="_msg190">
+ <trans-unit id="_msg191">
<source xml:space="preserve">(un)select all</source>
<context-group purpose="location"><context context-type="linenumber">335</context></context-group>
</trans-unit>
- <trans-unit id="_msg191">
+ <trans-unit id="_msg192">
<source xml:space="preserve">Tree mode</source>
<context-group purpose="location"><context context-type="linenumber">351</context></context-group>
</trans-unit>
- <trans-unit id="_msg192">
+ <trans-unit id="_msg193">
<source xml:space="preserve">List mode</source>
<context-group purpose="location"><context context-type="linenumber">364</context></context-group>
</trans-unit>
- <trans-unit id="_msg193">
+ <trans-unit id="_msg194">
<source xml:space="preserve">Amount</source>
<context-group purpose="location"><context context-type="linenumber">420</context></context-group>
</trans-unit>
- <trans-unit id="_msg194">
+ <trans-unit id="_msg195">
<source xml:space="preserve">Received with label</source>
<context-group purpose="location"><context context-type="linenumber">425</context></context-group>
</trans-unit>
- <trans-unit id="_msg195">
+ <trans-unit id="_msg196">
<source xml:space="preserve">Received with address</source>
<context-group purpose="location"><context context-type="linenumber">430</context></context-group>
</trans-unit>
- <trans-unit id="_msg196">
+ <trans-unit id="_msg197">
<source xml:space="preserve">Date</source>
<context-group purpose="location"><context context-type="linenumber">435</context></context-group>
</trans-unit>
- <trans-unit id="_msg197">
+ <trans-unit id="_msg198">
<source xml:space="preserve">Confirmations</source>
<context-group purpose="location"><context context-type="linenumber">440</context></context-group>
</trans-unit>
- <trans-unit id="_msg198">
+ <trans-unit id="_msg199">
<source xml:space="preserve">Confirmed</source>
<context-group purpose="location"><context context-type="linenumber">443</context></context-group>
</trans-unit>
@@ -878,88 +882,88 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../coincontroldialog.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="CoinControlDialog">
- <trans-unit id="_msg199">
+ <trans-unit id="_msg200">
<source xml:space="preserve">Copy amount</source>
<context-group purpose="location"><context context-type="linenumber">69</context></context-group>
</trans-unit>
- <trans-unit id="_msg200">
+ <trans-unit id="_msg201">
<source xml:space="preserve">&amp;Copy address</source>
<context-group purpose="location"><context context-type="linenumber">58</context></context-group>
</trans-unit>
- <trans-unit id="_msg201">
+ <trans-unit id="_msg202">
<source xml:space="preserve">Copy &amp;label</source>
<context-group purpose="location"><context context-type="linenumber">59</context></context-group>
</trans-unit>
- <trans-unit id="_msg202">
+ <trans-unit id="_msg203">
<source xml:space="preserve">Copy &amp;amount</source>
<context-group purpose="location"><context context-type="linenumber">60</context></context-group>
</trans-unit>
- <trans-unit id="_msg203">
+ <trans-unit id="_msg204">
<source xml:space="preserve">Copy transaction &amp;ID and output index</source>
<context-group purpose="location"><context context-type="linenumber">61</context></context-group>
</trans-unit>
- <trans-unit id="_msg204">
+ <trans-unit id="_msg205">
<source xml:space="preserve">L&amp;ock unspent</source>
<context-group purpose="location"><context context-type="linenumber">63</context></context-group>
</trans-unit>
- <trans-unit id="_msg205">
+ <trans-unit id="_msg206">
<source xml:space="preserve">&amp;Unlock unspent</source>
<context-group purpose="location"><context context-type="linenumber">64</context></context-group>
</trans-unit>
- <trans-unit id="_msg206">
+ <trans-unit id="_msg207">
<source xml:space="preserve">Copy quantity</source>
<context-group purpose="location"><context context-type="linenumber">68</context></context-group>
</trans-unit>
- <trans-unit id="_msg207">
+ <trans-unit id="_msg208">
<source xml:space="preserve">Copy fee</source>
<context-group purpose="location"><context context-type="linenumber">70</context></context-group>
</trans-unit>
- <trans-unit id="_msg208">
+ <trans-unit id="_msg209">
<source xml:space="preserve">Copy after fee</source>
<context-group purpose="location"><context context-type="linenumber">71</context></context-group>
</trans-unit>
- <trans-unit id="_msg209">
+ <trans-unit id="_msg210">
<source xml:space="preserve">Copy bytes</source>
<context-group purpose="location"><context context-type="linenumber">72</context></context-group>
</trans-unit>
- <trans-unit id="_msg210">
+ <trans-unit id="_msg211">
<source xml:space="preserve">Copy dust</source>
<context-group purpose="location"><context context-type="linenumber">73</context></context-group>
</trans-unit>
- <trans-unit id="_msg211">
+ <trans-unit id="_msg212">
<source xml:space="preserve">Copy change</source>
<context-group purpose="location"><context context-type="linenumber">74</context></context-group>
</trans-unit>
- <trans-unit id="_msg212">
+ <trans-unit id="_msg213">
<source xml:space="preserve">(%1 locked)</source>
<context-group purpose="location"><context context-type="linenumber">380</context></context-group>
</trans-unit>
- <trans-unit id="_msg213">
+ <trans-unit id="_msg214">
<source xml:space="preserve">yes</source>
<context-group purpose="location"><context context-type="linenumber">534</context></context-group>
</trans-unit>
- <trans-unit id="_msg214">
+ <trans-unit id="_msg215">
<source xml:space="preserve">no</source>
<context-group purpose="location"><context context-type="linenumber">534</context></context-group>
</trans-unit>
- <trans-unit id="_msg215">
+ <trans-unit id="_msg216">
<source xml:space="preserve">This label turns red if any recipient receives an amount smaller than the current dust threshold.</source>
<context-group purpose="location"><context context-type="linenumber">548</context></context-group>
</trans-unit>
- <trans-unit id="_msg216">
+ <trans-unit id="_msg217">
<source xml:space="preserve">Can vary +/- %1 satoshi(s) per input.</source>
<context-group purpose="location"><context context-type="linenumber">553</context></context-group>
</trans-unit>
- <trans-unit id="_msg217">
+ <trans-unit id="_msg218">
<source xml:space="preserve">(no label)</source>
<context-group purpose="location"><context context-type="linenumber">600</context></context-group>
<context-group purpose="location"><context context-type="linenumber">654</context></context-group>
</trans-unit>
- <trans-unit id="_msg218">
+ <trans-unit id="_msg219">
<source xml:space="preserve">change from %1 (%2)</source>
<context-group purpose="location"><context context-type="linenumber">647</context></context-group>
</trans-unit>
- <trans-unit id="_msg219">
+ <trans-unit id="_msg220">
<source xml:space="preserve">(change)</source>
<context-group purpose="location"><context context-type="linenumber">648</context></context-group>
</trans-unit>
@@ -967,114 +971,114 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../walletcontroller.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="CreateWalletActivity">
- <trans-unit id="_msg220">
+ <trans-unit id="_msg221">
<source xml:space="preserve">Create Wallet</source>
<context-group purpose="location"><context context-type="linenumber">244</context></context-group>
<note annotates="source" from="developer">Title of window indicating the progress of creation of a new wallet.</note>
</trans-unit>
- <trans-unit id="_msg221">
+ <trans-unit id="_msg222">
<source xml:space="preserve">Creating Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
<context-group purpose="location"><context context-type="linenumber">247</context></context-group>
<note annotates="source" from="developer">Descriptive text of the create wallet progress window which indicates to the user which wallet is currently being created.</note>
</trans-unit>
- <trans-unit id="_msg222">
+ <trans-unit id="_msg223">
<source xml:space="preserve">Create wallet failed</source>
<context-group purpose="location"><context context-type="linenumber">280</context></context-group>
</trans-unit>
- <trans-unit id="_msg223">
+ <trans-unit id="_msg224">
<source xml:space="preserve">Create wallet warning</source>
<context-group purpose="location"><context context-type="linenumber">282</context></context-group>
</trans-unit>
- <trans-unit id="_msg224">
+ <trans-unit id="_msg225">
<source xml:space="preserve">Can&apos;t list signers</source>
<context-group purpose="location"><context context-type="linenumber">298</context></context-group>
</trans-unit>
- <trans-unit id="_msg225">
+ <trans-unit id="_msg226">
<source xml:space="preserve">Too many external signers found</source>
<context-group purpose="location"><context context-type="linenumber">301</context></context-group>
</trans-unit>
</group>
<group restype="x-trolltech-linguist-context" resname="LoadWalletsActivity">
- <trans-unit id="_msg226">
+ <trans-unit id="_msg227">
<source xml:space="preserve">Load Wallets</source>
<context-group purpose="location"><context context-type="linenumber">375</context></context-group>
<note annotates="source" from="developer">Title of progress window which is displayed when wallets are being loaded.</note>
</trans-unit>
- <trans-unit id="_msg227">
+ <trans-unit id="_msg228">
<source xml:space="preserve">Loading wallets…</source>
<context-group purpose="location"><context context-type="linenumber">378</context></context-group>
<note annotates="source" from="developer">Descriptive text of the load wallets progress window which indicates to the user that wallets are currently being loaded.</note>
</trans-unit>
</group>
<group restype="x-trolltech-linguist-context" resname="OpenWalletActivity">
- <trans-unit id="_msg228">
+ <trans-unit id="_msg229">
<source xml:space="preserve">Open wallet failed</source>
<context-group purpose="location"><context context-type="linenumber">332</context></context-group>
</trans-unit>
- <trans-unit id="_msg229">
+ <trans-unit id="_msg230">
<source xml:space="preserve">Open wallet warning</source>
<context-group purpose="location"><context context-type="linenumber">334</context></context-group>
</trans-unit>
- <trans-unit id="_msg230">
+ <trans-unit id="_msg231">
<source xml:space="preserve">default wallet</source>
<context-group purpose="location"><context context-type="linenumber">344</context></context-group>
</trans-unit>
- <trans-unit id="_msg231">
+ <trans-unit id="_msg232">
<source xml:space="preserve">Open Wallet</source>
<context-group purpose="location"><context context-type="linenumber">348</context></context-group>
<note annotates="source" from="developer">Title of window indicating the progress of opening of a wallet.</note>
</trans-unit>
- <trans-unit id="_msg232">
+ <trans-unit id="_msg233">
<source xml:space="preserve">Opening Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
<context-group purpose="location"><context context-type="linenumber">351</context></context-group>
<note annotates="source" from="developer">Descriptive text of the open wallet progress window which indicates to the user which wallet is currently being opened.</note>
</trans-unit>
</group>
<group restype="x-trolltech-linguist-context" resname="RestoreWalletActivity">
- <trans-unit id="_msg233">
+ <trans-unit id="_msg234">
<source xml:space="preserve">Restore Wallet</source>
<context-group purpose="location"><context context-type="linenumber">400</context></context-group>
<note annotates="source" from="developer">Title of progress window which is displayed when wallets are being restored.</note>
</trans-unit>
- <trans-unit id="_msg234">
+ <trans-unit id="_msg235">
<source xml:space="preserve">Restoring Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
<context-group purpose="location"><context context-type="linenumber">403</context></context-group>
<note annotates="source" from="developer">Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored.</note>
</trans-unit>
- <trans-unit id="_msg235">
+ <trans-unit id="_msg236">
<source xml:space="preserve">Restore wallet failed</source>
<context-group purpose="location"><context context-type="linenumber">422</context></context-group>
<note annotates="source" from="developer">Title of message box which is displayed when the wallet could not be restored.</note>
</trans-unit>
- <trans-unit id="_msg236">
+ <trans-unit id="_msg237">
<source xml:space="preserve">Restore wallet warning</source>
<context-group purpose="location"><context context-type="linenumber">425</context></context-group>
<note annotates="source" from="developer">Title of message box which is displayed when the wallet is restored with some warning.</note>
</trans-unit>
- <trans-unit id="_msg237">
+ <trans-unit id="_msg238">
<source xml:space="preserve">Restore wallet message</source>
<context-group purpose="location"><context context-type="linenumber">428</context></context-group>
<note annotates="source" from="developer">Title of message box which is displayed when the wallet is successfully restored.</note>
</trans-unit>
</group>
<group restype="x-trolltech-linguist-context" resname="WalletController">
- <trans-unit id="_msg238">
+ <trans-unit id="_msg239">
<source xml:space="preserve">Close wallet</source>
<context-group purpose="location"><context context-type="linenumber">84</context></context-group>
</trans-unit>
- <trans-unit id="_msg239">
+ <trans-unit id="_msg240">
<source xml:space="preserve">Are you sure you wish to close the wallet &lt;i&gt;%1&lt;/i&gt;?</source>
<context-group purpose="location"><context context-type="linenumber">85</context></context-group>
</trans-unit>
- <trans-unit id="_msg240">
+ <trans-unit id="_msg241">
<source xml:space="preserve">Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source>
<context-group purpose="location"><context context-type="linenumber">86</context></context-group>
</trans-unit>
- <trans-unit id="_msg241">
+ <trans-unit id="_msg242">
<source xml:space="preserve">Close all wallets</source>
<context-group purpose="location"><context context-type="linenumber">99</context></context-group>
</trans-unit>
- <trans-unit id="_msg242">
+ <trans-unit id="_msg243">
<source xml:space="preserve">Are you sure you wish to close all wallets?</source>
<context-group purpose="location"><context context-type="linenumber">100</context></context-group>
</trans-unit>
@@ -1082,59 +1086,59 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../forms/createwalletdialog.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="CreateWalletDialog">
- <trans-unit id="_msg243">
+ <trans-unit id="_msg244">
<source xml:space="preserve">Create Wallet</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
</trans-unit>
- <trans-unit id="_msg244">
+ <trans-unit id="_msg245">
<source xml:space="preserve">Wallet Name</source>
<context-group purpose="location"><context context-type="linenumber">25</context></context-group>
</trans-unit>
- <trans-unit id="_msg245">
+ <trans-unit id="_msg246">
<source xml:space="preserve">Wallet</source>
<context-group purpose="location"><context context-type="linenumber">38</context></context-group>
</trans-unit>
- <trans-unit id="_msg246">
+ <trans-unit id="_msg247">
<source xml:space="preserve">Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source>
<context-group purpose="location"><context context-type="linenumber">47</context></context-group>
</trans-unit>
- <trans-unit id="_msg247">
+ <trans-unit id="_msg248">
<source xml:space="preserve">Encrypt Wallet</source>
<context-group purpose="location"><context context-type="linenumber">50</context></context-group>
</trans-unit>
- <trans-unit id="_msg248">
+ <trans-unit id="_msg249">
<source xml:space="preserve">Advanced Options</source>
<context-group purpose="location"><context context-type="linenumber">76</context></context-group>
</trans-unit>
- <trans-unit id="_msg249">
+ <trans-unit id="_msg250">
<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>
<context-group purpose="location"><context context-type="linenumber">85</context></context-group>
</trans-unit>
- <trans-unit id="_msg250">
+ <trans-unit id="_msg251">
<source xml:space="preserve">Disable Private Keys</source>
<context-group purpose="location"><context context-type="linenumber">88</context></context-group>
</trans-unit>
- <trans-unit id="_msg251">
+ <trans-unit id="_msg252">
<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>
<context-group purpose="location"><context context-type="linenumber">95</context></context-group>
</trans-unit>
- <trans-unit id="_msg252">
+ <trans-unit id="_msg253">
<source xml:space="preserve">Make Blank Wallet</source>
<context-group purpose="location"><context context-type="linenumber">98</context></context-group>
</trans-unit>
- <trans-unit id="_msg253">
+ <trans-unit id="_msg254">
<source xml:space="preserve">Use descriptors for scriptPubKey management</source>
<context-group purpose="location"><context context-type="linenumber">105</context></context-group>
</trans-unit>
- <trans-unit id="_msg254">
+ <trans-unit id="_msg255">
<source xml:space="preserve">Descriptor Wallet</source>
<context-group purpose="location"><context context-type="linenumber">108</context></context-group>
</trans-unit>
- <trans-unit id="_msg255">
+ <trans-unit id="_msg256">
<source xml:space="preserve">Use an external signing device such as a hardware wallet. Configure the external signer script in wallet preferences first.</source>
<context-group purpose="location"><context context-type="linenumber">118</context></context-group>
</trans-unit>
- <trans-unit id="_msg256">
+ <trans-unit id="_msg257">
<source xml:space="preserve">External signer</source>
<context-group purpose="location"><context context-type="linenumber">121</context></context-group>
</trans-unit>
@@ -1142,15 +1146,15 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../createwalletdialog.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="CreateWalletDialog">
- <trans-unit id="_msg257">
+ <trans-unit id="_msg258">
<source xml:space="preserve">Create</source>
<context-group purpose="location"><context context-type="linenumber">22</context></context-group>
</trans-unit>
- <trans-unit id="_msg258">
+ <trans-unit id="_msg259">
<source xml:space="preserve">Compiled without sqlite support (required for descriptor wallets)</source>
<context-group purpose="location"><context context-type="linenumber">90</context></context-group>
</trans-unit>
- <trans-unit id="_msg259">
+ <trans-unit id="_msg260">
<source xml:space="preserve">Compiled without external signing support (required for external signing)</source>
<context-group purpose="location"><context context-type="linenumber">104</context></context-group>
<note annotates="source" from="developer">&quot;External signing&quot; means using devices such as hardware wallets.</note>
@@ -1159,23 +1163,23 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../forms/editaddressdialog.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="EditAddressDialog">
- <trans-unit id="_msg260">
+ <trans-unit id="_msg261">
<source xml:space="preserve">Edit Address</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
</trans-unit>
- <trans-unit id="_msg261">
+ <trans-unit id="_msg262">
<source xml:space="preserve">&amp;Label</source>
<context-group purpose="location"><context context-type="linenumber">25</context></context-group>
</trans-unit>
- <trans-unit id="_msg262">
+ <trans-unit id="_msg263">
<source xml:space="preserve">The label associated with this address list entry</source>
<context-group purpose="location"><context context-type="linenumber">35</context></context-group>
</trans-unit>
- <trans-unit id="_msg263">
+ <trans-unit id="_msg264">
<source xml:space="preserve">The address associated with this address list entry. This can only be modified for sending addresses.</source>
<context-group purpose="location"><context context-type="linenumber">52</context></context-group>
</trans-unit>
- <trans-unit id="_msg264">
+ <trans-unit id="_msg265">
<source xml:space="preserve">&amp;Address</source>
<context-group purpose="location"><context context-type="linenumber">42</context></context-group>
</trans-unit>
@@ -1183,35 +1187,35 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../editaddressdialog.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="EditAddressDialog">
- <trans-unit id="_msg265">
+ <trans-unit id="_msg266">
<source xml:space="preserve">New sending address</source>
<context-group purpose="location"><context context-type="linenumber">29</context></context-group>
</trans-unit>
- <trans-unit id="_msg266">
+ <trans-unit id="_msg267">
<source xml:space="preserve">Edit receiving address</source>
<context-group purpose="location"><context context-type="linenumber">32</context></context-group>
</trans-unit>
- <trans-unit id="_msg267">
+ <trans-unit id="_msg268">
<source xml:space="preserve">Edit sending address</source>
<context-group purpose="location"><context context-type="linenumber">36</context></context-group>
</trans-unit>
- <trans-unit id="_msg268">
+ <trans-unit id="_msg269">
<source xml:space="preserve">The entered address &quot;%1&quot; is not a valid Bitcoin address.</source>
<context-group purpose="location"><context context-type="linenumber">113</context></context-group>
</trans-unit>
- <trans-unit id="_msg269">
+ <trans-unit id="_msg270">
<source xml:space="preserve">Address &quot;%1&quot; already exists as a receiving address with label &quot;%2&quot; and so cannot be added as a sending address.</source>
<context-group purpose="location"><context context-type="linenumber">146</context></context-group>
</trans-unit>
- <trans-unit id="_msg270">
+ <trans-unit id="_msg271">
<source xml:space="preserve">The entered address &quot;%1&quot; is already in the address book with label &quot;%2&quot;.</source>
<context-group purpose="location"><context context-type="linenumber">151</context></context-group>
</trans-unit>
- <trans-unit id="_msg271">
+ <trans-unit id="_msg272">
<source xml:space="preserve">Could not unlock wallet.</source>
<context-group purpose="location"><context context-type="linenumber">123</context></context-group>
</trans-unit>
- <trans-unit id="_msg272">
+ <trans-unit id="_msg273">
<source xml:space="preserve">New key generation failed.</source>
<context-group purpose="location"><context context-type="linenumber">128</context></context-group>
</trans-unit>
@@ -1219,90 +1223,90 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../intro.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="FreespaceChecker">
- <trans-unit id="_msg273">
+ <trans-unit id="_msg274">
<source xml:space="preserve">A new data directory will be created.</source>
<context-group purpose="location"><context context-type="linenumber">73</context></context-group>
</trans-unit>
- <trans-unit id="_msg274">
+ <trans-unit id="_msg275">
<source xml:space="preserve">name</source>
<context-group purpose="location"><context context-type="linenumber">95</context></context-group>
</trans-unit>
- <trans-unit id="_msg275">
+ <trans-unit id="_msg276">
<source xml:space="preserve">Directory already exists. Add %1 if you intend to create a new directory here.</source>
<context-group purpose="location"><context context-type="linenumber">97</context></context-group>
</trans-unit>
- <trans-unit id="_msg276">
+ <trans-unit id="_msg277">
<source xml:space="preserve">Path already exists, and is not a directory.</source>
<context-group purpose="location"><context context-type="linenumber">100</context></context-group>
</trans-unit>
- <trans-unit id="_msg277">
+ <trans-unit id="_msg278">
<source xml:space="preserve">Cannot create data directory here.</source>
<context-group purpose="location"><context context-type="linenumber">107</context></context-group>
</trans-unit>
</group>
<group restype="x-trolltech-linguist-context" resname="Intro">
- <trans-unit id="_msg278">
+ <trans-unit id="_msg279">
<source xml:space="preserve">Bitcoin</source>
<context-group purpose="location"><context context-type="linenumber">139</context></context-group>
</trans-unit>
<group restype="x-gettext-plurals">
<context-group purpose="location"><context context-type="linenumber">301</context></context-group>
- <trans-unit id="_msg279[0]">
+ <trans-unit id="_msg280[0]">
<source xml:space="preserve">%n GB of space available</source>
</trans-unit>
- <trans-unit id="_msg279[1]">
+ <trans-unit id="_msg280[1]">
<source xml:space="preserve">%n GB of space available</source>
</trans-unit>
</group>
<group restype="x-gettext-plurals">
<context-group purpose="location"><context context-type="linenumber">303</context></context-group>
- <trans-unit id="_msg280[0]">
+ <trans-unit id="_msg281[0]">
<source xml:space="preserve">(of %n GB needed)</source>
</trans-unit>
- <trans-unit id="_msg280[1]">
+ <trans-unit id="_msg281[1]">
<source xml:space="preserve">(of %n GB needed)</source>
</trans-unit>
</group>
<group restype="x-gettext-plurals">
<context-group purpose="location"><context context-type="linenumber">306</context></context-group>
- <trans-unit id="_msg281[0]">
+ <trans-unit id="_msg282[0]">
<source xml:space="preserve">(%n GB needed for full chain)</source>
</trans-unit>
- <trans-unit id="_msg281[1]">
+ <trans-unit id="_msg282[1]">
<source xml:space="preserve">(%n GB needed for full chain)</source>
</trans-unit>
</group>
- <trans-unit id="_msg282">
+ <trans-unit id="_msg283">
<source xml:space="preserve">At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
<context-group purpose="location"><context context-type="linenumber">378</context></context-group>
</trans-unit>
- <trans-unit id="_msg283">
+ <trans-unit id="_msg284">
<source xml:space="preserve">Approximately %1 GB of data will be stored in this directory.</source>
<context-group purpose="location"><context context-type="linenumber">381</context></context-group>
</trans-unit>
<group restype="x-gettext-plurals">
<context-group purpose="location"><context context-type="linenumber">390</context></context-group>
<note annotates="source" from="developer">Explanatory text on the capability of the current prune target.</note>
- <trans-unit id="_msg284[0]">
+ <trans-unit id="_msg285[0]">
<source xml:space="preserve">(sufficient to restore backups %n day(s) old)</source>
</trans-unit>
- <trans-unit id="_msg284[1]">
+ <trans-unit id="_msg285[1]">
<source xml:space="preserve">(sufficient to restore backups %n day(s) old)</source>
</trans-unit>
</group>
- <trans-unit id="_msg285">
+ <trans-unit id="_msg286">
<source xml:space="preserve">%1 will download and store a copy of the Bitcoin block chain.</source>
<context-group purpose="location"><context context-type="linenumber">392</context></context-group>
</trans-unit>
- <trans-unit id="_msg286">
+ <trans-unit id="_msg287">
<source xml:space="preserve">The wallet will also be stored in this directory.</source>
<context-group purpose="location"><context context-type="linenumber">394</context></context-group>
</trans-unit>
- <trans-unit id="_msg287">
+ <trans-unit id="_msg288">
<source xml:space="preserve">Error: Specified data directory &quot;%1&quot; cannot be created.</source>
<context-group purpose="location"><context context-type="linenumber">250</context></context-group>
</trans-unit>
- <trans-unit id="_msg288">
+ <trans-unit id="_msg289">
<source xml:space="preserve">Error</source>
<context-group purpose="location"><context context-type="linenumber">280</context></context-group>
</trans-unit>
@@ -1310,25 +1314,25 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../utilitydialog.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="HelpMessageDialog">
- <trans-unit id="_msg289">
+ <trans-unit id="_msg290">
<source xml:space="preserve">version</source>
<context-group purpose="location"><context context-type="linenumber">38</context></context-group>
</trans-unit>
- <trans-unit id="_msg290">
+ <trans-unit id="_msg291">
<source xml:space="preserve">About %1</source>
<context-group purpose="location"><context context-type="linenumber">42</context></context-group>
</trans-unit>
- <trans-unit id="_msg291">
+ <trans-unit id="_msg292">
<source xml:space="preserve">Command-line options</source>
<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="_msg292">
+ <trans-unit id="_msg293">
<source xml:space="preserve">%1 is shutting down…</source>
<context-group purpose="location"><context context-type="linenumber">145</context></context-group>
</trans-unit>
- <trans-unit id="_msg293">
+ <trans-unit id="_msg294">
<source xml:space="preserve">Do not shut down the computer until this window disappears.</source>
<context-group purpose="location"><context context-type="linenumber">146</context></context-group>
</trans-unit>
@@ -1336,22 +1340,18 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../forms/intro.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="Intro">
- <trans-unit id="_msg294">
+ <trans-unit id="_msg295">
<source xml:space="preserve">Welcome</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
</trans-unit>
- <trans-unit id="_msg295">
+ <trans-unit id="_msg296">
<source xml:space="preserve">Welcome to %1.</source>
<context-group purpose="location"><context context-type="linenumber">23</context></context-group>
</trans-unit>
- <trans-unit id="_msg296">
+ <trans-unit id="_msg297">
<source xml:space="preserve">As this is the first time the program is launched, you can choose where %1 will store its data.</source>
<context-group purpose="location"><context context-type="linenumber">49</context></context-group>
</trans-unit>
- <trans-unit id="_msg297">
- <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>
- <context-group purpose="location"><context context-type="linenumber">206</context></context-group>
- </trans-unit>
<trans-unit id="_msg298">
<source xml:space="preserve">Limit block chain storage to</source>
<context-group purpose="location"><context context-type="linenumber">238</context></context-group>
@@ -1369,14 +1369,18 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<context-group purpose="location"><context context-type="linenumber">216</context></context-group>
</trans-unit>
<trans-unit id="_msg302">
+ <source xml:space="preserve">When you click OK, %1 will begin to download and process the full %4 block chain (%2 GB) starting with the earliest transactions in %3 when %4 initially launched.</source>
+ <context-group purpose="location"><context context-type="linenumber">206</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg303">
<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>
<context-group purpose="location"><context context-type="linenumber">226</context></context-group>
</trans-unit>
- <trans-unit id="_msg303">
+ <trans-unit id="_msg304">
<source xml:space="preserve">Use the default data directory</source>
<context-group purpose="location"><context context-type="linenumber">66</context></context-group>
</trans-unit>
- <trans-unit id="_msg304">
+ <trans-unit id="_msg305">
<source xml:space="preserve">Use a custom data directory:</source>
<context-group purpose="location"><context context-type="linenumber">73</context></context-group>
</trans-unit>
@@ -1384,54 +1388,54 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../forms/modaloverlay.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="ModalOverlay">
- <trans-unit id="_msg305">
+ <trans-unit id="_msg306">
<source xml:space="preserve">Form</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
</trans-unit>
- <trans-unit id="_msg306">
+ <trans-unit id="_msg307">
<source xml:space="preserve">Recent transactions may not yet be visible, and therefore your wallet&apos;s balance might be incorrect. This information will be correct once your wallet has finished synchronizing with the bitcoin network, as detailed below.</source>
<context-group purpose="location"><context context-type="linenumber">133</context></context-group>
</trans-unit>
- <trans-unit id="_msg307">
+ <trans-unit id="_msg308">
<source xml:space="preserve">Attempting to spend bitcoins that are affected by not-yet-displayed transactions will not be accepted by the network.</source>
<context-group purpose="location"><context context-type="linenumber">152</context></context-group>
</trans-unit>
- <trans-unit id="_msg308">
+ <trans-unit id="_msg309">
<source xml:space="preserve">Number of blocks left</source>
<context-group purpose="location"><context context-type="linenumber">215</context></context-group>
</trans-unit>
- <trans-unit id="_msg309">
+ <trans-unit id="_msg310">
<source xml:space="preserve">Unknown…</source>
<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">152</context></context-group>
+ <context-group purpose="location"><context context-type="sourcefile">../modaloverlay.cpp</context><context context-type="linenumber">155</context></context-group>
</trans-unit>
- <trans-unit id="_msg310">
+ <trans-unit id="_msg311">
<source xml:space="preserve">calculating…</source>
<context-group purpose="location"><context context-type="linenumber">292</context></context-group>
<context-group purpose="location"><context context-type="linenumber">312</context></context-group>
</trans-unit>
- <trans-unit id="_msg311">
+ <trans-unit id="_msg312">
<source xml:space="preserve">Last block time</source>
<context-group purpose="location"><context context-type="linenumber">235</context></context-group>
</trans-unit>
- <trans-unit id="_msg312">
+ <trans-unit id="_msg313">
<source xml:space="preserve">Progress</source>
<context-group purpose="location"><context context-type="linenumber">261</context></context-group>
</trans-unit>
- <trans-unit id="_msg313">
+ <trans-unit id="_msg314">
<source xml:space="preserve">Progress increase per hour</source>
<context-group purpose="location"><context context-type="linenumber">285</context></context-group>
</trans-unit>
- <trans-unit id="_msg314">
+ <trans-unit id="_msg315">
<source xml:space="preserve">Estimated time left until synced</source>
<context-group purpose="location"><context context-type="linenumber">305</context></context-group>
</trans-unit>
- <trans-unit id="_msg315">
+ <trans-unit id="_msg316">
<source xml:space="preserve">Hide</source>
<context-group purpose="location"><context context-type="linenumber">342</context></context-group>
</trans-unit>
- <trans-unit id="_msg316">
+ <trans-unit id="_msg317">
<source xml:space="preserve">Esc</source>
<context-group purpose="location"><context context-type="linenumber">345</context></context-group>
</trans-unit>
@@ -1439,33 +1443,37 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../modaloverlay.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="ModalOverlay">
- <trans-unit id="_msg317">
+ <trans-unit id="_msg318">
<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>
<context-group purpose="location"><context context-type="linenumber">34</context></context-group>
</trans-unit>
- <trans-unit id="_msg318">
+ <trans-unit id="_msg319">
<source xml:space="preserve">Unknown. Syncing Headers (%1, %2%)…</source>
- <context-group purpose="location"><context context-type="linenumber">158</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">161</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg320">
+ <source xml:space="preserve">Unknown. Pre-syncing Headers (%1, %2%)…</source>
+ <context-group purpose="location"><context context-type="linenumber">166</context></context-group>
</trans-unit>
</group>
<group restype="x-trolltech-linguist-context" resname="QObject">
- <trans-unit id="_msg319">
+ <trans-unit id="_msg321">
<source xml:space="preserve">unknown</source>
- <context-group purpose="location"><context context-type="linenumber">123</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">126</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../forms/openuridialog.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="OpenURIDialog">
- <trans-unit id="_msg320">
+ <trans-unit id="_msg322">
<source xml:space="preserve">Open bitcoin URI</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
</trans-unit>
- <trans-unit id="_msg321">
+ <trans-unit id="_msg323">
<source xml:space="preserve">URI:</source>
<context-group purpose="location"><context context-type="linenumber">22</context></context-group>
</trans-unit>
- <trans-unit id="_msg322">
+ <trans-unit id="_msg324">
<source xml:space="preserve">Paste address from clipboard</source>
<context-group purpose="location"><context context-type="linenumber">36</context></context-group>
<note annotates="source" from="developer">Tooltip text for button that allows you to paste an address that is in your clipboard.</note>
@@ -1474,310 +1482,310 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../forms/optionsdialog.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="OptionsDialog">
- <trans-unit id="_msg323">
+ <trans-unit id="_msg325">
<source xml:space="preserve">Options</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
</trans-unit>
- <trans-unit id="_msg324">
+ <trans-unit id="_msg326">
<source xml:space="preserve">&amp;Main</source>
<context-group purpose="location"><context context-type="linenumber">27</context></context-group>
</trans-unit>
- <trans-unit id="_msg325">
+ <trans-unit id="_msg327">
<source xml:space="preserve">Automatically start %1 after logging in to the system.</source>
<context-group purpose="location"><context context-type="linenumber">33</context></context-group>
</trans-unit>
- <trans-unit id="_msg326">
+ <trans-unit id="_msg328">
<source xml:space="preserve">&amp;Start %1 on system login</source>
<context-group purpose="location"><context context-type="linenumber">36</context></context-group>
</trans-unit>
- <trans-unit id="_msg327">
+ <trans-unit id="_msg329">
<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>
<context-group purpose="location"><context context-type="linenumber">58</context></context-group>
</trans-unit>
- <trans-unit id="_msg328">
+ <trans-unit id="_msg330">
<source xml:space="preserve">Size of &amp;database cache</source>
<context-group purpose="location"><context context-type="linenumber">111</context></context-group>
</trans-unit>
- <trans-unit id="_msg329">
+ <trans-unit id="_msg331">
<source xml:space="preserve">Number of script &amp;verification threads</source>
<context-group purpose="location"><context context-type="linenumber">157</context></context-group>
</trans-unit>
- <trans-unit id="_msg330">
+ <trans-unit id="_msg332">
<source xml:space="preserve">IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source>
<context-group purpose="location"><context context-type="linenumber">388</context></context-group>
<context-group purpose="location"><context context-type="linenumber">575</context></context-group>
</trans-unit>
- <trans-unit id="_msg331">
+ <trans-unit id="_msg333">
<source xml:space="preserve">Shows if the supplied default SOCKS5 proxy is used to reach peers via this network type.</source>
<context-group purpose="location"><context context-type="linenumber">457</context></context-group>
<context-group purpose="location"><context context-type="linenumber">480</context></context-group>
<context-group purpose="location"><context context-type="linenumber">503</context></context-group>
</trans-unit>
- <trans-unit id="_msg332">
+ <trans-unit id="_msg334">
<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>
<context-group purpose="location"><context context-type="linenumber">672</context></context-group>
</trans-unit>
- <trans-unit id="_msg333">
+ <trans-unit id="_msg335">
<source xml:space="preserve">Options set in this dialog are overridden by the command line:</source>
<context-group purpose="location"><context context-type="linenumber">899</context></context-group>
</trans-unit>
- <trans-unit id="_msg334">
+ <trans-unit id="_msg336">
<source xml:space="preserve">Open the %1 configuration file from the working directory.</source>
<context-group purpose="location"><context context-type="linenumber">944</context></context-group>
</trans-unit>
- <trans-unit id="_msg335">
+ <trans-unit id="_msg337">
<source xml:space="preserve">Open Configuration File</source>
<context-group purpose="location"><context context-type="linenumber">947</context></context-group>
</trans-unit>
- <trans-unit id="_msg336">
+ <trans-unit id="_msg338">
<source xml:space="preserve">Reset all client options to default.</source>
<context-group purpose="location"><context context-type="linenumber">957</context></context-group>
</trans-unit>
- <trans-unit id="_msg337">
+ <trans-unit id="_msg339">
<source xml:space="preserve">&amp;Reset Options</source>
<context-group purpose="location"><context context-type="linenumber">960</context></context-group>
</trans-unit>
- <trans-unit id="_msg338">
+ <trans-unit id="_msg340">
<source xml:space="preserve">&amp;Network</source>
<context-group purpose="location"><context context-type="linenumber">315</context></context-group>
</trans-unit>
- <trans-unit id="_msg339">
+ <trans-unit id="_msg341">
<source xml:space="preserve">Prune &amp;block storage to</source>
<context-group purpose="location"><context context-type="linenumber">61</context></context-group>
</trans-unit>
- <trans-unit id="_msg340">
+ <trans-unit id="_msg342">
<source xml:space="preserve">GB</source>
<context-group purpose="location"><context context-type="linenumber">71</context></context-group>
</trans-unit>
- <trans-unit id="_msg341">
+ <trans-unit id="_msg343">
<source xml:space="preserve">Reverting this setting requires re-downloading the entire blockchain.</source>
<context-group purpose="location"><context context-type="linenumber">96</context></context-group>
</trans-unit>
- <trans-unit id="_msg342">
+ <trans-unit id="_msg344">
<source xml:space="preserve">Maximum database cache size. A larger cache can contribute to faster sync, after which the benefit is less pronounced for most use cases. Lowering the cache size will reduce memory usage. Unused mempool memory is shared for this cache.</source>
<context-group purpose="location"><context context-type="linenumber">108</context></context-group>
<note annotates="source" from="developer">Tooltip text for Options window setting that sets the size of the database cache. Explains the corresponding effects of increasing/decreasing this value.</note>
</trans-unit>
- <trans-unit id="_msg343">
+ <trans-unit id="_msg345">
<source xml:space="preserve">MiB</source>
<context-group purpose="location"><context context-type="linenumber">127</context></context-group>
</trans-unit>
- <trans-unit id="_msg344">
+ <trans-unit id="_msg346">
<source xml:space="preserve">Set the number of script verification threads. Negative values correspond to the number of cores you want to leave free to the system.</source>
<context-group purpose="location"><context context-type="linenumber">154</context></context-group>
<note annotates="source" from="developer">Tooltip text for Options window setting that sets the number of script verification threads. Explains that negative values mean to leave these many cores free to the system.</note>
</trans-unit>
- <trans-unit id="_msg345">
+ <trans-unit id="_msg347">
<source xml:space="preserve">(0 = auto, &lt;0 = leave that many cores free)</source>
<context-group purpose="location"><context context-type="linenumber">170</context></context-group>
</trans-unit>
- <trans-unit id="_msg346">
+ <trans-unit id="_msg348">
<source xml:space="preserve">This allows you or a third party tool to communicate with the node through command-line and JSON-RPC commands.</source>
<context-group purpose="location"><context context-type="linenumber">192</context></context-group>
<note annotates="source" from="developer">Tooltip text for Options window setting that enables the RPC server.</note>
</trans-unit>
- <trans-unit id="_msg347">
+ <trans-unit id="_msg349">
<source xml:space="preserve">Enable R&amp;PC server</source>
<context-group purpose="location"><context context-type="linenumber">195</context></context-group>
<note annotates="source" from="developer">An Options window setting to enable the RPC server.</note>
</trans-unit>
- <trans-unit id="_msg348">
+ <trans-unit id="_msg350">
<source xml:space="preserve">W&amp;allet</source>
<context-group purpose="location"><context context-type="linenumber">216</context></context-group>
</trans-unit>
- <trans-unit id="_msg349">
+ <trans-unit id="_msg351">
<source xml:space="preserve">Whether to set subtract fee from amount as default or not.</source>
<context-group purpose="location"><context context-type="linenumber">222</context></context-group>
<note annotates="source" from="developer">Tooltip text for Options window setting that sets subtracting the fee from a sending amount as default.</note>
</trans-unit>
- <trans-unit id="_msg350">
+ <trans-unit id="_msg352">
<source xml:space="preserve">Subtract &amp;fee from amount by default</source>
<context-group purpose="location"><context context-type="linenumber">225</context></context-group>
<note annotates="source" from="developer">An Options window setting to set subtracting the fee from a sending amount as default.</note>
</trans-unit>
- <trans-unit id="_msg351">
+ <trans-unit id="_msg353">
<source xml:space="preserve">Expert</source>
<context-group purpose="location"><context context-type="linenumber">232</context></context-group>
</trans-unit>
- <trans-unit id="_msg352">
+ <trans-unit id="_msg354">
<source xml:space="preserve">Enable coin &amp;control features</source>
<context-group purpose="location"><context context-type="linenumber">241</context></context-group>
</trans-unit>
- <trans-unit id="_msg353">
+ <trans-unit id="_msg355">
<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>
<context-group purpose="location"><context context-type="linenumber">248</context></context-group>
</trans-unit>
- <trans-unit id="_msg354">
+ <trans-unit id="_msg356">
<source xml:space="preserve">&amp;Spend unconfirmed change</source>
<context-group purpose="location"><context context-type="linenumber">251</context></context-group>
</trans-unit>
- <trans-unit id="_msg355">
+ <trans-unit id="_msg357">
<source xml:space="preserve">Enable &amp;PSBT controls</source>
<context-group purpose="location"><context context-type="linenumber">258</context></context-group>
<note annotates="source" from="developer">An options window setting to enable PSBT controls.</note>
</trans-unit>
- <trans-unit id="_msg356">
+ <trans-unit id="_msg358">
<source xml:space="preserve">Whether to show PSBT controls.</source>
<context-group purpose="location"><context context-type="linenumber">261</context></context-group>
<note annotates="source" from="developer">Tooltip text for options window setting that enables PSBT controls.</note>
</trans-unit>
- <trans-unit id="_msg357">
+ <trans-unit id="_msg359">
<source xml:space="preserve">External Signer (e.g. hardware wallet)</source>
<context-group purpose="location"><context context-type="linenumber">271</context></context-group>
</trans-unit>
- <trans-unit id="_msg358">
+ <trans-unit id="_msg360">
<source xml:space="preserve">&amp;External signer script path</source>
<context-group purpose="location"><context context-type="linenumber">279</context></context-group>
</trans-unit>
- <trans-unit id="_msg359">
+ <trans-unit id="_msg361">
<source xml:space="preserve">Full path to a Bitcoin Core compatible script (e.g. C:\Downloads\hwi.exe or /Users/you/Downloads/hwi.py). Beware: malware can steal your coins!</source>
<context-group purpose="location"><context context-type="linenumber">289</context></context-group>
</trans-unit>
- <trans-unit id="_msg360">
+ <trans-unit id="_msg362">
<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>
<context-group purpose="location"><context context-type="linenumber">321</context></context-group>
</trans-unit>
- <trans-unit id="_msg361">
+ <trans-unit id="_msg363">
<source xml:space="preserve">Map port using &amp;UPnP</source>
<context-group purpose="location"><context context-type="linenumber">324</context></context-group>
</trans-unit>
- <trans-unit id="_msg362">
+ <trans-unit id="_msg364">
<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>
<context-group purpose="location"><context context-type="linenumber">331</context></context-group>
</trans-unit>
- <trans-unit id="_msg363">
+ <trans-unit id="_msg365">
<source xml:space="preserve">Map port using NA&amp;T-PMP</source>
<context-group purpose="location"><context context-type="linenumber">334</context></context-group>
</trans-unit>
- <trans-unit id="_msg364">
+ <trans-unit id="_msg366">
<source xml:space="preserve">Accept connections from outside.</source>
<context-group purpose="location"><context context-type="linenumber">341</context></context-group>
</trans-unit>
- <trans-unit id="_msg365">
+ <trans-unit id="_msg367">
<source xml:space="preserve">Allow incomin&amp;g connections</source>
<context-group purpose="location"><context context-type="linenumber">344</context></context-group>
</trans-unit>
- <trans-unit id="_msg366">
+ <trans-unit id="_msg368">
<source xml:space="preserve">Connect to the Bitcoin network through a SOCKS5 proxy.</source>
<context-group purpose="location"><context context-type="linenumber">351</context></context-group>
</trans-unit>
- <trans-unit id="_msg367">
+ <trans-unit id="_msg369">
<source xml:space="preserve">&amp;Connect through SOCKS5 proxy (default proxy):</source>
<context-group purpose="location"><context context-type="linenumber">354</context></context-group>
</trans-unit>
- <trans-unit id="_msg368">
+ <trans-unit id="_msg370">
<source xml:space="preserve">Proxy &amp;IP:</source>
<context-group purpose="location"><context context-type="linenumber">363</context></context-group>
<context-group purpose="location"><context context-type="linenumber">550</context></context-group>
</trans-unit>
- <trans-unit id="_msg369">
+ <trans-unit id="_msg371">
<source xml:space="preserve">&amp;Port:</source>
<context-group purpose="location"><context context-type="linenumber">395</context></context-group>
<context-group purpose="location"><context context-type="linenumber">582</context></context-group>
</trans-unit>
- <trans-unit id="_msg370">
+ <trans-unit id="_msg372">
<source xml:space="preserve">Port of the proxy (e.g. 9050)</source>
<context-group purpose="location"><context context-type="linenumber">420</context></context-group>
<context-group purpose="location"><context context-type="linenumber">607</context></context-group>
</trans-unit>
- <trans-unit id="_msg371">
+ <trans-unit id="_msg373">
<source xml:space="preserve">Used for reaching peers via:</source>
<context-group purpose="location"><context context-type="linenumber">444</context></context-group>
</trans-unit>
- <trans-unit id="_msg372">
+ <trans-unit id="_msg374">
<source xml:space="preserve">IPv4</source>
<context-group purpose="location"><context context-type="linenumber">467</context></context-group>
</trans-unit>
- <trans-unit id="_msg373">
+ <trans-unit id="_msg375">
<source xml:space="preserve">IPv6</source>
<context-group purpose="location"><context context-type="linenumber">490</context></context-group>
</trans-unit>
- <trans-unit id="_msg374">
+ <trans-unit id="_msg376">
<source xml:space="preserve">Tor</source>
<context-group purpose="location"><context context-type="linenumber">513</context></context-group>
</trans-unit>
- <trans-unit id="_msg375">
+ <trans-unit id="_msg377">
<source xml:space="preserve">&amp;Window</source>
<context-group purpose="location"><context context-type="linenumber">643</context></context-group>
</trans-unit>
- <trans-unit id="_msg376">
+ <trans-unit id="_msg378">
<source xml:space="preserve">Show the icon in the system tray.</source>
<context-group purpose="location"><context context-type="linenumber">649</context></context-group>
</trans-unit>
- <trans-unit id="_msg377">
+ <trans-unit id="_msg379">
<source xml:space="preserve">&amp;Show tray icon</source>
<context-group purpose="location"><context context-type="linenumber">652</context></context-group>
</trans-unit>
- <trans-unit id="_msg378">
+ <trans-unit id="_msg380">
<source xml:space="preserve">Show only a tray icon after minimizing the window.</source>
<context-group purpose="location"><context context-type="linenumber">662</context></context-group>
</trans-unit>
- <trans-unit id="_msg379">
+ <trans-unit id="_msg381">
<source xml:space="preserve">&amp;Minimize to the tray instead of the taskbar</source>
<context-group purpose="location"><context context-type="linenumber">665</context></context-group>
</trans-unit>
- <trans-unit id="_msg380">
+ <trans-unit id="_msg382">
<source xml:space="preserve">M&amp;inimize on close</source>
<context-group purpose="location"><context context-type="linenumber">675</context></context-group>
</trans-unit>
- <trans-unit id="_msg381">
+ <trans-unit id="_msg383">
<source xml:space="preserve">&amp;Display</source>
<context-group purpose="location"><context context-type="linenumber">696</context></context-group>
</trans-unit>
- <trans-unit id="_msg382">
+ <trans-unit id="_msg384">
<source xml:space="preserve">User Interface &amp;language:</source>
<context-group purpose="location"><context context-type="linenumber">704</context></context-group>
</trans-unit>
- <trans-unit id="_msg383">
+ <trans-unit id="_msg385">
<source xml:space="preserve">The user interface language can be set here. This setting will take effect after restarting %1.</source>
<context-group purpose="location"><context context-type="linenumber">717</context></context-group>
</trans-unit>
- <trans-unit id="_msg384">
+ <trans-unit id="_msg386">
<source xml:space="preserve">&amp;Unit to show amounts in:</source>
<context-group purpose="location"><context context-type="linenumber">728</context></context-group>
</trans-unit>
- <trans-unit id="_msg385">
+ <trans-unit id="_msg387">
<source xml:space="preserve">Choose the default subdivision unit to show in the interface and when sending coins.</source>
<context-group purpose="location"><context context-type="linenumber">741</context></context-group>
</trans-unit>
- <trans-unit id="_msg386">
+ <trans-unit id="_msg388">
<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>
<context-group purpose="location"><context context-type="linenumber">752</context></context-group>
<context-group purpose="location"><context context-type="linenumber">765</context></context-group>
</trans-unit>
- <trans-unit id="_msg387">
+ <trans-unit id="_msg389">
<source xml:space="preserve">&amp;Third-party transaction URLs</source>
<context-group purpose="location"><context context-type="linenumber">755</context></context-group>
</trans-unit>
- <trans-unit id="_msg388">
+ <trans-unit id="_msg390">
<source xml:space="preserve">Whether to show coin control features or not.</source>
<context-group purpose="location"><context context-type="linenumber">238</context></context-group>
</trans-unit>
- <trans-unit id="_msg389">
+ <trans-unit id="_msg391">
<source xml:space="preserve">Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor onion services.</source>
<context-group purpose="location"><context context-type="linenumber">538</context></context-group>
</trans-unit>
- <trans-unit id="_msg390">
+ <trans-unit id="_msg392">
<source xml:space="preserve">Use separate SOCKS&amp;5 proxy to reach peers via Tor onion services:</source>
<context-group purpose="location"><context context-type="linenumber">541</context></context-group>
</trans-unit>
- <trans-unit id="_msg391">
+ <trans-unit id="_msg393">
<source xml:space="preserve">Monospaced font in the Overview tab:</source>
<context-group purpose="location"><context context-type="linenumber">777</context></context-group>
</trans-unit>
- <trans-unit id="_msg392">
+ <trans-unit id="_msg394">
<source xml:space="preserve">embedded &quot;%1&quot;</source>
<context-group purpose="location"><context context-type="linenumber">785</context></context-group>
</trans-unit>
- <trans-unit id="_msg393">
+ <trans-unit id="_msg395">
<source xml:space="preserve">closest matching &quot;%1&quot;</source>
<context-group purpose="location"><context context-type="linenumber">834</context></context-group>
</trans-unit>
- <trans-unit id="_msg394">
+ <trans-unit id="_msg396">
<source xml:space="preserve">&amp;OK</source>
<context-group purpose="location"><context context-type="linenumber">1040</context></context-group>
</trans-unit>
- <trans-unit id="_msg395">
+ <trans-unit id="_msg397">
<source xml:space="preserve">&amp;Cancel</source>
<context-group purpose="location"><context context-type="linenumber">1053</context></context-group>
</trans-unit>
@@ -1785,71 +1793,71 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../optionsdialog.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="OptionsDialog">
- <trans-unit id="_msg396">
+ <trans-unit id="_msg398">
<source xml:space="preserve">Compiled without external signing support (required for external signing)</source>
<context-group purpose="location"><context context-type="linenumber">96</context></context-group>
<note annotates="source" from="developer">&quot;External signing&quot; means using devices such as hardware wallets.</note>
</trans-unit>
- <trans-unit id="_msg397">
+ <trans-unit id="_msg399">
<source xml:space="preserve">default</source>
<context-group purpose="location"><context context-type="linenumber">108</context></context-group>
</trans-unit>
- <trans-unit id="_msg398">
+ <trans-unit id="_msg400">
<source xml:space="preserve">none</source>
<context-group purpose="location"><context context-type="linenumber">194</context></context-group>
</trans-unit>
- <trans-unit id="_msg399">
+ <trans-unit id="_msg401">
<source xml:space="preserve">Confirm options reset</source>
<context-group purpose="location"><context context-type="linenumber">301</context></context-group>
<note annotates="source" from="developer">Window title text of pop-up window shown when the user has chosen to reset options.</note>
</trans-unit>
- <trans-unit id="_msg400">
+ <trans-unit id="_msg402">
<source xml:space="preserve">Client restart required to activate changes.</source>
<context-group purpose="location"><context context-type="linenumber">292</context></context-group>
<context-group purpose="location"><context context-type="linenumber">371</context></context-group>
<note annotates="source" from="developer">Text explaining that the settings changed will not come into effect until the client is restarted.</note>
</trans-unit>
- <trans-unit id="_msg401">
+ <trans-unit id="_msg403">
<source xml:space="preserve">Current settings will be backed up at &quot;%1&quot;.</source>
<context-group purpose="location"><context context-type="linenumber">296</context></context-group>
<note annotates="source" from="developer">Text explaining to the user that the client&apos;s current settings will be backed up at a specific location. %1 is a stand-in argument for the backup location&apos;s path.</note>
</trans-unit>
- <trans-unit id="_msg402">
+ <trans-unit id="_msg404">
<source xml:space="preserve">Client will be shut down. Do you want to proceed?</source>
<context-group purpose="location"><context context-type="linenumber">299</context></context-group>
<note annotates="source" from="developer">Text asking the user to confirm if they would like to proceed with a client shutdown.</note>
</trans-unit>
- <trans-unit id="_msg403">
+ <trans-unit id="_msg405">
<source xml:space="preserve">Configuration options</source>
<context-group purpose="location"><context context-type="linenumber">319</context></context-group>
<note annotates="source" from="developer">Window title text of pop-up box that allows opening up of configuration file.</note>
</trans-unit>
- <trans-unit id="_msg404">
+ <trans-unit id="_msg406">
<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>
<context-group purpose="location"><context context-type="linenumber">322</context></context-group>
<note annotates="source" from="developer">Explanatory text about the priority order of instructions considered by client. The order from high to low being: command-line, configuration file, GUI settings.</note>
</trans-unit>
- <trans-unit id="_msg405">
+ <trans-unit id="_msg407">
<source xml:space="preserve">Continue</source>
<context-group purpose="location"><context context-type="linenumber">325</context></context-group>
</trans-unit>
- <trans-unit id="_msg406">
+ <trans-unit id="_msg408">
<source xml:space="preserve">Cancel</source>
<context-group purpose="location"><context context-type="linenumber">326</context></context-group>
</trans-unit>
- <trans-unit id="_msg407">
+ <trans-unit id="_msg409">
<source xml:space="preserve">Error</source>
<context-group purpose="location"><context context-type="linenumber">335</context></context-group>
</trans-unit>
- <trans-unit id="_msg408">
+ <trans-unit id="_msg410">
<source xml:space="preserve">The configuration file could not be opened.</source>
<context-group purpose="location"><context context-type="linenumber">335</context></context-group>
</trans-unit>
- <trans-unit id="_msg409">
+ <trans-unit id="_msg411">
<source xml:space="preserve">This change would require a client restart.</source>
<context-group purpose="location"><context context-type="linenumber">375</context></context-group>
</trans-unit>
- <trans-unit id="_msg410">
+ <trans-unit id="_msg412">
<source xml:space="preserve">The supplied proxy address is invalid.</source>
<context-group purpose="location"><context context-type="linenumber">403</context></context-group>
</trans-unit>
@@ -1857,7 +1865,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../optionsmodel.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="OptionsModel">
- <trans-unit id="_msg411">
+ <trans-unit id="_msg413">
<source xml:space="preserve">Could not read setting &quot;%1&quot;, %2.</source>
<context-group purpose="location"><context context-type="linenumber">204</context></context-group>
</trans-unit>
@@ -1865,76 +1873,76 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../forms/overviewpage.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="OverviewPage">
- <trans-unit id="_msg412">
+ <trans-unit id="_msg414">
<source xml:space="preserve">Form</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
</trans-unit>
- <trans-unit id="_msg413">
+ <trans-unit id="_msg415">
<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>
<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="_msg414">
+ <trans-unit id="_msg416">
<source xml:space="preserve">Watch-only:</source>
<context-group purpose="location"><context context-type="linenumber">284</context></context-group>
</trans-unit>
- <trans-unit id="_msg415">
+ <trans-unit id="_msg417">
<source xml:space="preserve">Available:</source>
<context-group purpose="location"><context context-type="linenumber">294</context></context-group>
</trans-unit>
- <trans-unit id="_msg416">
+ <trans-unit id="_msg418">
<source xml:space="preserve">Your current spendable balance</source>
<context-group purpose="location"><context context-type="linenumber">304</context></context-group>
</trans-unit>
- <trans-unit id="_msg417">
+ <trans-unit id="_msg419">
<source xml:space="preserve">Pending:</source>
<context-group purpose="location"><context context-type="linenumber">339</context></context-group>
</trans-unit>
- <trans-unit id="_msg418">
+ <trans-unit id="_msg420">
<source xml:space="preserve">Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</source>
<context-group purpose="location"><context context-type="linenumber">139</context></context-group>
</trans-unit>
- <trans-unit id="_msg419">
+ <trans-unit id="_msg421">
<source xml:space="preserve">Immature:</source>
<context-group purpose="location"><context context-type="linenumber">239</context></context-group>
</trans-unit>
- <trans-unit id="_msg420">
+ <trans-unit id="_msg422">
<source xml:space="preserve">Mined balance that has not yet matured</source>
<context-group purpose="location"><context context-type="linenumber">210</context></context-group>
</trans-unit>
- <trans-unit id="_msg421">
+ <trans-unit id="_msg423">
<source xml:space="preserve">Balances</source>
<context-group purpose="location"><context context-type="linenumber">60</context></context-group>
</trans-unit>
- <trans-unit id="_msg422">
+ <trans-unit id="_msg424">
<source xml:space="preserve">Total:</source>
<context-group purpose="location"><context context-type="linenumber">200</context></context-group>
</trans-unit>
- <trans-unit id="_msg423">
+ <trans-unit id="_msg425">
<source xml:space="preserve">Your current total balance</source>
<context-group purpose="location"><context context-type="linenumber">249</context></context-group>
</trans-unit>
- <trans-unit id="_msg424">
+ <trans-unit id="_msg426">
<source xml:space="preserve">Your current balance in watch-only addresses</source>
<context-group purpose="location"><context context-type="linenumber">323</context></context-group>
</trans-unit>
- <trans-unit id="_msg425">
+ <trans-unit id="_msg427">
<source xml:space="preserve">Spendable:</source>
<context-group purpose="location"><context context-type="linenumber">346</context></context-group>
</trans-unit>
- <trans-unit id="_msg426">
+ <trans-unit id="_msg428">
<source xml:space="preserve">Recent transactions</source>
<context-group purpose="location"><context context-type="linenumber">395</context></context-group>
</trans-unit>
- <trans-unit id="_msg427">
+ <trans-unit id="_msg429">
<source xml:space="preserve">Unconfirmed transactions to watch-only addresses</source>
<context-group purpose="location"><context context-type="linenumber">120</context></context-group>
</trans-unit>
- <trans-unit id="_msg428">
+ <trans-unit id="_msg430">
<source xml:space="preserve">Mined balance in watch-only addresses that has not yet matured</source>
<context-group purpose="location"><context context-type="linenumber">158</context></context-group>
</trans-unit>
- <trans-unit id="_msg429">
+ <trans-unit id="_msg431">
<source xml:space="preserve">Current total balance in watch-only addresses</source>
<context-group purpose="location"><context context-type="linenumber">268</context></context-group>
</trans-unit>
@@ -1942,35 +1950,35 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../overviewpage.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="OverviewPage">
- <trans-unit id="_msg430">
+ <trans-unit id="_msg432">
<source xml:space="preserve">Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings-&gt;Mask values.</source>
- <context-group purpose="location"><context context-type="linenumber">186</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">185</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../forms/psbtoperationsdialog.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="PSBTOperationsDialog">
- <trans-unit id="_msg431">
+ <trans-unit id="_msg433">
<source xml:space="preserve">Dialog</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
</trans-unit>
- <trans-unit id="_msg432">
+ <trans-unit id="_msg434">
<source xml:space="preserve">Sign Tx</source>
<context-group purpose="location"><context context-type="linenumber">86</context></context-group>
</trans-unit>
- <trans-unit id="_msg433">
+ <trans-unit id="_msg435">
<source xml:space="preserve">Broadcast Tx</source>
<context-group purpose="location"><context context-type="linenumber">102</context></context-group>
</trans-unit>
- <trans-unit id="_msg434">
+ <trans-unit id="_msg436">
<source xml:space="preserve">Copy to Clipboard</source>
<context-group purpose="location"><context context-type="linenumber">122</context></context-group>
</trans-unit>
- <trans-unit id="_msg435">
+ <trans-unit id="_msg437">
<source xml:space="preserve">Save…</source>
<context-group purpose="location"><context context-type="linenumber">129</context></context-group>
</trans-unit>
- <trans-unit id="_msg436">
+ <trans-unit id="_msg438">
<source xml:space="preserve">Close</source>
<context-group purpose="location"><context context-type="linenumber">136</context></context-group>
</trans-unit>
@@ -1978,108 +1986,108 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../psbtoperationsdialog.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="PSBTOperationsDialog">
- <trans-unit id="_msg437">
+ <trans-unit id="_msg439">
<source xml:space="preserve">Failed to load transaction: %1</source>
<context-group purpose="location"><context context-type="linenumber">61</context></context-group>
</trans-unit>
- <trans-unit id="_msg438">
+ <trans-unit id="_msg440">
<source xml:space="preserve">Failed to sign transaction: %1</source>
<context-group purpose="location"><context context-type="linenumber">86</context></context-group>
</trans-unit>
- <trans-unit id="_msg439">
+ <trans-unit id="_msg441">
<source xml:space="preserve">Cannot sign inputs while wallet is locked.</source>
<context-group purpose="location"><context context-type="linenumber">94</context></context-group>
</trans-unit>
- <trans-unit id="_msg440">
+ <trans-unit id="_msg442">
<source xml:space="preserve">Could not sign any more inputs.</source>
<context-group purpose="location"><context context-type="linenumber">96</context></context-group>
</trans-unit>
- <trans-unit id="_msg441">
+ <trans-unit id="_msg443">
<source xml:space="preserve">Signed %1 inputs, but more signatures are still required.</source>
<context-group purpose="location"><context context-type="linenumber">98</context></context-group>
</trans-unit>
- <trans-unit id="_msg442">
+ <trans-unit id="_msg444">
<source xml:space="preserve">Signed transaction successfully. Transaction is ready to broadcast.</source>
<context-group purpose="location"><context context-type="linenumber">101</context></context-group>
</trans-unit>
- <trans-unit id="_msg443">
+ <trans-unit id="_msg445">
<source xml:space="preserve">Unknown error processing transaction.</source>
<context-group purpose="location"><context context-type="linenumber">113</context></context-group>
</trans-unit>
- <trans-unit id="_msg444">
+ <trans-unit id="_msg446">
<source xml:space="preserve">Transaction broadcast successfully! Transaction ID: %1</source>
<context-group purpose="location"><context context-type="linenumber">123</context></context-group>
</trans-unit>
- <trans-unit id="_msg445">
+ <trans-unit id="_msg447">
<source xml:space="preserve">Transaction broadcast failed: %1</source>
<context-group purpose="location"><context context-type="linenumber">126</context></context-group>
</trans-unit>
- <trans-unit id="_msg446">
+ <trans-unit id="_msg448">
<source xml:space="preserve">PSBT copied to clipboard.</source>
<context-group purpose="location"><context context-type="linenumber">135</context></context-group>
</trans-unit>
- <trans-unit id="_msg447">
+ <trans-unit id="_msg449">
<source xml:space="preserve">Save Transaction Data</source>
<context-group purpose="location"><context context-type="linenumber">158</context></context-group>
</trans-unit>
- <trans-unit id="_msg448">
+ <trans-unit id="_msg450">
<source xml:space="preserve">Partially Signed Transaction (Binary)</source>
<context-group purpose="location"><context context-type="linenumber">160</context></context-group>
<note annotates="source" from="developer">Expanded name of the binary PSBT file format. See: BIP 174.</note>
</trans-unit>
- <trans-unit id="_msg449">
+ <trans-unit id="_msg451">
<source xml:space="preserve">PSBT saved to disk.</source>
<context-group purpose="location"><context context-type="linenumber">167</context></context-group>
</trans-unit>
- <trans-unit id="_msg450">
+ <trans-unit id="_msg452">
<source xml:space="preserve"> * Sends %1 to %2</source>
<context-group purpose="location"><context context-type="linenumber">183</context></context-group>
</trans-unit>
- <trans-unit id="_msg451">
+ <trans-unit id="_msg453">
<source xml:space="preserve">Unable to calculate transaction fee or total transaction amount.</source>
<context-group purpose="location"><context context-type="linenumber">193</context></context-group>
</trans-unit>
- <trans-unit id="_msg452">
+ <trans-unit id="_msg454">
<source xml:space="preserve">Pays transaction fee: </source>
<context-group purpose="location"><context context-type="linenumber">195</context></context-group>
</trans-unit>
- <trans-unit id="_msg453">
+ <trans-unit id="_msg455">
<source xml:space="preserve">Total Amount</source>
<context-group purpose="location"><context context-type="linenumber">207</context></context-group>
</trans-unit>
- <trans-unit id="_msg454">
+ <trans-unit id="_msg456">
<source xml:space="preserve">or</source>
<context-group purpose="location"><context context-type="linenumber">210</context></context-group>
</trans-unit>
- <trans-unit id="_msg455">
+ <trans-unit id="_msg457">
<source xml:space="preserve">Transaction has %1 unsigned inputs.</source>
<context-group purpose="location"><context context-type="linenumber">216</context></context-group>
</trans-unit>
- <trans-unit id="_msg456">
+ <trans-unit id="_msg458">
<source xml:space="preserve">Transaction is missing some information about inputs.</source>
<context-group purpose="location"><context context-type="linenumber">262</context></context-group>
</trans-unit>
- <trans-unit id="_msg457">
+ <trans-unit id="_msg459">
<source xml:space="preserve">Transaction still needs signature(s).</source>
<context-group purpose="location"><context context-type="linenumber">266</context></context-group>
</trans-unit>
- <trans-unit id="_msg458">
+ <trans-unit id="_msg460">
<source xml:space="preserve">(But no wallet is loaded.)</source>
<context-group purpose="location"><context context-type="linenumber">269</context></context-group>
</trans-unit>
- <trans-unit id="_msg459">
+ <trans-unit id="_msg461">
<source xml:space="preserve">(But this wallet cannot sign transactions.)</source>
<context-group purpose="location"><context context-type="linenumber">272</context></context-group>
</trans-unit>
- <trans-unit id="_msg460">
+ <trans-unit id="_msg462">
<source xml:space="preserve">(But this wallet does not have the right keys.)</source>
<context-group purpose="location"><context context-type="linenumber">275</context></context-group>
</trans-unit>
- <trans-unit id="_msg461">
+ <trans-unit id="_msg463">
<source xml:space="preserve">Transaction is fully signed and ready for broadcast.</source>
<context-group purpose="location"><context context-type="linenumber">283</context></context-group>
</trans-unit>
- <trans-unit id="_msg462">
+ <trans-unit id="_msg464">
<source xml:space="preserve">Transaction status is unknown.</source>
<context-group purpose="location"><context context-type="linenumber">287</context></context-group>
</trans-unit>
@@ -2087,37 +2095,37 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../paymentserver.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="PaymentServer">
- <trans-unit id="_msg463">
+ <trans-unit id="_msg465">
<source xml:space="preserve">Payment request error</source>
<context-group purpose="location"><context context-type="linenumber">152</context></context-group>
</trans-unit>
- <trans-unit id="_msg464">
+ <trans-unit id="_msg466">
<source xml:space="preserve">Cannot start bitcoin: click-to-pay handler</source>
<context-group purpose="location"><context context-type="linenumber">153</context></context-group>
</trans-unit>
- <trans-unit id="_msg465">
+ <trans-unit id="_msg467">
<source xml:space="preserve">URI handling</source>
<context-group purpose="location"><context context-type="linenumber">201</context></context-group>
<context-group purpose="location"><context context-type="linenumber">217</context></context-group>
<context-group purpose="location"><context context-type="linenumber">223</context></context-group>
<context-group purpose="location"><context context-type="linenumber">230</context></context-group>
</trans-unit>
- <trans-unit id="_msg466">
+ <trans-unit id="_msg468">
<source xml:space="preserve">&apos;bitcoin://&apos; is not a valid URI. Use &apos;bitcoin:&apos; instead.</source>
<context-group purpose="location"><context context-type="linenumber">201</context></context-group>
</trans-unit>
- <trans-unit id="_msg467">
+ <trans-unit id="_msg469">
<source xml:space="preserve">Cannot process payment request because BIP70 is not supported.
Due to widespread security flaws in BIP70 it&apos;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>
<context-group purpose="location"><context context-type="linenumber">218</context></context-group>
<context-group purpose="location"><context context-type="linenumber">241</context></context-group>
</trans-unit>
- <trans-unit id="_msg468">
+ <trans-unit id="_msg470">
<source xml:space="preserve">URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</source>
<context-group purpose="location"><context context-type="linenumber">231</context></context-group>
</trans-unit>
- <trans-unit id="_msg469">
+ <trans-unit id="_msg471">
<source xml:space="preserve">Payment request file handling</source>
<context-group purpose="location"><context context-type="linenumber">240</context></context-group>
</trans-unit>
@@ -2125,52 +2133,52 @@ If you are receiving this error you should request the merchant provide a BIP21
</body></file>
<file original="../peertablemodel.h" datatype="c" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="PeerTableModel">
- <trans-unit id="_msg470">
+ <trans-unit id="_msg472">
<source xml:space="preserve">User Agent</source>
<context-group purpose="location"><context context-type="linenumber">112</context></context-group>
<note annotates="source" from="developer">Title of Peers Table column which contains the peer&apos;s User Agent string.</note>
</trans-unit>
- <trans-unit id="_msg471">
+ <trans-unit id="_msg473">
<source xml:space="preserve">Ping</source>
<context-group purpose="location"><context context-type="linenumber">103</context></context-group>
<note annotates="source" from="developer">Title of Peers Table column which indicates the current latency of the connection with the peer.</note>
</trans-unit>
- <trans-unit id="_msg472">
+ <trans-unit id="_msg474">
<source xml:space="preserve">Peer</source>
<context-group purpose="location"><context context-type="linenumber">85</context></context-group>
<note annotates="source" from="developer">Title of Peers Table column which contains a unique number used to identify a connection.</note>
</trans-unit>
- <trans-unit id="_msg473">
+ <trans-unit id="_msg475">
<source xml:space="preserve">Age</source>
<context-group purpose="location"><context context-type="linenumber">88</context></context-group>
<note annotates="source" from="developer">Title of Peers Table column which indicates the duration (length of time) since the peer connection started.</note>
</trans-unit>
- <trans-unit id="_msg474">
+ <trans-unit id="_msg476">
<source xml:space="preserve">Direction</source>
<context-group purpose="location"><context context-type="linenumber">94</context></context-group>
<note annotates="source" from="developer">Title of Peers Table column which indicates the direction the peer connection was initiated from.</note>
</trans-unit>
- <trans-unit id="_msg475">
+ <trans-unit id="_msg477">
<source xml:space="preserve">Sent</source>
<context-group purpose="location"><context context-type="linenumber">106</context></context-group>
<note annotates="source" from="developer">Title of Peers Table column which indicates the total amount of network information we have sent to the peer.</note>
</trans-unit>
- <trans-unit id="_msg476">
+ <trans-unit id="_msg478">
<source xml:space="preserve">Received</source>
<context-group purpose="location"><context context-type="linenumber">109</context></context-group>
<note annotates="source" from="developer">Title of Peers Table column which indicates the total amount of network information we have received from the peer.</note>
</trans-unit>
- <trans-unit id="_msg477">
+ <trans-unit id="_msg479">
<source xml:space="preserve">Address</source>
<context-group purpose="location"><context context-type="linenumber">91</context></context-group>
<note annotates="source" from="developer">Title of Peers Table column which contains the IP/Onion/I2P address of the connected peer.</note>
</trans-unit>
- <trans-unit id="_msg478">
+ <trans-unit id="_msg480">
<source xml:space="preserve">Type</source>
<context-group purpose="location"><context context-type="linenumber">97</context></context-group>
<note annotates="source" from="developer">Title of Peers Table column which describes the type of peer connection. The &quot;type&quot; describes why the connection exists.</note>
</trans-unit>
- <trans-unit id="_msg479">
+ <trans-unit id="_msg481">
<source xml:space="preserve">Network</source>
<context-group purpose="location"><context context-type="linenumber">100</context></context-group>
<note annotates="source" from="developer">Title of Peers Table column which states the network the peer connected through.</note>
@@ -2179,12 +2187,12 @@ If you are receiving this error you should request the merchant provide a BIP21
</body></file>
<file original="../peertablemodel.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="PeerTableModel">
- <trans-unit id="_msg480">
+ <trans-unit id="_msg482">
<source xml:space="preserve">Inbound</source>
<context-group purpose="location"><context context-type="linenumber">78</context></context-group>
<note annotates="source" from="developer">An Inbound Connection from a Peer.</note>
</trans-unit>
- <trans-unit id="_msg481">
+ <trans-unit id="_msg483">
<source xml:space="preserve">Outbound</source>
<context-group purpose="location"><context context-type="linenumber">80</context></context-group>
<note annotates="source" from="developer">An Outbound Connection to a Peer.</note>
@@ -2193,7 +2201,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</body></file>
<file original="../bitcoinunits.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="QObject">
- <trans-unit id="_msg482">
+ <trans-unit id="_msg484">
<source xml:space="preserve">Amount</source>
<context-group purpose="location"><context context-type="linenumber">197</context></context-group>
</trans-unit>
@@ -2201,162 +2209,162 @@ If you are receiving this error you should request the merchant provide a BIP21
</body></file>
<file original="../guiutil.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="QObject">
- <trans-unit id="_msg483">
+ <trans-unit id="_msg485">
<source xml:space="preserve">Enter a Bitcoin address (e.g. %1)</source>
<context-group purpose="location"><context context-type="linenumber">129</context></context-group>
</trans-unit>
- <trans-unit id="_msg484">
+ <trans-unit id="_msg486">
<source xml:space="preserve">Ctrl+W</source>
<context-group purpose="location"><context context-type="linenumber">417</context></context-group>
</trans-unit>
- <trans-unit id="_msg485">
+ <trans-unit id="_msg487">
<source xml:space="preserve">Unroutable</source>
<context-group purpose="location"><context context-type="linenumber">673</context></context-group>
</trans-unit>
- <trans-unit id="_msg486">
+ <trans-unit id="_msg488">
<source xml:space="preserve">Internal</source>
<context-group purpose="location"><context context-type="linenumber">679</context></context-group>
</trans-unit>
- <trans-unit id="_msg487">
+ <trans-unit id="_msg489">
<source xml:space="preserve">Inbound</source>
<context-group purpose="location"><context context-type="linenumber">692</context></context-group>
<note annotates="source" from="developer">An inbound connection from a peer. An inbound connection is a connection initiated by a peer.</note>
</trans-unit>
- <trans-unit id="_msg488">
+ <trans-unit id="_msg490">
<source xml:space="preserve">Outbound</source>
<context-group purpose="location"><context context-type="linenumber">695</context></context-group>
<note annotates="source" from="developer">An outbound connection to a peer. An outbound connection is a connection initiated by us.</note>
</trans-unit>
- <trans-unit id="_msg489">
+ <trans-unit id="_msg491">
<source xml:space="preserve">Full Relay</source>
<context-group purpose="location"><context context-type="linenumber">700</context></context-group>
<note annotates="source" from="developer">Peer connection type that relays all network information.</note>
</trans-unit>
- <trans-unit id="_msg490">
+ <trans-unit id="_msg492">
<source xml:space="preserve">Block Relay</source>
<context-group purpose="location"><context context-type="linenumber">703</context></context-group>
<note annotates="source" from="developer">Peer connection type that relays network information about blocks and not transactions or addresses.</note>
</trans-unit>
- <trans-unit id="_msg491">
+ <trans-unit id="_msg493">
<source xml:space="preserve">Manual</source>
<context-group purpose="location"><context context-type="linenumber">705</context></context-group>
<note annotates="source" from="developer">Peer connection type established manually through one of several methods.</note>
</trans-unit>
- <trans-unit id="_msg492">
+ <trans-unit id="_msg494">
<source xml:space="preserve">Feeler</source>
<context-group purpose="location"><context context-type="linenumber">707</context></context-group>
<note annotates="source" from="developer">Short-lived peer connection type that tests the aliveness of known addresses.</note>
</trans-unit>
- <trans-unit id="_msg493">
+ <trans-unit id="_msg495">
<source xml:space="preserve">Address Fetch</source>
<context-group purpose="location"><context context-type="linenumber">709</context></context-group>
<note annotates="source" from="developer">Short-lived peer connection type that solicits known addresses from a peer.</note>
</trans-unit>
- <trans-unit id="_msg494">
+ <trans-unit id="_msg496">
<source xml:space="preserve">%1 d</source>
<context-group purpose="location"><context context-type="linenumber">722</context></context-group>
<context-group purpose="location"><context context-type="linenumber">734</context></context-group>
</trans-unit>
- <trans-unit id="_msg495">
+ <trans-unit id="_msg497">
<source xml:space="preserve">%1 h</source>
<context-group purpose="location"><context context-type="linenumber">723</context></context-group>
<context-group purpose="location"><context context-type="linenumber">735</context></context-group>
</trans-unit>
- <trans-unit id="_msg496">
+ <trans-unit id="_msg498">
<source xml:space="preserve">%1 m</source>
<context-group purpose="location"><context context-type="linenumber">724</context></context-group>
<context-group purpose="location"><context context-type="linenumber">736</context></context-group>
</trans-unit>
- <trans-unit id="_msg497">
+ <trans-unit id="_msg499">
<source xml:space="preserve">%1 s</source>
<context-group purpose="location"><context context-type="linenumber">726</context></context-group>
<context-group purpose="location"><context context-type="linenumber">737</context></context-group>
<context-group purpose="location"><context context-type="linenumber">763</context></context-group>
</trans-unit>
- <trans-unit id="_msg498">
+ <trans-unit id="_msg500">
<source xml:space="preserve">None</source>
<context-group purpose="location"><context context-type="linenumber">751</context></context-group>
</trans-unit>
- <trans-unit id="_msg499">
+ <trans-unit id="_msg501">
<source xml:space="preserve">N/A</source>
<context-group purpose="location"><context context-type="linenumber">757</context></context-group>
</trans-unit>
- <trans-unit id="_msg500">
+ <trans-unit id="_msg502">
<source xml:space="preserve">%1 ms</source>
<context-group purpose="location"><context context-type="linenumber">758</context></context-group>
</trans-unit>
<group restype="x-gettext-plurals">
<context-group purpose="location"><context context-type="linenumber">776</context></context-group>
- <trans-unit id="_msg501[0]">
+ <trans-unit id="_msg503[0]">
<source xml:space="preserve">%n second(s)</source>
</trans-unit>
- <trans-unit id="_msg501[1]">
+ <trans-unit id="_msg503[1]">
<source xml:space="preserve">%n second(s)</source>
</trans-unit>
</group>
<group restype="x-gettext-plurals">
<context-group purpose="location"><context context-type="linenumber">780</context></context-group>
- <trans-unit id="_msg502[0]">
+ <trans-unit id="_msg504[0]">
<source xml:space="preserve">%n minute(s)</source>
</trans-unit>
- <trans-unit id="_msg502[1]">
+ <trans-unit id="_msg504[1]">
<source xml:space="preserve">%n minute(s)</source>
</trans-unit>
</group>
<group restype="x-gettext-plurals">
<context-group purpose="location"><context context-type="linenumber">784</context></context-group>
- <trans-unit id="_msg503[0]">
+ <trans-unit id="_msg505[0]">
<source xml:space="preserve">%n hour(s)</source>
</trans-unit>
- <trans-unit id="_msg503[1]">
+ <trans-unit id="_msg505[1]">
<source xml:space="preserve">%n hour(s)</source>
</trans-unit>
</group>
<group restype="x-gettext-plurals">
<context-group purpose="location"><context context-type="linenumber">788</context></context-group>
- <trans-unit id="_msg504[0]">
+ <trans-unit id="_msg506[0]">
<source xml:space="preserve">%n day(s)</source>
</trans-unit>
- <trans-unit id="_msg504[1]">
+ <trans-unit id="_msg506[1]">
<source xml:space="preserve">%n day(s)</source>
</trans-unit>
</group>
<group restype="x-gettext-plurals">
<context-group purpose="location"><context context-type="linenumber">792</context></context-group>
<context-group purpose="location"><context context-type="linenumber">798</context></context-group>
- <trans-unit id="_msg505[0]">
+ <trans-unit id="_msg507[0]">
<source xml:space="preserve">%n week(s)</source>
</trans-unit>
- <trans-unit id="_msg505[1]">
+ <trans-unit id="_msg507[1]">
<source xml:space="preserve">%n week(s)</source>
</trans-unit>
</group>
- <trans-unit id="_msg506">
+ <trans-unit id="_msg508">
<source xml:space="preserve">%1 and %2</source>
<context-group purpose="location"><context context-type="linenumber">798</context></context-group>
</trans-unit>
<group restype="x-gettext-plurals">
<context-group purpose="location"><context context-type="linenumber">798</context></context-group>
- <trans-unit id="_msg507[0]">
+ <trans-unit id="_msg509[0]">
<source xml:space="preserve">%n year(s)</source>
</trans-unit>
- <trans-unit id="_msg507[1]">
+ <trans-unit id="_msg509[1]">
<source xml:space="preserve">%n year(s)</source>
</trans-unit>
</group>
- <trans-unit id="_msg508">
+ <trans-unit id="_msg510">
<source xml:space="preserve">%1 B</source>
<context-group purpose="location"><context context-type="linenumber">806</context></context-group>
</trans-unit>
- <trans-unit id="_msg509">
+ <trans-unit id="_msg511">
<source xml:space="preserve">%1 kB</source>
<context-group purpose="location"><context context-type="linenumber">808</context></context-group>
</trans-unit>
- <trans-unit id="_msg510">
+ <trans-unit id="_msg512">
<source xml:space="preserve">%1 MB</source>
<context-group purpose="location"><context context-type="linenumber">810</context></context-group>
</trans-unit>
- <trans-unit id="_msg511">
+ <trans-unit id="_msg513">
<source xml:space="preserve">%1 GB</source>
<context-group purpose="location"><context context-type="linenumber">812</context></context-group>
</trans-unit>
@@ -2364,31 +2372,31 @@ If you are receiving this error you should request the merchant provide a BIP21
</body></file>
<file original="../qrimagewidget.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="QRImageWidget">
- <trans-unit id="_msg512">
+ <trans-unit id="_msg514">
<source xml:space="preserve">&amp;Save Image…</source>
<context-group purpose="location"><context context-type="linenumber">30</context></context-group>
</trans-unit>
- <trans-unit id="_msg513">
+ <trans-unit id="_msg515">
<source xml:space="preserve">&amp;Copy Image</source>
<context-group purpose="location"><context context-type="linenumber">31</context></context-group>
</trans-unit>
- <trans-unit id="_msg514">
+ <trans-unit id="_msg516">
<source xml:space="preserve">Resulting URI too long, try to reduce the text for label / message.</source>
<context-group purpose="location"><context context-type="linenumber">42</context></context-group>
</trans-unit>
- <trans-unit id="_msg515">
+ <trans-unit id="_msg517">
<source xml:space="preserve">Error encoding URI into QR Code.</source>
<context-group purpose="location"><context context-type="linenumber">49</context></context-group>
</trans-unit>
- <trans-unit id="_msg516">
+ <trans-unit id="_msg518">
<source xml:space="preserve">QR code support not available.</source>
<context-group purpose="location"><context context-type="linenumber">90</context></context-group>
</trans-unit>
- <trans-unit id="_msg517">
+ <trans-unit id="_msg519">
<source xml:space="preserve">Save QR Code</source>
<context-group purpose="location"><context context-type="linenumber">120</context></context-group>
</trans-unit>
- <trans-unit id="_msg518">
+ <trans-unit id="_msg520">
<source xml:space="preserve">PNG Image</source>
<context-group purpose="location"><context context-type="linenumber">123</context></context-group>
<note annotates="source" from="developer">Expanded name of the PNG file format. See: https://en.wikipedia.org/wiki/Portable_Network_Graphics.</note>
@@ -2397,7 +2405,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</body></file>
<file original="../forms/debugwindow.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="RPCConsole">
- <trans-unit id="_msg519">
+ <trans-unit id="_msg521">
<source xml:space="preserve">N/A</source>
<context-group purpose="location"><context context-type="linenumber">75</context></context-group>
<context-group purpose="location"><context context-type="linenumber">101</context></context-group>
@@ -2438,291 +2446,291 @@ If you are receiving this error you should request the merchant provide a BIP21
<context-group purpose="location"><context context-type="linenumber">1662</context></context-group>
<context-group purpose="location"><context context-type="sourcefile">../rpcconsole.h</context><context context-type="linenumber">143</context></context-group>
</trans-unit>
- <trans-unit id="_msg520">
+ <trans-unit id="_msg522">
<source xml:space="preserve">Client version</source>
<context-group purpose="location"><context context-type="linenumber">65</context></context-group>
</trans-unit>
- <trans-unit id="_msg521">
+ <trans-unit id="_msg523">
<source xml:space="preserve">&amp;Information</source>
<context-group purpose="location"><context context-type="linenumber">43</context></context-group>
</trans-unit>
- <trans-unit id="_msg522">
+ <trans-unit id="_msg524">
<source xml:space="preserve">General</source>
<context-group purpose="location"><context context-type="linenumber">58</context></context-group>
</trans-unit>
- <trans-unit id="_msg523">
+ <trans-unit id="_msg525">
<source xml:space="preserve">Datadir</source>
<context-group purpose="location"><context context-type="linenumber">114</context></context-group>
</trans-unit>
- <trans-unit id="_msg524">
+ <trans-unit id="_msg526">
<source xml:space="preserve">To specify a non-default location of the data directory use the &apos;%1&apos; option.</source>
<context-group purpose="location"><context context-type="linenumber">124</context></context-group>
</trans-unit>
- <trans-unit id="_msg525">
+ <trans-unit id="_msg527">
<source xml:space="preserve">Blocksdir</source>
<context-group purpose="location"><context context-type="linenumber">143</context></context-group>
</trans-unit>
- <trans-unit id="_msg526">
+ <trans-unit id="_msg528">
<source xml:space="preserve">To specify a non-default location of the blocks directory use the &apos;%1&apos; option.</source>
<context-group purpose="location"><context context-type="linenumber">153</context></context-group>
</trans-unit>
- <trans-unit id="_msg527">
+ <trans-unit id="_msg529">
<source xml:space="preserve">Startup time</source>
<context-group purpose="location"><context context-type="linenumber">172</context></context-group>
</trans-unit>
- <trans-unit id="_msg528">
+ <trans-unit id="_msg530">
<source xml:space="preserve">Network</source>
<context-group purpose="location"><context context-type="linenumber">201</context></context-group>
<context-group purpose="location"><context context-type="linenumber">1093</context></context-group>
</trans-unit>
- <trans-unit id="_msg529">
+ <trans-unit id="_msg531">
<source xml:space="preserve">Name</source>
<context-group purpose="location"><context context-type="linenumber">208</context></context-group>
</trans-unit>
- <trans-unit id="_msg530">
+ <trans-unit id="_msg532">
<source xml:space="preserve">Number of connections</source>
<context-group purpose="location"><context context-type="linenumber">231</context></context-group>
</trans-unit>
- <trans-unit id="_msg531">
+ <trans-unit id="_msg533">
<source xml:space="preserve">Block chain</source>
<context-group purpose="location"><context context-type="linenumber">260</context></context-group>
</trans-unit>
- <trans-unit id="_msg532">
+ <trans-unit id="_msg534">
<source xml:space="preserve">Memory Pool</source>
<context-group purpose="location"><context context-type="linenumber">319</context></context-group>
</trans-unit>
- <trans-unit id="_msg533">
+ <trans-unit id="_msg535">
<source xml:space="preserve">Current number of transactions</source>
<context-group purpose="location"><context context-type="linenumber">326</context></context-group>
</trans-unit>
- <trans-unit id="_msg534">
+ <trans-unit id="_msg536">
<source xml:space="preserve">Memory usage</source>
<context-group purpose="location"><context context-type="linenumber">349</context></context-group>
</trans-unit>
- <trans-unit id="_msg535">
+ <trans-unit id="_msg537">
<source xml:space="preserve">Wallet: </source>
<context-group purpose="location"><context context-type="linenumber">443</context></context-group>
</trans-unit>
- <trans-unit id="_msg536">
+ <trans-unit id="_msg538">
<source xml:space="preserve">(none)</source>
<context-group purpose="location"><context context-type="linenumber">454</context></context-group>
</trans-unit>
- <trans-unit id="_msg537">
+ <trans-unit id="_msg539">
<source xml:space="preserve">&amp;Reset</source>
<context-group purpose="location"><context context-type="linenumber">665</context></context-group>
</trans-unit>
- <trans-unit id="_msg538">
+ <trans-unit id="_msg540">
<source xml:space="preserve">Received</source>
<context-group purpose="location"><context context-type="linenumber">745</context></context-group>
<context-group purpose="location"><context context-type="linenumber">1453</context></context-group>
</trans-unit>
- <trans-unit id="_msg539">
+ <trans-unit id="_msg541">
<source xml:space="preserve">Sent</source>
<context-group purpose="location"><context context-type="linenumber">825</context></context-group>
<context-group purpose="location"><context context-type="linenumber">1430</context></context-group>
</trans-unit>
- <trans-unit id="_msg540">
+ <trans-unit id="_msg542">
<source xml:space="preserve">&amp;Peers</source>
<context-group purpose="location"><context context-type="linenumber">866</context></context-group>
</trans-unit>
- <trans-unit id="_msg541">
+ <trans-unit id="_msg543">
<source xml:space="preserve">Banned peers</source>
<context-group purpose="location"><context context-type="linenumber">942</context></context-group>
</trans-unit>
- <trans-unit id="_msg542">
+ <trans-unit id="_msg544">
<source xml:space="preserve">Select a peer to view detailed information.</source>
<context-group purpose="location"><context context-type="linenumber">1010</context></context-group>
<context-group purpose="location"><context context-type="sourcefile">../rpcconsole.cpp</context><context context-type="linenumber">1155</context></context-group>
</trans-unit>
- <trans-unit id="_msg543">
+ <trans-unit id="_msg545">
<source xml:space="preserve">Version</source>
<context-group purpose="location"><context context-type="linenumber">1116</context></context-group>
</trans-unit>
- <trans-unit id="_msg544">
+ <trans-unit id="_msg546">
<source xml:space="preserve">Starting Block</source>
<context-group purpose="location"><context context-type="linenumber">1240</context></context-group>
</trans-unit>
- <trans-unit id="_msg545">
+ <trans-unit id="_msg547">
<source xml:space="preserve">Synced Headers</source>
<context-group purpose="location"><context context-type="linenumber">1263</context></context-group>
</trans-unit>
- <trans-unit id="_msg546">
+ <trans-unit id="_msg548">
<source xml:space="preserve">Synced Blocks</source>
<context-group purpose="location"><context context-type="linenumber">1286</context></context-group>
</trans-unit>
- <trans-unit id="_msg547">
+ <trans-unit id="_msg549">
<source xml:space="preserve">Last Transaction</source>
<context-group purpose="location"><context context-type="linenumber">1361</context></context-group>
</trans-unit>
- <trans-unit id="_msg548">
+ <trans-unit id="_msg550">
<source xml:space="preserve">The mapped Autonomous System used for diversifying peer selection.</source>
<context-group purpose="location"><context context-type="linenumber">1571</context></context-group>
</trans-unit>
- <trans-unit id="_msg549">
+ <trans-unit id="_msg551">
<source xml:space="preserve">Mapped AS</source>
<context-group purpose="location"><context context-type="linenumber">1574</context></context-group>
</trans-unit>
- <trans-unit id="_msg550">
+ <trans-unit id="_msg552">
<source xml:space="preserve">Whether we relay addresses to this peer.</source>
<context-group purpose="location"><context context-type="linenumber">1597</context></context-group>
<note annotates="source" from="developer">Tooltip text for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</note>
</trans-unit>
- <trans-unit id="_msg551">
+ <trans-unit id="_msg553">
<source xml:space="preserve">Address Relay</source>
<context-group purpose="location"><context context-type="linenumber">1600</context></context-group>
<note annotates="source" from="developer">Text title for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</note>
</trans-unit>
- <trans-unit id="_msg552">
+ <trans-unit id="_msg554">
<source xml:space="preserve">The total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</source>
<context-group purpose="location"><context context-type="linenumber">1623</context></context-group>
<note annotates="source" from="developer">Tooltip text for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</note>
</trans-unit>
- <trans-unit id="_msg553">
+ <trans-unit id="_msg555">
<source xml:space="preserve">The total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</source>
<context-group purpose="location"><context context-type="linenumber">1649</context></context-group>
<note annotates="source" from="developer">Tooltip text for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</note>
</trans-unit>
- <trans-unit id="_msg554">
+ <trans-unit id="_msg556">
<source xml:space="preserve">Addresses Processed</source>
<context-group purpose="location"><context context-type="linenumber">1626</context></context-group>
<note annotates="source" from="developer">Text title for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</note>
</trans-unit>
- <trans-unit id="_msg555">
+ <trans-unit id="_msg557">
<source xml:space="preserve">Addresses Rate-Limited</source>
<context-group purpose="location"><context context-type="linenumber">1652</context></context-group>
<note annotates="source" from="developer">Text title for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</note>
</trans-unit>
- <trans-unit id="_msg556">
+ <trans-unit id="_msg558">
<source xml:space="preserve">User Agent</source>
<context-group purpose="location"><context context-type="linenumber">88</context></context-group>
<context-group purpose="location"><context context-type="linenumber">1139</context></context-group>
</trans-unit>
- <trans-unit id="_msg557">
+ <trans-unit id="_msg559">
<source xml:space="preserve">Node window</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
</trans-unit>
- <trans-unit id="_msg558">
+ <trans-unit id="_msg560">
<source xml:space="preserve">Current block height</source>
<context-group purpose="location"><context context-type="linenumber">267</context></context-group>
</trans-unit>
- <trans-unit id="_msg559">
+ <trans-unit id="_msg561">
<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>
<context-group purpose="location"><context context-type="linenumber">397</context></context-group>
</trans-unit>
- <trans-unit id="_msg560">
+ <trans-unit id="_msg562">
<source xml:space="preserve">Decrease font size</source>
<context-group purpose="location"><context context-type="linenumber">475</context></context-group>
</trans-unit>
- <trans-unit id="_msg561">
+ <trans-unit id="_msg563">
<source xml:space="preserve">Increase font size</source>
<context-group purpose="location"><context context-type="linenumber">495</context></context-group>
</trans-unit>
- <trans-unit id="_msg562">
+ <trans-unit id="_msg564">
<source xml:space="preserve">Permissions</source>
<context-group purpose="location"><context context-type="linenumber">1041</context></context-group>
</trans-unit>
- <trans-unit id="_msg563">
+ <trans-unit id="_msg565">
<source xml:space="preserve">The direction and type of peer connection: %1</source>
<context-group purpose="location"><context context-type="linenumber">1064</context></context-group>
</trans-unit>
- <trans-unit id="_msg564">
+ <trans-unit id="_msg566">
<source xml:space="preserve">Direction/Type</source>
<context-group purpose="location"><context context-type="linenumber">1067</context></context-group>
</trans-unit>
- <trans-unit id="_msg565">
+ <trans-unit id="_msg567">
<source xml:space="preserve">The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS.</source>
<context-group purpose="location"><context context-type="linenumber">1090</context></context-group>
</trans-unit>
- <trans-unit id="_msg566">
+ <trans-unit id="_msg568">
<source xml:space="preserve">Services</source>
<context-group purpose="location"><context context-type="linenumber">1162</context></context-group>
</trans-unit>
- <trans-unit id="_msg567">
+ <trans-unit id="_msg569">
<source xml:space="preserve">Whether the peer requested us to relay transactions.</source>
<context-group purpose="location"><context context-type="linenumber">1188</context></context-group>
</trans-unit>
- <trans-unit id="_msg568">
+ <trans-unit id="_msg570">
<source xml:space="preserve">Wants Tx Relay</source>
<context-group purpose="location"><context context-type="linenumber">1191</context></context-group>
</trans-unit>
- <trans-unit id="_msg569">
+ <trans-unit id="_msg571">
<source xml:space="preserve">High bandwidth BIP152 compact block relay: %1</source>
<context-group purpose="location"><context context-type="linenumber">1214</context></context-group>
</trans-unit>
- <trans-unit id="_msg570">
+ <trans-unit id="_msg572">
<source xml:space="preserve">High Bandwidth</source>
<context-group purpose="location"><context context-type="linenumber">1217</context></context-group>
</trans-unit>
- <trans-unit id="_msg571">
+ <trans-unit id="_msg573">
<source xml:space="preserve">Connection Time</source>
<context-group purpose="location"><context context-type="linenumber">1309</context></context-group>
</trans-unit>
- <trans-unit id="_msg572">
+ <trans-unit id="_msg574">
<source xml:space="preserve">Elapsed time since a novel block passing initial validity checks was received from this peer.</source>
<context-group purpose="location"><context context-type="linenumber">1332</context></context-group>
</trans-unit>
- <trans-unit id="_msg573">
+ <trans-unit id="_msg575">
<source xml:space="preserve">Last Block</source>
<context-group purpose="location"><context context-type="linenumber">1335</context></context-group>
</trans-unit>
- <trans-unit id="_msg574">
+ <trans-unit id="_msg576">
<source xml:space="preserve">Elapsed time since a novel transaction accepted into our mempool was received from this peer.</source>
<context-group purpose="location"><context context-type="linenumber">1358</context></context-group>
<note annotates="source" from="developer">Tooltip text for the Last Transaction field in the peer details area.</note>
</trans-unit>
- <trans-unit id="_msg575">
+ <trans-unit id="_msg577">
<source xml:space="preserve">Last Send</source>
<context-group purpose="location"><context context-type="linenumber">1384</context></context-group>
</trans-unit>
- <trans-unit id="_msg576">
+ <trans-unit id="_msg578">
<source xml:space="preserve">Last Receive</source>
<context-group purpose="location"><context context-type="linenumber">1407</context></context-group>
</trans-unit>
- <trans-unit id="_msg577">
+ <trans-unit id="_msg579">
<source xml:space="preserve">Ping Time</source>
<context-group purpose="location"><context context-type="linenumber">1476</context></context-group>
</trans-unit>
- <trans-unit id="_msg578">
+ <trans-unit id="_msg580">
<source xml:space="preserve">The duration of a currently outstanding ping.</source>
<context-group purpose="location"><context context-type="linenumber">1499</context></context-group>
</trans-unit>
- <trans-unit id="_msg579">
+ <trans-unit id="_msg581">
<source xml:space="preserve">Ping Wait</source>
<context-group purpose="location"><context context-type="linenumber">1502</context></context-group>
</trans-unit>
- <trans-unit id="_msg580">
+ <trans-unit id="_msg582">
<source xml:space="preserve">Min Ping</source>
<context-group purpose="location"><context context-type="linenumber">1525</context></context-group>
</trans-unit>
- <trans-unit id="_msg581">
+ <trans-unit id="_msg583">
<source xml:space="preserve">Time Offset</source>
<context-group purpose="location"><context context-type="linenumber">1548</context></context-group>
</trans-unit>
- <trans-unit id="_msg582">
+ <trans-unit id="_msg584">
<source xml:space="preserve">Last block time</source>
<context-group purpose="location"><context context-type="linenumber">290</context></context-group>
</trans-unit>
- <trans-unit id="_msg583">
+ <trans-unit id="_msg585">
<source xml:space="preserve">&amp;Open</source>
<context-group purpose="location"><context context-type="linenumber">400</context></context-group>
</trans-unit>
- <trans-unit id="_msg584">
+ <trans-unit id="_msg586">
<source xml:space="preserve">&amp;Console</source>
<context-group purpose="location"><context context-type="linenumber">426</context></context-group>
</trans-unit>
- <trans-unit id="_msg585">
+ <trans-unit id="_msg587">
<source xml:space="preserve">&amp;Network Traffic</source>
<context-group purpose="location"><context context-type="linenumber">613</context></context-group>
</trans-unit>
- <trans-unit id="_msg586">
+ <trans-unit id="_msg588">
<source xml:space="preserve">Totals</source>
<context-group purpose="location"><context context-type="linenumber">681</context></context-group>
</trans-unit>
- <trans-unit id="_msg587">
+ <trans-unit id="_msg589">
<source xml:space="preserve">Debug log file</source>
<context-group purpose="location"><context context-type="linenumber">390</context></context-group>
</trans-unit>
- <trans-unit id="_msg588">
+ <trans-unit id="_msg590">
<source xml:space="preserve">Clear console</source>
<context-group purpose="location"><context context-type="linenumber">515</context></context-group>
</trans-unit>
@@ -2730,139 +2738,139 @@ If you are receiving this error you should request the merchant provide a BIP21
</body></file>
<file original="../rpcconsole.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="RPCConsole">
- <trans-unit id="_msg589">
+ <trans-unit id="_msg591">
<source xml:space="preserve">In:</source>
<context-group purpose="location"><context context-type="linenumber">953</context></context-group>
</trans-unit>
- <trans-unit id="_msg590">
+ <trans-unit id="_msg592">
<source xml:space="preserve">Out:</source>
<context-group purpose="location"><context context-type="linenumber">954</context></context-group>
</trans-unit>
- <trans-unit id="_msg591">
+ <trans-unit id="_msg593">
<source xml:space="preserve">Inbound: initiated by peer</source>
<context-group purpose="location"><context context-type="linenumber">496</context></context-group>
<note annotates="source" from="developer">Explanatory text for an inbound peer connection.</note>
</trans-unit>
- <trans-unit id="_msg592">
+ <trans-unit id="_msg594">
<source xml:space="preserve">Outbound Full Relay: default</source>
<context-group purpose="location"><context context-type="linenumber">500</context></context-group>
<note annotates="source" from="developer">Explanatory text for an outbound peer connection that relays all network information. This is the default behavior for outbound connections.</note>
</trans-unit>
- <trans-unit id="_msg593">
+ <trans-unit id="_msg595">
<source xml:space="preserve">Outbound Block Relay: does not relay transactions or addresses</source>
<context-group purpose="location"><context context-type="linenumber">503</context></context-group>
<note annotates="source" from="developer">Explanatory text for an outbound peer connection that relays network information about blocks and not transactions or addresses.</note>
</trans-unit>
- <trans-unit id="_msg594">
+ <trans-unit id="_msg596">
<source xml:space="preserve">Outbound Manual: added using RPC %1 or %2/%3 configuration options</source>
<context-group purpose="location"><context context-type="linenumber">508</context></context-group>
<note annotates="source" from="developer">Explanatory text for an outbound peer connection that was established manually through one of several methods. The numbered arguments are stand-ins for the methods available to establish manual connections.</note>
</trans-unit>
- <trans-unit id="_msg595">
+ <trans-unit id="_msg597">
<source xml:space="preserve">Outbound Feeler: short-lived, for testing addresses</source>
<context-group purpose="location"><context context-type="linenumber">514</context></context-group>
<note annotates="source" from="developer">Explanatory text for a short-lived outbound peer connection that is used to test the aliveness of known addresses.</note>
</trans-unit>
- <trans-unit id="_msg596">
+ <trans-unit id="_msg598">
<source xml:space="preserve">Outbound Address Fetch: short-lived, for soliciting addresses</source>
<context-group purpose="location"><context context-type="linenumber">517</context></context-group>
<note annotates="source" from="developer">Explanatory text for a short-lived outbound peer connection that is used to request addresses from a peer.</note>
</trans-unit>
- <trans-unit id="_msg597">
+ <trans-unit id="_msg599">
<source xml:space="preserve">we selected the peer for high bandwidth relay</source>
<context-group purpose="location"><context context-type="linenumber">521</context></context-group>
</trans-unit>
- <trans-unit id="_msg598">
+ <trans-unit id="_msg600">
<source xml:space="preserve">the peer selected us for high bandwidth relay</source>
<context-group purpose="location"><context context-type="linenumber">522</context></context-group>
</trans-unit>
- <trans-unit id="_msg599">
+ <trans-unit id="_msg601">
<source xml:space="preserve">no high bandwidth relay selected</source>
<context-group purpose="location"><context context-type="linenumber">523</context></context-group>
</trans-unit>
- <trans-unit id="_msg600">
+ <trans-unit id="_msg602">
<source xml:space="preserve">Ctrl++</source>
<context-group purpose="location"><context context-type="linenumber">536</context></context-group>
<note annotates="source" from="developer">Main shortcut to increase the RPC console font size.</note>
</trans-unit>
- <trans-unit id="_msg601">
+ <trans-unit id="_msg603">
<source xml:space="preserve">Ctrl+=</source>
<context-group purpose="location"><context context-type="linenumber">538</context></context-group>
<note annotates="source" from="developer">Secondary shortcut to increase the RPC console font size.</note>
</trans-unit>
- <trans-unit id="_msg602">
+ <trans-unit id="_msg604">
<source xml:space="preserve">Ctrl+-</source>
<context-group purpose="location"><context context-type="linenumber">542</context></context-group>
<note annotates="source" from="developer">Main shortcut to decrease the RPC console font size.</note>
</trans-unit>
- <trans-unit id="_msg603">
+ <trans-unit id="_msg605">
<source xml:space="preserve">Ctrl+_</source>
<context-group purpose="location"><context context-type="linenumber">544</context></context-group>
<note annotates="source" from="developer">Secondary shortcut to decrease the RPC console font size.</note>
</trans-unit>
- <trans-unit id="_msg604">
+ <trans-unit id="_msg606">
<source xml:space="preserve">&amp;Copy address</source>
<context-group purpose="location"><context context-type="linenumber">695</context></context-group>
<note annotates="source" from="developer">Context menu action to copy the address of a peer.</note>
</trans-unit>
- <trans-unit id="_msg605">
+ <trans-unit id="_msg607">
<source xml:space="preserve">&amp;Disconnect</source>
<context-group purpose="location"><context context-type="linenumber">699</context></context-group>
</trans-unit>
- <trans-unit id="_msg606">
+ <trans-unit id="_msg608">
<source xml:space="preserve">1 &amp;hour</source>
<context-group purpose="location"><context context-type="linenumber">700</context></context-group>
</trans-unit>
- <trans-unit id="_msg607">
+ <trans-unit id="_msg609">
<source xml:space="preserve">1 d&amp;ay</source>
<context-group purpose="location"><context context-type="linenumber">701</context></context-group>
</trans-unit>
- <trans-unit id="_msg608">
+ <trans-unit id="_msg610">
<source xml:space="preserve">1 &amp;week</source>
<context-group purpose="location"><context context-type="linenumber">702</context></context-group>
</trans-unit>
- <trans-unit id="_msg609">
+ <trans-unit id="_msg611">
<source xml:space="preserve">1 &amp;year</source>
<context-group purpose="location"><context context-type="linenumber">703</context></context-group>
</trans-unit>
- <trans-unit id="_msg610">
+ <trans-unit id="_msg612">
<source xml:space="preserve">&amp;Copy IP/Netmask</source>
<context-group purpose="location"><context context-type="linenumber">729</context></context-group>
<note annotates="source" from="developer">Context menu action to copy the IP/Netmask of a banned peer. IP/Netmask is the combination of a peer&apos;s IP address and its Netmask. For IP address, see: https://en.wikipedia.org/wiki/IP_address.</note>
</trans-unit>
- <trans-unit id="_msg611">
+ <trans-unit id="_msg613">
<source xml:space="preserve">&amp;Unban</source>
<context-group purpose="location"><context context-type="linenumber">733</context></context-group>
</trans-unit>
- <trans-unit id="_msg612">
+ <trans-unit id="_msg614">
<source xml:space="preserve">Network activity disabled</source>
<context-group purpose="location"><context context-type="linenumber">957</context></context-group>
</trans-unit>
- <trans-unit id="_msg613">
+ <trans-unit id="_msg615">
<source xml:space="preserve">Executing command without any wallet</source>
<context-group purpose="location"><context context-type="linenumber">1035</context></context-group>
</trans-unit>
- <trans-unit id="_msg614">
+ <trans-unit id="_msg616">
<source xml:space="preserve">Ctrl+I</source>
<context-group purpose="location"><context context-type="linenumber">1351</context></context-group>
</trans-unit>
- <trans-unit id="_msg615">
+ <trans-unit id="_msg617">
<source xml:space="preserve">Ctrl+T</source>
<context-group purpose="location"><context context-type="linenumber">1352</context></context-group>
</trans-unit>
- <trans-unit id="_msg616">
+ <trans-unit id="_msg618">
<source xml:space="preserve">Ctrl+N</source>
<context-group purpose="location"><context context-type="linenumber">1353</context></context-group>
</trans-unit>
- <trans-unit id="_msg617">
+ <trans-unit id="_msg619">
<source xml:space="preserve">Ctrl+P</source>
<context-group purpose="location"><context context-type="linenumber">1354</context></context-group>
</trans-unit>
- <trans-unit id="_msg618">
+ <trans-unit id="_msg620">
<source xml:space="preserve">Executing command using &quot;%1&quot; wallet</source>
<context-group purpose="location"><context context-type="linenumber">1033</context></context-group>
</trans-unit>
- <trans-unit id="_msg619">
+ <trans-unit id="_msg621">
<source xml:space="preserve">Welcome to the %1 RPC console.
Use up and down arrows to navigate history, and %2 to clear screen.
Use %3 and %4 to increase or decrease the font size.
@@ -2873,16 +2881,16 @@ For more information on using this console, type %6.
<context-group purpose="location"><context context-type="linenumber">887</context></context-group>
<note annotates="source" from="developer">RPC console welcome message. Placeholders %7 and %8 are style tags for the warning content, and they are not space separated from the rest of the text intentionally.</note>
</trans-unit>
- <trans-unit id="_msg620">
+ <trans-unit id="_msg622">
<source xml:space="preserve">Executing…</source>
<context-group purpose="location"><context context-type="linenumber">1043</context></context-group>
<note annotates="source" from="developer">A console message indicating an entered command is currently being executed.</note>
</trans-unit>
- <trans-unit id="_msg621">
+ <trans-unit id="_msg623">
<source xml:space="preserve">(peer: %1)</source>
<context-group purpose="location"><context context-type="linenumber">1161</context></context-group>
</trans-unit>
- <trans-unit id="_msg622">
+ <trans-unit id="_msg624">
<source xml:space="preserve">via %1</source>
<context-group purpose="location"><context context-type="linenumber">1163</context></context-group>
</trans-unit>
@@ -2890,31 +2898,31 @@ For more information on using this console, type %6.
</body></file>
<file original="../rpcconsole.h" datatype="c" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="RPCConsole">
- <trans-unit id="_msg623">
+ <trans-unit id="_msg625">
<source xml:space="preserve">Yes</source>
<context-group purpose="location"><context context-type="linenumber">142</context></context-group>
</trans-unit>
- <trans-unit id="_msg624">
+ <trans-unit id="_msg626">
<source xml:space="preserve">No</source>
<context-group purpose="location"><context context-type="linenumber">142</context></context-group>
</trans-unit>
- <trans-unit id="_msg625">
+ <trans-unit id="_msg627">
<source xml:space="preserve">To</source>
<context-group purpose="location"><context context-type="linenumber">142</context></context-group>
</trans-unit>
- <trans-unit id="_msg626">
+ <trans-unit id="_msg628">
<source xml:space="preserve">From</source>
<context-group purpose="location"><context context-type="linenumber">142</context></context-group>
</trans-unit>
- <trans-unit id="_msg627">
+ <trans-unit id="_msg629">
<source xml:space="preserve">Ban for</source>
<context-group purpose="location"><context context-type="linenumber">143</context></context-group>
</trans-unit>
- <trans-unit id="_msg628">
+ <trans-unit id="_msg630">
<source xml:space="preserve">Never</source>
<context-group purpose="location"><context context-type="linenumber">185</context></context-group>
</trans-unit>
- <trans-unit id="_msg629">
+ <trans-unit id="_msg631">
<source xml:space="preserve">Unknown</source>
<context-group purpose="location"><context context-type="linenumber">143</context></context-group>
</trans-unit>
@@ -2922,72 +2930,72 @@ For more information on using this console, type %6.
</body></file>
<file original="../forms/receivecoinsdialog.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="ReceiveCoinsDialog">
- <trans-unit id="_msg630">
+ <trans-unit id="_msg632">
<source xml:space="preserve">&amp;Amount:</source>
<context-group purpose="location"><context context-type="linenumber">37</context></context-group>
</trans-unit>
- <trans-unit id="_msg631">
+ <trans-unit id="_msg633">
<source xml:space="preserve">&amp;Label:</source>
<context-group purpose="location"><context context-type="linenumber">83</context></context-group>
</trans-unit>
- <trans-unit id="_msg632">
+ <trans-unit id="_msg634">
<source xml:space="preserve">&amp;Message:</source>
<context-group purpose="location"><context context-type="linenumber">53</context></context-group>
</trans-unit>
- <trans-unit id="_msg633">
+ <trans-unit id="_msg635">
<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>
<context-group purpose="location"><context context-type="linenumber">50</context></context-group>
</trans-unit>
- <trans-unit id="_msg634">
+ <trans-unit id="_msg636">
<source xml:space="preserve">An optional label to associate with the new receiving address.</source>
<context-group purpose="location"><context context-type="linenumber">80</context></context-group>
</trans-unit>
- <trans-unit id="_msg635">
+ <trans-unit id="_msg637">
<source xml:space="preserve">Use this form to request payments. All fields are &lt;b&gt;optional&lt;/b&gt;.</source>
<context-group purpose="location"><context context-type="linenumber">73</context></context-group>
</trans-unit>
- <trans-unit id="_msg636">
+ <trans-unit id="_msg638">
<source xml:space="preserve">An optional amount to request. Leave this empty or zero to not request a specific amount.</source>
<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="_msg637">
+ <trans-unit id="_msg639">
<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>
<context-group purpose="location"><context context-type="linenumber">66</context></context-group>
</trans-unit>
- <trans-unit id="_msg638">
+ <trans-unit id="_msg640">
<source xml:space="preserve">An optional message that is attached to the payment request and may be displayed to the sender.</source>
<context-group purpose="location"><context context-type="linenumber">96</context></context-group>
</trans-unit>
- <trans-unit id="_msg639">
+ <trans-unit id="_msg641">
<source xml:space="preserve">&amp;Create new receiving address</source>
<context-group purpose="location"><context context-type="linenumber">111</context></context-group>
</trans-unit>
- <trans-unit id="_msg640">
+ <trans-unit id="_msg642">
<source xml:space="preserve">Clear all fields of the form.</source>
<context-group purpose="location"><context context-type="linenumber">134</context></context-group>
</trans-unit>
- <trans-unit id="_msg641">
+ <trans-unit id="_msg643">
<source xml:space="preserve">Clear</source>
<context-group purpose="location"><context context-type="linenumber">137</context></context-group>
</trans-unit>
- <trans-unit id="_msg642">
+ <trans-unit id="_msg644">
<source xml:space="preserve">Requested payments history</source>
<context-group purpose="location"><context context-type="linenumber">273</context></context-group>
</trans-unit>
- <trans-unit id="_msg643">
+ <trans-unit id="_msg645">
<source xml:space="preserve">Show the selected request (does the same as double clicking an entry)</source>
<context-group purpose="location"><context context-type="linenumber">298</context></context-group>
</trans-unit>
- <trans-unit id="_msg644">
+ <trans-unit id="_msg646">
<source xml:space="preserve">Show</source>
<context-group purpose="location"><context context-type="linenumber">301</context></context-group>
</trans-unit>
- <trans-unit id="_msg645">
+ <trans-unit id="_msg647">
<source xml:space="preserve">Remove the selected entries from the list</source>
<context-group purpose="location"><context context-type="linenumber">318</context></context-group>
</trans-unit>
- <trans-unit id="_msg646">
+ <trans-unit id="_msg648">
<source xml:space="preserve">Remove</source>
<context-group purpose="location"><context context-type="linenumber">321</context></context-group>
</trans-unit>
@@ -2995,31 +3003,31 @@ For more information on using this console, type %6.
</body></file>
<file original="../receivecoinsdialog.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="ReceiveCoinsDialog">
- <trans-unit id="_msg647">
+ <trans-unit id="_msg649">
<source xml:space="preserve">Copy &amp;URI</source>
<context-group purpose="location"><context context-type="linenumber">47</context></context-group>
</trans-unit>
- <trans-unit id="_msg648">
+ <trans-unit id="_msg650">
<source xml:space="preserve">&amp;Copy address</source>
<context-group purpose="location"><context context-type="linenumber">48</context></context-group>
</trans-unit>
- <trans-unit id="_msg649">
+ <trans-unit id="_msg651">
<source xml:space="preserve">Copy &amp;label</source>
<context-group purpose="location"><context context-type="linenumber">49</context></context-group>
</trans-unit>
- <trans-unit id="_msg650">
+ <trans-unit id="_msg652">
<source xml:space="preserve">Copy &amp;message</source>
<context-group purpose="location"><context context-type="linenumber">50</context></context-group>
</trans-unit>
- <trans-unit id="_msg651">
+ <trans-unit id="_msg653">
<source xml:space="preserve">Copy &amp;amount</source>
<context-group purpose="location"><context context-type="linenumber">51</context></context-group>
</trans-unit>
- <trans-unit id="_msg652">
+ <trans-unit id="_msg654">
<source xml:space="preserve">Could not unlock wallet.</source>
<context-group purpose="location"><context context-type="linenumber">176</context></context-group>
</trans-unit>
- <trans-unit id="_msg653">
+ <trans-unit id="_msg655">
<source xml:space="preserve">Could not generate new %1 address</source>
<context-group purpose="location"><context context-type="linenumber">181</context></context-group>
</trans-unit>
@@ -3027,51 +3035,51 @@ For more information on using this console, type %6.
</body></file>
<file original="../forms/receiverequestdialog.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="ReceiveRequestDialog">
- <trans-unit id="_msg654">
+ <trans-unit id="_msg656">
<source xml:space="preserve">Request payment to …</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
</trans-unit>
- <trans-unit id="_msg655">
+ <trans-unit id="_msg657">
<source xml:space="preserve">Address:</source>
<context-group purpose="location"><context context-type="linenumber">90</context></context-group>
</trans-unit>
- <trans-unit id="_msg656">
+ <trans-unit id="_msg658">
<source xml:space="preserve">Amount:</source>
<context-group purpose="location"><context context-type="linenumber">119</context></context-group>
</trans-unit>
- <trans-unit id="_msg657">
+ <trans-unit id="_msg659">
<source xml:space="preserve">Label:</source>
<context-group purpose="location"><context context-type="linenumber">148</context></context-group>
</trans-unit>
- <trans-unit id="_msg658">
+ <trans-unit id="_msg660">
<source xml:space="preserve">Message:</source>
<context-group purpose="location"><context context-type="linenumber">180</context></context-group>
</trans-unit>
- <trans-unit id="_msg659">
+ <trans-unit id="_msg661">
<source xml:space="preserve">Wallet:</source>
<context-group purpose="location"><context context-type="linenumber">212</context></context-group>
</trans-unit>
- <trans-unit id="_msg660">
+ <trans-unit id="_msg662">
<source xml:space="preserve">Copy &amp;URI</source>
<context-group purpose="location"><context context-type="linenumber">240</context></context-group>
</trans-unit>
- <trans-unit id="_msg661">
+ <trans-unit id="_msg663">
<source xml:space="preserve">Copy &amp;Address</source>
<context-group purpose="location"><context context-type="linenumber">250</context></context-group>
</trans-unit>
- <trans-unit id="_msg662">
+ <trans-unit id="_msg664">
<source xml:space="preserve">&amp;Verify</source>
<context-group purpose="location"><context context-type="linenumber">260</context></context-group>
</trans-unit>
- <trans-unit id="_msg663">
+ <trans-unit id="_msg665">
<source xml:space="preserve">Verify this address on e.g. a hardware wallet screen</source>
<context-group purpose="location"><context context-type="linenumber">263</context></context-group>
</trans-unit>
- <trans-unit id="_msg664">
+ <trans-unit id="_msg666">
<source xml:space="preserve">&amp;Save Image…</source>
<context-group purpose="location"><context context-type="linenumber">273</context></context-group>
</trans-unit>
- <trans-unit id="_msg665">
+ <trans-unit id="_msg667">
<source xml:space="preserve">Payment information</source>
<context-group purpose="location"><context context-type="linenumber">39</context></context-group>
</trans-unit>
@@ -3079,7 +3087,7 @@ For more information on using this console, type %6.
</body></file>
<file original="../receiverequestdialog.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="ReceiveRequestDialog">
- <trans-unit id="_msg666">
+ <trans-unit id="_msg668">
<source xml:space="preserve">Request payment to %1</source>
<context-group purpose="location"><context context-type="linenumber">49</context></context-group>
</trans-unit>
@@ -3087,31 +3095,31 @@ For more information on using this console, type %6.
</body></file>
<file original="../recentrequeststablemodel.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="RecentRequestsTableModel">
- <trans-unit id="_msg667">
+ <trans-unit id="_msg669">
<source xml:space="preserve">Date</source>
<context-group purpose="location"><context context-type="linenumber">32</context></context-group>
</trans-unit>
- <trans-unit id="_msg668">
+ <trans-unit id="_msg670">
<source xml:space="preserve">Label</source>
<context-group purpose="location"><context context-type="linenumber">32</context></context-group>
</trans-unit>
- <trans-unit id="_msg669">
+ <trans-unit id="_msg671">
<source xml:space="preserve">Message</source>
<context-group purpose="location"><context context-type="linenumber">32</context></context-group>
</trans-unit>
- <trans-unit id="_msg670">
+ <trans-unit id="_msg672">
<source xml:space="preserve">(no label)</source>
<context-group purpose="location"><context context-type="linenumber">70</context></context-group>
</trans-unit>
- <trans-unit id="_msg671">
+ <trans-unit id="_msg673">
<source xml:space="preserve">(no message)</source>
<context-group purpose="location"><context context-type="linenumber">79</context></context-group>
</trans-unit>
- <trans-unit id="_msg672">
+ <trans-unit id="_msg674">
<source xml:space="preserve">(no amount requested)</source>
<context-group purpose="location"><context context-type="linenumber">87</context></context-group>
</trans-unit>
- <trans-unit id="_msg673">
+ <trans-unit id="_msg675">
<source xml:space="preserve">Requested</source>
<context-group purpose="location"><context context-type="linenumber">130</context></context-group>
</trans-unit>
@@ -3119,154 +3127,154 @@ For more information on using this console, type %6.
</body></file>
<file original="../forms/sendcoinsdialog.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="SendCoinsDialog">
- <trans-unit id="_msg674">
+ <trans-unit id="_msg676">
<source xml:space="preserve">Send Coins</source>
<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">759</context></context-group>
+ <context-group purpose="location"><context context-type="sourcefile">../sendcoinsdialog.cpp</context><context context-type="linenumber">757</context></context-group>
</trans-unit>
- <trans-unit id="_msg675">
+ <trans-unit id="_msg677">
<source xml:space="preserve">Coin Control Features</source>
<context-group purpose="location"><context context-type="linenumber">90</context></context-group>
</trans-unit>
- <trans-unit id="_msg676">
+ <trans-unit id="_msg678">
<source xml:space="preserve">automatically selected</source>
<context-group purpose="location"><context context-type="linenumber">120</context></context-group>
</trans-unit>
- <trans-unit id="_msg677">
+ <trans-unit id="_msg679">
<source xml:space="preserve">Insufficient funds!</source>
<context-group purpose="location"><context context-type="linenumber">139</context></context-group>
</trans-unit>
- <trans-unit id="_msg678">
+ <trans-unit id="_msg680">
<source xml:space="preserve">Quantity:</source>
<context-group purpose="location"><context context-type="linenumber">228</context></context-group>
</trans-unit>
- <trans-unit id="_msg679">
+ <trans-unit id="_msg681">
<source xml:space="preserve">Bytes:</source>
<context-group purpose="location"><context context-type="linenumber">263</context></context-group>
</trans-unit>
- <trans-unit id="_msg680">
+ <trans-unit id="_msg682">
<source xml:space="preserve">Amount:</source>
<context-group purpose="location"><context context-type="linenumber">311</context></context-group>
</trans-unit>
- <trans-unit id="_msg681">
+ <trans-unit id="_msg683">
<source xml:space="preserve">Fee:</source>
<context-group purpose="location"><context context-type="linenumber">391</context></context-group>
</trans-unit>
- <trans-unit id="_msg682">
+ <trans-unit id="_msg684">
<source xml:space="preserve">After Fee:</source>
<context-group purpose="location"><context context-type="linenumber">442</context></context-group>
</trans-unit>
- <trans-unit id="_msg683">
+ <trans-unit id="_msg685">
<source xml:space="preserve">Change:</source>
<context-group purpose="location"><context context-type="linenumber">474</context></context-group>
</trans-unit>
- <trans-unit id="_msg684">
+ <trans-unit id="_msg686">
<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>
<context-group purpose="location"><context context-type="linenumber">518</context></context-group>
</trans-unit>
- <trans-unit id="_msg685">
+ <trans-unit id="_msg687">
<source xml:space="preserve">Custom change address</source>
<context-group purpose="location"><context context-type="linenumber">521</context></context-group>
</trans-unit>
- <trans-unit id="_msg686">
+ <trans-unit id="_msg688">
<source xml:space="preserve">Transaction Fee:</source>
<context-group purpose="location"><context context-type="linenumber">727</context></context-group>
</trans-unit>
- <trans-unit id="_msg687">
+ <trans-unit id="_msg689">
<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>
<context-group purpose="location"><context context-type="linenumber">765</context></context-group>
</trans-unit>
- <trans-unit id="_msg688">
+ <trans-unit id="_msg690">
<source xml:space="preserve">Warning: Fee estimation is currently not possible.</source>
<context-group purpose="location"><context context-type="linenumber">774</context></context-group>
</trans-unit>
- <trans-unit id="_msg689">
+ <trans-unit id="_msg691">
<source xml:space="preserve">per kilobyte</source>
<context-group purpose="location"><context context-type="linenumber">856</context></context-group>
</trans-unit>
- <trans-unit id="_msg690">
+ <trans-unit id="_msg692">
<source xml:space="preserve">Hide</source>
<context-group purpose="location"><context context-type="linenumber">803</context></context-group>
</trans-unit>
- <trans-unit id="_msg691">
+ <trans-unit id="_msg693">
<source xml:space="preserve">Recommended:</source>
<context-group purpose="location"><context context-type="linenumber">915</context></context-group>
</trans-unit>
- <trans-unit id="_msg692">
+ <trans-unit id="_msg694">
<source xml:space="preserve">Custom:</source>
<context-group purpose="location"><context context-type="linenumber">945</context></context-group>
</trans-unit>
- <trans-unit id="_msg693">
+ <trans-unit id="_msg695">
<source xml:space="preserve">Send to multiple recipients at once</source>
<context-group purpose="location"><context context-type="linenumber">1160</context></context-group>
</trans-unit>
- <trans-unit id="_msg694">
+ <trans-unit id="_msg696">
<source xml:space="preserve">Add &amp;Recipient</source>
<context-group purpose="location"><context context-type="linenumber">1163</context></context-group>
</trans-unit>
- <trans-unit id="_msg695">
+ <trans-unit id="_msg697">
<source xml:space="preserve">Clear all fields of the form.</source>
<context-group purpose="location"><context context-type="linenumber">1143</context></context-group>
</trans-unit>
- <trans-unit id="_msg696">
+ <trans-unit id="_msg698">
<source xml:space="preserve">Inputs…</source>
<context-group purpose="location"><context context-type="linenumber">110</context></context-group>
</trans-unit>
- <trans-unit id="_msg697">
+ <trans-unit id="_msg699">
<source xml:space="preserve">Dust:</source>
<context-group purpose="location"><context context-type="linenumber">343</context></context-group>
</trans-unit>
- <trans-unit id="_msg698">
+ <trans-unit id="_msg700">
<source xml:space="preserve">Choose…</source>
<context-group purpose="location"><context context-type="linenumber">741</context></context-group>
</trans-unit>
- <trans-unit id="_msg699">
+ <trans-unit id="_msg701">
<source xml:space="preserve">Hide transaction fee settings</source>
<context-group purpose="location"><context context-type="linenumber">800</context></context-group>
</trans-unit>
- <trans-unit id="_msg700">
+ <trans-unit id="_msg702">
<source xml:space="preserve">Specify a custom fee per kB (1,000 bytes) of the transaction&apos;s virtual size.
Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100 satoshis per kvB&quot; for a transaction size of 500 virtual bytes (half of 1 kvB) would ultimately yield a fee of only 50 satoshis.</source>
<context-group purpose="location"><context context-type="linenumber">851</context></context-group>
</trans-unit>
- <trans-unit id="_msg701">
+ <trans-unit id="_msg703">
<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>
<context-group purpose="location"><context context-type="linenumber">886</context></context-group>
</trans-unit>
- <trans-unit id="_msg702">
+ <trans-unit id="_msg704">
<source xml:space="preserve">A too low fee might result in a never confirming transaction (read the tooltip)</source>
<context-group purpose="location"><context context-type="linenumber">889</context></context-group>
</trans-unit>
- <trans-unit id="_msg703">
+ <trans-unit id="_msg705">
<source xml:space="preserve">(Smart fee not initialized yet. This usually takes a few blocks…)</source>
<context-group purpose="location"><context context-type="linenumber">994</context></context-group>
</trans-unit>
- <trans-unit id="_msg704">
+ <trans-unit id="_msg706">
<source xml:space="preserve">Confirmation time target:</source>
<context-group purpose="location"><context context-type="linenumber">1020</context></context-group>
</trans-unit>
- <trans-unit id="_msg705">
+ <trans-unit id="_msg707">
<source xml:space="preserve">Enable Replace-By-Fee</source>
<context-group purpose="location"><context context-type="linenumber">1078</context></context-group>
</trans-unit>
- <trans-unit id="_msg706">
+ <trans-unit id="_msg708">
<source xml:space="preserve">With Replace-By-Fee (BIP-125) you can increase a transaction&apos;s fee after it is sent. Without this, a higher fee may be recommended to compensate for increased transaction delay risk.</source>
<context-group purpose="location"><context context-type="linenumber">1081</context></context-group>
</trans-unit>
- <trans-unit id="_msg707">
+ <trans-unit id="_msg709">
<source xml:space="preserve">Clear &amp;All</source>
<context-group purpose="location"><context context-type="linenumber">1146</context></context-group>
</trans-unit>
- <trans-unit id="_msg708">
+ <trans-unit id="_msg710">
<source xml:space="preserve">Balance:</source>
<context-group purpose="location"><context context-type="linenumber">1201</context></context-group>
</trans-unit>
- <trans-unit id="_msg709">
+ <trans-unit id="_msg711">
<source xml:space="preserve">Confirm the send action</source>
<context-group purpose="location"><context context-type="linenumber">1117</context></context-group>
</trans-unit>
- <trans-unit id="_msg710">
+ <trans-unit id="_msg712">
<source xml:space="preserve">S&amp;end</source>
<context-group purpose="location"><context context-type="linenumber">1120</context></context-group>
</trans-unit>
@@ -3274,278 +3282,278 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
</body></file>
<file original="../sendcoinsdialog.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="SendCoinsDialog">
- <trans-unit id="_msg711">
+ <trans-unit id="_msg713">
<source xml:space="preserve">Copy quantity</source>
<context-group purpose="location"><context context-type="linenumber">99</context></context-group>
</trans-unit>
- <trans-unit id="_msg712">
+ <trans-unit id="_msg714">
<source xml:space="preserve">Copy amount</source>
<context-group purpose="location"><context context-type="linenumber">100</context></context-group>
</trans-unit>
- <trans-unit id="_msg713">
+ <trans-unit id="_msg715">
<source xml:space="preserve">Copy fee</source>
<context-group purpose="location"><context context-type="linenumber">101</context></context-group>
</trans-unit>
- <trans-unit id="_msg714">
+ <trans-unit id="_msg716">
<source xml:space="preserve">Copy after fee</source>
<context-group purpose="location"><context context-type="linenumber">102</context></context-group>
</trans-unit>
- <trans-unit id="_msg715">
+ <trans-unit id="_msg717">
<source xml:space="preserve">Copy bytes</source>
<context-group purpose="location"><context context-type="linenumber">103</context></context-group>
</trans-unit>
- <trans-unit id="_msg716">
+ <trans-unit id="_msg718">
<source xml:space="preserve">Copy dust</source>
<context-group purpose="location"><context context-type="linenumber">104</context></context-group>
</trans-unit>
- <trans-unit id="_msg717">
+ <trans-unit id="_msg719">
<source xml:space="preserve">Copy change</source>
<context-group purpose="location"><context context-type="linenumber">105</context></context-group>
</trans-unit>
- <trans-unit id="_msg718">
+ <trans-unit id="_msg720">
<source xml:space="preserve">%1 (%2 blocks)</source>
- <context-group purpose="location"><context context-type="linenumber">181</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">179</context></context-group>
</trans-unit>
- <trans-unit id="_msg719">
+ <trans-unit id="_msg721">
<source xml:space="preserve">Sign on device</source>
- <context-group purpose="location"><context context-type="linenumber">211</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">209</context></context-group>
<note annotates="source" from="developer">&quot;device&quot; usually means a hardware wallet.</note>
</trans-unit>
- <trans-unit id="_msg720">
+ <trans-unit id="_msg722">
<source xml:space="preserve">Connect your hardware wallet first.</source>
- <context-group purpose="location"><context context-type="linenumber">214</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">212</context></context-group>
</trans-unit>
- <trans-unit id="_msg721">
+ <trans-unit id="_msg723">
<source xml:space="preserve">Set external signer script path in Options -&gt; Wallet</source>
- <context-group purpose="location"><context context-type="linenumber">218</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">216</context></context-group>
<note annotates="source" from="developer">&quot;External signer&quot; means using devices such as hardware wallets.</note>
</trans-unit>
- <trans-unit id="_msg722">
+ <trans-unit id="_msg724">
<source xml:space="preserve">Cr&amp;eate Unsigned</source>
- <context-group purpose="location"><context context-type="linenumber">221</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">219</context></context-group>
</trans-unit>
- <trans-unit id="_msg723">
+ <trans-unit id="_msg725">
<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>
- <context-group purpose="location"><context context-type="linenumber">222</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">220</context></context-group>
</trans-unit>
- <trans-unit id="_msg724">
+ <trans-unit id="_msg726">
<source xml:space="preserve"> from wallet &apos;%1&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">312</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">310</context></context-group>
</trans-unit>
- <trans-unit id="_msg725">
+ <trans-unit id="_msg727">
<source xml:space="preserve">%1 to &apos;%2&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">323</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">321</context></context-group>
</trans-unit>
- <trans-unit id="_msg726">
+ <trans-unit id="_msg728">
<source xml:space="preserve">%1 to %2</source>
- <context-group purpose="location"><context context-type="linenumber">328</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">326</context></context-group>
</trans-unit>
- <trans-unit id="_msg727">
+ <trans-unit id="_msg729">
<source xml:space="preserve">To review recipient list click &quot;Show Details…&quot;</source>
- <context-group purpose="location"><context context-type="linenumber">394</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">392</context></context-group>
</trans-unit>
- <trans-unit id="_msg728">
+ <trans-unit id="_msg730">
<source xml:space="preserve">Sign failed</source>
- <context-group purpose="location"><context context-type="linenumber">454</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">452</context></context-group>
</trans-unit>
- <trans-unit id="_msg729">
+ <trans-unit id="_msg731">
<source xml:space="preserve">External signer not found</source>
- <context-group purpose="location"><context context-type="linenumber">459</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">457</context></context-group>
<note annotates="source" from="developer">&quot;External signer&quot; means using devices such as hardware wallets.</note>
</trans-unit>
- <trans-unit id="_msg730">
+ <trans-unit id="_msg732">
<source xml:space="preserve">External signer failure</source>
- <context-group purpose="location"><context context-type="linenumber">464</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">462</context></context-group>
<note annotates="source" from="developer">&quot;External signer&quot; means using devices such as hardware wallets.</note>
</trans-unit>
- <trans-unit id="_msg731">
+ <trans-unit id="_msg733">
<source xml:space="preserve">Save Transaction Data</source>
- <context-group purpose="location"><context context-type="linenumber">430</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">428</context></context-group>
</trans-unit>
- <trans-unit id="_msg732">
+ <trans-unit id="_msg734">
<source xml:space="preserve">Partially Signed Transaction (Binary)</source>
- <context-group purpose="location"><context context-type="linenumber">432</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">430</context></context-group>
<note annotates="source" from="developer">Expanded name of the binary PSBT file format. See: BIP 174.</note>
</trans-unit>
- <trans-unit id="_msg733">
+ <trans-unit id="_msg735">
<source xml:space="preserve">PSBT saved</source>
- <context-group purpose="location"><context context-type="linenumber">439</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">437</context></context-group>
</trans-unit>
- <trans-unit id="_msg734">
+ <trans-unit id="_msg736">
<source xml:space="preserve">External balance:</source>
- <context-group purpose="location"><context context-type="linenumber">705</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">703</context></context-group>
</trans-unit>
- <trans-unit id="_msg735">
+ <trans-unit id="_msg737">
<source xml:space="preserve">or</source>
- <context-group purpose="location"><context context-type="linenumber">390</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">388</context></context-group>
</trans-unit>
- <trans-unit id="_msg736">
+ <trans-unit id="_msg738">
<source xml:space="preserve">You can increase the fee later (signals Replace-By-Fee, BIP-125).</source>
- <context-group purpose="location"><context context-type="linenumber">372</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">370</context></context-group>
</trans-unit>
- <trans-unit id="_msg737">
+ <trans-unit id="_msg739">
<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>
- <context-group purpose="location"><context context-type="linenumber">342</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">340</context></context-group>
<note annotates="source" from="developer">Text to inform a user attempting to create a transaction of their current options. At this stage, a user can only create a PSBT. This string is displayed when private keys are disabled and an external signer is not available.</note>
</trans-unit>
- <trans-unit id="_msg738">
+ <trans-unit id="_msg740">
<source xml:space="preserve">Do you want to create this transaction?</source>
- <context-group purpose="location"><context context-type="linenumber">336</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">334</context></context-group>
<note annotates="source" from="developer">Message displayed when attempting to create a transaction. Cautionary text to prompt the user to verify that the displayed transaction details represent the transaction the user intends to create.</note>
</trans-unit>
- <trans-unit id="_msg739">
+ <trans-unit id="_msg741">
<source xml:space="preserve">Please, review your transaction. You can create and send this transaction or create 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>
- <context-group purpose="location"><context context-type="linenumber">347</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">345</context></context-group>
<note annotates="source" from="developer">Text to inform a user attempting to create a transaction of their current options. At this stage, a user can send their transaction or create a PSBT. This string is displayed when both private keys and PSBT controls are enabled.</note>
</trans-unit>
- <trans-unit id="_msg740">
+ <trans-unit id="_msg742">
<source xml:space="preserve">Please, review your transaction.</source>
- <context-group purpose="location"><context context-type="linenumber">350</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">348</context></context-group>
<note annotates="source" from="developer">Text to prompt a user to review the details of the transaction they are attempting to send.</note>
</trans-unit>
- <trans-unit id="_msg741">
+ <trans-unit id="_msg743">
<source xml:space="preserve">Transaction fee</source>
- <context-group purpose="location"><context context-type="linenumber">358</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">356</context></context-group>
</trans-unit>
- <trans-unit id="_msg742">
+ <trans-unit id="_msg744">
<source xml:space="preserve">Not signalling Replace-By-Fee, BIP-125.</source>
- <context-group purpose="location"><context context-type="linenumber">374</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">372</context></context-group>
</trans-unit>
- <trans-unit id="_msg743">
+ <trans-unit id="_msg745">
<source xml:space="preserve">Total Amount</source>
- <context-group purpose="location"><context context-type="linenumber">387</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">385</context></context-group>
</trans-unit>
- <trans-unit id="_msg744">
+ <trans-unit id="_msg746">
<source xml:space="preserve">Confirm send coins</source>
- <context-group purpose="location"><context context-type="linenumber">486</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">484</context></context-group>
</trans-unit>
- <trans-unit id="_msg745">
+ <trans-unit id="_msg747">
<source xml:space="preserve">Watch-only balance:</source>
- <context-group purpose="location"><context context-type="linenumber">708</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">706</context></context-group>
</trans-unit>
- <trans-unit id="_msg746">
+ <trans-unit id="_msg748">
<source xml:space="preserve">The recipient address is not valid. Please recheck.</source>
- <context-group purpose="location"><context context-type="linenumber">732</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">730</context></context-group>
</trans-unit>
- <trans-unit id="_msg747">
+ <trans-unit id="_msg749">
<source xml:space="preserve">The amount to pay must be larger than 0.</source>
- <context-group purpose="location"><context context-type="linenumber">735</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">733</context></context-group>
</trans-unit>
- <trans-unit id="_msg748">
+ <trans-unit id="_msg750">
<source xml:space="preserve">The amount exceeds your balance.</source>
- <context-group purpose="location"><context context-type="linenumber">738</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">736</context></context-group>
</trans-unit>
- <trans-unit id="_msg749">
+ <trans-unit id="_msg751">
<source xml:space="preserve">The total exceeds your balance when the %1 transaction fee is included.</source>
- <context-group purpose="location"><context context-type="linenumber">741</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">739</context></context-group>
</trans-unit>
- <trans-unit id="_msg750">
+ <trans-unit id="_msg752">
<source xml:space="preserve">Duplicate address found: addresses should only be used once each.</source>
- <context-group purpose="location"><context context-type="linenumber">744</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">742</context></context-group>
</trans-unit>
- <trans-unit id="_msg751">
+ <trans-unit id="_msg753">
<source xml:space="preserve">Transaction creation failed!</source>
- <context-group purpose="location"><context context-type="linenumber">747</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">745</context></context-group>
</trans-unit>
- <trans-unit id="_msg752">
+ <trans-unit id="_msg754">
<source xml:space="preserve">A fee higher than %1 is considered an absurdly high fee.</source>
- <context-group purpose="location"><context context-type="linenumber">751</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">749</context></context-group>
</trans-unit>
<group restype="x-gettext-plurals">
- <context-group purpose="location"><context context-type="linenumber">874</context></context-group>
- <trans-unit id="_msg753[0]">
+ <context-group purpose="location"><context context-type="linenumber">872</context></context-group>
+ <trans-unit id="_msg755[0]">
<source xml:space="preserve">Estimated to begin confirmation within %n block(s).</source>
</trans-unit>
- <trans-unit id="_msg753[1]">
+ <trans-unit id="_msg755[1]">
<source xml:space="preserve">Estimated to begin confirmation within %n block(s).</source>
</trans-unit>
</group>
- <trans-unit id="_msg754">
+ <trans-unit id="_msg756">
<source xml:space="preserve">Warning: Invalid Bitcoin address</source>
- <context-group purpose="location"><context context-type="linenumber">975</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">973</context></context-group>
</trans-unit>
- <trans-unit id="_msg755">
+ <trans-unit id="_msg757">
<source xml:space="preserve">Warning: Unknown change address</source>
- <context-group purpose="location"><context context-type="linenumber">980</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">978</context></context-group>
</trans-unit>
- <trans-unit id="_msg756">
+ <trans-unit id="_msg758">
<source xml:space="preserve">Confirm custom change address</source>
- <context-group purpose="location"><context context-type="linenumber">983</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">981</context></context-group>
</trans-unit>
- <trans-unit id="_msg757">
+ <trans-unit id="_msg759">
<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>
- <context-group purpose="location"><context context-type="linenumber">983</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">981</context></context-group>
</trans-unit>
- <trans-unit id="_msg758">
+ <trans-unit id="_msg760">
<source xml:space="preserve">(no label)</source>
- <context-group purpose="location"><context context-type="linenumber">1004</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1002</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../forms/sendcoinsentry.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="SendCoinsEntry">
- <trans-unit id="_msg759">
+ <trans-unit id="_msg761">
<source xml:space="preserve">A&amp;mount:</source>
<context-group purpose="location"><context context-type="linenumber">151</context></context-group>
</trans-unit>
- <trans-unit id="_msg760">
+ <trans-unit id="_msg762">
<source xml:space="preserve">Pay &amp;To:</source>
<context-group purpose="location"><context context-type="linenumber">35</context></context-group>
</trans-unit>
- <trans-unit id="_msg761">
+ <trans-unit id="_msg763">
<source xml:space="preserve">&amp;Label:</source>
<context-group purpose="location"><context context-type="linenumber">128</context></context-group>
</trans-unit>
- <trans-unit id="_msg762">
+ <trans-unit id="_msg764">
<source xml:space="preserve">Choose previously used address</source>
<context-group purpose="location"><context context-type="linenumber">60</context></context-group>
</trans-unit>
- <trans-unit id="_msg763">
+ <trans-unit id="_msg765">
<source xml:space="preserve">The Bitcoin address to send the payment to</source>
<context-group purpose="location"><context context-type="linenumber">53</context></context-group>
</trans-unit>
- <trans-unit id="_msg764">
+ <trans-unit id="_msg766">
<source xml:space="preserve">Alt+A</source>
<context-group purpose="location"><context context-type="linenumber">76</context></context-group>
</trans-unit>
- <trans-unit id="_msg765">
+ <trans-unit id="_msg767">
<source xml:space="preserve">Paste address from clipboard</source>
<context-group purpose="location"><context context-type="linenumber">83</context></context-group>
</trans-unit>
- <trans-unit id="_msg766">
+ <trans-unit id="_msg768">
<source xml:space="preserve">Alt+P</source>
<context-group purpose="location"><context context-type="linenumber">99</context></context-group>
</trans-unit>
- <trans-unit id="_msg767">
+ <trans-unit id="_msg769">
<source xml:space="preserve">Remove this entry</source>
<context-group purpose="location"><context context-type="linenumber">106</context></context-group>
</trans-unit>
- <trans-unit id="_msg768">
+ <trans-unit id="_msg770">
<source xml:space="preserve">The amount to send in the selected unit</source>
<context-group purpose="location"><context context-type="linenumber">166</context></context-group>
</trans-unit>
- <trans-unit id="_msg769">
+ <trans-unit id="_msg771">
<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>
<context-group purpose="location"><context context-type="linenumber">173</context></context-group>
</trans-unit>
- <trans-unit id="_msg770">
+ <trans-unit id="_msg772">
<source xml:space="preserve">S&amp;ubtract fee from amount</source>
<context-group purpose="location"><context context-type="linenumber">176</context></context-group>
</trans-unit>
- <trans-unit id="_msg771">
+ <trans-unit id="_msg773">
<source xml:space="preserve">Use available balance</source>
<context-group purpose="location"><context context-type="linenumber">183</context></context-group>
</trans-unit>
- <trans-unit id="_msg772">
+ <trans-unit id="_msg774">
<source xml:space="preserve">Message:</source>
<context-group purpose="location"><context context-type="linenumber">192</context></context-group>
</trans-unit>
- <trans-unit id="_msg773">
+ <trans-unit id="_msg775">
<source xml:space="preserve">Enter a label for this address to add it to the list of used addresses</source>
<context-group purpose="location"><context context-type="linenumber">141</context></context-group>
<context-group purpose="location"><context context-type="linenumber">144</context></context-group>
</trans-unit>
- <trans-unit id="_msg774">
+ <trans-unit id="_msg776">
<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>
<context-group purpose="location"><context context-type="linenumber">202</context></context-group>
</trans-unit>
@@ -3553,11 +3561,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
</body></file>
<file original="../sendcoinsdialog.h" datatype="c" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="SendConfirmationDialog">
- <trans-unit id="_msg775">
+ <trans-unit id="_msg777">
<source xml:space="preserve">Send</source>
<context-group purpose="location"><context context-type="linenumber">144</context></context-group>
</trans-unit>
- <trans-unit id="_msg776">
+ <trans-unit id="_msg778">
<source xml:space="preserve">Create Unsigned</source>
<context-group purpose="location"><context context-type="linenumber">146</context></context-group>
</trans-unit>
@@ -3565,105 +3573,105 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
</body></file>
<file original="../forms/signverifymessagedialog.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="SignVerifyMessageDialog">
- <trans-unit id="_msg777">
+ <trans-unit id="_msg779">
<source xml:space="preserve">Signatures - Sign / Verify a Message</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
</trans-unit>
- <trans-unit id="_msg778">
+ <trans-unit id="_msg780">
<source xml:space="preserve">&amp;Sign Message</source>
<context-group purpose="location"><context context-type="linenumber">27</context></context-group>
</trans-unit>
- <trans-unit id="_msg779">
+ <trans-unit id="_msg781">
<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>
<context-group purpose="location"><context context-type="linenumber">33</context></context-group>
</trans-unit>
- <trans-unit id="_msg780">
+ <trans-unit id="_msg782">
<source xml:space="preserve">The Bitcoin address to sign the message with</source>
<context-group purpose="location"><context context-type="linenumber">51</context></context-group>
</trans-unit>
- <trans-unit id="_msg781">
+ <trans-unit id="_msg783">
<source xml:space="preserve">Choose previously used address</source>
<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="_msg782">
+ <trans-unit id="_msg784">
<source xml:space="preserve">Alt+A</source>
<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="_msg783">
+ <trans-unit id="_msg785">
<source xml:space="preserve">Paste address from clipboard</source>
<context-group purpose="location"><context context-type="linenumber">78</context></context-group>
</trans-unit>
- <trans-unit id="_msg784">
+ <trans-unit id="_msg786">
<source xml:space="preserve">Alt+P</source>
<context-group purpose="location"><context context-type="linenumber">88</context></context-group>
</trans-unit>
- <trans-unit id="_msg785">
+ <trans-unit id="_msg787">
<source xml:space="preserve">Enter the message you want to sign here</source>
<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="_msg786">
+ <trans-unit id="_msg788">
<source xml:space="preserve">Signature</source>
<context-group purpose="location"><context context-type="linenumber">110</context></context-group>
</trans-unit>
- <trans-unit id="_msg787">
+ <trans-unit id="_msg789">
<source xml:space="preserve">Copy the current signature to the system clipboard</source>
<context-group purpose="location"><context context-type="linenumber">140</context></context-group>
</trans-unit>
- <trans-unit id="_msg788">
+ <trans-unit id="_msg790">
<source xml:space="preserve">Sign the message to prove you own this Bitcoin address</source>
<context-group purpose="location"><context context-type="linenumber">161</context></context-group>
</trans-unit>
- <trans-unit id="_msg789">
+ <trans-unit id="_msg791">
<source xml:space="preserve">Sign &amp;Message</source>
<context-group purpose="location"><context context-type="linenumber">164</context></context-group>
</trans-unit>
- <trans-unit id="_msg790">
+ <trans-unit id="_msg792">
<source xml:space="preserve">Reset all sign message fields</source>
<context-group purpose="location"><context context-type="linenumber">178</context></context-group>
</trans-unit>
- <trans-unit id="_msg791">
+ <trans-unit id="_msg793">
<source xml:space="preserve">Clear &amp;All</source>
<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="_msg792">
+ <trans-unit id="_msg794">
<source xml:space="preserve">&amp;Verify Message</source>
<context-group purpose="location"><context context-type="linenumber">240</context></context-group>
</trans-unit>
- <trans-unit id="_msg793">
+ <trans-unit id="_msg795">
<source xml:space="preserve">Enter the receiver&apos;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>
<context-group purpose="location"><context context-type="linenumber">246</context></context-group>
</trans-unit>
- <trans-unit id="_msg794">
+ <trans-unit id="_msg796">
<source xml:space="preserve">The Bitcoin address the message was signed with</source>
<context-group purpose="location"><context context-type="linenumber">267</context></context-group>
</trans-unit>
- <trans-unit id="_msg795">
+ <trans-unit id="_msg797">
<source xml:space="preserve">The signed message to verify</source>
<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="_msg796">
+ <trans-unit id="_msg798">
<source xml:space="preserve">The signature given when the message was signed</source>
<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="_msg797">
+ <trans-unit id="_msg799">
<source xml:space="preserve">Verify the message to ensure it was signed with the specified Bitcoin address</source>
<context-group purpose="location"><context context-type="linenumber">318</context></context-group>
</trans-unit>
- <trans-unit id="_msg798">
+ <trans-unit id="_msg800">
<source xml:space="preserve">Verify &amp;Message</source>
<context-group purpose="location"><context context-type="linenumber">321</context></context-group>
</trans-unit>
- <trans-unit id="_msg799">
+ <trans-unit id="_msg801">
<source xml:space="preserve">Reset all verify message fields</source>
<context-group purpose="location"><context context-type="linenumber">335</context></context-group>
</trans-unit>
- <trans-unit id="_msg800">
+ <trans-unit id="_msg802">
<source xml:space="preserve">Click &quot;Sign Message&quot; to generate signature</source>
<context-group purpose="location"><context context-type="linenumber">125</context></context-group>
</trans-unit>
@@ -3671,61 +3679,61 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
</body></file>
<file original="../signverifymessagedialog.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="SignVerifyMessageDialog">
- <trans-unit id="_msg801">
+ <trans-unit id="_msg803">
<source xml:space="preserve">The entered address is invalid.</source>
<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="_msg802">
+ <trans-unit id="_msg804">
<source xml:space="preserve">Please check the address and try again.</source>
<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="_msg803">
+ <trans-unit id="_msg805">
<source xml:space="preserve">The entered address does not refer to a key.</source>
<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="_msg804">
+ <trans-unit id="_msg806">
<source xml:space="preserve">Wallet unlock was cancelled.</source>
<context-group purpose="location"><context context-type="linenumber">135</context></context-group>
</trans-unit>
- <trans-unit id="_msg805">
+ <trans-unit id="_msg807">
<source xml:space="preserve">No error</source>
<context-group purpose="location"><context context-type="linenumber">146</context></context-group>
</trans-unit>
- <trans-unit id="_msg806">
+ <trans-unit id="_msg808">
<source xml:space="preserve">Private key for the entered address is not available.</source>
<context-group purpose="location"><context context-type="linenumber">149</context></context-group>
</trans-unit>
- <trans-unit id="_msg807">
+ <trans-unit id="_msg809">
<source xml:space="preserve">Message signing failed.</source>
<context-group purpose="location"><context context-type="linenumber">152</context></context-group>
</trans-unit>
- <trans-unit id="_msg808">
+ <trans-unit id="_msg810">
<source xml:space="preserve">Message signed.</source>
<context-group purpose="location"><context context-type="linenumber">164</context></context-group>
</trans-unit>
- <trans-unit id="_msg809">
+ <trans-unit id="_msg811">
<source xml:space="preserve">The signature could not be decoded.</source>
<context-group purpose="location"><context context-type="linenumber">233</context></context-group>
</trans-unit>
- <trans-unit id="_msg810">
+ <trans-unit id="_msg812">
<source xml:space="preserve">Please check the signature and try again.</source>
<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="_msg811">
+ <trans-unit id="_msg813">
<source xml:space="preserve">The signature did not match the message digest.</source>
<context-group purpose="location"><context context-type="linenumber">240</context></context-group>
</trans-unit>
- <trans-unit id="_msg812">
+ <trans-unit id="_msg814">
<source xml:space="preserve">Message verification failed.</source>
<context-group purpose="location"><context context-type="linenumber">246</context></context-group>
</trans-unit>
- <trans-unit id="_msg813">
+ <trans-unit id="_msg815">
<source xml:space="preserve">Message verified.</source>
<context-group purpose="location"><context context-type="linenumber">214</context></context-group>
</trans-unit>
@@ -3733,11 +3741,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
</body></file>
<file original="../splashscreen.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="SplashScreen">
- <trans-unit id="_msg814">
+ <trans-unit id="_msg816">
<source xml:space="preserve">(press q to shutdown and continue later)</source>
<context-group purpose="location"><context context-type="linenumber">187</context></context-group>
</trans-unit>
- <trans-unit id="_msg815">
+ <trans-unit id="_msg817">
<source xml:space="preserve">press q to shutdown</source>
<context-group purpose="location"><context context-type="linenumber">188</context></context-group>
</trans-unit>
@@ -3745,7 +3753,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
</body></file>
<file original="../trafficgraphwidget.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="TrafficGraphWidget">
- <trans-unit id="_msg816">
+ <trans-unit id="_msg818">
<source xml:space="preserve">kB/s</source>
<context-group purpose="location"><context context-type="linenumber">79</context></context-group>
</trans-unit>
@@ -3753,82 +3761,82 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
</body></file>
<file original="../transactiondesc.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="TransactionDesc">
- <trans-unit id="_msg817">
+ <trans-unit id="_msg819">
<source xml:space="preserve">conflicted with a transaction with %1 confirmations</source>
<context-group purpose="location"><context context-type="linenumber">43</context></context-group>
<note annotates="source" from="developer">Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that conflicts with a confirmed transaction.</note>
</trans-unit>
- <trans-unit id="_msg818">
+ <trans-unit id="_msg820">
<source xml:space="preserve">0/unconfirmed, in memory pool</source>
<context-group purpose="location"><context context-type="linenumber">50</context></context-group>
<note annotates="source" from="developer">Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that is in the memory pool.</note>
</trans-unit>
- <trans-unit id="_msg819">
+ <trans-unit id="_msg821">
<source xml:space="preserve">0/unconfirmed, not in memory pool</source>
<context-group purpose="location"><context context-type="linenumber">55</context></context-group>
<note annotates="source" from="developer">Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that is not in the memory pool.</note>
</trans-unit>
- <trans-unit id="_msg820">
+ <trans-unit id="_msg822">
<source xml:space="preserve">abandoned</source>
<context-group purpose="location"><context context-type="linenumber">61</context></context-group>
<note annotates="source" from="developer">Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</note>
</trans-unit>
- <trans-unit id="_msg821">
+ <trans-unit id="_msg823">
<source xml:space="preserve">%1/unconfirmed</source>
<context-group purpose="location"><context context-type="linenumber">69</context></context-group>
<note annotates="source" from="developer">Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</note>
</trans-unit>
- <trans-unit id="_msg822">
+ <trans-unit id="_msg824">
<source xml:space="preserve">%1 confirmations</source>
<context-group purpose="location"><context context-type="linenumber">74</context></context-group>
<note annotates="source" from="developer">Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</note>
</trans-unit>
- <trans-unit id="_msg823">
+ <trans-unit id="_msg825">
<source xml:space="preserve">Status</source>
<context-group purpose="location"><context context-type="linenumber">124</context></context-group>
</trans-unit>
- <trans-unit id="_msg824">
+ <trans-unit id="_msg826">
<source xml:space="preserve">Date</source>
<context-group purpose="location"><context context-type="linenumber">127</context></context-group>
</trans-unit>
- <trans-unit id="_msg825">
+ <trans-unit id="_msg827">
<source xml:space="preserve">Source</source>
<context-group purpose="location"><context context-type="linenumber">134</context></context-group>
</trans-unit>
- <trans-unit id="_msg826">
+ <trans-unit id="_msg828">
<source xml:space="preserve">Generated</source>
<context-group purpose="location"><context context-type="linenumber">134</context></context-group>
</trans-unit>
- <trans-unit id="_msg827">
+ <trans-unit id="_msg829">
<source xml:space="preserve">From</source>
<context-group purpose="location"><context context-type="linenumber">139</context></context-group>
<context-group purpose="location"><context context-type="linenumber">153</context></context-group>
<context-group purpose="location"><context context-type="linenumber">225</context></context-group>
</trans-unit>
- <trans-unit id="_msg828">
+ <trans-unit id="_msg830">
<source xml:space="preserve">unknown</source>
<context-group purpose="location"><context context-type="linenumber">153</context></context-group>
</trans-unit>
- <trans-unit id="_msg829">
+ <trans-unit id="_msg831">
<source xml:space="preserve">To</source>
<context-group purpose="location"><context context-type="linenumber">154</context></context-group>
<context-group purpose="location"><context context-type="linenumber">174</context></context-group>
<context-group purpose="location"><context context-type="linenumber">244</context></context-group>
</trans-unit>
- <trans-unit id="_msg830">
+ <trans-unit id="_msg832">
<source xml:space="preserve">own address</source>
<context-group purpose="location"><context context-type="linenumber">156</context></context-group>
</trans-unit>
- <trans-unit id="_msg831">
+ <trans-unit id="_msg833">
<source xml:space="preserve">watch-only</source>
<context-group purpose="location"><context context-type="linenumber">156</context></context-group>
<context-group purpose="location"><context context-type="linenumber">225</context></context-group>
</trans-unit>
- <trans-unit id="_msg832">
+ <trans-unit id="_msg834">
<source xml:space="preserve">label</source>
<context-group purpose="location"><context context-type="linenumber">158</context></context-group>
</trans-unit>
- <trans-unit id="_msg833">
+ <trans-unit id="_msg835">
<source xml:space="preserve">Credit</source>
<context-group purpose="location"><context context-type="linenumber">194</context></context-group>
<context-group purpose="location"><context context-type="linenumber">206</context></context-group>
@@ -3838,98 +3846,98 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
</trans-unit>
<group restype="x-gettext-plurals">
<context-group purpose="location"><context context-type="linenumber">196</context></context-group>
- <trans-unit id="_msg834[0]">
+ <trans-unit id="_msg836[0]">
<source xml:space="preserve">matures in %n more block(s)</source>
</trans-unit>
- <trans-unit id="_msg834[1]">
+ <trans-unit id="_msg836[1]">
<source xml:space="preserve">matures in %n more block(s)</source>
</trans-unit>
</group>
- <trans-unit id="_msg835">
+ <trans-unit id="_msg837">
<source xml:space="preserve">not accepted</source>
<context-group purpose="location"><context context-type="linenumber">198</context></context-group>
</trans-unit>
- <trans-unit id="_msg836">
+ <trans-unit id="_msg838">
<source xml:space="preserve">Debit</source>
<context-group purpose="location"><context context-type="linenumber">258</context></context-group>
<context-group purpose="location"><context context-type="linenumber">284</context></context-group>
<context-group purpose="location"><context context-type="linenumber">347</context></context-group>
</trans-unit>
- <trans-unit id="_msg837">
+ <trans-unit id="_msg839">
<source xml:space="preserve">Total debit</source>
<context-group purpose="location"><context context-type="linenumber">268</context></context-group>
</trans-unit>
- <trans-unit id="_msg838">
+ <trans-unit id="_msg840">
<source xml:space="preserve">Total credit</source>
<context-group purpose="location"><context context-type="linenumber">269</context></context-group>
</trans-unit>
- <trans-unit id="_msg839">
+ <trans-unit id="_msg841">
<source xml:space="preserve">Transaction fee</source>
<context-group purpose="location"><context context-type="linenumber">274</context></context-group>
</trans-unit>
- <trans-unit id="_msg840">
+ <trans-unit id="_msg842">
<source xml:space="preserve">Net amount</source>
<context-group purpose="location"><context context-type="linenumber">296</context></context-group>
</trans-unit>
- <trans-unit id="_msg841">
+ <trans-unit id="_msg843">
<source xml:space="preserve">Message</source>
<context-group purpose="location"><context context-type="linenumber">302</context></context-group>
<context-group purpose="location"><context context-type="linenumber">314</context></context-group>
</trans-unit>
- <trans-unit id="_msg842">
+ <trans-unit id="_msg844">
<source xml:space="preserve">Comment</source>
<context-group purpose="location"><context context-type="linenumber">304</context></context-group>
</trans-unit>
- <trans-unit id="_msg843">
+ <trans-unit id="_msg845">
<source xml:space="preserve">Transaction ID</source>
<context-group purpose="location"><context context-type="linenumber">306</context></context-group>
</trans-unit>
- <trans-unit id="_msg844">
+ <trans-unit id="_msg846">
<source xml:space="preserve">Transaction total size</source>
<context-group purpose="location"><context context-type="linenumber">307</context></context-group>
</trans-unit>
- <trans-unit id="_msg845">
+ <trans-unit id="_msg847">
<source xml:space="preserve">Transaction virtual size</source>
<context-group purpose="location"><context context-type="linenumber">308</context></context-group>
</trans-unit>
- <trans-unit id="_msg846">
+ <trans-unit id="_msg848">
<source xml:space="preserve">Output index</source>
<context-group purpose="location"><context context-type="linenumber">309</context></context-group>
</trans-unit>
- <trans-unit id="_msg847">
+ <trans-unit id="_msg849">
<source xml:space="preserve"> (Certificate was not verified)</source>
<context-group purpose="location"><context context-type="linenumber">325</context></context-group>
</trans-unit>
- <trans-unit id="_msg848">
+ <trans-unit id="_msg850">
<source xml:space="preserve">Merchant</source>
<context-group purpose="location"><context context-type="linenumber">328</context></context-group>
</trans-unit>
- <trans-unit id="_msg849">
+ <trans-unit id="_msg851">
<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 &quot;not accepted&quot; and it won&apos;t be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.</source>
<context-group purpose="location"><context context-type="linenumber">336</context></context-group>
</trans-unit>
- <trans-unit id="_msg850">
+ <trans-unit id="_msg852">
<source xml:space="preserve">Debug information</source>
<context-group purpose="location"><context context-type="linenumber">344</context></context-group>
</trans-unit>
- <trans-unit id="_msg851">
+ <trans-unit id="_msg853">
<source xml:space="preserve">Transaction</source>
<context-group purpose="location"><context context-type="linenumber">352</context></context-group>
</trans-unit>
- <trans-unit id="_msg852">
+ <trans-unit id="_msg854">
<source xml:space="preserve">Inputs</source>
<context-group purpose="location"><context context-type="linenumber">355</context></context-group>
</trans-unit>
- <trans-unit id="_msg853">
+ <trans-unit id="_msg855">
<source xml:space="preserve">Amount</source>
<context-group purpose="location"><context context-type="linenumber">376</context></context-group>
</trans-unit>
- <trans-unit id="_msg854">
+ <trans-unit id="_msg856">
<source xml:space="preserve">true</source>
<context-group purpose="location"><context context-type="linenumber">377</context></context-group>
<context-group purpose="location"><context context-type="linenumber">378</context></context-group>
</trans-unit>
- <trans-unit id="_msg855">
+ <trans-unit id="_msg857">
<source xml:space="preserve">false</source>
<context-group purpose="location"><context context-type="linenumber">377</context></context-group>
<context-group purpose="location"><context context-type="linenumber">378</context></context-group>
@@ -3938,7 +3946,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
</body></file>
<file original="../forms/transactiondescdialog.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="TransactionDescDialog">
- <trans-unit id="_msg856">
+ <trans-unit id="_msg858">
<source xml:space="preserve">This pane shows a detailed description of the transaction</source>
<context-group purpose="location"><context context-type="linenumber">20</context></context-group>
</trans-unit>
@@ -3946,7 +3954,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
</body></file>
<file original="../transactiondescdialog.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="TransactionDescDialog">
- <trans-unit id="_msg857">
+ <trans-unit id="_msg859">
<source xml:space="preserve">Details for %1</source>
<context-group purpose="location"><context context-type="linenumber">18</context></context-group>
</trans-unit>
@@ -3954,99 +3962,99 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
</body></file>
<file original="../transactiontablemodel.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="TransactionTableModel">
- <trans-unit id="_msg858">
+ <trans-unit id="_msg860">
<source xml:space="preserve">Date</source>
<context-group purpose="location"><context context-type="linenumber">261</context></context-group>
</trans-unit>
- <trans-unit id="_msg859">
+ <trans-unit id="_msg861">
<source xml:space="preserve">Type</source>
<context-group purpose="location"><context context-type="linenumber">261</context></context-group>
</trans-unit>
- <trans-unit id="_msg860">
+ <trans-unit id="_msg862">
<source xml:space="preserve">Label</source>
<context-group purpose="location"><context context-type="linenumber">261</context></context-group>
</trans-unit>
- <trans-unit id="_msg861">
+ <trans-unit id="_msg863">
<source xml:space="preserve">Unconfirmed</source>
<context-group purpose="location"><context context-type="linenumber">321</context></context-group>
</trans-unit>
- <trans-unit id="_msg862">
+ <trans-unit id="_msg864">
<source xml:space="preserve">Abandoned</source>
<context-group purpose="location"><context context-type="linenumber">324</context></context-group>
</trans-unit>
- <trans-unit id="_msg863">
+ <trans-unit id="_msg865">
<source xml:space="preserve">Confirming (%1 of %2 recommended confirmations)</source>
<context-group purpose="location"><context context-type="linenumber">327</context></context-group>
</trans-unit>
- <trans-unit id="_msg864">
+ <trans-unit id="_msg866">
<source xml:space="preserve">Confirmed (%1 confirmations)</source>
<context-group purpose="location"><context context-type="linenumber">330</context></context-group>
</trans-unit>
- <trans-unit id="_msg865">
+ <trans-unit id="_msg867">
<source xml:space="preserve">Conflicted</source>
<context-group purpose="location"><context context-type="linenumber">333</context></context-group>
</trans-unit>
- <trans-unit id="_msg866">
+ <trans-unit id="_msg868">
<source xml:space="preserve">Immature (%1 confirmations, will be available after %2)</source>
<context-group purpose="location"><context context-type="linenumber">336</context></context-group>
</trans-unit>
- <trans-unit id="_msg867">
+ <trans-unit id="_msg869">
<source xml:space="preserve">Generated but not accepted</source>
<context-group purpose="location"><context context-type="linenumber">339</context></context-group>
</trans-unit>
- <trans-unit id="_msg868">
+ <trans-unit id="_msg870">
<source xml:space="preserve">Received with</source>
<context-group purpose="location"><context context-type="linenumber">378</context></context-group>
</trans-unit>
- <trans-unit id="_msg869">
+ <trans-unit id="_msg871">
<source xml:space="preserve">Received from</source>
<context-group purpose="location"><context context-type="linenumber">380</context></context-group>
</trans-unit>
- <trans-unit id="_msg870">
+ <trans-unit id="_msg872">
<source xml:space="preserve">Sent to</source>
<context-group purpose="location"><context context-type="linenumber">383</context></context-group>
</trans-unit>
- <trans-unit id="_msg871">
+ <trans-unit id="_msg873">
<source xml:space="preserve">Payment to yourself</source>
<context-group purpose="location"><context context-type="linenumber">385</context></context-group>
</trans-unit>
- <trans-unit id="_msg872">
+ <trans-unit id="_msg874">
<source xml:space="preserve">Mined</source>
<context-group purpose="location"><context context-type="linenumber">387</context></context-group>
</trans-unit>
- <trans-unit id="_msg873">
+ <trans-unit id="_msg875">
<source xml:space="preserve">watch-only</source>
<context-group purpose="location"><context context-type="linenumber">415</context></context-group>
</trans-unit>
- <trans-unit id="_msg874">
+ <trans-unit id="_msg876">
<source xml:space="preserve">(n/a)</source>
<context-group purpose="location"><context context-type="linenumber">431</context></context-group>
</trans-unit>
- <trans-unit id="_msg875">
+ <trans-unit id="_msg877">
<source xml:space="preserve">(no label)</source>
<context-group purpose="location"><context context-type="linenumber">638</context></context-group>
</trans-unit>
- <trans-unit id="_msg876">
+ <trans-unit id="_msg878">
<source xml:space="preserve">Transaction status. Hover over this field to show number of confirmations.</source>
<context-group purpose="location"><context context-type="linenumber">677</context></context-group>
</trans-unit>
- <trans-unit id="_msg877">
+ <trans-unit id="_msg879">
<source xml:space="preserve">Date and time that the transaction was received.</source>
<context-group purpose="location"><context context-type="linenumber">679</context></context-group>
</trans-unit>
- <trans-unit id="_msg878">
+ <trans-unit id="_msg880">
<source xml:space="preserve">Type of transaction.</source>
<context-group purpose="location"><context context-type="linenumber">681</context></context-group>
</trans-unit>
- <trans-unit id="_msg879">
+ <trans-unit id="_msg881">
<source xml:space="preserve">Whether or not a watch-only address is involved in this transaction.</source>
<context-group purpose="location"><context context-type="linenumber">683</context></context-group>
</trans-unit>
- <trans-unit id="_msg880">
+ <trans-unit id="_msg882">
<source xml:space="preserve">User-defined intent/purpose of the transaction.</source>
<context-group purpose="location"><context context-type="linenumber">685</context></context-group>
</trans-unit>
- <trans-unit id="_msg881">
+ <trans-unit id="_msg883">
<source xml:space="preserve">Amount removed from or added to balance.</source>
<context-group purpose="location"><context context-type="linenumber">687</context></context-group>
</trans-unit>
@@ -4054,166 +4062,166 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
</body></file>
<file original="../transactionview.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="TransactionView">
- <trans-unit id="_msg882">
+ <trans-unit id="_msg884">
<source xml:space="preserve">All</source>
<context-group purpose="location"><context context-type="linenumber">73</context></context-group>
<context-group purpose="location"><context context-type="linenumber">89</context></context-group>
</trans-unit>
- <trans-unit id="_msg883">
+ <trans-unit id="_msg885">
<source xml:space="preserve">Today</source>
<context-group purpose="location"><context context-type="linenumber">74</context></context-group>
</trans-unit>
- <trans-unit id="_msg884">
+ <trans-unit id="_msg886">
<source xml:space="preserve">This week</source>
<context-group purpose="location"><context context-type="linenumber">75</context></context-group>
</trans-unit>
- <trans-unit id="_msg885">
+ <trans-unit id="_msg887">
<source xml:space="preserve">This month</source>
<context-group purpose="location"><context context-type="linenumber">76</context></context-group>
</trans-unit>
- <trans-unit id="_msg886">
+ <trans-unit id="_msg888">
<source xml:space="preserve">Last month</source>
<context-group purpose="location"><context context-type="linenumber">77</context></context-group>
</trans-unit>
- <trans-unit id="_msg887">
+ <trans-unit id="_msg889">
<source xml:space="preserve">This year</source>
<context-group purpose="location"><context context-type="linenumber">78</context></context-group>
</trans-unit>
- <trans-unit id="_msg888">
+ <trans-unit id="_msg890">
<source xml:space="preserve">Received with</source>
<context-group purpose="location"><context context-type="linenumber">90</context></context-group>
</trans-unit>
- <trans-unit id="_msg889">
+ <trans-unit id="_msg891">
<source xml:space="preserve">Sent to</source>
<context-group purpose="location"><context context-type="linenumber">92</context></context-group>
</trans-unit>
- <trans-unit id="_msg890">
+ <trans-unit id="_msg892">
<source xml:space="preserve">To yourself</source>
<context-group purpose="location"><context context-type="linenumber">94</context></context-group>
</trans-unit>
- <trans-unit id="_msg891">
+ <trans-unit id="_msg893">
<source xml:space="preserve">Mined</source>
<context-group purpose="location"><context context-type="linenumber">95</context></context-group>
</trans-unit>
- <trans-unit id="_msg892">
+ <trans-unit id="_msg894">
<source xml:space="preserve">Other</source>
<context-group purpose="location"><context context-type="linenumber">96</context></context-group>
</trans-unit>
- <trans-unit id="_msg893">
+ <trans-unit id="_msg895">
<source xml:space="preserve">Enter address, transaction id, or label to search</source>
<context-group purpose="location"><context context-type="linenumber">101</context></context-group>
</trans-unit>
- <trans-unit id="_msg894">
+ <trans-unit id="_msg896">
<source xml:space="preserve">Min amount</source>
<context-group purpose="location"><context context-type="linenumber">105</context></context-group>
</trans-unit>
- <trans-unit id="_msg895">
+ <trans-unit id="_msg897">
<source xml:space="preserve">Range…</source>
<context-group purpose="location"><context context-type="linenumber">79</context></context-group>
</trans-unit>
- <trans-unit id="_msg896">
+ <trans-unit id="_msg898">
<source xml:space="preserve">&amp;Copy address</source>
<context-group purpose="location"><context context-type="linenumber">169</context></context-group>
</trans-unit>
- <trans-unit id="_msg897">
+ <trans-unit id="_msg899">
<source xml:space="preserve">Copy &amp;label</source>
<context-group purpose="location"><context context-type="linenumber">170</context></context-group>
</trans-unit>
- <trans-unit id="_msg898">
+ <trans-unit id="_msg900">
<source xml:space="preserve">Copy &amp;amount</source>
<context-group purpose="location"><context context-type="linenumber">171</context></context-group>
</trans-unit>
- <trans-unit id="_msg899">
+ <trans-unit id="_msg901">
<source xml:space="preserve">Copy transaction &amp;ID</source>
<context-group purpose="location"><context context-type="linenumber">172</context></context-group>
</trans-unit>
- <trans-unit id="_msg900">
+ <trans-unit id="_msg902">
<source xml:space="preserve">Copy &amp;raw transaction</source>
<context-group purpose="location"><context context-type="linenumber">173</context></context-group>
</trans-unit>
- <trans-unit id="_msg901">
+ <trans-unit id="_msg903">
<source xml:space="preserve">Copy full transaction &amp;details</source>
<context-group purpose="location"><context context-type="linenumber">174</context></context-group>
</trans-unit>
- <trans-unit id="_msg902">
+ <trans-unit id="_msg904">
<source xml:space="preserve">&amp;Show transaction details</source>
<context-group purpose="location"><context context-type="linenumber">175</context></context-group>
</trans-unit>
- <trans-unit id="_msg903">
+ <trans-unit id="_msg905">
<source xml:space="preserve">Increase transaction &amp;fee</source>
<context-group purpose="location"><context context-type="linenumber">177</context></context-group>
</trans-unit>
- <trans-unit id="_msg904">
+ <trans-unit id="_msg906">
<source xml:space="preserve">A&amp;bandon transaction</source>
<context-group purpose="location"><context context-type="linenumber">180</context></context-group>
</trans-unit>
- <trans-unit id="_msg905">
+ <trans-unit id="_msg907">
<source xml:space="preserve">&amp;Edit address label</source>
<context-group purpose="location"><context context-type="linenumber">181</context></context-group>
</trans-unit>
- <trans-unit id="_msg906">
+ <trans-unit id="_msg908">
<source xml:space="preserve">Show in %1</source>
<context-group purpose="location"><context context-type="linenumber">240</context></context-group>
<note annotates="source" from="developer">Transactions table context menu action to show the selected transaction in a third-party block explorer. %1 is a stand-in argument for the URL of the explorer.</note>
</trans-unit>
- <trans-unit id="_msg907">
+ <trans-unit id="_msg909">
<source xml:space="preserve">Export Transaction History</source>
<context-group purpose="location"><context context-type="linenumber">359</context></context-group>
</trans-unit>
- <trans-unit id="_msg908">
+ <trans-unit id="_msg910">
<source xml:space="preserve">Comma separated file</source>
<context-group purpose="location"><context context-type="linenumber">362</context></context-group>
<note annotates="source" from="developer">Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</note>
</trans-unit>
- <trans-unit id="_msg909">
+ <trans-unit id="_msg911">
<source xml:space="preserve">Confirmed</source>
<context-group purpose="location"><context context-type="linenumber">371</context></context-group>
</trans-unit>
- <trans-unit id="_msg910">
+ <trans-unit id="_msg912">
<source xml:space="preserve">Watch-only</source>
<context-group purpose="location"><context context-type="linenumber">373</context></context-group>
</trans-unit>
- <trans-unit id="_msg911">
+ <trans-unit id="_msg913">
<source xml:space="preserve">Date</source>
<context-group purpose="location"><context context-type="linenumber">374</context></context-group>
</trans-unit>
- <trans-unit id="_msg912">
+ <trans-unit id="_msg914">
<source xml:space="preserve">Type</source>
<context-group purpose="location"><context context-type="linenumber">375</context></context-group>
</trans-unit>
- <trans-unit id="_msg913">
+ <trans-unit id="_msg915">
<source xml:space="preserve">Label</source>
<context-group purpose="location"><context context-type="linenumber">376</context></context-group>
</trans-unit>
- <trans-unit id="_msg914">
+ <trans-unit id="_msg916">
<source xml:space="preserve">Address</source>
<context-group purpose="location"><context context-type="linenumber">377</context></context-group>
</trans-unit>
- <trans-unit id="_msg915">
+ <trans-unit id="_msg917">
<source xml:space="preserve">ID</source>
<context-group purpose="location"><context context-type="linenumber">379</context></context-group>
</trans-unit>
- <trans-unit id="_msg916">
+ <trans-unit id="_msg918">
<source xml:space="preserve">Exporting Failed</source>
<context-group purpose="location"><context context-type="linenumber">382</context></context-group>
</trans-unit>
- <trans-unit id="_msg917">
+ <trans-unit id="_msg919">
<source xml:space="preserve">There was an error trying to save the transaction history to %1.</source>
<context-group purpose="location"><context context-type="linenumber">382</context></context-group>
</trans-unit>
- <trans-unit id="_msg918">
+ <trans-unit id="_msg920">
<source xml:space="preserve">Exporting Successful</source>
<context-group purpose="location"><context context-type="linenumber">386</context></context-group>
</trans-unit>
- <trans-unit id="_msg919">
+ <trans-unit id="_msg921">
<source xml:space="preserve">The transaction history was successfully saved to %1.</source>
<context-group purpose="location"><context context-type="linenumber">386</context></context-group>
</trans-unit>
- <trans-unit id="_msg920">
+ <trans-unit id="_msg922">
<source xml:space="preserve">Range:</source>
<context-group purpose="location"><context context-type="linenumber">558</context></context-group>
</trans-unit>
- <trans-unit id="_msg921">
+ <trans-unit id="_msg923">
<source xml:space="preserve">to</source>
<context-group purpose="location"><context context-type="linenumber">566</context></context-group>
</trans-unit>
@@ -4221,39 +4229,39 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
</body></file>
<file original="../walletframe.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="WalletFrame">
- <trans-unit id="_msg922">
+ <trans-unit id="_msg924">
<source xml:space="preserve">No wallet has been loaded.
Go to File &gt; Open Wallet to load a wallet.
- OR -</source>
<context-group purpose="location"><context context-type="linenumber">45</context></context-group>
</trans-unit>
- <trans-unit id="_msg923">
+ <trans-unit id="_msg925">
<source xml:space="preserve">Create a new wallet</source>
<context-group purpose="location"><context context-type="linenumber">50</context></context-group>
</trans-unit>
- <trans-unit id="_msg924">
+ <trans-unit id="_msg926">
<source xml:space="preserve">Error</source>
<context-group purpose="location"><context context-type="linenumber">201</context></context-group>
<context-group purpose="location"><context context-type="linenumber">211</context></context-group>
<context-group purpose="location"><context context-type="linenumber">229</context></context-group>
</trans-unit>
- <trans-unit id="_msg925">
+ <trans-unit id="_msg927">
<source xml:space="preserve">Unable to decode PSBT from clipboard (invalid base64)</source>
<context-group purpose="location"><context context-type="linenumber">201</context></context-group>
</trans-unit>
- <trans-unit id="_msg926">
+ <trans-unit id="_msg928">
<source xml:space="preserve">Load Transaction Data</source>
<context-group purpose="location"><context context-type="linenumber">207</context></context-group>
</trans-unit>
- <trans-unit id="_msg927">
+ <trans-unit id="_msg929">
<source xml:space="preserve">Partially Signed Transaction (*.psbt)</source>
<context-group purpose="location"><context context-type="linenumber">208</context></context-group>
</trans-unit>
- <trans-unit id="_msg928">
+ <trans-unit id="_msg930">
<source xml:space="preserve">PSBT file must be smaller than 100 MiB</source>
<context-group purpose="location"><context context-type="linenumber">211</context></context-group>
</trans-unit>
- <trans-unit id="_msg929">
+ <trans-unit id="_msg931">
<source xml:space="preserve">Unable to decode PSBT</source>
<context-group purpose="location"><context context-type="linenumber">229</context></context-group>
</trans-unit>
@@ -4261,108 +4269,108 @@ Go to File &gt; Open Wallet to load a wallet.
</body></file>
<file original="../walletmodel.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="WalletModel">
- <trans-unit id="_msg930">
+ <trans-unit id="_msg932">
<source xml:space="preserve">Send Coins</source>
- <context-group purpose="location"><context context-type="linenumber">221</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">232</context></context-group>
</trans-unit>
- <trans-unit id="_msg931">
+ <trans-unit id="_msg933">
<source xml:space="preserve">Fee bump error</source>
- <context-group purpose="location"><context context-type="linenumber">484</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">536</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">551</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">556</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">495</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">547</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="_msg932">
+ <trans-unit id="_msg934">
<source xml:space="preserve">Increasing transaction fee failed</source>
- <context-group purpose="location"><context context-type="linenumber">484</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">495</context></context-group>
</trans-unit>
- <trans-unit id="_msg933">
+ <trans-unit id="_msg935">
<source xml:space="preserve">Do you want to increase the fee?</source>
- <context-group purpose="location"><context context-type="linenumber">491</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">502</context></context-group>
<note annotates="source" from="developer">Asks a user if they would like to manually increase the fee of a transaction that has already been created.</note>
</trans-unit>
- <trans-unit id="_msg934">
+ <trans-unit id="_msg936">
<source xml:space="preserve">Current fee:</source>
- <context-group purpose="location"><context context-type="linenumber">495</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">506</context></context-group>
</trans-unit>
- <trans-unit id="_msg935">
+ <trans-unit id="_msg937">
<source xml:space="preserve">Increase:</source>
- <context-group purpose="location"><context context-type="linenumber">499</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">510</context></context-group>
</trans-unit>
- <trans-unit id="_msg936">
+ <trans-unit id="_msg938">
<source xml:space="preserve">New fee:</source>
- <context-group purpose="location"><context context-type="linenumber">503</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">514</context></context-group>
</trans-unit>
- <trans-unit id="_msg937">
+ <trans-unit id="_msg939">
<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>
- <context-group purpose="location"><context context-type="linenumber">511</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">522</context></context-group>
</trans-unit>
- <trans-unit id="_msg938">
+ <trans-unit id="_msg940">
<source xml:space="preserve">Confirm fee bump</source>
- <context-group purpose="location"><context context-type="linenumber">514</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">525</context></context-group>
</trans-unit>
- <trans-unit id="_msg939">
+ <trans-unit id="_msg941">
<source xml:space="preserve">Can&apos;t draft transaction.</source>
- <context-group purpose="location"><context context-type="linenumber">536</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">547</context></context-group>
</trans-unit>
- <trans-unit id="_msg940">
+ <trans-unit id="_msg942">
<source xml:space="preserve">PSBT copied</source>
- <context-group purpose="location"><context context-type="linenumber">543</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">554</context></context-group>
</trans-unit>
- <trans-unit id="_msg941">
+ <trans-unit id="_msg943">
<source xml:space="preserve">Can&apos;t sign transaction.</source>
- <context-group purpose="location"><context context-type="linenumber">551</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">562</context></context-group>
</trans-unit>
- <trans-unit id="_msg942">
+ <trans-unit id="_msg944">
<source xml:space="preserve">Could not commit transaction</source>
- <context-group purpose="location"><context context-type="linenumber">556</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">567</context></context-group>
</trans-unit>
- <trans-unit id="_msg943">
+ <trans-unit id="_msg945">
<source xml:space="preserve">Can&apos;t display address</source>
- <context-group purpose="location"><context context-type="linenumber">570</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">581</context></context-group>
</trans-unit>
- <trans-unit id="_msg944">
+ <trans-unit id="_msg946">
<source xml:space="preserve">default wallet</source>
- <context-group purpose="location"><context context-type="linenumber">588</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">599</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../walletview.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="WalletView">
- <trans-unit id="_msg945">
+ <trans-unit id="_msg947">
<source xml:space="preserve">&amp;Export</source>
<context-group purpose="location"><context context-type="linenumber">51</context></context-group>
</trans-unit>
- <trans-unit id="_msg946">
+ <trans-unit id="_msg948">
<source xml:space="preserve">Export the data in the current tab to a file</source>
<context-group purpose="location"><context context-type="linenumber">52</context></context-group>
</trans-unit>
- <trans-unit id="_msg947">
+ <trans-unit id="_msg949">
<source xml:space="preserve">Backup Wallet</source>
<context-group purpose="location"><context context-type="linenumber">214</context></context-group>
</trans-unit>
- <trans-unit id="_msg948">
+ <trans-unit id="_msg950">
<source xml:space="preserve">Wallet Data</source>
<context-group purpose="location"><context context-type="linenumber">216</context></context-group>
<note annotates="source" from="developer">Name of the wallet data file format.</note>
</trans-unit>
- <trans-unit id="_msg949">
+ <trans-unit id="_msg951">
<source xml:space="preserve">Backup Failed</source>
<context-group purpose="location"><context context-type="linenumber">222</context></context-group>
</trans-unit>
- <trans-unit id="_msg950">
+ <trans-unit id="_msg952">
<source xml:space="preserve">There was an error trying to save the wallet data to %1.</source>
<context-group purpose="location"><context context-type="linenumber">222</context></context-group>
</trans-unit>
- <trans-unit id="_msg951">
+ <trans-unit id="_msg953">
<source xml:space="preserve">Backup Successful</source>
<context-group purpose="location"><context context-type="linenumber">226</context></context-group>
</trans-unit>
- <trans-unit id="_msg952">
+ <trans-unit id="_msg954">
<source xml:space="preserve">The wallet data was successfully saved to %1.</source>
<context-group purpose="location"><context context-type="linenumber">226</context></context-group>
</trans-unit>
- <trans-unit id="_msg953">
+ <trans-unit id="_msg955">
<source xml:space="preserve">Cancel</source>
<context-group purpose="location"><context context-type="linenumber">263</context></context-group>
</trans-unit>
@@ -4370,689 +4378,787 @@ Go to File &gt; Open Wallet to load a wallet.
</body></file>
<file original="../bitcoinstrings.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="bitcoin-core">
- <trans-unit id="_msg954">
+ <trans-unit id="_msg956">
<source xml:space="preserve">The %s developers</source>
<context-group purpose="location"><context context-type="linenumber">12</context></context-group>
</trans-unit>
- <trans-unit id="_msg955">
+ <trans-unit id="_msg957">
<source xml:space="preserve">%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring a backup.</source>
<context-group purpose="location"><context context-type="linenumber">13</context></context-group>
</trans-unit>
- <trans-unit id="_msg956">
+ <trans-unit id="_msg958">
<source xml:space="preserve">-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source>
<context-group purpose="location"><context context-type="linenumber">20</context></context-group>
</trans-unit>
- <trans-unit id="_msg957">
+ <trans-unit id="_msg959">
<source xml:space="preserve">Cannot downgrade wallet from version %i to version %i. Wallet version unchanged.</source>
<context-group purpose="location"><context context-type="linenumber">38</context></context-group>
</trans-unit>
- <trans-unit id="_msg958">
+ <trans-unit id="_msg960">
<source xml:space="preserve">Cannot obtain a lock on data directory %s. %s is probably already running.</source>
<context-group purpose="location"><context context-type="linenumber">41</context></context-group>
</trans-unit>
- <trans-unit id="_msg959">
+ <trans-unit id="_msg961">
<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>
<context-group purpose="location"><context context-type="linenumber">46</context></context-group>
</trans-unit>
- <trans-unit id="_msg960">
+ <trans-unit id="_msg962">
<source xml:space="preserve">Distributed under the MIT software license, see the accompanying file %s or %s</source>
<context-group purpose="location"><context context-type="linenumber">50</context></context-group>
</trans-unit>
- <trans-unit id="_msg961">
+ <trans-unit id="_msg963">
<source xml:space="preserve">Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect.</source>
<context-group purpose="location"><context context-type="linenumber">56</context></context-group>
</trans-unit>
- <trans-unit id="_msg962">
+ <trans-unit id="_msg964">
<source xml:space="preserve">Error reading %s! Transaction data may be missing or incorrect. Rescanning wallet.</source>
<context-group purpose="location"><context context-type="linenumber">59</context></context-group>
</trans-unit>
- <trans-unit id="_msg963">
+ <trans-unit id="_msg965">
<source xml:space="preserve">Error: Dumpfile format record is incorrect. Got &quot;%s&quot;, expected &quot;format&quot;.</source>
- <context-group purpose="location"><context context-type="linenumber">62</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">65</context></context-group>
</trans-unit>
- <trans-unit id="_msg964">
+ <trans-unit id="_msg966">
<source xml:space="preserve">Error: Dumpfile identifier record is incorrect. Got &quot;%s&quot;, expected &quot;%s&quot;.</source>
- <context-group purpose="location"><context context-type="linenumber">64</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">67</context></context-group>
</trans-unit>
- <trans-unit id="_msg965">
+ <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>
- <context-group purpose="location"><context context-type="linenumber">66</context></context-group>
- </trans-unit>
- <trans-unit id="_msg966">
- <source xml:space="preserve">Error: Legacy wallets only support the &quot;legacy&quot;, &quot;p2sh-segwit&quot;, and &quot;bech32&quot; address types</source>
<context-group purpose="location"><context context-type="linenumber">69</context></context-group>
</trans-unit>
- <trans-unit id="_msg967">
- <source xml:space="preserve">Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
- <context-group purpose="location"><context context-type="linenumber">75</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>
- <context-group purpose="location"><context context-type="linenumber">78</context></context-group>
+ <source xml:space="preserve">Error: Legacy wallets only support the &quot;legacy&quot;, &quot;p2sh-segwit&quot;, and &quot;bech32&quot; address types</source>
+ <context-group purpose="location"><context context-type="linenumber">75</context></context-group>
</trans-unit>
<trans-unit id="_msg969">
- <source xml:space="preserve">Invalid amount for -maxtxfee=&lt;amount&gt;: &apos;%s&apos; (must be at least the minrelay fee of %s to prevent stuck transactions)</source>
- <context-group purpose="location"><context context-type="linenumber">81</context></context-group>
+ <source xml:space="preserve">Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
+ <context-group purpose="location"><context context-type="linenumber">87</context></context-group>
</trans-unit>
<trans-unit id="_msg970">
- <source xml:space="preserve">Invalid or corrupt peers.dat (%s). If you believe this is a bug, please report it to %s. As a workaround, you can move the file (%s) out of the way (rename, move, or delete) to have a new one created on the next start.</source>
- <context-group purpose="location"><context context-type="linenumber">84</context></context-group>
+ <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>
+ <context-group purpose="location"><context context-type="linenumber">90</context></context-group>
</trans-unit>
<trans-unit id="_msg971">
- <source xml:space="preserve">More than one onion bind address is provided. Using %s for the automatically created Tor onion service.</source>
- <context-group purpose="location"><context context-type="linenumber">88</context></context-group>
+ <source xml:space="preserve">Invalid amount for -maxtxfee=&lt;amount&gt;: &apos;%s&apos; (must be at least the minrelay fee of %s to prevent stuck transactions)</source>
+ <context-group purpose="location"><context context-type="linenumber">96</context></context-group>
</trans-unit>
<trans-unit id="_msg972">
- <source xml:space="preserve">No dump file provided. To use createfromdump, -dumpfile=&lt;filename&gt; must be provided.</source>
- <context-group purpose="location"><context context-type="linenumber">91</context></context-group>
+ <source xml:space="preserve">Invalid or corrupt peers.dat (%s). If you believe this is a bug, please report it to %s. As a workaround, you can move the file (%s) out of the way (rename, move, or delete) to have a new one created on the next start.</source>
+ <context-group purpose="location"><context context-type="linenumber">99</context></context-group>
</trans-unit>
<trans-unit id="_msg973">
- <source xml:space="preserve">No dump file provided. To use dump, -dumpfile=&lt;filename&gt; must be provided.</source>
- <context-group purpose="location"><context context-type="linenumber">94</context></context-group>
+ <source xml:space="preserve">More than one onion bind address is provided. Using %s for the automatically created Tor onion service.</source>
+ <context-group purpose="location"><context context-type="linenumber">103</context></context-group>
</trans-unit>
<trans-unit id="_msg974">
- <source xml:space="preserve">No wallet file format provided. To use createfromdump, -format=&lt;format&gt; must be provided.</source>
- <context-group purpose="location"><context context-type="linenumber">96</context></context-group>
+ <source xml:space="preserve">No dump file provided. To use createfromdump, -dumpfile=&lt;filename&gt; must be provided.</source>
+ <context-group purpose="location"><context context-type="linenumber">106</context></context-group>
</trans-unit>
<trans-unit id="_msg975">
- <source xml:space="preserve">Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is not provided (no -proxy= and no -onion= given) or it is explicitly forbidden (-onion=0)</source>
- <context-group purpose="location"><context context-type="linenumber">99</context></context-group>
+ <source xml:space="preserve">No dump file provided. To use dump, -dumpfile=&lt;filename&gt; must be provided.</source>
+ <context-group purpose="location"><context context-type="linenumber">109</context></context-group>
</trans-unit>
<trans-unit id="_msg976">
- <source xml:space="preserve">Please check that your computer&apos;s date and time are correct! If your clock is wrong, %s will not work properly.</source>
- <context-group purpose="location"><context context-type="linenumber">103</context></context-group>
+ <source xml:space="preserve">No wallet file format provided. To use createfromdump, -format=&lt;format&gt; must be provided.</source>
+ <context-group purpose="location"><context context-type="linenumber">111</context></context-group>
</trans-unit>
<trans-unit id="_msg977">
- <source xml:space="preserve">Please contribute if you find %s useful. Visit %s for further information about the software.</source>
- <context-group purpose="location"><context context-type="linenumber">106</context></context-group>
+ <source xml:space="preserve">Please check that your computer&apos;s date and time are correct! If your clock is wrong, %s will not work properly.</source>
+ <context-group purpose="location"><context context-type="linenumber">121</context></context-group>
</trans-unit>
<trans-unit id="_msg978">
- <source xml:space="preserve">Prune configured below the minimum of %d MiB. Please use a higher number.</source>
- <context-group purpose="location"><context context-type="linenumber">109</context></context-group>
+ <source xml:space="preserve">Please contribute if you find %s useful. Visit %s for further information about the software.</source>
+ <context-group purpose="location"><context context-type="linenumber">124</context></context-group>
</trans-unit>
<trans-unit id="_msg979">
- <source xml:space="preserve">Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead.</source>
- <context-group purpose="location"><context context-type="linenumber">111</context></context-group>
+ <source xml:space="preserve">Prune configured below the minimum of %d MiB. Please use a higher number.</source>
+ <context-group purpose="location"><context context-type="linenumber">127</context></context-group>
</trans-unit>
<trans-unit id="_msg980">
- <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>
- <context-group purpose="location"><context context-type="linenumber">114</context></context-group>
+ <source xml:space="preserve">Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead.</source>
+ <context-group purpose="location"><context context-type="linenumber">129</context></context-group>
</trans-unit>
<trans-unit id="_msg981">
- <source xml:space="preserve">SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported</source>
- <context-group purpose="location"><context context-type="linenumber">117</context></context-group>
+ <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>
+ <context-group purpose="location"><context context-type="linenumber">132</context></context-group>
</trans-unit>
<trans-unit id="_msg982">
- <source xml:space="preserve">The block database contains a block which appears to be from the future. This may be due to your computer&apos;s date and time being set incorrectly. Only rebuild the block database if you are sure that your computer&apos;s date and time are correct</source>
- <context-group purpose="location"><context context-type="linenumber">123</context></context-group>
+ <source xml:space="preserve">SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported</source>
+ <context-group purpose="location"><context context-type="linenumber">135</context></context-group>
</trans-unit>
<trans-unit id="_msg983">
- <source xml:space="preserve">The block index db contains a legacy &apos;txindex&apos;. To clear the occupied disk space, run a full -reindex, otherwise ignore this error. This error message will not be displayed again.</source>
- <context-group purpose="location"><context context-type="linenumber">128</context></context-group>
+ <source xml:space="preserve">The block database contains a block which appears to be from the future. This may be due to your computer&apos;s date and time being set incorrectly. Only rebuild the block database if you are sure that your computer&apos;s date and time are correct</source>
+ <context-group purpose="location"><context context-type="linenumber">141</context></context-group>
</trans-unit>
<trans-unit id="_msg984">
- <source xml:space="preserve">The transaction amount is too small to send after the fee has been deducted</source>
- <context-group purpose="location"><context context-type="linenumber">132</context></context-group>
+ <source xml:space="preserve">The block index db contains a legacy &apos;txindex&apos;. To clear the occupied disk space, run a full -reindex, otherwise ignore this error. This error message will not be displayed again.</source>
+ <context-group purpose="location"><context context-type="linenumber">146</context></context-group>
</trans-unit>
<trans-unit id="_msg985">
- <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>
- <context-group purpose="location"><context context-type="linenumber">134</context></context-group>
+ <source xml:space="preserve">The transaction amount is too small to send after the fee has been deducted</source>
+ <context-group purpose="location"><context context-type="linenumber">150</context></context-group>
</trans-unit>
<trans-unit id="_msg986">
- <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>
- <context-group purpose="location"><context context-type="linenumber">138</context></context-group>
+ <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>
+ <context-group purpose="location"><context context-type="linenumber">152</context></context-group>
</trans-unit>
<trans-unit id="_msg987">
- <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>
- <context-group purpose="location"><context context-type="linenumber">141</context></context-group>
+ <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>
+ <context-group purpose="location"><context context-type="linenumber">156</context></context-group>
</trans-unit>
<trans-unit id="_msg988">
- <source xml:space="preserve">This is the transaction fee you may discard if change is smaller than dust at this level</source>
- <context-group purpose="location"><context context-type="linenumber">144</context></context-group>
+ <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>
+ <context-group purpose="location"><context context-type="linenumber">159</context></context-group>
</trans-unit>
<trans-unit id="_msg989">
- <source xml:space="preserve">This is the transaction fee you may pay when fee estimates are not available.</source>
- <context-group purpose="location"><context context-type="linenumber">147</context></context-group>
+ <source xml:space="preserve">This is the transaction fee you may discard if change is smaller than dust at this level</source>
+ <context-group purpose="location"><context context-type="linenumber">162</context></context-group>
</trans-unit>
<trans-unit id="_msg990">
- <source xml:space="preserve">Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments.</source>
- <context-group purpose="location"><context context-type="linenumber">149</context></context-group>
+ <source xml:space="preserve">This is the transaction fee you may pay when fee estimates are not available.</source>
+ <context-group purpose="location"><context context-type="linenumber">165</context></context-group>
</trans-unit>
<trans-unit id="_msg991">
- <source xml:space="preserve">Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.</source>
- <context-group purpose="location"><context context-type="linenumber">152</context></context-group>
+ <source xml:space="preserve">Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments.</source>
+ <context-group purpose="location"><context context-type="linenumber">167</context></context-group>
</trans-unit>
<trans-unit id="_msg992">
- <source xml:space="preserve">Unknown wallet file format &quot;%s&quot; provided. Please provide one of &quot;bdb&quot; or &quot;sqlite&quot;.</source>
- <context-group purpose="location"><context context-type="linenumber">155</context></context-group>
+ <source xml:space="preserve">Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.</source>
+ <context-group purpose="location"><context context-type="linenumber">170</context></context-group>
</trans-unit>
<trans-unit id="_msg993">
- <source xml:space="preserve">Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database.</source>
- <context-group purpose="location"><context context-type="linenumber">158</context></context-group>
+ <source xml:space="preserve">Unknown wallet file format &quot;%s&quot; provided. Please provide one of &quot;bdb&quot; or &quot;sqlite&quot;.</source>
+ <context-group purpose="location"><context context-type="linenumber">173</context></context-group>
</trans-unit>
<trans-unit id="_msg994">
- <source xml:space="preserve">Wallet created successfully. The legacy wallet type is being deprecated and support for creating and opening legacy wallets will be removed in the future.</source>
- <context-group purpose="location"><context context-type="linenumber">161</context></context-group>
+ <source xml:space="preserve">Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database.</source>
+ <context-group purpose="location"><context context-type="linenumber">184</context></context-group>
</trans-unit>
<trans-unit id="_msg995">
- <source xml:space="preserve">Warning: Dumpfile wallet format &quot;%s&quot; does not match command line specified format &quot;%s&quot;.</source>
- <context-group purpose="location"><context context-type="linenumber">165</context></context-group>
+ <source xml:space="preserve">Wallet created successfully. The legacy wallet type is being deprecated and support for creating and opening legacy wallets will be removed in the future.</source>
+ <context-group purpose="location"><context context-type="linenumber">187</context></context-group>
</trans-unit>
<trans-unit id="_msg996">
- <source xml:space="preserve">Warning: Private keys detected in wallet {%s} with disabled private keys</source>
- <context-group purpose="location"><context context-type="linenumber">168</context></context-group>
+ <source xml:space="preserve">Warning: Dumpfile wallet format &quot;%s&quot; does not match command line specified format &quot;%s&quot;.</source>
+ <context-group purpose="location"><context context-type="linenumber">191</context></context-group>
</trans-unit>
<trans-unit id="_msg997">
- <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>
- <context-group purpose="location"><context context-type="linenumber">170</context></context-group>
+ <source xml:space="preserve">Warning: Private keys detected in wallet {%s} with disabled private keys</source>
+ <context-group purpose="location"><context context-type="linenumber">194</context></context-group>
</trans-unit>
<trans-unit id="_msg998">
- <source xml:space="preserve">Witness data for blocks after height %d requires validation. Please restart with -reindex.</source>
- <context-group purpose="location"><context context-type="linenumber">173</context></context-group>
+ <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>
+ <context-group purpose="location"><context context-type="linenumber">196</context></context-group>
</trans-unit>
<trans-unit id="_msg999">
- <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>
- <context-group purpose="location"><context context-type="linenumber">176</context></context-group>
+ <source xml:space="preserve">Witness data for blocks after height %d requires validation. Please restart with -reindex.</source>
+ <context-group purpose="location"><context context-type="linenumber">199</context></context-group>
</trans-unit>
<trans-unit id="_msg1000">
- <source xml:space="preserve">%s is set very high!</source>
- <context-group purpose="location"><context context-type="linenumber">179</context></context-group>
+ <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>
+ <context-group purpose="location"><context context-type="linenumber">202</context></context-group>
</trans-unit>
<trans-unit id="_msg1001">
- <source xml:space="preserve">-maxmempool must be at least %d MB</source>
- <context-group purpose="location"><context context-type="linenumber">180</context></context-group>
+ <source xml:space="preserve">%s is set very high!</source>
+ <context-group purpose="location"><context context-type="linenumber">211</context></context-group>
</trans-unit>
<trans-unit id="_msg1002">
- <source xml:space="preserve">A fatal internal error occurred, see debug.log for details</source>
- <context-group purpose="location"><context context-type="linenumber">181</context></context-group>
+ <source xml:space="preserve">-maxmempool must be at least %d MB</source>
+ <context-group purpose="location"><context context-type="linenumber">212</context></context-group>
</trans-unit>
<trans-unit id="_msg1003">
- <source xml:space="preserve">Cannot resolve -%s address: &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">182</context></context-group>
+ <source xml:space="preserve">A fatal internal error occurred, see debug.log for details</source>
+ <context-group purpose="location"><context context-type="linenumber">213</context></context-group>
</trans-unit>
<trans-unit id="_msg1004">
- <source xml:space="preserve">Cannot set -forcednsseed to true when setting -dnsseed to false.</source>
- <context-group purpose="location"><context context-type="linenumber">183</context></context-group>
+ <source xml:space="preserve">Cannot resolve -%s address: &apos;%s&apos;</source>
+ <context-group purpose="location"><context context-type="linenumber">214</context></context-group>
</trans-unit>
<trans-unit id="_msg1005">
- <source xml:space="preserve">Cannot set -peerblockfilters without -blockfilterindex.</source>
- <context-group purpose="location"><context context-type="linenumber">184</context></context-group>
+ <source xml:space="preserve">Cannot set -forcednsseed to true when setting -dnsseed to false.</source>
+ <context-group purpose="location"><context context-type="linenumber">215</context></context-group>
</trans-unit>
<trans-unit id="_msg1006">
- <source xml:space="preserve">Cannot write to data directory &apos;%s&apos;; check permissions.</source>
- <context-group purpose="location"><context context-type="linenumber">185</context></context-group>
+ <source xml:space="preserve">Cannot set -peerblockfilters without -blockfilterindex.</source>
+ <context-group purpose="location"><context context-type="linenumber">216</context></context-group>
</trans-unit>
<trans-unit id="_msg1007">
- <source xml:space="preserve">The -txindex upgrade started by a previous version cannot be completed. Restart with the previous version or run a full -reindex.</source>
- <context-group purpose="location"><context context-type="linenumber">120</context></context-group>
+ <source xml:space="preserve">Cannot write to data directory &apos;%s&apos;; check permissions.</source>
+ <context-group purpose="location"><context context-type="linenumber">217</context></context-group>
</trans-unit>
<trans-unit id="_msg1008">
+ <source xml:space="preserve">The -txindex upgrade started by a previous version cannot be completed. Restart with the previous version or run a full -reindex.</source>
+ <context-group purpose="location"><context context-type="linenumber">138</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1009">
<source xml:space="preserve">%s request to listen on port %u. This port is considered &quot;bad&quot; and thus it is unlikely that any Bitcoin Core peers connect to it. See doc/p2p-bad-ports.md for details and a full list.</source>
<context-group purpose="location"><context context-type="linenumber">16</context></context-group>
</trans-unit>
- <trans-unit id="_msg1009">
+ <trans-unit id="_msg1010">
<source xml:space="preserve">-reindex-chainstate option is not compatible with -blockfilterindex. Please temporarily disable blockfilterindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
<context-group purpose="location"><context context-type="linenumber">23</context></context-group>
</trans-unit>
- <trans-unit id="_msg1010">
+ <trans-unit id="_msg1011">
<source xml:space="preserve">-reindex-chainstate option is not compatible with -coinstatsindex. Please temporarily disable coinstatsindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
<context-group purpose="location"><context context-type="linenumber">27</context></context-group>
</trans-unit>
- <trans-unit id="_msg1011">
+ <trans-unit id="_msg1012">
<source xml:space="preserve">-reindex-chainstate option is not compatible with -txindex. Please temporarily disable txindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
<context-group purpose="location"><context context-type="linenumber">31</context></context-group>
</trans-unit>
- <trans-unit id="_msg1012">
+ <trans-unit id="_msg1013">
<source xml:space="preserve">Assumed-valid: last wallet synchronisation goes beyond available block data. You need to wait for the background validation chain to download more blocks.</source>
<context-group purpose="location"><context context-type="linenumber">35</context></context-group>
</trans-unit>
- <trans-unit id="_msg1013">
+ <trans-unit id="_msg1014">
<source xml:space="preserve">Cannot provide specific connections and have addrman find outgoing connections at the same time.</source>
<context-group purpose="location"><context context-type="linenumber">43</context></context-group>
</trans-unit>
- <trans-unit id="_msg1014">
+ <trans-unit id="_msg1015">
<source xml:space="preserve">Error loading %s: External signer wallet being loaded without external signer support compiled</source>
<context-group purpose="location"><context context-type="linenumber">53</context></context-group>
</trans-unit>
- <trans-unit id="_msg1015">
- <source xml:space="preserve">Failed to rename invalid peers.dat file. Please move or delete it and try again.</source>
+ <trans-unit id="_msg1016">
+ <source xml:space="preserve">Error: Address book data in wallet cannot be identified to belong to migrated wallets</source>
+ <context-group purpose="location"><context context-type="linenumber">62</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1017">
+ <source xml:space="preserve">Error: Duplicate descriptors created during migration. Your wallet may be corrupted.</source>
<context-group purpose="location"><context context-type="linenumber">72</context></context-group>
</trans-unit>
- <trans-unit id="_msg1016">
+ <trans-unit id="_msg1018">
+ <source xml:space="preserve">Error: Transaction %s in wallet cannot be identified to belong to migrated wallets</source>
+ <context-group purpose="location"><context context-type="linenumber">78</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1019">
+ <source xml:space="preserve">Error: Unable to produce descriptors for this legacy wallet. Make sure the wallet is unlocked first</source>
+ <context-group purpose="location"><context context-type="linenumber">81</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1020">
+ <source xml:space="preserve">Failed to rename invalid peers.dat file. Please move or delete it and try again.</source>
+ <context-group purpose="location"><context context-type="linenumber">84</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1021">
+ <source xml:space="preserve">Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6</source>
+ <context-group purpose="location"><context context-type="linenumber">93</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1022">
+ <source xml:space="preserve">Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is explicitly forbidden: -onion=0</source>
+ <context-group purpose="location"><context context-type="linenumber">114</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1023">
+ <source xml:space="preserve">Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is not provided: none of -proxy, -onion or -listenonion is given</source>
+ <context-group purpose="location"><context context-type="linenumber">117</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1024">
+ <source xml:space="preserve">Unrecognized descriptor found. Loading wallet %s
+
+The wallet might had been created on a newer version.
+Please try running the latest software version.
+</source>
+ <context-group purpose="location"><context context-type="linenumber">176</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1025">
+ <source xml:space="preserve">Unsupported category-specific logging level -loglevel=%s. Expected -loglevel=&lt;category&gt;:&lt;loglevel&gt;. Valid categories: %s. Valid loglevels: %s.</source>
+ <context-group purpose="location"><context context-type="linenumber">181</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1026">
+ <source xml:space="preserve">
+Unable to cleanup failed migration</source>
+ <context-group purpose="location"><context context-type="linenumber">205</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1027">
+ <source xml:space="preserve">
+Unable to restore backup of wallet.</source>
+ <context-group purpose="location"><context context-type="linenumber">208</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1028">
<source xml:space="preserve">Config setting for %s only applied on %s network when in [%s] section.</source>
- <context-group purpose="location"><context context-type="linenumber">186</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">218</context></context-group>
</trans-unit>
- <trans-unit id="_msg1017">
+ <trans-unit id="_msg1029">
<source xml:space="preserve">Copyright (C) %i-%i</source>
- <context-group purpose="location"><context context-type="linenumber">187</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">219</context></context-group>
</trans-unit>
- <trans-unit id="_msg1018">
+ <trans-unit id="_msg1030">
<source xml:space="preserve">Corrupted block database detected</source>
- <context-group purpose="location"><context context-type="linenumber">188</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">220</context></context-group>
</trans-unit>
- <trans-unit id="_msg1019">
+ <trans-unit id="_msg1031">
<source xml:space="preserve">Could not find asmap file %s</source>
- <context-group purpose="location"><context context-type="linenumber">189</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">221</context></context-group>
</trans-unit>
- <trans-unit id="_msg1020">
+ <trans-unit id="_msg1032">
<source xml:space="preserve">Could not parse asmap file %s</source>
- <context-group purpose="location"><context context-type="linenumber">190</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">222</context></context-group>
</trans-unit>
- <trans-unit id="_msg1021">
+ <trans-unit id="_msg1033">
<source xml:space="preserve">Disk space is too low!</source>
- <context-group purpose="location"><context context-type="linenumber">191</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">223</context></context-group>
</trans-unit>
- <trans-unit id="_msg1022">
+ <trans-unit id="_msg1034">
<source xml:space="preserve">Do you want to rebuild the block database now?</source>
- <context-group purpose="location"><context context-type="linenumber">192</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">224</context></context-group>
</trans-unit>
- <trans-unit id="_msg1023">
+ <trans-unit id="_msg1035">
<source xml:space="preserve">Done loading</source>
- <context-group purpose="location"><context context-type="linenumber">193</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">225</context></context-group>
</trans-unit>
- <trans-unit id="_msg1024">
+ <trans-unit id="_msg1036">
<source xml:space="preserve">Dump file %s does not exist.</source>
- <context-group purpose="location"><context context-type="linenumber">194</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">226</context></context-group>
</trans-unit>
- <trans-unit id="_msg1025">
+ <trans-unit id="_msg1037">
<source xml:space="preserve">Error creating %s</source>
- <context-group purpose="location"><context context-type="linenumber">195</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">227</context></context-group>
</trans-unit>
- <trans-unit id="_msg1026">
+ <trans-unit id="_msg1038">
<source xml:space="preserve">Error initializing block database</source>
- <context-group purpose="location"><context context-type="linenumber">196</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">228</context></context-group>
</trans-unit>
- <trans-unit id="_msg1027">
+ <trans-unit id="_msg1039">
<source xml:space="preserve">Error initializing wallet database environment %s!</source>
- <context-group purpose="location"><context context-type="linenumber">197</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">229</context></context-group>
</trans-unit>
- <trans-unit id="_msg1028">
+ <trans-unit id="_msg1040">
<source xml:space="preserve">Error loading %s</source>
- <context-group purpose="location"><context context-type="linenumber">198</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">230</context></context-group>
</trans-unit>
- <trans-unit id="_msg1029">
+ <trans-unit id="_msg1041">
<source xml:space="preserve">Error loading %s: Private keys can only be disabled during creation</source>
- <context-group purpose="location"><context context-type="linenumber">199</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">231</context></context-group>
</trans-unit>
- <trans-unit id="_msg1030">
+ <trans-unit id="_msg1042">
<source xml:space="preserve">Error loading %s: Wallet corrupted</source>
- <context-group purpose="location"><context context-type="linenumber">200</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">232</context></context-group>
</trans-unit>
- <trans-unit id="_msg1031">
+ <trans-unit id="_msg1043">
<source xml:space="preserve">Error loading %s: Wallet requires newer version of %s</source>
- <context-group purpose="location"><context context-type="linenumber">201</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">233</context></context-group>
</trans-unit>
- <trans-unit id="_msg1032">
+ <trans-unit id="_msg1044">
<source xml:space="preserve">Error loading block database</source>
- <context-group purpose="location"><context context-type="linenumber">202</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">234</context></context-group>
</trans-unit>
- <trans-unit id="_msg1033">
+ <trans-unit id="_msg1045">
<source xml:space="preserve">Error opening block database</source>
- <context-group purpose="location"><context context-type="linenumber">203</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">235</context></context-group>
</trans-unit>
- <trans-unit id="_msg1034">
+ <trans-unit id="_msg1046">
<source xml:space="preserve">Error reading from database, shutting down.</source>
- <context-group purpose="location"><context context-type="linenumber">204</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">236</context></context-group>
</trans-unit>
- <trans-unit id="_msg1035">
+ <trans-unit id="_msg1047">
<source xml:space="preserve">Error reading next record from wallet database</source>
- <context-group purpose="location"><context context-type="linenumber">205</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">237</context></context-group>
</trans-unit>
- <trans-unit id="_msg1036">
+ <trans-unit id="_msg1048">
+ <source xml:space="preserve">Error: Could not add watchonly tx to watchonly wallet</source>
+ <context-group purpose="location"><context context-type="linenumber">238</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1049">
+ <source xml:space="preserve">Error: Could not delete watchonly transactions</source>
+ <context-group purpose="location"><context context-type="linenumber">239</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1050">
<source xml:space="preserve">Error: Couldn&apos;t create cursor into database</source>
- <context-group purpose="location"><context context-type="linenumber">206</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">240</context></context-group>
</trans-unit>
- <trans-unit id="_msg1037">
+ <trans-unit id="_msg1051">
<source xml:space="preserve">Error: Disk space is low for %s</source>
- <context-group purpose="location"><context context-type="linenumber">207</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">241</context></context-group>
</trans-unit>
- <trans-unit id="_msg1038">
+ <trans-unit id="_msg1052">
<source xml:space="preserve">Error: Dumpfile checksum does not match. Computed %s, expected %s</source>
- <context-group purpose="location"><context context-type="linenumber">208</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">242</context></context-group>
</trans-unit>
- <trans-unit id="_msg1039">
+ <trans-unit id="_msg1053">
+ <source xml:space="preserve">Error: Failed to create new watchonly wallet</source>
+ <context-group purpose="location"><context context-type="linenumber">243</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1054">
<source xml:space="preserve">Error: Got key that was not hex: %s</source>
- <context-group purpose="location"><context context-type="linenumber">209</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">244</context></context-group>
</trans-unit>
- <trans-unit id="_msg1040">
+ <trans-unit id="_msg1055">
<source xml:space="preserve">Error: Got value that was not hex: %s</source>
- <context-group purpose="location"><context context-type="linenumber">210</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">245</context></context-group>
</trans-unit>
- <trans-unit id="_msg1041">
+ <trans-unit id="_msg1056">
<source xml:space="preserve">Error: Keypool ran out, please call keypoolrefill first</source>
- <context-group purpose="location"><context context-type="linenumber">211</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">246</context></context-group>
</trans-unit>
- <trans-unit id="_msg1042">
+ <trans-unit id="_msg1057">
<source xml:space="preserve">Error: Missing checksum</source>
- <context-group purpose="location"><context context-type="linenumber">212</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">247</context></context-group>
</trans-unit>
- <trans-unit id="_msg1043">
+ <trans-unit id="_msg1058">
<source xml:space="preserve">Error: No %s addresses available.</source>
- <context-group purpose="location"><context context-type="linenumber">213</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">248</context></context-group>
</trans-unit>
- <trans-unit id="_msg1044">
+ <trans-unit id="_msg1059">
+ <source xml:space="preserve">Error: Not all watchonly txs could be deleted</source>
+ <context-group purpose="location"><context context-type="linenumber">249</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1060">
+ <source xml:space="preserve">Error: This wallet already uses SQLite</source>
+ <context-group purpose="location"><context context-type="linenumber">250</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1061">
+ <source xml:space="preserve">Error: This wallet is already a descriptor wallet</source>
+ <context-group purpose="location"><context context-type="linenumber">251</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1062">
+ <source xml:space="preserve">Error: Unable to begin reading all records in the database</source>
+ <context-group purpose="location"><context context-type="linenumber">252</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1063">
+ <source xml:space="preserve">Error: Unable to make a backup of your wallet</source>
+ <context-group purpose="location"><context context-type="linenumber">253</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1064">
<source xml:space="preserve">Error: Unable to parse version %u as a uint32_t</source>
- <context-group purpose="location"><context context-type="linenumber">214</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">254</context></context-group>
</trans-unit>
- <trans-unit id="_msg1045">
+ <trans-unit id="_msg1065">
+ <source xml:space="preserve">Error: Unable to read all records in the database</source>
+ <context-group purpose="location"><context context-type="linenumber">255</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1066">
+ <source xml:space="preserve">Error: Unable to remove watchonly address book data</source>
+ <context-group purpose="location"><context context-type="linenumber">256</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1067">
<source xml:space="preserve">Error: Unable to write record to new wallet</source>
- <context-group purpose="location"><context context-type="linenumber">215</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">257</context></context-group>
</trans-unit>
- <trans-unit id="_msg1046">
+ <trans-unit id="_msg1068">
<source xml:space="preserve">Failed to listen on any port. Use -listen=0 if you want this.</source>
- <context-group purpose="location"><context context-type="linenumber">216</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">258</context></context-group>
</trans-unit>
- <trans-unit id="_msg1047">
+ <trans-unit id="_msg1069">
<source xml:space="preserve">Failed to rescan the wallet during initialization</source>
- <context-group purpose="location"><context context-type="linenumber">217</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">259</context></context-group>
</trans-unit>
- <trans-unit id="_msg1048">
+ <trans-unit id="_msg1070">
<source xml:space="preserve">Failed to verify database</source>
- <context-group purpose="location"><context context-type="linenumber">218</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">260</context></context-group>
</trans-unit>
- <trans-unit id="_msg1049">
+ <trans-unit id="_msg1071">
<source xml:space="preserve">Fee rate (%s) is lower than the minimum fee rate setting (%s)</source>
- <context-group purpose="location"><context context-type="linenumber">219</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">261</context></context-group>
</trans-unit>
- <trans-unit id="_msg1050">
+ <trans-unit id="_msg1072">
<source xml:space="preserve">Ignoring duplicate -wallet %s.</source>
- <context-group purpose="location"><context context-type="linenumber">220</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">262</context></context-group>
</trans-unit>
- <trans-unit id="_msg1051">
+ <trans-unit id="_msg1073">
<source xml:space="preserve">Importing…</source>
- <context-group purpose="location"><context context-type="linenumber">221</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">263</context></context-group>
</trans-unit>
- <trans-unit id="_msg1052">
+ <trans-unit id="_msg1074">
<source xml:space="preserve">Incorrect or no genesis block found. Wrong datadir for network?</source>
- <context-group purpose="location"><context context-type="linenumber">222</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">264</context></context-group>
</trans-unit>
- <trans-unit id="_msg1053">
+ <trans-unit id="_msg1075">
<source xml:space="preserve">Initialization sanity check failed. %s is shutting down.</source>
- <context-group purpose="location"><context context-type="linenumber">223</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">265</context></context-group>
</trans-unit>
- <trans-unit id="_msg1054">
+ <trans-unit id="_msg1076">
<source xml:space="preserve">Input not found or already spent</source>
- <context-group purpose="location"><context context-type="linenumber">224</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">266</context></context-group>
</trans-unit>
- <trans-unit id="_msg1055">
+ <trans-unit id="_msg1077">
<source xml:space="preserve">Insufficient funds</source>
- <context-group purpose="location"><context context-type="linenumber">225</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">267</context></context-group>
</trans-unit>
- <trans-unit id="_msg1056">
+ <trans-unit id="_msg1078">
<source xml:space="preserve">Invalid -i2psam address or hostname: &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">226</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">268</context></context-group>
</trans-unit>
- <trans-unit id="_msg1057">
+ <trans-unit id="_msg1079">
<source xml:space="preserve">Invalid -onion address or hostname: &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">227</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">269</context></context-group>
</trans-unit>
- <trans-unit id="_msg1058">
+ <trans-unit id="_msg1080">
<source xml:space="preserve">Invalid -proxy address or hostname: &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">228</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">270</context></context-group>
</trans-unit>
- <trans-unit id="_msg1059">
+ <trans-unit id="_msg1081">
<source xml:space="preserve">Invalid P2P permission: &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">229</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">271</context></context-group>
</trans-unit>
- <trans-unit id="_msg1060">
+ <trans-unit id="_msg1082">
<source xml:space="preserve">Invalid amount for -%s=&lt;amount&gt;: &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">230</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">272</context></context-group>
</trans-unit>
- <trans-unit id="_msg1061">
+ <trans-unit id="_msg1083">
<source xml:space="preserve">Invalid amount for -discardfee=&lt;amount&gt;: &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">231</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">273</context></context-group>
</trans-unit>
- <trans-unit id="_msg1062">
+ <trans-unit id="_msg1084">
<source xml:space="preserve">Invalid amount for -fallbackfee=&lt;amount&gt;: &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">232</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">274</context></context-group>
</trans-unit>
- <trans-unit id="_msg1063">
+ <trans-unit id="_msg1085">
<source xml:space="preserve">Invalid amount for -paytxfee=&lt;amount&gt;: &apos;%s&apos; (must be at least %s)</source>
- <context-group purpose="location"><context context-type="linenumber">233</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">275</context></context-group>
</trans-unit>
- <trans-unit id="_msg1064">
+ <trans-unit id="_msg1086">
<source xml:space="preserve">Invalid netmask specified in -whitelist: &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">234</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">276</context></context-group>
</trans-unit>
- <trans-unit id="_msg1065">
+ <trans-unit id="_msg1087">
<source xml:space="preserve">Listening for incoming connections failed (listen returned error %s)</source>
- <context-group purpose="location"><context context-type="linenumber">235</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">277</context></context-group>
</trans-unit>
- <trans-unit id="_msg1066">
+ <trans-unit id="_msg1088">
<source xml:space="preserve">Loading P2P addresses…</source>
- <context-group purpose="location"><context context-type="linenumber">236</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">278</context></context-group>
</trans-unit>
- <trans-unit id="_msg1067">
+ <trans-unit id="_msg1089">
<source xml:space="preserve">Loading banlist…</source>
- <context-group purpose="location"><context context-type="linenumber">237</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">279</context></context-group>
</trans-unit>
- <trans-unit id="_msg1068">
+ <trans-unit id="_msg1090">
<source xml:space="preserve">Loading block index…</source>
- <context-group purpose="location"><context context-type="linenumber">238</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">280</context></context-group>
</trans-unit>
- <trans-unit id="_msg1069">
+ <trans-unit id="_msg1091">
<source xml:space="preserve">Loading wallet…</source>
- <context-group purpose="location"><context context-type="linenumber">239</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">281</context></context-group>
</trans-unit>
- <trans-unit id="_msg1070">
+ <trans-unit id="_msg1092">
<source xml:space="preserve">Missing amount</source>
- <context-group purpose="location"><context context-type="linenumber">240</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">282</context></context-group>
</trans-unit>
- <trans-unit id="_msg1071">
+ <trans-unit id="_msg1093">
<source xml:space="preserve">Missing solving data for estimating transaction size</source>
- <context-group purpose="location"><context context-type="linenumber">241</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">283</context></context-group>
</trans-unit>
- <trans-unit id="_msg1072">
+ <trans-unit id="_msg1094">
<source xml:space="preserve">Need to specify a port with -whitebind: &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">242</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">284</context></context-group>
</trans-unit>
- <trans-unit id="_msg1073">
+ <trans-unit id="_msg1095">
<source xml:space="preserve">No addresses available</source>
- <context-group purpose="location"><context context-type="linenumber">243</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">285</context></context-group>
</trans-unit>
- <trans-unit id="_msg1074">
+ <trans-unit id="_msg1096">
<source xml:space="preserve">Not enough file descriptors available.</source>
- <context-group purpose="location"><context context-type="linenumber">244</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">286</context></context-group>
</trans-unit>
- <trans-unit id="_msg1075">
+ <trans-unit id="_msg1097">
<source xml:space="preserve">Prune cannot be configured with a negative value.</source>
- <context-group purpose="location"><context context-type="linenumber">245</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">287</context></context-group>
</trans-unit>
- <trans-unit id="_msg1076">
+ <trans-unit id="_msg1098">
<source xml:space="preserve">Prune mode is incompatible with -txindex.</source>
- <context-group purpose="location"><context context-type="linenumber">246</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">288</context></context-group>
</trans-unit>
- <trans-unit id="_msg1077">
+ <trans-unit id="_msg1099">
<source xml:space="preserve">Pruning blockstore…</source>
- <context-group purpose="location"><context context-type="linenumber">247</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">289</context></context-group>
</trans-unit>
- <trans-unit id="_msg1078">
+ <trans-unit id="_msg1100">
<source xml:space="preserve">Reducing -maxconnections from %d to %d, because of system limitations.</source>
- <context-group purpose="location"><context context-type="linenumber">248</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">290</context></context-group>
</trans-unit>
- <trans-unit id="_msg1079">
+ <trans-unit id="_msg1101">
<source xml:space="preserve">Replaying blocks…</source>
- <context-group purpose="location"><context context-type="linenumber">249</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">291</context></context-group>
</trans-unit>
- <trans-unit id="_msg1080">
+ <trans-unit id="_msg1102">
<source xml:space="preserve">Rescanning…</source>
- <context-group purpose="location"><context context-type="linenumber">250</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">292</context></context-group>
</trans-unit>
- <trans-unit id="_msg1081">
+ <trans-unit id="_msg1103">
<source xml:space="preserve">SQLiteDatabase: Failed to execute statement to verify database: %s</source>
- <context-group purpose="location"><context context-type="linenumber">251</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">293</context></context-group>
</trans-unit>
- <trans-unit id="_msg1082">
+ <trans-unit id="_msg1104">
<source xml:space="preserve">SQLiteDatabase: Failed to prepare statement to verify database: %s</source>
- <context-group purpose="location"><context context-type="linenumber">252</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">294</context></context-group>
</trans-unit>
- <trans-unit id="_msg1083">
+ <trans-unit id="_msg1105">
<source xml:space="preserve">SQLiteDatabase: Failed to read database verification error: %s</source>
- <context-group purpose="location"><context context-type="linenumber">253</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">295</context></context-group>
</trans-unit>
- <trans-unit id="_msg1084">
+ <trans-unit id="_msg1106">
<source xml:space="preserve">SQLiteDatabase: Unexpected application id. Expected %u, got %u</source>
- <context-group purpose="location"><context context-type="linenumber">254</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">296</context></context-group>
</trans-unit>
- <trans-unit id="_msg1085">
+ <trans-unit id="_msg1107">
<source xml:space="preserve">Section [%s] is not recognized.</source>
- <context-group purpose="location"><context context-type="linenumber">255</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">297</context></context-group>
</trans-unit>
- <trans-unit id="_msg1086">
+ <trans-unit id="_msg1108">
<source xml:space="preserve">Signing transaction failed</source>
- <context-group purpose="location"><context context-type="linenumber">256</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">298</context></context-group>
</trans-unit>
- <trans-unit id="_msg1087">
+ <trans-unit id="_msg1109">
<source xml:space="preserve">Specified -walletdir &quot;%s&quot; does not exist</source>
- <context-group purpose="location"><context context-type="linenumber">257</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">299</context></context-group>
</trans-unit>
- <trans-unit id="_msg1088">
+ <trans-unit id="_msg1110">
<source xml:space="preserve">Specified -walletdir &quot;%s&quot; is a relative path</source>
- <context-group purpose="location"><context context-type="linenumber">258</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">300</context></context-group>
</trans-unit>
- <trans-unit id="_msg1089">
+ <trans-unit id="_msg1111">
<source xml:space="preserve">Specified -walletdir &quot;%s&quot; is not a directory</source>
- <context-group purpose="location"><context context-type="linenumber">259</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">301</context></context-group>
</trans-unit>
- <trans-unit id="_msg1090">
+ <trans-unit id="_msg1112">
<source xml:space="preserve">Specified blocks directory &quot;%s&quot; does not exist.</source>
- <context-group purpose="location"><context context-type="linenumber">260</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">302</context></context-group>
</trans-unit>
- <trans-unit id="_msg1091">
+ <trans-unit id="_msg1113">
<source xml:space="preserve">Starting network threads…</source>
- <context-group purpose="location"><context context-type="linenumber">261</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">303</context></context-group>
</trans-unit>
- <trans-unit id="_msg1092">
+ <trans-unit id="_msg1114">
<source xml:space="preserve">The source code is available from %s.</source>
- <context-group purpose="location"><context context-type="linenumber">262</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">304</context></context-group>
</trans-unit>
- <trans-unit id="_msg1093">
+ <trans-unit id="_msg1115">
<source xml:space="preserve">The specified config file %s does not exist</source>
- <context-group purpose="location"><context context-type="linenumber">263</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">305</context></context-group>
</trans-unit>
- <trans-unit id="_msg1094">
+ <trans-unit id="_msg1116">
<source xml:space="preserve">The transaction amount is too small to pay the fee</source>
- <context-group purpose="location"><context context-type="linenumber">264</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">306</context></context-group>
</trans-unit>
- <trans-unit id="_msg1095">
+ <trans-unit id="_msg1117">
<source xml:space="preserve">The wallet will avoid paying less than the minimum relay fee.</source>
- <context-group purpose="location"><context context-type="linenumber">265</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">307</context></context-group>
</trans-unit>
- <trans-unit id="_msg1096">
+ <trans-unit id="_msg1118">
<source xml:space="preserve">This is experimental software.</source>
- <context-group purpose="location"><context context-type="linenumber">266</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">308</context></context-group>
</trans-unit>
- <trans-unit id="_msg1097">
+ <trans-unit id="_msg1119">
<source xml:space="preserve">This is the minimum transaction fee you pay on every transaction.</source>
- <context-group purpose="location"><context context-type="linenumber">267</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">309</context></context-group>
</trans-unit>
- <trans-unit id="_msg1098">
+ <trans-unit id="_msg1120">
<source xml:space="preserve">This is the transaction fee you will pay if you send a transaction.</source>
- <context-group purpose="location"><context context-type="linenumber">268</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">310</context></context-group>
</trans-unit>
- <trans-unit id="_msg1099">
+ <trans-unit id="_msg1121">
<source xml:space="preserve">Transaction amount too small</source>
- <context-group purpose="location"><context context-type="linenumber">269</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">311</context></context-group>
</trans-unit>
- <trans-unit id="_msg1100">
+ <trans-unit id="_msg1122">
<source xml:space="preserve">Transaction amounts must not be negative</source>
- <context-group purpose="location"><context context-type="linenumber">270</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">312</context></context-group>
</trans-unit>
- <trans-unit id="_msg1101">
+ <trans-unit id="_msg1123">
<source xml:space="preserve">Transaction change output index out of range</source>
- <context-group purpose="location"><context context-type="linenumber">271</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">313</context></context-group>
</trans-unit>
- <trans-unit id="_msg1102">
+ <trans-unit id="_msg1124">
<source xml:space="preserve">Transaction has too long of a mempool chain</source>
- <context-group purpose="location"><context context-type="linenumber">272</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">314</context></context-group>
</trans-unit>
- <trans-unit id="_msg1103">
+ <trans-unit id="_msg1125">
<source xml:space="preserve">Transaction must have at least one recipient</source>
- <context-group purpose="location"><context context-type="linenumber">273</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">315</context></context-group>
</trans-unit>
- <trans-unit id="_msg1104">
+ <trans-unit id="_msg1126">
<source xml:space="preserve">Transaction needs a change address, but we can&apos;t generate it.</source>
- <context-group purpose="location"><context context-type="linenumber">274</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">316</context></context-group>
</trans-unit>
- <trans-unit id="_msg1105">
+ <trans-unit id="_msg1127">
<source xml:space="preserve">Transaction too large</source>
- <context-group purpose="location"><context context-type="linenumber">275</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">317</context></context-group>
</trans-unit>
- <trans-unit id="_msg1106">
+ <trans-unit id="_msg1128">
<source xml:space="preserve">Unable to allocate memory for -maxsigcachesize: &apos;%s&apos; MiB</source>
- <context-group purpose="location"><context context-type="linenumber">276</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">318</context></context-group>
</trans-unit>
- <trans-unit id="_msg1107">
+ <trans-unit id="_msg1129">
<source xml:space="preserve">Unable to bind to %s on this computer (bind returned error %s)</source>
- <context-group purpose="location"><context context-type="linenumber">277</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">319</context></context-group>
</trans-unit>
- <trans-unit id="_msg1108">
+ <trans-unit id="_msg1130">
<source xml:space="preserve">Unable to bind to %s on this computer. %s is probably already running.</source>
- <context-group purpose="location"><context context-type="linenumber">278</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">320</context></context-group>
</trans-unit>
- <trans-unit id="_msg1109">
+ <trans-unit id="_msg1131">
<source xml:space="preserve">Unable to create the PID file &apos;%s&apos;: %s</source>
- <context-group purpose="location"><context context-type="linenumber">279</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">321</context></context-group>
</trans-unit>
- <trans-unit id="_msg1110">
+ <trans-unit id="_msg1132">
+ <source xml:space="preserve">Unable to find UTXO for external input</source>
+ <context-group purpose="location"><context context-type="linenumber">322</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1133">
<source xml:space="preserve">Unable to generate initial keys</source>
- <context-group purpose="location"><context context-type="linenumber">280</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">323</context></context-group>
</trans-unit>
- <trans-unit id="_msg1111">
+ <trans-unit id="_msg1134">
<source xml:space="preserve">Unable to generate keys</source>
- <context-group purpose="location"><context context-type="linenumber">281</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">324</context></context-group>
</trans-unit>
- <trans-unit id="_msg1112">
+ <trans-unit id="_msg1135">
<source xml:space="preserve">Unable to open %s for writing</source>
- <context-group purpose="location"><context context-type="linenumber">282</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">325</context></context-group>
</trans-unit>
- <trans-unit id="_msg1113">
+ <trans-unit id="_msg1136">
<source xml:space="preserve">Unable to parse -maxuploadtarget: &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">283</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">326</context></context-group>
</trans-unit>
- <trans-unit id="_msg1114">
+ <trans-unit id="_msg1137">
<source xml:space="preserve">Unable to start HTTP server. See debug log for details.</source>
- <context-group purpose="location"><context context-type="linenumber">284</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">327</context></context-group>
</trans-unit>
- <trans-unit id="_msg1115">
+ <trans-unit id="_msg1138">
+ <source xml:space="preserve">Unable to unload the wallet before migrating</source>
+ <context-group purpose="location"><context context-type="linenumber">328</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1139">
<source xml:space="preserve">Unknown -blockfilterindex value %s.</source>
- <context-group purpose="location"><context context-type="linenumber">285</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">329</context></context-group>
</trans-unit>
- <trans-unit id="_msg1116">
+ <trans-unit id="_msg1140">
<source xml:space="preserve">Unknown address type &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">286</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">330</context></context-group>
</trans-unit>
- <trans-unit id="_msg1117">
+ <trans-unit id="_msg1141">
<source xml:space="preserve">Unknown change type &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">287</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">331</context></context-group>
</trans-unit>
- <trans-unit id="_msg1118">
+ <trans-unit id="_msg1142">
<source xml:space="preserve">Unknown network specified in -onlynet: &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">288</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">332</context></context-group>
</trans-unit>
- <trans-unit id="_msg1119">
+ <trans-unit id="_msg1143">
<source xml:space="preserve">Unknown new rules activated (versionbit %i)</source>
- <context-group purpose="location"><context context-type="linenumber">289</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">333</context></context-group>
</trans-unit>
- <trans-unit id="_msg1120">
+ <trans-unit id="_msg1144">
+ <source xml:space="preserve">Unsupported global logging level -loglevel=%s. Valid values: %s.</source>
+ <context-group purpose="location"><context context-type="linenumber">334</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1145">
<source xml:space="preserve">Unsupported logging category %s=%s.</source>
- <context-group purpose="location"><context context-type="linenumber">290</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">335</context></context-group>
</trans-unit>
- <trans-unit id="_msg1121">
+ <trans-unit id="_msg1146">
<source xml:space="preserve">User Agent comment (%s) contains unsafe characters.</source>
- <context-group purpose="location"><context context-type="linenumber">291</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">336</context></context-group>
</trans-unit>
- <trans-unit id="_msg1122">
+ <trans-unit id="_msg1147">
<source xml:space="preserve">Verifying blocks…</source>
- <context-group purpose="location"><context context-type="linenumber">292</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">337</context></context-group>
</trans-unit>
- <trans-unit id="_msg1123">
+ <trans-unit id="_msg1148">
<source xml:space="preserve">Verifying wallet(s)…</source>
- <context-group purpose="location"><context context-type="linenumber">293</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">338</context></context-group>
</trans-unit>
- <trans-unit id="_msg1124">
+ <trans-unit id="_msg1149">
<source xml:space="preserve">Wallet needed to be rewritten: restart %s to complete</source>
- <context-group purpose="location"><context context-type="linenumber">294</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">339</context></context-group>
</trans-unit>
</group>
</body></file>
diff --git a/src/qt/modaloverlay.cpp b/src/qt/modaloverlay.cpp
index 97ee75a31f..dfa33764f6 100644
--- a/src/qt/modaloverlay.cpp
+++ b/src/qt/modaloverlay.cpp
@@ -78,13 +78,16 @@ bool ModalOverlay::event(QEvent* ev) {
return QWidget::event(ev);
}
-void ModalOverlay::setKnownBestHeight(int count, const QDateTime& blockDate)
+void ModalOverlay::setKnownBestHeight(int count, const QDateTime& blockDate, bool presync)
{
- if (count > bestHeaderHeight) {
+ if (!presync && count > bestHeaderHeight) {
bestHeaderHeight = count;
bestHeaderDate = blockDate;
UpdateHeaderSyncLabel();
}
+ if (presync) {
+ UpdateHeaderPresyncLabel(count, blockDate);
+ }
}
void ModalOverlay::tipUpdate(int count, const QDateTime& blockDate, double nVerificationProgress)
@@ -158,6 +161,11 @@ void ModalOverlay::UpdateHeaderSyncLabel() {
ui->numberOfBlocksLeft->setText(tr("Unknown. Syncing Headers (%1, %2%)…").arg(bestHeaderHeight).arg(QString::number(100.0 / (bestHeaderHeight + est_headers_left) * bestHeaderHeight, 'f', 1)));
}
+void ModalOverlay::UpdateHeaderPresyncLabel(int height, const QDateTime& blockDate) {
+ int est_headers_left = blockDate.secsTo(QDateTime::currentDateTime()) / Params().GetConsensus().nPowTargetSpacing;
+ ui->numberOfBlocksLeft->setText(tr("Unknown. Pre-syncing Headers (%1, %2%)…").arg(height).arg(QString::number(100.0 / (height + est_headers_left) * height, 'f', 1)));
+}
+
void ModalOverlay::toggleVisibility()
{
showHide(layerIsVisible, true);
diff --git a/src/qt/modaloverlay.h b/src/qt/modaloverlay.h
index 1d8af5cbf6..682c94cd01 100644
--- a/src/qt/modaloverlay.h
+++ b/src/qt/modaloverlay.h
@@ -26,7 +26,7 @@ public:
~ModalOverlay();
void tipUpdate(int count, const QDateTime& blockDate, double nVerificationProgress);
- void setKnownBestHeight(int count, const QDateTime& blockDate);
+ void setKnownBestHeight(int count, const QDateTime& blockDate, bool presync);
// will show or hide the modal layer
void showHide(bool hide = false, bool userRequested = false);
@@ -52,6 +52,7 @@ private:
bool userClosed;
QPropertyAnimation m_animation;
void UpdateHeaderSyncLabel();
+ void UpdateHeaderPresyncLabel(int height, const QDateTime& blockDate);
};
#endif // BITCOIN_QT_MODALOVERLAY_H
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 70fccdef1c..295450d6b7 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -661,7 +661,7 @@ void RPCConsole::setClientModel(ClientModel *model, int bestblock_height, int64_
setNumConnections(model->getNumConnections());
connect(model, &ClientModel::numConnectionsChanged, this, &RPCConsole::setNumConnections);
- setNumBlocks(bestblock_height, QDateTime::fromSecsSinceEpoch(bestblock_date), verification_progress, false);
+ setNumBlocks(bestblock_height, QDateTime::fromSecsSinceEpoch(bestblock_date), verification_progress, SyncType::BLOCK_SYNC);
connect(model, &ClientModel::numBlocksChanged, this, &RPCConsole::setNumBlocks);
updateNetworkState();
@@ -973,9 +973,9 @@ void RPCConsole::setNetworkActive(bool networkActive)
updateNetworkState();
}
-void RPCConsole::setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, bool headers)
+void RPCConsole::setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, SyncType synctype)
{
- if (!headers) {
+ if (synctype == SyncType::BLOCK_SYNC) {
ui->numberOfBlocks->setText(QString::number(count));
ui->lastBlockTime->setText(blockDate.toString());
}
@@ -1182,11 +1182,11 @@ void RPCConsole::updateDetailWidget()
ui->peerSubversion->setText(QString::fromStdString(stats->nodeStats.cleanSubVer));
ui->peerConnectionType->setText(GUIUtil::ConnectionTypeToQString(stats->nodeStats.m_conn_type, /*prepend_direction=*/true));
ui->peerNetwork->setText(GUIUtil::NetworkToQString(stats->nodeStats.m_network));
- if (stats->nodeStats.m_permissionFlags == NetPermissionFlags::None) {
+ if (stats->nodeStats.m_permission_flags == NetPermissionFlags::None) {
ui->peerPermissions->setText(ts.na);
} else {
QStringList permissions;
- for (const auto& permission : NetPermissions::ToStrings(stats->nodeStats.m_permissionFlags)) {
+ for (const auto& permission : NetPermissions::ToStrings(stats->nodeStats.m_permission_flags)) {
permissions.append(QString::fromStdString(permission));
}
ui->peerPermissions->setText(permissions.join(" & "));
diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h
index 1a54fe0cad..a3c713e966 100644
--- a/src/qt/rpcconsole.h
+++ b/src/qt/rpcconsole.h
@@ -9,6 +9,7 @@
#include <config/bitcoin-config.h>
#endif
+#include <qt/clientmodel.h>
#include <qt/guiutil.h>
#include <qt/peertablemodel.h>
@@ -19,7 +20,6 @@
#include <QThread>
#include <QWidget>
-class ClientModel;
class PlatformStyle;
class RPCExecutor;
class RPCTimerInterface;
@@ -121,7 +121,7 @@ public Q_SLOTS:
/** Set network state shown in the UI */
void setNetworkActive(bool networkActive);
/** Set number of blocks and last block date shown in the UI */
- void setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, bool headers);
+ void setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, SyncType synctype);
/** Set size (number of transactions and memory usage) of the mempool in the UI */
void setMempoolSize(long numberOfTxs, size_t dynUsage);
/** Go forward or back in history */
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index a75c1098a5..53c352b393 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -839,7 +839,7 @@ void SendCoinsDialog::updateCoinControlState()
m_coin_control->fAllowWatchOnly = model->wallet().privateKeysDisabled() && !model->wallet().hasExternalSigner();
}
-void SendCoinsDialog::updateNumberOfBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, bool headers, SynchronizationState sync_state) {
+void SendCoinsDialog::updateNumberOfBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, SyncType synctype, SynchronizationState sync_state) {
if (sync_state == SynchronizationState::POST_INIT) {
updateSmartFeeLabel();
}
diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h
index b58d4690a0..dcdf189532 100644
--- a/src/qt/sendcoinsdialog.h
+++ b/src/qt/sendcoinsdialog.h
@@ -5,6 +5,7 @@
#ifndef BITCOIN_QT_SENDCOINSDIALOG_H
#define BITCOIN_QT_SENDCOINSDIALOG_H
+#include <qt/clientmodel.h>
#include <qt/walletmodel.h>
#include <QDialog>
@@ -12,7 +13,6 @@
#include <QString>
#include <QTimer>
-class ClientModel;
class PlatformStyle;
class SendCoinsEntry;
class SendCoinsRecipient;
@@ -111,7 +111,7 @@ private Q_SLOTS:
void coinControlClipboardLowOutput();
void coinControlClipboardChange();
void updateFeeSectionControls();
- void updateNumberOfBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, bool headers, SynchronizationState sync_state);
+ void updateNumberOfBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, SyncType synctype, SynchronizationState sync_state);
void updateSmartFeeLabel();
Q_SIGNALS:
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 8f116a05ef..d1daf06732 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -767,7 +767,7 @@ static RPCHelpMan pruneblockchain()
ChainstateManager& chainman = EnsureAnyChainman(request.context);
LOCK(cs_main);
- CChainState& active_chainstate = chainman.ActiveChainstate();
+ Chainstate& active_chainstate = chainman.ActiveChainstate();
CChain& active_chain = active_chainstate.m_chain;
int heightParam = request.params[0].getInt<int>();
@@ -833,9 +833,9 @@ static std::optional<kernel::CCoinsStats> GetUTXOStats(CCoinsView* view, node::B
// Use CoinStatsIndex if it is requested and available and a hash_type of Muhash or None was requested
if ((hash_type == kernel::CoinStatsHashType::MUHASH || hash_type == kernel::CoinStatsHashType::NONE) && g_coin_stats_index && index_requested) {
if (pindex) {
- return g_coin_stats_index->LookUpStats(pindex);
+ return g_coin_stats_index->LookUpStats(*pindex);
} else {
- CBlockIndex* block_index = WITH_LOCK(::cs_main, return blockman.LookupBlockIndex(view->GetBestBlock()));
+ CBlockIndex& block_index = *CHECK_NONFATAL(WITH_LOCK(::cs_main, return blockman.LookupBlockIndex(view->GetBestBlock())));
return g_coin_stats_index->LookUpStats(block_index);
}
}
@@ -908,7 +908,7 @@ static RPCHelpMan gettxoutsetinfo()
NodeContext& node = EnsureAnyNodeContext(request.context);
ChainstateManager& chainman = EnsureChainman(node);
- CChainState& active_chainstate = chainman.ActiveChainstate();
+ Chainstate& active_chainstate = chainman.ActiveChainstate();
active_chainstate.ForceFlushStateToDisk();
CCoinsView* coins_view;
@@ -1048,7 +1048,7 @@ static RPCHelpMan gettxout()
fMempool = request.params[2].get_bool();
Coin coin;
- CChainState& active_chainstate = chainman.ActiveChainstate();
+ Chainstate& active_chainstate = chainman.ActiveChainstate();
CCoinsViewCache* coins_view = &active_chainstate.CoinsTip();
if (fMempool) {
@@ -1105,7 +1105,7 @@ static RPCHelpMan verifychain()
ChainstateManager& chainman = EnsureAnyChainman(request.context);
LOCK(cs_main);
- CChainState& active_chainstate = chainman.ActiveChainstate();
+ Chainstate& active_chainstate = chainman.ActiveChainstate();
return CVerifyDB().VerifyDB(
active_chainstate, chainman.GetParams().GetConsensus(), active_chainstate.CoinsTip(), check_level, check_depth);
},
@@ -1233,7 +1233,7 @@ RPCHelpMan getblockchaininfo()
const ArgsManager& args{EnsureAnyArgsman(request.context)};
ChainstateManager& chainman = EnsureAnyChainman(request.context);
LOCK(cs_main);
- CChainState& active_chainstate = chainman.ActiveChainstate();
+ Chainstate& active_chainstate = chainman.ActiveChainstate();
const CBlockIndex& tip{*CHECK_NONFATAL(active_chainstate.m_chain.Tip())};
const int height{tip.nHeight};
@@ -1328,7 +1328,7 @@ static RPCHelpMan getdeploymentinfo()
{
const ChainstateManager& chainman = EnsureAnyChainman(request.context);
LOCK(cs_main);
- const CChainState& active_chainstate = chainman.ActiveChainstate();
+ const Chainstate& active_chainstate = chainman.ActiveChainstate();
const CBlockIndex* blockindex;
if (request.params[0].isNull()) {
@@ -2129,7 +2129,7 @@ static RPCHelpMan scantxoutset()
for (const UniValue& scanobject : request.params[1].get_array().getValues()) {
FlatSigningProvider provider;
auto scripts = EvalDescriptorStringOrObject(scanobject, provider);
- for (const auto& script : scripts) {
+ for (CScript& script : scripts) {
std::string inferred = InferDescriptor(script, provider)->ToString();
needles.emplace(script);
descriptors.emplace(std::move(script), std::move(inferred));
@@ -2148,7 +2148,7 @@ static RPCHelpMan scantxoutset()
{
ChainstateManager& chainman = EnsureChainman(node);
LOCK(cs_main);
- CChainState& active_chainstate = chainman.ActiveChainstate();
+ Chainstate& active_chainstate = chainman.ActiveChainstate();
active_chainstate.ForceFlushStateToDisk();
pcursor = CHECK_NONFATAL(active_chainstate.CoinsDB().Cursor());
tip = CHECK_NONFATAL(active_chainstate.m_chain.Tip());
@@ -2328,7 +2328,7 @@ static RPCHelpMan dumptxoutset()
UniValue CreateUTXOSnapshot(
NodeContext& node,
- CChainState& chainstate,
+ Chainstate& chainstate,
AutoFile& afile,
const fs::path& path,
const fs::path& temppath)
diff --git a/src/rpc/blockchain.h b/src/rpc/blockchain.h
index a332fd4892..6cdb5fa48b 100644
--- a/src/rpc/blockchain.h
+++ b/src/rpc/blockchain.h
@@ -20,7 +20,7 @@ extern RecursiveMutex cs_main;
class CBlock;
class CBlockIndex;
-class CChainState;
+class Chainstate;
class UniValue;
namespace node {
struct NodeContext;
@@ -54,7 +54,7 @@ void CalculatePercentilesByWeight(CAmount result[NUM_GETBLOCKSTATS_PERCENTILES],
*/
UniValue CreateUTXOSnapshot(
node::NodeContext& node,
- CChainState& chainstate,
+ Chainstate& chainstate,
AutoFile& afile,
const fs::path& path,
const fs::path& tmppath);
diff --git a/src/rpc/mempool.cpp b/src/rpc/mempool.cpp
index db09a0c7b6..5c1770704d 100644
--- a/src/rpc/mempool.cpp
+++ b/src/rpc/mempool.cpp
@@ -168,7 +168,7 @@ static RPCHelpMan testmempoolaccept()
NodeContext& node = EnsureAnyNodeContext(request.context);
CTxMemPool& mempool = EnsureMemPool(node);
ChainstateManager& chainman = EnsureChainman(node);
- CChainState& chainstate = chainman.ActiveChainstate();
+ Chainstate& chainstate = chainman.ActiveChainstate();
const PackageMempoolAcceptResult package_result = [&] {
LOCK(::cs_main);
if (txns.size() > 1) return ProcessNewPackage(chainstate, mempool, txns, /*test_accept=*/true);
@@ -810,7 +810,7 @@ static RPCHelpMan submitpackage()
NodeContext& node = EnsureAnyNodeContext(request.context);
CTxMemPool& mempool = EnsureMemPool(node);
- CChainState& chainstate = EnsureChainman(node).ActiveChainstate();
+ Chainstate& chainstate = EnsureChainman(node).ActiveChainstate();
const auto package_result = WITH_LOCK(::cs_main, return ProcessNewPackage(chainstate, mempool, txns, /*test_accept=*/ false));
// First catch any errors.
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index 91feb2c24b..354af22ef4 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -132,7 +132,7 @@ static bool GenerateBlock(ChainstateManager& chainman, CBlock& block, uint64_t&
}
std::shared_ptr<const CBlock> shared_pblock = std::make_shared<const CBlock>(block);
- if (!chainman.ProcessNewBlock(shared_pblock, true, nullptr)) {
+ if (!chainman.ProcessNewBlock(shared_pblock, /*force_processing=*/true, /*min_pow_checked=*/true, nullptr)) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted");
}
@@ -598,7 +598,7 @@ static RPCHelpMan getblocktemplate()
std::string strMode = "template";
UniValue lpval = NullUniValue;
std::set<std::string> setClientRules;
- CChainState& active_chainstate = chainman.ActiveChainstate();
+ Chainstate& active_chainstate = chainman.ActiveChainstate();
CChain& active_chain = active_chainstate.m_chain;
if (!request.params[0].isNull())
{
@@ -981,7 +981,7 @@ static RPCHelpMan submitblock()
bool new_block;
auto sc = std::make_shared<submitblock_StateCatcher>(block.GetHash());
RegisterSharedValidationInterface(sc);
- bool accepted = chainman.ProcessNewBlock(blockptr, /*force_processing=*/true, /*new_block=*/&new_block);
+ bool accepted = chainman.ProcessNewBlock(blockptr, /*force_processing=*/true, /*min_pow_checked=*/true, /*new_block=*/&new_block);
UnregisterSharedValidationInterface(sc);
if (!new_block && accepted) {
return "duplicate";
@@ -1023,7 +1023,7 @@ static RPCHelpMan submitheader()
}
BlockValidationState state;
- chainman.ProcessNewBlockHeaders({h}, state);
+ chainman.ProcessNewBlockHeaders({h}, /*min_pow_checked=*/true, state);
if (state.IsValid()) return UniValue::VNULL;
if (state.IsError()) {
throw JSONRPCError(RPC_VERIFY_ERROR, state.ToString());
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index 06f46040b8..e221b3462d 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -132,6 +132,7 @@ static RPCHelpMan getpeerinfo()
{RPCResult::Type::BOOL, "bip152_hb_to", "Whether we selected peer as (compact blocks) high-bandwidth peer"},
{RPCResult::Type::BOOL, "bip152_hb_from", "Whether peer selected us as (compact blocks) high-bandwidth peer"},
{RPCResult::Type::NUM, "startingheight", /*optional=*/true, "The starting height (block) of the peer"},
+ {RPCResult::Type::NUM, "presynced_headers", /*optional=*/true, "The current height of header pre-synchronization with this peer, or -1 if no low-work sync is in progress"},
{RPCResult::Type::NUM, "synced_headers", /*optional=*/true, "The last header we have in common with this peer"},
{RPCResult::Type::NUM, "synced_blocks", /*optional=*/true, "The last block we have in common with this peer"},
{RPCResult::Type::ARR, "inflight", /*optional=*/true, "",
@@ -226,6 +227,7 @@ static RPCHelpMan getpeerinfo()
obj.pushKV("bip152_hb_from", stats.m_bip152_highbandwidth_from);
if (fStateStats) {
obj.pushKV("startingheight", statestats.m_starting_height);
+ obj.pushKV("presynced_headers", statestats.presync_height);
obj.pushKV("synced_headers", statestats.nSyncHeight);
obj.pushKV("synced_blocks", statestats.nCommonHeight);
UniValue heights(UniValue::VARR);
@@ -240,7 +242,7 @@ static RPCHelpMan getpeerinfo()
obj.pushKV("addr_rate_limited", statestats.m_addr_rate_limited);
}
UniValue permissions(UniValue::VARR);
- for (const auto& permission : NetPermissions::ToStrings(stats.m_permissionFlags)) {
+ for (const auto& permission : NetPermissions::ToStrings(stats.m_permission_flags)) {
permissions.push_back(permission);
}
obj.pushKV("permissions", permissions);
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index 7ffb499330..f365de7d0c 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -51,7 +51,7 @@ using node::GetTransaction;
using node::NodeContext;
using node::PSBTAnalysis;
-static void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry, CChainState& active_chainstate)
+static void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry, Chainstate& active_chainstate)
{
// Call into TxToUniv() in bitcoin-common to decode the transaction hex.
//
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
index e9987d73be..83a352dbea 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -21,8 +21,6 @@
#include <mutex>
#include <unordered_map>
-using SteadyClock = std::chrono::steady_clock;
-
static GlobalMutex g_rpc_warmup_mutex;
static std::atomic<bool> g_rpc_running{false};
static bool fRPCInWarmup GUARDED_BY(g_rpc_warmup_mutex) = true;
diff --git a/src/rpc/txoutproof.cpp b/src/rpc/txoutproof.cpp
index dcf6c6bee1..cd8b49bfe1 100644
--- a/src/rpc/txoutproof.cpp
+++ b/src/rpc/txoutproof.cpp
@@ -66,7 +66,7 @@ static RPCHelpMan gettxoutproof()
}
} else {
LOCK(cs_main);
- CChainState& active_chainstate = chainman.ActiveChainstate();
+ Chainstate& 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) {
diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp
index 24ab21a947..43935650fa 100644
--- a/src/rpc/util.cpp
+++ b/src/rpc/util.cpp
@@ -50,7 +50,8 @@ void RPCTypeCheck(const UniValue& params,
void RPCTypeCheckArgument(const UniValue& value, const UniValueType& typeExpected)
{
if (!typeExpected.typeAny && value.type() != typeExpected.type) {
- throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Expected type %s, got %s", uvTypeName(typeExpected.type), uvTypeName(value.type())));
+ throw JSONRPCError(RPC_TYPE_ERROR,
+ strprintf("JSON value of type %s is not of expected type %s", uvTypeName(value.type()), uvTypeName(typeExpected.type)));
}
}
diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp
index 434e106dad..864eb8864f 100644
--- a/src/script/descriptor.cpp
+++ b/src/script/descriptor.cpp
@@ -572,7 +572,7 @@ public:
if (pos++) ret += ",";
std::string tmp;
if (!scriptarg->ToStringHelper(arg, tmp, type, cache)) return false;
- ret += std::move(tmp);
+ ret += tmp;
}
return true;
}
@@ -596,7 +596,7 @@ public:
tmp = pubkey->ToString();
break;
}
- ret += std::move(tmp);
+ ret += tmp;
}
std::string subscript;
if (!ToStringSubScriptHelper(arg, subscript, type, cache)) return false;
@@ -612,7 +612,7 @@ public:
return AddChecksum(ret);
}
- bool ToPrivateString(const SigningProvider& arg, std::string& out) const final
+ bool ToPrivateString(const SigningProvider& arg, std::string& out) const override
{
bool ret = ToStringHelper(&arg, out, StringType::PRIVATE);
out = AddChecksum(out);
@@ -698,6 +698,7 @@ public:
return OutputTypeFromDestination(m_destination);
}
bool IsSingleType() const final { return true; }
+ bool ToPrivateString(const SigningProvider& arg, std::string& out) const final { return false; }
};
/** A parsed raw(H) descriptor. */
@@ -718,6 +719,7 @@ public:
return OutputTypeFromDestination(dest);
}
bool IsSingleType() const final { return true; }
+ bool ToPrivateString(const SigningProvider& arg, std::string& out) const final { return false; }
};
/** A parsed pk(P) descriptor. */
@@ -912,7 +914,7 @@ protected:
}
std::string tmp;
if (!m_subdescriptor_args[pos]->ToStringHelper(arg, tmp, type, cache)) return false;
- ret += std::move(tmp);
+ ret += tmp;
while (!path.empty() && path.back()) {
if (path.size() > 1) ret += '}';
path.pop_back();
diff --git a/src/sync.h b/src/sync.h
index 7ec4b668ac..c34d969041 100644
--- a/src/sync.h
+++ b/src/sync.h
@@ -261,7 +261,7 @@ inline RecursiveMutex* MaybeCheckNotHeld(RecursiveMutex* cs) LOCKS_EXCLUDED(cs)
#define LOCK(cs) DebugLock<decltype(cs)> UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
#define LOCK2(cs1, cs2) \
DebugLock<decltype(cs1)> criticalblock1(MaybeCheckNotHeld(cs1), #cs1, __FILE__, __LINE__); \
- DebugLock<decltype(cs2)> criticalblock2(MaybeCheckNotHeld(cs2), #cs2, __FILE__, __LINE__);
+ DebugLock<decltype(cs2)> criticalblock2(MaybeCheckNotHeld(cs2), #cs2, __FILE__, __LINE__)
#define TRY_LOCK(cs, name) DebugLock<decltype(cs)> name(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__, true)
#define WAIT_LOCK(cs, name) DebugLock<decltype(cs)> name(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
diff --git a/src/test/blockfilter_index_tests.cpp b/src/test/blockfilter_index_tests.cpp
index 1a182209b8..2798e998af 100644
--- a/src/test/blockfilter_index_tests.cpp
+++ b/src/test/blockfilter_index_tests.cpp
@@ -101,7 +101,7 @@ bool BuildChainTestingSetup::BuildChain(const CBlockIndex* pindex,
CBlockHeader header = block->GetBlockHeader();
BlockValidationState state;
- if (!Assert(m_node.chainman)->ProcessNewBlockHeaders({header}, state, &pindex)) {
+ if (!Assert(m_node.chainman)->ProcessNewBlockHeaders({header}, true, state, &pindex)) {
return false;
}
}
@@ -178,7 +178,7 @@ BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, BuildChainTestingSetup)
uint256 chainA_last_header = last_header;
for (size_t i = 0; i < 2; i++) {
const auto& block = chainA[i];
- BOOST_REQUIRE(Assert(m_node.chainman)->ProcessNewBlock(block, true, nullptr));
+ BOOST_REQUIRE(Assert(m_node.chainman)->ProcessNewBlock(block, true, true, nullptr));
}
for (size_t i = 0; i < 2; i++) {
const auto& block = chainA[i];
@@ -196,7 +196,7 @@ BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, BuildChainTestingSetup)
uint256 chainB_last_header = last_header;
for (size_t i = 0; i < 3; i++) {
const auto& block = chainB[i];
- BOOST_REQUIRE(Assert(m_node.chainman)->ProcessNewBlock(block, true, nullptr));
+ BOOST_REQUIRE(Assert(m_node.chainman)->ProcessNewBlock(block, true, true, nullptr));
}
for (size_t i = 0; i < 3; i++) {
const auto& block = chainB[i];
@@ -227,7 +227,7 @@ BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, BuildChainTestingSetup)
// Reorg back to chain A.
for (size_t i = 2; i < 4; i++) {
const auto& block = chainA[i];
- BOOST_REQUIRE(Assert(m_node.chainman)->ProcessNewBlock(block, true, nullptr));
+ BOOST_REQUIRE(Assert(m_node.chainman)->ProcessNewBlock(block, true, true, nullptr));
}
// Check that chain A and B blocks can be retrieved.
diff --git a/src/test/coinstatsindex_tests.cpp b/src/test/coinstatsindex_tests.cpp
index c93d05a93b..2a6a777cfe 100644
--- a/src/test/coinstatsindex_tests.cpp
+++ b/src/test/coinstatsindex_tests.cpp
@@ -5,6 +5,7 @@
#include <chainparams.h>
#include <index/coinstatsindex.h>
#include <interfaces/chain.h>
+#include <kernel/coinstats.h>
#include <test/util/setup_common.h>
#include <test/util/validation.h>
#include <util/time.h>
@@ -38,7 +39,7 @@ BOOST_FIXTURE_TEST_CASE(coinstatsindex_initial_sync, TestChain100Setup)
}
// CoinStatsIndex should not be found before it is started.
- BOOST_CHECK(!coin_stats_index.LookUpStats(block_index));
+ BOOST_CHECK(!coin_stats_index.LookUpStats(*block_index));
// BlockUntilSyncedToCurrentChain should return false before CoinStatsIndex
// is started.
@@ -54,10 +55,10 @@ BOOST_FIXTURE_TEST_CASE(coinstatsindex_initial_sync, TestChain100Setup)
LOCK(cs_main);
genesis_block_index = m_node.chainman->ActiveChain().Genesis();
}
- BOOST_CHECK(coin_stats_index.LookUpStats(genesis_block_index));
+ BOOST_CHECK(coin_stats_index.LookUpStats(*genesis_block_index));
// Check that CoinStatsIndex updates with new blocks.
- BOOST_CHECK(coin_stats_index.LookUpStats(block_index));
+ BOOST_CHECK(coin_stats_index.LookUpStats(*block_index));
const CScript script_pub_key{CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG};
std::vector<CMutableTransaction> noTxns;
@@ -71,7 +72,7 @@ BOOST_FIXTURE_TEST_CASE(coinstatsindex_initial_sync, TestChain100Setup)
LOCK(cs_main);
new_block_index = m_node.chainman->ActiveChain().Tip();
}
- BOOST_CHECK(coin_stats_index.LookUpStats(new_block_index));
+ BOOST_CHECK(coin_stats_index.LookUpStats(*new_block_index));
BOOST_CHECK(block_index != new_block_index);
@@ -85,7 +86,7 @@ BOOST_FIXTURE_TEST_CASE(coinstatsindex_initial_sync, TestChain100Setup)
// make sure index is not corrupted and is able to reload.
BOOST_FIXTURE_TEST_CASE(coinstatsindex_unclean_shutdown, TestChain100Setup)
{
- CChainState& chainstate = Assert(m_node.chainman)->ActiveChainstate();
+ Chainstate& chainstate = Assert(m_node.chainman)->ActiveChainstate();
const CChainParams& params = Params();
{
CoinStatsIndex index{interfaces::MakeChain(m_node), 1 << 20};
@@ -102,7 +103,7 @@ BOOST_FIXTURE_TEST_CASE(coinstatsindex_unclean_shutdown, TestChain100Setup)
LOCK(cs_main);
BlockValidationState state;
BOOST_CHECK(CheckBlock(block, state, params.GetConsensus()));
- BOOST_CHECK(chainstate.AcceptBlock(new_block, state, &new_block_index, true, nullptr, nullptr));
+ BOOST_CHECK(chainstate.AcceptBlock(new_block, state, &new_block_index, true, nullptr, nullptr, true));
CCoinsViewCache view(&chainstate.CoinsTip());
BOOST_CHECK(chainstate.ConnectBlock(block, state, new_block_index, view));
}
diff --git a/src/test/denialofservice_tests.cpp b/src/test/denialofservice_tests.cpp
index 66c4605afa..7889156d51 100644
--- a/src/test/denialofservice_tests.cpp
+++ b/src/test/denialofservice_tests.cpp
@@ -68,7 +68,6 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
/*successfully_connected=*/true,
/*remote_services=*/ServiceFlags(NODE_NETWORK | NODE_WITNESS),
/*local_services=*/ServiceFlags(NODE_NETWORK | NODE_WITNESS),
- /*permission_flags=*/NetPermissionFlags::None,
/*version=*/PROTOCOL_VERSION,
/*relay_txs=*/true);
TestOnlyResetTimeData();
diff --git a/src/test/descriptor_tests.cpp b/src/test/descriptor_tests.cpp
index d0ad037228..6b2ef74e19 100644
--- a/src/test/descriptor_tests.cpp
+++ b/src/test/descriptor_tests.cpp
@@ -126,7 +126,7 @@ std::set<std::pair<CPubKey, KeyOriginInfo>> GetKeyOriginData(const FlatSigningPr
return ret;
}
-void DoCheck(const std::string& prv, const std::string& pub, const std::string& norm_prv, const std::string& norm_pub, int flags, const std::vector<std::vector<std::string>>& scripts, const std::optional<OutputType>& type, const std::set<std::vector<uint32_t>>& paths = ONLY_EMPTY,
+void DoCheck(const std::string& prv, const std::string& pub, const std::string& norm_pub, int flags, const std::vector<std::vector<std::string>>& scripts, const std::optional<OutputType>& type, const std::set<std::vector<uint32_t>>& paths = ONLY_EMPTY,
bool replace_apostrophe_with_h_in_prv=false, bool replace_apostrophe_with_h_in_pub=false)
{
FlatSigningProvider keys_priv, keys_pub;
@@ -340,29 +340,29 @@ void DoCheck(const std::string& prv, const std::string& pub, const std::string&
BOOST_CHECK_MESSAGE(left_paths.empty(), "Not all expected key paths found: " + prv);
}
-void Check(const std::string& prv, const std::string& pub, const std::string& norm_prv, const std::string& norm_pub, int flags, const std::vector<std::vector<std::string>>& scripts, const std::optional<OutputType>& type, const std::set<std::vector<uint32_t>>& paths = ONLY_EMPTY)
+void Check(const std::string& prv, const std::string& pub, const std::string& norm_pub, int flags, const std::vector<std::vector<std::string>>& scripts, const std::optional<OutputType>& type, const std::set<std::vector<uint32_t>>& paths = ONLY_EMPTY)
{
bool found_apostrophes_in_prv = false;
bool found_apostrophes_in_pub = false;
// Do not replace apostrophes with 'h' in prv and pub
- DoCheck(prv, pub, norm_prv, norm_pub, flags, scripts, type, paths);
+ DoCheck(prv, pub, norm_pub, flags, scripts, type, paths);
// Replace apostrophes with 'h' in prv but not in pub, if apostrophes are found in prv
if (prv.find('\'') != std::string::npos) {
found_apostrophes_in_prv = true;
- DoCheck(prv, pub, norm_prv, norm_pub, flags, scripts, type, paths, /* replace_apostrophe_with_h_in_prv = */true, /*replace_apostrophe_with_h_in_pub = */false);
+ DoCheck(prv, pub, norm_pub, flags, scripts, type, paths, /* replace_apostrophe_with_h_in_prv = */true, /*replace_apostrophe_with_h_in_pub = */false);
}
// Replace apostrophes with 'h' in pub but not in prv, if apostrophes are found in pub
if (pub.find('\'') != std::string::npos) {
found_apostrophes_in_pub = true;
- DoCheck(prv, pub, norm_prv, norm_pub, flags, scripts, type, paths, /* replace_apostrophe_with_h_in_prv = */false, /*replace_apostrophe_with_h_in_pub = */true);
+ DoCheck(prv, pub, norm_pub, flags, scripts, type, paths, /* replace_apostrophe_with_h_in_prv = */false, /*replace_apostrophe_with_h_in_pub = */true);
}
// Replace apostrophes with 'h' both in prv and in pub, if apostrophes are found in both
if (found_apostrophes_in_prv && found_apostrophes_in_pub) {
- DoCheck(prv, pub, norm_prv, norm_pub, flags, scripts, type, paths, /* replace_apostrophe_with_h_in_prv = */true, /*replace_apostrophe_with_h_in_pub = */true);
+ DoCheck(prv, pub, norm_pub, flags, scripts, type, paths, /* replace_apostrophe_with_h_in_prv = */true, /*replace_apostrophe_with_h_in_pub = */true);
}
}
@@ -373,60 +373,61 @@ BOOST_FIXTURE_TEST_SUITE(descriptor_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(descriptor_test)
{
// Basic single-key compressed
- Check("combo(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "combo(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "combo(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "combo(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", SIGNABLE, {{"2103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bdac","76a9149a1c78a507689f6f54b847ad1cef1e614ee23f1e88ac","00149a1c78a507689f6f54b847ad1cef1e614ee23f1e","a91484ab21b1b2fd065d4504ff693d832434b6108d7b87"}}, std::nullopt);
- Check("pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", SIGNABLE, {{"2103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bdac"}}, std::nullopt);
- Check("pkh([deadbeef/1/2'/3/4']L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "pkh([deadbeef/1/2'/3/4']03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "pkh([deadbeef/1/2'/3/4']L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "pkh([deadbeef/1/2'/3/4']03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", SIGNABLE, {{"76a9149a1c78a507689f6f54b847ad1cef1e614ee23f1e88ac"}}, OutputType::LEGACY, {{1,0x80000002UL,3,0x80000004UL}});
- Check("wpkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "wpkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "wpkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "wpkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", SIGNABLE, {{"00149a1c78a507689f6f54b847ad1cef1e614ee23f1e"}}, OutputType::BECH32);
- Check("sh(wpkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))", "sh(wpkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", "sh(wpkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))", "sh(wpkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", SIGNABLE, {{"a91484ab21b1b2fd065d4504ff693d832434b6108d7b87"}}, OutputType::P2SH_SEGWIT);
- Check("tr(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "tr(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", SIGNABLE | XONLY_KEYS, {{"512077aab6e066f8a7419c5ab714c12c67d25007ed55a43cadcacb4d7a970a093f11"}}, OutputType::BECH32M);
+ Check("combo(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "combo(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "combo(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", SIGNABLE, {{"2103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bdac","76a9149a1c78a507689f6f54b847ad1cef1e614ee23f1e88ac","00149a1c78a507689f6f54b847ad1cef1e614ee23f1e","a91484ab21b1b2fd065d4504ff693d832434b6108d7b87"}}, std::nullopt);
+ Check("pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", SIGNABLE, {{"2103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bdac"}}, std::nullopt);
+ Check("pkh([deadbeef/1/2'/3/4']L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "pkh([deadbeef/1/2'/3/4']03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "pkh([deadbeef/1/2'/3/4']03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", SIGNABLE, {{"76a9149a1c78a507689f6f54b847ad1cef1e614ee23f1e88ac"}}, OutputType::LEGACY, {{1,0x80000002UL,3,0x80000004UL}});
+ Check("wpkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "wpkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "wpkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", SIGNABLE, {{"00149a1c78a507689f6f54b847ad1cef1e614ee23f1e"}}, OutputType::BECH32);
+ Check("sh(wpkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))", "sh(wpkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", "sh(wpkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", SIGNABLE, {{"a91484ab21b1b2fd065d4504ff693d832434b6108d7b87"}}, OutputType::P2SH_SEGWIT);
+ Check("tr(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", SIGNABLE | XONLY_KEYS, {{"512077aab6e066f8a7419c5ab714c12c67d25007ed55a43cadcacb4d7a970a093f11"}}, OutputType::BECH32M);
CheckUnparsable("sh(wpkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY2))", "sh(wpkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5))", "wpkh(): Pubkey '03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5' is invalid"); // Invalid pubkey
CheckUnparsable("pkh(deadbeef/1/2'/3/4']L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "pkh(deadbeef/1/2'/3/4']03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "pkh(): Key origin start '[ character expected but not found, got 'd' instead"); // Missing start bracket in key origin
CheckUnparsable("pkh([deadbeef]/1/2'/3/4']L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "pkh([deadbeef]/1/2'/3/4']03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "pkh(): Multiple ']' characters found for a single pubkey"); // Multiple end brackets in key origin
// Basic single-key uncompressed
- Check("combo(5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "combo(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", "combo(5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "combo(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)",SIGNABLE, {{"4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235ac","76a914b5bd079c4d57cc7fc28ecf8213a6b791625b818388ac"}}, std::nullopt);
- Check("pk(5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "pk(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", "pk(5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "pk(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", SIGNABLE, {{"4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235ac"}}, std::nullopt);
- Check("pkh(5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "pkh(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", "pkh(5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "pkh(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", SIGNABLE, {{"76a914b5bd079c4d57cc7fc28ecf8213a6b791625b818388ac"}}, OutputType::LEGACY);
+ Check("combo(5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "combo(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", "combo(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)",SIGNABLE, {{"4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235ac","76a914b5bd079c4d57cc7fc28ecf8213a6b791625b818388ac"}}, std::nullopt);
+ Check("pk(5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "pk(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", "pk(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", SIGNABLE, {{"4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235ac"}}, std::nullopt);
+ Check("pkh(5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "pkh(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", "pkh(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", SIGNABLE, {{"76a914b5bd079c4d57cc7fc28ecf8213a6b791625b818388ac"}}, OutputType::LEGACY);
CheckUnparsable("wpkh(5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "wpkh(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", "wpkh(): Uncompressed keys are not allowed"); // No uncompressed keys in witness
CheckUnparsable("wsh(pk(5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss))", "wsh(pk(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235))", "pk(): Uncompressed keys are not allowed"); // No uncompressed keys in witness
CheckUnparsable("sh(wpkh(5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss))", "sh(wpkh(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235))", "wpkh(): Uncompressed keys are not allowed"); // No uncompressed keys in witness
// Some unconventional single-key constructions
- Check("sh(pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))", "sh(pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", "sh(pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))", "sh(pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", SIGNABLE, {{"a9141857af51a5e516552b3086430fd8ce55f7c1a52487"}}, OutputType::LEGACY);
- Check("sh(pkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))", "sh(pkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", "sh(pkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))", "sh(pkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", SIGNABLE, {{"a9141a31ad23bf49c247dd531a623c2ef57da3c400c587"}}, OutputType::LEGACY);
- Check("wsh(pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))", "wsh(pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", "wsh(pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))", "wsh(pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", SIGNABLE, {{"00202e271faa2325c199d25d22e1ead982e45b64eeb4f31e73dbdf41bd4b5fec23fa"}}, OutputType::BECH32);
- Check("wsh(pkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))", "wsh(pkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", "wsh(pkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))", "wsh(pkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", SIGNABLE, {{"0020338e023079b91c58571b20e602d7805fb808c22473cbc391a41b1bd3a192e75b"}}, OutputType::BECH32);
- Check("sh(wsh(pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)))", "sh(wsh(pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))", "sh(wsh(pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)))", "sh(wsh(pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))", SIGNABLE, {{"a91472d0c5a3bfad8c3e7bd5303a72b94240e80b6f1787"}}, OutputType::P2SH_SEGWIT);
- Check("sh(wsh(pkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)))", "sh(wsh(pkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))", "sh(wsh(pkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)))", "sh(wsh(pkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))", SIGNABLE, {{"a914b61b92e2ca21bac1e72a3ab859a742982bea960a87"}}, OutputType::P2SH_SEGWIT);
- Check("tr(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5,{pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5),{pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1),pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5)}})", "tr(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5,{pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5),{pk(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd),pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5)}})", "tr(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5,{pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5),{pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1),pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5)}})", "tr(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5,{pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5),{pk(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd),pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5)}})", XONLY_KEYS | SIGNABLE | MISSING_PRIVKEYS, {{"51201497ae16f30dacb88523ed9301bff17773b609e8a90518a3f96ea328a47d1500"}}, OutputType::BECH32M);
+ Check("sh(pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))", "sh(pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", "sh(pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", SIGNABLE, {{"a9141857af51a5e516552b3086430fd8ce55f7c1a52487"}}, OutputType::LEGACY);
+ Check("sh(pkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))", "sh(pkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", "sh(pkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", SIGNABLE, {{"a9141a31ad23bf49c247dd531a623c2ef57da3c400c587"}}, OutputType::LEGACY);
+ Check("wsh(pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))", "wsh(pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", "wsh(pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", SIGNABLE, {{"00202e271faa2325c199d25d22e1ead982e45b64eeb4f31e73dbdf41bd4b5fec23fa"}}, OutputType::BECH32);
+ Check("wsh(pkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))", "wsh(pkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", "wsh(pkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", SIGNABLE, {{"0020338e023079b91c58571b20e602d7805fb808c22473cbc391a41b1bd3a192e75b"}}, OutputType::BECH32);
+ Check("sh(wsh(pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)))", "sh(wsh(pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))", "sh(wsh(pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))", SIGNABLE, {{"a91472d0c5a3bfad8c3e7bd5303a72b94240e80b6f1787"}}, OutputType::P2SH_SEGWIT);
+ Check("sh(wsh(pkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)))", "sh(wsh(pkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))", "sh(wsh(pkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))", SIGNABLE, {{"a914b61b92e2ca21bac1e72a3ab859a742982bea960a87"}}, OutputType::P2SH_SEGWIT);
+ Check("tr(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5,{pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5),{pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1),pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5)}})", "tr(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5,{pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5),{pk(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd),pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5)}})", "tr(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5,{pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5),{pk(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd),pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5)}})", XONLY_KEYS | SIGNABLE | MISSING_PRIVKEYS, {{"51201497ae16f30dacb88523ed9301bff17773b609e8a90518a3f96ea328a47d1500"}}, OutputType::BECH32M);
// Versions with BIP32 derivations
- Check("combo([01234567]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc)", "combo([01234567]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL)", "combo([01234567]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc)", "combo([01234567]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL)", SIGNABLE, {{"2102d2b36900396c9282fa14628566582f206a5dd0bcc8d5e892611806cafb0301f0ac","76a91431a507b815593dfc51ffc7245ae7e5aee304246e88ac","001431a507b815593dfc51ffc7245ae7e5aee304246e","a9142aafb926eb247cb18240a7f4c07983ad1f37922687"}}, std::nullopt);
- Check("pk(xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0)", "pk(xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0)", "pk(xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0)", "pk(xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0)", DEFAULT, {{"210379e45b3cf75f9c5f9befd8e9506fb962f6a9d185ac87001ec44a8d3df8d4a9e3ac"}}, std::nullopt, {{0}});
- Check("pkh(xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647'/0)", "pkh(xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2147483647'/0)", "pkh([bd16bee5/2147483647']xprv9vHkqa6XAPwKqSKSEJMcAB3yoCZhaSVsGZbSkFY5L3Lfjjk8sjZucbsbvEw5o3QrSA69nPfZDCgFnNnLhQ2ohpZuwummndnPasDw2Qr6dC2/0)", "pkh([bd16bee5/2147483647']xpub69H7F5dQzmVd3vPuLKtcXJziMEQByuDidnX3YdwgtNsecY5HRGtAAQC5mXTt4dsv9RzyjgDjAQs9VGVV6ydYCHnprc9vvaA5YtqWyL6hyds/0)", HARDENED, {{"76a914ebdc90806a9c4356c1c88e42216611e1cb4c1c1788ac"}}, OutputType::LEGACY, {{0xFFFFFFFFUL,0}});
- Check("wpkh([ffffffff/13']xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*)", "wpkh([ffffffff/13']xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*)", "wpkh([ffffffff/13']xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*)", "wpkh([ffffffff/13']xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*)", RANGE, {{"0014326b2249e3a25d5dc60935f044ee835d090ba859"},{"0014af0bd98abc2f2cae66e36896a39ffe2d32984fb7"},{"00141fa798efd1cbf95cebf912c031b8a4a6e9fb9f27"}}, OutputType::BECH32, {{0x8000000DUL, 1, 2, 0}, {0x8000000DUL, 1, 2, 1}, {0x8000000DUL, 1, 2, 2}});
- Check("sh(wpkh(xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))", "sh(wpkh(xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*'))", "sh(wpkh(xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))", "sh(wpkh(xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*'))", RANGE | HARDENED | DERIVE_HARDENED, {{"a9149a4d9901d6af519b2a23d4a2f51650fcba87ce7b87"},{"a914bed59fc0024fae941d6e20a3b44a109ae740129287"},{"a9148483aa1116eb9c05c482a72bada4b1db24af654387"}}, OutputType::P2SH_SEGWIT, {{10, 20, 30, 40, 0x80000000UL}, {10, 20, 30, 40, 0x80000001UL}, {10, 20, 30, 40, 0x80000002UL}});
- Check("combo(xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334/*)", "combo(xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV/*)", "combo(xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334/*)", "combo(xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV/*)", RANGE, {{"2102df12b7035bdac8e3bab862a3a83d06ea6b17b6753d52edecba9be46f5d09e076ac","76a914f90e3178ca25f2c808dc76624032d352fdbdfaf288ac","0014f90e3178ca25f2c808dc76624032d352fdbdfaf2","a91408f3ea8c68d4a7585bf9e8bda226723f70e445f087"},{"21032869a233c9adff9a994e4966e5b821fd5bac066da6c3112488dc52383b4a98ecac","76a914a8409d1b6dfb1ed2a3e8aa5e0ef2ff26b15b75b788ac","0014a8409d1b6dfb1ed2a3e8aa5e0ef2ff26b15b75b7","a91473e39884cb71ae4e5ac9739e9225026c99763e6687"}}, std::nullopt, {{0}, {1}});
- Check("tr(xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/0/*,pk(xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/1/*))", "tr(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/0/*,pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/*))", "tr(xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/0/*,pk(xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/1/*))", "tr(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/0/*,pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/*))", XONLY_KEYS | RANGE, {{"512078bc707124daa551b65af74de2ec128b7525e10f374dc67b64e00ce0ab8b3e12"}, {"512001f0a02a17808c20134b78faab80ef93ffba82261ccef0a2314f5d62b6438f11"}, {"512021024954fcec88237a9386fce80ef2ced5f1e91b422b26c59ccfc174c8d1ad25"}}, OutputType::BECH32M, {{0, 0}, {0, 1}, {0, 2}, {1, 0}, {1, 1}, {1, 2}});
+ Check("combo([01234567]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc)", "combo([01234567]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL)", "combo([01234567]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL)", SIGNABLE, {{"2102d2b36900396c9282fa14628566582f206a5dd0bcc8d5e892611806cafb0301f0ac","76a91431a507b815593dfc51ffc7245ae7e5aee304246e88ac","001431a507b815593dfc51ffc7245ae7e5aee304246e","a9142aafb926eb247cb18240a7f4c07983ad1f37922687"}}, std::nullopt);
+ Check("pk(xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0)", "pk(xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0)", "pk(xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0)", DEFAULT, {{"210379e45b3cf75f9c5f9befd8e9506fb962f6a9d185ac87001ec44a8d3df8d4a9e3ac"}}, std::nullopt, {{0}});
+ Check("pkh(xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647'/0)", "pkh(xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2147483647'/0)", "pkh([bd16bee5/2147483647']xpub69H7F5dQzmVd3vPuLKtcXJziMEQByuDidnX3YdwgtNsecY5HRGtAAQC5mXTt4dsv9RzyjgDjAQs9VGVV6ydYCHnprc9vvaA5YtqWyL6hyds/0)", HARDENED, {{"76a914ebdc90806a9c4356c1c88e42216611e1cb4c1c1788ac"}}, OutputType::LEGACY, {{0xFFFFFFFFUL,0}});
+
+ Check("wpkh([ffffffff/13']xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*)", "wpkh([ffffffff/13']xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*)", "wpkh([ffffffff/13']xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*)", RANGE, {{"0014326b2249e3a25d5dc60935f044ee835d090ba859"},{"0014af0bd98abc2f2cae66e36896a39ffe2d32984fb7"},{"00141fa798efd1cbf95cebf912c031b8a4a6e9fb9f27"}}, OutputType::BECH32, {{0x8000000DUL, 1, 2, 0}, {0x8000000DUL, 1, 2, 1}, {0x8000000DUL, 1, 2, 2}});
+ Check("sh(wpkh(xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))", "sh(wpkh(xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*'))", "sh(wpkh(xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*'))", RANGE | HARDENED | DERIVE_HARDENED, {{"a9149a4d9901d6af519b2a23d4a2f51650fcba87ce7b87"},{"a914bed59fc0024fae941d6e20a3b44a109ae740129287"},{"a9148483aa1116eb9c05c482a72bada4b1db24af654387"}}, OutputType::P2SH_SEGWIT, {{10, 20, 30, 40, 0x80000000UL}, {10, 20, 30, 40, 0x80000001UL}, {10, 20, 30, 40, 0x80000002UL}});
+ Check("combo(xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334/*)", "combo(xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV/*)", "combo(xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV/*)", RANGE, {{"2102df12b7035bdac8e3bab862a3a83d06ea6b17b6753d52edecba9be46f5d09e076ac","76a914f90e3178ca25f2c808dc76624032d352fdbdfaf288ac","0014f90e3178ca25f2c808dc76624032d352fdbdfaf2","a91408f3ea8c68d4a7585bf9e8bda226723f70e445f087"},{"21032869a233c9adff9a994e4966e5b821fd5bac066da6c3112488dc52383b4a98ecac","76a914a8409d1b6dfb1ed2a3e8aa5e0ef2ff26b15b75b788ac","0014a8409d1b6dfb1ed2a3e8aa5e0ef2ff26b15b75b7","a91473e39884cb71ae4e5ac9739e9225026c99763e6687"}}, std::nullopt, {{0}, {1}});
+ Check("tr(xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/0/*,pk(xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/1/*))", "tr(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/0/*,pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/*))", "tr(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/0/*,pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/*))", XONLY_KEYS | RANGE, {{"512078bc707124daa551b65af74de2ec128b7525e10f374dc67b64e00ce0ab8b3e12"}, {"512001f0a02a17808c20134b78faab80ef93ffba82261ccef0a2314f5d62b6438f11"}, {"512021024954fcec88237a9386fce80ef2ced5f1e91b422b26c59ccfc174c8d1ad25"}}, OutputType::BECH32M, {{0, 0}, {0, 1}, {0, 2}, {1, 0}, {1, 1}, {1, 2}});
// Mixed xpubs and const pubkeys
- Check("wsh(multi(1,xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334/0,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))","wsh(multi(1,xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV/0,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))","wsh(multi(1,xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334/0,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))","wsh(multi(1,xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV/0,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", MIXED_PUBKEYS, {{"0020cb155486048b23a6da976d4c6fe071a2dbc8a7b57aaf225b8955f2e2a27b5f00"}},OutputType::BECH32,{{0},{}});
+ Check("wsh(multi(1,xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334/0,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))","wsh(multi(1,xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV/0,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))","wsh(multi(1,xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV/0,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", MIXED_PUBKEYS, {{"0020cb155486048b23a6da976d4c6fe071a2dbc8a7b57aaf225b8955f2e2a27b5f00"}},OutputType::BECH32,{{0},{}});
// Mixed range xpubs and const pubkeys
- Check("multi(1,xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334/*,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)","multi(1,xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV/*,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)","multi(1,xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334/*,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)","multi(1,xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV/*,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", RANGE | MIXED_PUBKEYS, {{"512102df12b7035bdac8e3bab862a3a83d06ea6b17b6753d52edecba9be46f5d09e0762103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd52ae"},{"5121032869a233c9adff9a994e4966e5b821fd5bac066da6c3112488dc52383b4a98ec2103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd52ae"},{"5121035d30b6c66dc1e036c45369da8287518cf7e0d6ed1e2b905171c605708f14ca032103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd52ae"}}, std::nullopt,{{2},{1},{0},{}});
+ Check("multi(1,xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334/*,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)","multi(1,xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV/*,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)","multi(1,xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV/*,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", RANGE | MIXED_PUBKEYS, {{"512102df12b7035bdac8e3bab862a3a83d06ea6b17b6753d52edecba9be46f5d09e0762103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd52ae"},{"5121032869a233c9adff9a994e4966e5b821fd5bac066da6c3112488dc52383b4a98ec2103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd52ae"},{"5121035d30b6c66dc1e036c45369da8287518cf7e0d6ed1e2b905171c605708f14ca032103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd52ae"}}, std::nullopt,{{2},{1},{0},{}});
CheckUnparsable("combo([012345678]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc)", "combo([012345678]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL)", "combo(): Fingerprint is not 4 bytes (9 characters instead of 8 characters)"); // Too long key fingerprint
CheckUnparsable("pkh(xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483648)", "pkh(xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2147483648)", "pkh(): Key path value 2147483648 is out of range"); // BIP 32 path element overflow
CheckUnparsable("pkh(xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/1aa)", "pkh(xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/1aa)", "pkh(): Key path value '1aa' is not a valid uint32"); // Path is not valid uint
- Check("pkh([01234567/10/20]xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647'/0)", "pkh([01234567/10/20]xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2147483647'/0)", "pkh([01234567/10/20/2147483647']xprv9vHkqa6XAPwKqSKSEJMcAB3yoCZhaSVsGZbSkFY5L3Lfjjk8sjZucbsbvEw5o3QrSA69nPfZDCgFnNnLhQ2ohpZuwummndnPasDw2Qr6dC2/0)", "pkh([01234567/10/20/2147483647']xpub69H7F5dQzmVd3vPuLKtcXJziMEQByuDidnX3YdwgtNsecY5HRGtAAQC5mXTt4dsv9RzyjgDjAQs9VGVV6ydYCHnprc9vvaA5YtqWyL6hyds/0)", HARDENED, {{"76a914ebdc90806a9c4356c1c88e42216611e1cb4c1c1788ac"}}, OutputType::LEGACY, {{10, 20, 0xFFFFFFFFUL, 0}});
+ Check("pkh([01234567/10/20]xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647'/0)", "pkh([01234567/10/20]xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2147483647'/0)", "pkh([01234567/10/20/2147483647']xpub69H7F5dQzmVd3vPuLKtcXJziMEQByuDidnX3YdwgtNsecY5HRGtAAQC5mXTt4dsv9RzyjgDjAQs9VGVV6ydYCHnprc9vvaA5YtqWyL6hyds/0)", HARDENED, {{"76a914ebdc90806a9c4356c1c88e42216611e1cb4c1c1788ac"}}, OutputType::LEGACY, {{10, 20, 0xFFFFFFFFUL, 0}});
// Multisig constructions
- Check("multi(1,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "multi(1,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", "multi(1,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "multi(1,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", SIGNABLE, {{"512103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea23552ae"}}, std::nullopt);
- Check("sortedmulti(1,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "sortedmulti(1,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", "sortedmulti(1,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "sortedmulti(1,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", SIGNABLE, {{"512103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea23552ae"}}, std::nullopt);
- Check("sortedmulti(1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "sortedmulti(1,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "sortedmulti(1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "sortedmulti(1,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", SIGNABLE, {{"512103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea23552ae"}}, std::nullopt);
- Check("sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))", "sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))", DEFAULT, {{"a91445a9a622a8b0a1269944be477640eedc447bbd8487"}}, OutputType::LEGACY, {{0x8000006FUL,222},{0}});
- Check("sortedmulti(2,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/*,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0/0/*)", "sortedmulti(2,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/*,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0/0/*)", "sortedmulti(2,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/*,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0/0/*)", "sortedmulti(2,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/*,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0/0/*)", RANGE, {{"5221025d5fc65ebb8d44a5274b53bac21ff8307fec2334a32df05553459f8b1f7fe1b62102fbd47cc8034098f0e6a94c6aeee8528abf0a2153a5d8e46d325b7284c046784652ae"}, {"52210264fd4d1f5dea8ded94c61e9641309349b62f27fbffe807291f664e286bfbe6472103f4ece6dfccfa37b211eb3d0af4d0c61dba9ef698622dc17eecdf764beeb005a652ae"}, {"5221022ccabda84c30bad578b13c89eb3b9544ce149787e5b538175b1d1ba259cbb83321024d902e1a2fc7a8755ab5b694c575fce742c48d9ff192e63df5193e4c7afe1f9c52ae"}}, std::nullopt, {{0}, {1}, {2}, {0, 0, 0}, {0, 0, 1}, {0, 0, 2}});
- Check("wsh(multi(2,xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647'/0,xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*,xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))", "wsh(multi(2,xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2147483647'/0,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*,xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*'))", "wsh(multi(2,[bd16bee5/2147483647']xprv9vHkqa6XAPwKqSKSEJMcAB3yoCZhaSVsGZbSkFY5L3Lfjjk8sjZucbsbvEw5o3QrSA69nPfZDCgFnNnLhQ2ohpZuwummndnPasDw2Qr6dC2/0,xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*,xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))", "wsh(multi(2,[bd16bee5/2147483647']xpub69H7F5dQzmVd3vPuLKtcXJziMEQByuDidnX3YdwgtNsecY5HRGtAAQC5mXTt4dsv9RzyjgDjAQs9VGVV6ydYCHnprc9vvaA5YtqWyL6hyds/0,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*,xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*'))", HARDENED | RANGE | DERIVE_HARDENED, {{"0020b92623201f3bb7c3771d45b2ad1d0351ea8fbf8cfe0a0e570264e1075fa1948f"},{"002036a08bbe4923af41cf4316817c93b8d37e2f635dd25cfff06bd50df6ae7ea203"},{"0020a96e7ab4607ca6b261bfe3245ffda9c746b28d3f59e83d34820ec0e2b36c139c"}}, OutputType::BECH32, {{0xFFFFFFFFUL,0}, {1,2,0}, {1,2,1}, {1,2,2}, {10, 20, 30, 40, 0x80000000UL}, {10, 20, 30, 40, 0x80000001UL}, {10, 20, 30, 40, 0x80000002UL}});
- Check("sh(wsh(multi(16,KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy,KwGNz6YCCQtYvFzMtrC6D3tKTKdBBboMrLTsjr2NYVBwapCkn7Mr,KxogYhiNfwxuswvXV66eFyKcCpm7dZ7TqHVqujHAVUjJxyivxQ9X,L2BUNduTSyZwZjwNHynQTF14mv2uz2NRq5n5sYWTb4FkkmqgEE9f,L1okJGHGn1kFjdXHKxXjwVVtmCMR2JA5QsbKCSpSb7ReQjezKeoD,KxDCNSST75HFPaW5QKpzHtAyaCQC7p9Vo3FYfi2u4dXD1vgMiboK,L5edQjFtnkcf5UWURn6UuuoFrabgDQUHdheKCziwN42aLwS3KizU,KzF8UWFcEC7BYTq8Go1xVimMkDmyNYVmXV5PV7RuDicvAocoPB8i,L3nHUboKG2w4VSJ5jYZ5CBM97oeK6YuKvfZxrefdShECcjEYKMWZ,KyjHo36dWkYhimKmVVmQTq3gERv3pnqA4xFCpvUgbGDJad7eS8WE,KwsfyHKRUTZPQtysN7M3tZ4GXTnuov5XRgjdF2XCG8faAPmFruRF,KzCUbGhN9LJhdeFfL9zQgTJMjqxdBKEekRGZX24hXdgCNCijkkap,KzgpMBwwsDLwkaC5UrmBgCYaBD2WgZ7PBoGYXR8KT7gCA9UTN5a3,KyBXTPy4T7YG4q9tcAM3LkvfRpD1ybHMvcJ2ehaWXaSqeGUxEdkP,KzJDe9iwJRPtKP2F2AoN6zBgzS7uiuAwhWCfGdNeYJ3PC1HNJ8M8,L1xbHrxynrqLKkoYc4qtoQPx6uy5qYXR5ZDYVYBSRmCV5piU3JG9)))","sh(wsh(multi(16,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8,02da72e8b46901a65d4374fe6315538d8f368557dda3a1dcf9ea903f3afe7314c8,0318c82dd0b53fd3a932d16e0ba9e278fcc937c582d5781be626ff16e201f72286,0297ccef1ef99f9d73dec9ad37476ddb232f1238aff877af19e72ba04493361009,02e502cfd5c3f972fe9a3e2a18827820638f96b6f347e54d63deb839011fd5765d,03e687710f0e3ebe81c1037074da939d409c0025f17eb86adb9427d28f0f7ae0e9,02c04d3a5274952acdbc76987f3184b346a483d43be40874624b29e3692c1df5af,02ed06e0f418b5b43a7ec01d1d7d27290fa15f75771cb69b642a51471c29c84acd,036d46073cbb9ffee90473f3da429abc8de7f8751199da44485682a989a4bebb24,02f5d1ff7c9029a80a4e36b9a5497027ef7f3e73384a4a94fbfe7c4e9164eec8bc,02e41deffd1b7cce11cde209a781adcffdabd1b91c0ba0375857a2bfd9302419f3,02d76625f7956a7fc505ab02556c23ee72d832f1bac391bcd2d3abce5710a13d06,0399eb0a5487515802dc14544cf10b3666623762fbed2ec38a3975716e2c29c232)))", "sh(wsh(multi(16,KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy,KwGNz6YCCQtYvFzMtrC6D3tKTKdBBboMrLTsjr2NYVBwapCkn7Mr,KxogYhiNfwxuswvXV66eFyKcCpm7dZ7TqHVqujHAVUjJxyivxQ9X,L2BUNduTSyZwZjwNHynQTF14mv2uz2NRq5n5sYWTb4FkkmqgEE9f,L1okJGHGn1kFjdXHKxXjwVVtmCMR2JA5QsbKCSpSb7ReQjezKeoD,KxDCNSST75HFPaW5QKpzHtAyaCQC7p9Vo3FYfi2u4dXD1vgMiboK,L5edQjFtnkcf5UWURn6UuuoFrabgDQUHdheKCziwN42aLwS3KizU,KzF8UWFcEC7BYTq8Go1xVimMkDmyNYVmXV5PV7RuDicvAocoPB8i,L3nHUboKG2w4VSJ5jYZ5CBM97oeK6YuKvfZxrefdShECcjEYKMWZ,KyjHo36dWkYhimKmVVmQTq3gERv3pnqA4xFCpvUgbGDJad7eS8WE,KwsfyHKRUTZPQtysN7M3tZ4GXTnuov5XRgjdF2XCG8faAPmFruRF,KzCUbGhN9LJhdeFfL9zQgTJMjqxdBKEekRGZX24hXdgCNCijkkap,KzgpMBwwsDLwkaC5UrmBgCYaBD2WgZ7PBoGYXR8KT7gCA9UTN5a3,KyBXTPy4T7YG4q9tcAM3LkvfRpD1ybHMvcJ2ehaWXaSqeGUxEdkP,KzJDe9iwJRPtKP2F2AoN6zBgzS7uiuAwhWCfGdNeYJ3PC1HNJ8M8,L1xbHrxynrqLKkoYc4qtoQPx6uy5qYXR5ZDYVYBSRmCV5piU3JG9)))","sh(wsh(multi(16,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8,02da72e8b46901a65d4374fe6315538d8f368557dda3a1dcf9ea903f3afe7314c8,0318c82dd0b53fd3a932d16e0ba9e278fcc937c582d5781be626ff16e201f72286,0297ccef1ef99f9d73dec9ad37476ddb232f1238aff877af19e72ba04493361009,02e502cfd5c3f972fe9a3e2a18827820638f96b6f347e54d63deb839011fd5765d,03e687710f0e3ebe81c1037074da939d409c0025f17eb86adb9427d28f0f7ae0e9,02c04d3a5274952acdbc76987f3184b346a483d43be40874624b29e3692c1df5af,02ed06e0f418b5b43a7ec01d1d7d27290fa15f75771cb69b642a51471c29c84acd,036d46073cbb9ffee90473f3da429abc8de7f8751199da44485682a989a4bebb24,02f5d1ff7c9029a80a4e36b9a5497027ef7f3e73384a4a94fbfe7c4e9164eec8bc,02e41deffd1b7cce11cde209a781adcffdabd1b91c0ba0375857a2bfd9302419f3,02d76625f7956a7fc505ab02556c23ee72d832f1bac391bcd2d3abce5710a13d06,0399eb0a5487515802dc14544cf10b3666623762fbed2ec38a3975716e2c29c232)))", SIGNABLE, {{"a9147fc63e13dc25e8a95a3cee3d9a714ac3afd96f1e87"}}, OutputType::P2SH_SEGWIT);
- Check("tr(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,pk(KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy))", "tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,pk(669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0))", "tr(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,pk(KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy))", "tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,pk(669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0))", SIGNABLE | XONLY_KEYS, {{"512017cf18db381d836d8923b1bdb246cfcd818da1a9f0e6e7907f187f0b2f937754"}}, OutputType::BECH32M);
+ Check("multi(1,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "multi(1,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", "multi(1,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", SIGNABLE, {{"512103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea23552ae"}}, std::nullopt);
+ Check("sortedmulti(1,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "sortedmulti(1,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", "sortedmulti(1,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", SIGNABLE, {{"512103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea23552ae"}}, std::nullopt);
+ Check("sortedmulti(1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "sortedmulti(1,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "sortedmulti(1,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", SIGNABLE, {{"512103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea23552ae"}}, std::nullopt);
+ Check("sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))", DEFAULT, {{"a91445a9a622a8b0a1269944be477640eedc447bbd8487"}}, OutputType::LEGACY, {{0x8000006FUL,222},{0}});
+ Check("sortedmulti(2,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/*,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0/0/*)", "sortedmulti(2,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/*,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0/0/*)", "sortedmulti(2,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/*,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0/0/*)", RANGE, {{"5221025d5fc65ebb8d44a5274b53bac21ff8307fec2334a32df05553459f8b1f7fe1b62102fbd47cc8034098f0e6a94c6aeee8528abf0a2153a5d8e46d325b7284c046784652ae"}, {"52210264fd4d1f5dea8ded94c61e9641309349b62f27fbffe807291f664e286bfbe6472103f4ece6dfccfa37b211eb3d0af4d0c61dba9ef698622dc17eecdf764beeb005a652ae"}, {"5221022ccabda84c30bad578b13c89eb3b9544ce149787e5b538175b1d1ba259cbb83321024d902e1a2fc7a8755ab5b694c575fce742c48d9ff192e63df5193e4c7afe1f9c52ae"}}, std::nullopt, {{0}, {1}, {2}, {0, 0, 0}, {0, 0, 1}, {0, 0, 2}});
+ Check("wsh(multi(2,xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647'/0,xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*,xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))", "wsh(multi(2,xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2147483647'/0,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*,xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*'))", "wsh(multi(2,[bd16bee5/2147483647']xpub69H7F5dQzmVd3vPuLKtcXJziMEQByuDidnX3YdwgtNsecY5HRGtAAQC5mXTt4dsv9RzyjgDjAQs9VGVV6ydYCHnprc9vvaA5YtqWyL6hyds/0,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*,xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*'))", HARDENED | RANGE | DERIVE_HARDENED, {{"0020b92623201f3bb7c3771d45b2ad1d0351ea8fbf8cfe0a0e570264e1075fa1948f"},{"002036a08bbe4923af41cf4316817c93b8d37e2f635dd25cfff06bd50df6ae7ea203"},{"0020a96e7ab4607ca6b261bfe3245ffda9c746b28d3f59e83d34820ec0e2b36c139c"}}, OutputType::BECH32, {{0xFFFFFFFFUL,0}, {1,2,0}, {1,2,1}, {1,2,2}, {10, 20, 30, 40, 0x80000000UL}, {10, 20, 30, 40, 0x80000001UL}, {10, 20, 30, 40, 0x80000002UL}});
+ Check("sh(wsh(multi(16,KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy,KwGNz6YCCQtYvFzMtrC6D3tKTKdBBboMrLTsjr2NYVBwapCkn7Mr,KxogYhiNfwxuswvXV66eFyKcCpm7dZ7TqHVqujHAVUjJxyivxQ9X,L2BUNduTSyZwZjwNHynQTF14mv2uz2NRq5n5sYWTb4FkkmqgEE9f,L1okJGHGn1kFjdXHKxXjwVVtmCMR2JA5QsbKCSpSb7ReQjezKeoD,KxDCNSST75HFPaW5QKpzHtAyaCQC7p9Vo3FYfi2u4dXD1vgMiboK,L5edQjFtnkcf5UWURn6UuuoFrabgDQUHdheKCziwN42aLwS3KizU,KzF8UWFcEC7BYTq8Go1xVimMkDmyNYVmXV5PV7RuDicvAocoPB8i,L3nHUboKG2w4VSJ5jYZ5CBM97oeK6YuKvfZxrefdShECcjEYKMWZ,KyjHo36dWkYhimKmVVmQTq3gERv3pnqA4xFCpvUgbGDJad7eS8WE,KwsfyHKRUTZPQtysN7M3tZ4GXTnuov5XRgjdF2XCG8faAPmFruRF,KzCUbGhN9LJhdeFfL9zQgTJMjqxdBKEekRGZX24hXdgCNCijkkap,KzgpMBwwsDLwkaC5UrmBgCYaBD2WgZ7PBoGYXR8KT7gCA9UTN5a3,KyBXTPy4T7YG4q9tcAM3LkvfRpD1ybHMvcJ2ehaWXaSqeGUxEdkP,KzJDe9iwJRPtKP2F2AoN6zBgzS7uiuAwhWCfGdNeYJ3PC1HNJ8M8,L1xbHrxynrqLKkoYc4qtoQPx6uy5qYXR5ZDYVYBSRmCV5piU3JG9)))","sh(wsh(multi(16,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8,02da72e8b46901a65d4374fe6315538d8f368557dda3a1dcf9ea903f3afe7314c8,0318c82dd0b53fd3a932d16e0ba9e278fcc937c582d5781be626ff16e201f72286,0297ccef1ef99f9d73dec9ad37476ddb232f1238aff877af19e72ba04493361009,02e502cfd5c3f972fe9a3e2a18827820638f96b6f347e54d63deb839011fd5765d,03e687710f0e3ebe81c1037074da939d409c0025f17eb86adb9427d28f0f7ae0e9,02c04d3a5274952acdbc76987f3184b346a483d43be40874624b29e3692c1df5af,02ed06e0f418b5b43a7ec01d1d7d27290fa15f75771cb69b642a51471c29c84acd,036d46073cbb9ffee90473f3da429abc8de7f8751199da44485682a989a4bebb24,02f5d1ff7c9029a80a4e36b9a5497027ef7f3e73384a4a94fbfe7c4e9164eec8bc,02e41deffd1b7cce11cde209a781adcffdabd1b91c0ba0375857a2bfd9302419f3,02d76625f7956a7fc505ab02556c23ee72d832f1bac391bcd2d3abce5710a13d06,0399eb0a5487515802dc14544cf10b3666623762fbed2ec38a3975716e2c29c232)))", "sh(wsh(multi(16,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8,02da72e8b46901a65d4374fe6315538d8f368557dda3a1dcf9ea903f3afe7314c8,0318c82dd0b53fd3a932d16e0ba9e278fcc937c582d5781be626ff16e201f72286,0297ccef1ef99f9d73dec9ad37476ddb232f1238aff877af19e72ba04493361009,02e502cfd5c3f972fe9a3e2a18827820638f96b6f347e54d63deb839011fd5765d,03e687710f0e3ebe81c1037074da939d409c0025f17eb86adb9427d28f0f7ae0e9,02c04d3a5274952acdbc76987f3184b346a483d43be40874624b29e3692c1df5af,02ed06e0f418b5b43a7ec01d1d7d27290fa15f75771cb69b642a51471c29c84acd,036d46073cbb9ffee90473f3da429abc8de7f8751199da44485682a989a4bebb24,02f5d1ff7c9029a80a4e36b9a5497027ef7f3e73384a4a94fbfe7c4e9164eec8bc,02e41deffd1b7cce11cde209a781adcffdabd1b91c0ba0375857a2bfd9302419f3,02d76625f7956a7fc505ab02556c23ee72d832f1bac391bcd2d3abce5710a13d06,0399eb0a5487515802dc14544cf10b3666623762fbed2ec38a3975716e2c29c232)))", SIGNABLE, {{"a9147fc63e13dc25e8a95a3cee3d9a714ac3afd96f1e87"}}, OutputType::P2SH_SEGWIT);
+ Check("tr(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,pk(KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy))", "tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,pk(669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0))", "tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,pk(669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0))", SIGNABLE | XONLY_KEYS, {{"512017cf18db381d836d8923b1bdb246cfcd818da1a9f0e6e7907f187f0b2f937754"}}, OutputType::BECH32M);
CheckUnparsable("sh(multi(16,KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy,KwGNz6YCCQtYvFzMtrC6D3tKTKdBBboMrLTsjr2NYVBwapCkn7Mr,KxogYhiNfwxuswvXV66eFyKcCpm7dZ7TqHVqujHAVUjJxyivxQ9X,L2BUNduTSyZwZjwNHynQTF14mv2uz2NRq5n5sYWTb4FkkmqgEE9f,L1okJGHGn1kFjdXHKxXjwVVtmCMR2JA5QsbKCSpSb7ReQjezKeoD,KxDCNSST75HFPaW5QKpzHtAyaCQC7p9Vo3FYfi2u4dXD1vgMiboK,L5edQjFtnkcf5UWURn6UuuoFrabgDQUHdheKCziwN42aLwS3KizU,KzF8UWFcEC7BYTq8Go1xVimMkDmyNYVmXV5PV7RuDicvAocoPB8i,L3nHUboKG2w4VSJ5jYZ5CBM97oeK6YuKvfZxrefdShECcjEYKMWZ,KyjHo36dWkYhimKmVVmQTq3gERv3pnqA4xFCpvUgbGDJad7eS8WE,KwsfyHKRUTZPQtysN7M3tZ4GXTnuov5XRgjdF2XCG8faAPmFruRF,KzCUbGhN9LJhdeFfL9zQgTJMjqxdBKEekRGZX24hXdgCNCijkkap,KzgpMBwwsDLwkaC5UrmBgCYaBD2WgZ7PBoGYXR8KT7gCA9UTN5a3,KyBXTPy4T7YG4q9tcAM3LkvfRpD1ybHMvcJ2ehaWXaSqeGUxEdkP,KzJDe9iwJRPtKP2F2AoN6zBgzS7uiuAwhWCfGdNeYJ3PC1HNJ8M8,L1xbHrxynrqLKkoYc4qtoQPx6uy5qYXR5ZDYVYBSRmCV5piU3JG9))","sh(multi(16,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8,02da72e8b46901a65d4374fe6315538d8f368557dda3a1dcf9ea903f3afe7314c8,0318c82dd0b53fd3a932d16e0ba9e278fcc937c582d5781be626ff16e201f72286,0297ccef1ef99f9d73dec9ad37476ddb232f1238aff877af19e72ba04493361009,02e502cfd5c3f972fe9a3e2a18827820638f96b6f347e54d63deb839011fd5765d,03e687710f0e3ebe81c1037074da939d409c0025f17eb86adb9427d28f0f7ae0e9,02c04d3a5274952acdbc76987f3184b346a483d43be40874624b29e3692c1df5af,02ed06e0f418b5b43a7ec01d1d7d27290fa15f75771cb69b642a51471c29c84acd,036d46073cbb9ffee90473f3da429abc8de7f8751199da44485682a989a4bebb24,02f5d1ff7c9029a80a4e36b9a5497027ef7f3e73384a4a94fbfe7c4e9164eec8bc,02e41deffd1b7cce11cde209a781adcffdabd1b91c0ba0375857a2bfd9302419f3,02d76625f7956a7fc505ab02556c23ee72d832f1bac391bcd2d3abce5710a13d06,0399eb0a5487515802dc14544cf10b3666623762fbed2ec38a3975716e2c29c232))", "P2SH script is too large, 547 bytes is larger than 520 bytes"); // P2SH does not fit 16 compressed pubkeys in a redeemscript
CheckUnparsable("wsh(multi(2,[aaaaaaaa][aaaaaaaa]xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647'/0,xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*,xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))", "wsh(multi(2,[aaaaaaaa][aaaaaaaa]xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2147483647'/0,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*,xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*'))", "Multi: Multiple ']' characters found for a single pubkey"); // Double key origin descriptor
CheckUnparsable("wsh(multi(2,[aaaagaaa]xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647'/0,xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*,xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))", "wsh(multi(2,[aaagaaaa]xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2147483647'/0,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*,xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*'))", "Multi: Fingerprint 'aaagaaaa' is not hex"); // Non hex fingerprint
@@ -438,8 +439,8 @@ BOOST_AUTO_TEST_CASE(descriptor_test)
CheckUnparsable("multi(3,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "multi(3,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", "Multisig threshold cannot be larger than the number of keys; threshold is 3 but only 2 keys specified"); // Threshold larger than number of keys
CheckUnparsable("multi(3,KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy,KwGNz6YCCQtYvFzMtrC6D3tKTKdBBboMrLTsjr2NYVBwapCkn7Mr,KxogYhiNfwxuswvXV66eFyKcCpm7dZ7TqHVqujHAVUjJxyivxQ9X,L2BUNduTSyZwZjwNHynQTF14mv2uz2NRq5n5sYWTb4FkkmqgEE9f)", "multi(3,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8)", "Cannot have 4 pubkeys in bare multisig; only at most 3 pubkeys"); // Threshold larger than number of keys
CheckUnparsable("sh(multi(16,KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy,KwGNz6YCCQtYvFzMtrC6D3tKTKdBBboMrLTsjr2NYVBwapCkn7Mr,KxogYhiNfwxuswvXV66eFyKcCpm7dZ7TqHVqujHAVUjJxyivxQ9X,L2BUNduTSyZwZjwNHynQTF14mv2uz2NRq5n5sYWTb4FkkmqgEE9f,L1okJGHGn1kFjdXHKxXjwVVtmCMR2JA5QsbKCSpSb7ReQjezKeoD,KxDCNSST75HFPaW5QKpzHtAyaCQC7p9Vo3FYfi2u4dXD1vgMiboK,L5edQjFtnkcf5UWURn6UuuoFrabgDQUHdheKCziwN42aLwS3KizU,KzF8UWFcEC7BYTq8Go1xVimMkDmyNYVmXV5PV7RuDicvAocoPB8i,L3nHUboKG2w4VSJ5jYZ5CBM97oeK6YuKvfZxrefdShECcjEYKMWZ,KyjHo36dWkYhimKmVVmQTq3gERv3pnqA4xFCpvUgbGDJad7eS8WE,KwsfyHKRUTZPQtysN7M3tZ4GXTnuov5XRgjdF2XCG8faAPmFruRF,KzCUbGhN9LJhdeFfL9zQgTJMjqxdBKEekRGZX24hXdgCNCijkkap,KzgpMBwwsDLwkaC5UrmBgCYaBD2WgZ7PBoGYXR8KT7gCA9UTN5a3,KyBXTPy4T7YG4q9tcAM3LkvfRpD1ybHMvcJ2ehaWXaSqeGUxEdkP,KzJDe9iwJRPtKP2F2AoN6zBgzS7uiuAwhWCfGdNeYJ3PC1HNJ8M8,L1xbHrxynrqLKkoYc4qtoQPx6uy5qYXR5ZDYVYBSRmCV5piU3JG9,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))","sh(multi(16,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8,02da72e8b46901a65d4374fe6315538d8f368557dda3a1dcf9ea903f3afe7314c8,0318c82dd0b53fd3a932d16e0ba9e278fcc937c582d5781be626ff16e201f72286,0297ccef1ef99f9d73dec9ad37476ddb232f1238aff877af19e72ba04493361009,02e502cfd5c3f972fe9a3e2a18827820638f96b6f347e54d63deb839011fd5765d,03e687710f0e3ebe81c1037074da939d409c0025f17eb86adb9427d28f0f7ae0e9,02c04d3a5274952acdbc76987f3184b346a483d43be40874624b29e3692c1df5af,02ed06e0f418b5b43a7ec01d1d7d27290fa15f75771cb69b642a51471c29c84acd,036d46073cbb9ffee90473f3da429abc8de7f8751199da44485682a989a4bebb24,02f5d1ff7c9029a80a4e36b9a5497027ef7f3e73384a4a94fbfe7c4e9164eec8bc,02e41deffd1b7cce11cde209a781adcffdabd1b91c0ba0375857a2bfd9302419f3,02d76625f7956a7fc505ab02556c23ee72d832f1bac391bcd2d3abce5710a13d06,0399eb0a5487515802dc14544cf10b3666623762fbed2ec38a3975716e2c29c232,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", "P2SH script is too large, 581 bytes is larger than 520 bytes"); // Cannot have more than 15 keys in a P2SH multisig, or we exceed maximum push size
- Check("wsh(multi(20,KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy,KwGNz6YCCQtYvFzMtrC6D3tKTKdBBboMrLTsjr2NYVBwapCkn7Mr,KxogYhiNfwxuswvXV66eFyKcCpm7dZ7TqHVqujHAVUjJxyivxQ9X,L2BUNduTSyZwZjwNHynQTF14mv2uz2NRq5n5sYWTb4FkkmqgEE9f,L1okJGHGn1kFjdXHKxXjwVVtmCMR2JA5QsbKCSpSb7ReQjezKeoD,KxDCNSST75HFPaW5QKpzHtAyaCQC7p9Vo3FYfi2u4dXD1vgMiboK,L5edQjFtnkcf5UWURn6UuuoFrabgDQUHdheKCziwN42aLwS3KizU,KzF8UWFcEC7BYTq8Go1xVimMkDmyNYVmXV5PV7RuDicvAocoPB8i,L3nHUboKG2w4VSJ5jYZ5CBM97oeK6YuKvfZxrefdShECcjEYKMWZ,KyjHo36dWkYhimKmVVmQTq3gERv3pnqA4xFCpvUgbGDJad7eS8WE,KwsfyHKRUTZPQtysN7M3tZ4GXTnuov5XRgjdF2XCG8faAPmFruRF,KzCUbGhN9LJhdeFfL9zQgTJMjqxdBKEekRGZX24hXdgCNCijkkap,KzgpMBwwsDLwkaC5UrmBgCYaBD2WgZ7PBoGYXR8KT7gCA9UTN5a3,KyBXTPy4T7YG4q9tcAM3LkvfRpD1ybHMvcJ2ehaWXaSqeGUxEdkP,KzJDe9iwJRPtKP2F2AoN6zBgzS7uiuAwhWCfGdNeYJ3PC1HNJ8M8,L1xbHrxynrqLKkoYc4qtoQPx6uy5qYXR5ZDYVYBSRmCV5piU3JG9,KzRedjSwMggebB3VufhbzpYJnvHfHe9kPJSjCU5QpJdAW3NSZxYS,Kyjtp5858xL7JfeV4PNRCKy2t6XvgqNNepArGY9F9F1SSPqNEMs3,L2D4RLHPiHBidkHS8ftx11jJk1hGFELvxh8LoxNQheaGT58dKenW,KyLPZdwY4td98bKkXqEXTEBX3vwEYTQo1yyLjX2jKXA63GBpmSjv))","wsh(multi(20,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8,02da72e8b46901a65d4374fe6315538d8f368557dda3a1dcf9ea903f3afe7314c8,0318c82dd0b53fd3a932d16e0ba9e278fcc937c582d5781be626ff16e201f72286,0297ccef1ef99f9d73dec9ad37476ddb232f1238aff877af19e72ba04493361009,02e502cfd5c3f972fe9a3e2a18827820638f96b6f347e54d63deb839011fd5765d,03e687710f0e3ebe81c1037074da939d409c0025f17eb86adb9427d28f0f7ae0e9,02c04d3a5274952acdbc76987f3184b346a483d43be40874624b29e3692c1df5af,02ed06e0f418b5b43a7ec01d1d7d27290fa15f75771cb69b642a51471c29c84acd,036d46073cbb9ffee90473f3da429abc8de7f8751199da44485682a989a4bebb24,02f5d1ff7c9029a80a4e36b9a5497027ef7f3e73384a4a94fbfe7c4e9164eec8bc,02e41deffd1b7cce11cde209a781adcffdabd1b91c0ba0375857a2bfd9302419f3,02d76625f7956a7fc505ab02556c23ee72d832f1bac391bcd2d3abce5710a13d06,0399eb0a5487515802dc14544cf10b3666623762fbed2ec38a3975716e2c29c232,02bc2feaa536991d269aae46abb8f3772a5b3ad592314945e51543e7da84c4af6e,0318bf32e5217c1eb771a6d5ce1cd39395dff7ff665704f175c9a5451d95a2f2ca,02c681a6243f16208c2004bb81f5a8a67edfdd3e3711534eadeec3dcf0b010c759,0249fdd6b69768b8d84b4893f8ff84b36835c50183de20fcae8f366a45290d01fd))", "wsh(multi(20,KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy,KwGNz6YCCQtYvFzMtrC6D3tKTKdBBboMrLTsjr2NYVBwapCkn7Mr,KxogYhiNfwxuswvXV66eFyKcCpm7dZ7TqHVqujHAVUjJxyivxQ9X,L2BUNduTSyZwZjwNHynQTF14mv2uz2NRq5n5sYWTb4FkkmqgEE9f,L1okJGHGn1kFjdXHKxXjwVVtmCMR2JA5QsbKCSpSb7ReQjezKeoD,KxDCNSST75HFPaW5QKpzHtAyaCQC7p9Vo3FYfi2u4dXD1vgMiboK,L5edQjFtnkcf5UWURn6UuuoFrabgDQUHdheKCziwN42aLwS3KizU,KzF8UWFcEC7BYTq8Go1xVimMkDmyNYVmXV5PV7RuDicvAocoPB8i,L3nHUboKG2w4VSJ5jYZ5CBM97oeK6YuKvfZxrefdShECcjEYKMWZ,KyjHo36dWkYhimKmVVmQTq3gERv3pnqA4xFCpvUgbGDJad7eS8WE,KwsfyHKRUTZPQtysN7M3tZ4GXTnuov5XRgjdF2XCG8faAPmFruRF,KzCUbGhN9LJhdeFfL9zQgTJMjqxdBKEekRGZX24hXdgCNCijkkap,KzgpMBwwsDLwkaC5UrmBgCYaBD2WgZ7PBoGYXR8KT7gCA9UTN5a3,KyBXTPy4T7YG4q9tcAM3LkvfRpD1ybHMvcJ2ehaWXaSqeGUxEdkP,KzJDe9iwJRPtKP2F2AoN6zBgzS7uiuAwhWCfGdNeYJ3PC1HNJ8M8,L1xbHrxynrqLKkoYc4qtoQPx6uy5qYXR5ZDYVYBSRmCV5piU3JG9,KzRedjSwMggebB3VufhbzpYJnvHfHe9kPJSjCU5QpJdAW3NSZxYS,Kyjtp5858xL7JfeV4PNRCKy2t6XvgqNNepArGY9F9F1SSPqNEMs3,L2D4RLHPiHBidkHS8ftx11jJk1hGFELvxh8LoxNQheaGT58dKenW,KyLPZdwY4td98bKkXqEXTEBX3vwEYTQo1yyLjX2jKXA63GBpmSjv))","wsh(multi(20,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8,02da72e8b46901a65d4374fe6315538d8f368557dda3a1dcf9ea903f3afe7314c8,0318c82dd0b53fd3a932d16e0ba9e278fcc937c582d5781be626ff16e201f72286,0297ccef1ef99f9d73dec9ad37476ddb232f1238aff877af19e72ba04493361009,02e502cfd5c3f972fe9a3e2a18827820638f96b6f347e54d63deb839011fd5765d,03e687710f0e3ebe81c1037074da939d409c0025f17eb86adb9427d28f0f7ae0e9,02c04d3a5274952acdbc76987f3184b346a483d43be40874624b29e3692c1df5af,02ed06e0f418b5b43a7ec01d1d7d27290fa15f75771cb69b642a51471c29c84acd,036d46073cbb9ffee90473f3da429abc8de7f8751199da44485682a989a4bebb24,02f5d1ff7c9029a80a4e36b9a5497027ef7f3e73384a4a94fbfe7c4e9164eec8bc,02e41deffd1b7cce11cde209a781adcffdabd1b91c0ba0375857a2bfd9302419f3,02d76625f7956a7fc505ab02556c23ee72d832f1bac391bcd2d3abce5710a13d06,0399eb0a5487515802dc14544cf10b3666623762fbed2ec38a3975716e2c29c232,02bc2feaa536991d269aae46abb8f3772a5b3ad592314945e51543e7da84c4af6e,0318bf32e5217c1eb771a6d5ce1cd39395dff7ff665704f175c9a5451d95a2f2ca,02c681a6243f16208c2004bb81f5a8a67edfdd3e3711534eadeec3dcf0b010c759,0249fdd6b69768b8d84b4893f8ff84b36835c50183de20fcae8f366a45290d01fd))", SIGNABLE, {{"0020376bd8344b8b6ebe504ff85ef743eaa1aa9272178223bcb6887e9378efb341ac"}}, OutputType::BECH32); // In P2WSH we can have up to 20 keys
-Check("sh(wsh(multi(20,KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy,KwGNz6YCCQtYvFzMtrC6D3tKTKdBBboMrLTsjr2NYVBwapCkn7Mr,KxogYhiNfwxuswvXV66eFyKcCpm7dZ7TqHVqujHAVUjJxyivxQ9X,L2BUNduTSyZwZjwNHynQTF14mv2uz2NRq5n5sYWTb4FkkmqgEE9f,L1okJGHGn1kFjdXHKxXjwVVtmCMR2JA5QsbKCSpSb7ReQjezKeoD,KxDCNSST75HFPaW5QKpzHtAyaCQC7p9Vo3FYfi2u4dXD1vgMiboK,L5edQjFtnkcf5UWURn6UuuoFrabgDQUHdheKCziwN42aLwS3KizU,KzF8UWFcEC7BYTq8Go1xVimMkDmyNYVmXV5PV7RuDicvAocoPB8i,L3nHUboKG2w4VSJ5jYZ5CBM97oeK6YuKvfZxrefdShECcjEYKMWZ,KyjHo36dWkYhimKmVVmQTq3gERv3pnqA4xFCpvUgbGDJad7eS8WE,KwsfyHKRUTZPQtysN7M3tZ4GXTnuov5XRgjdF2XCG8faAPmFruRF,KzCUbGhN9LJhdeFfL9zQgTJMjqxdBKEekRGZX24hXdgCNCijkkap,KzgpMBwwsDLwkaC5UrmBgCYaBD2WgZ7PBoGYXR8KT7gCA9UTN5a3,KyBXTPy4T7YG4q9tcAM3LkvfRpD1ybHMvcJ2ehaWXaSqeGUxEdkP,KzJDe9iwJRPtKP2F2AoN6zBgzS7uiuAwhWCfGdNeYJ3PC1HNJ8M8,L1xbHrxynrqLKkoYc4qtoQPx6uy5qYXR5ZDYVYBSRmCV5piU3JG9,KzRedjSwMggebB3VufhbzpYJnvHfHe9kPJSjCU5QpJdAW3NSZxYS,Kyjtp5858xL7JfeV4PNRCKy2t6XvgqNNepArGY9F9F1SSPqNEMs3,L2D4RLHPiHBidkHS8ftx11jJk1hGFELvxh8LoxNQheaGT58dKenW,KyLPZdwY4td98bKkXqEXTEBX3vwEYTQo1yyLjX2jKXA63GBpmSjv)))","sh(wsh(multi(20,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8,02da72e8b46901a65d4374fe6315538d8f368557dda3a1dcf9ea903f3afe7314c8,0318c82dd0b53fd3a932d16e0ba9e278fcc937c582d5781be626ff16e201f72286,0297ccef1ef99f9d73dec9ad37476ddb232f1238aff877af19e72ba04493361009,02e502cfd5c3f972fe9a3e2a18827820638f96b6f347e54d63deb839011fd5765d,03e687710f0e3ebe81c1037074da939d409c0025f17eb86adb9427d28f0f7ae0e9,02c04d3a5274952acdbc76987f3184b346a483d43be40874624b29e3692c1df5af,02ed06e0f418b5b43a7ec01d1d7d27290fa15f75771cb69b642a51471c29c84acd,036d46073cbb9ffee90473f3da429abc8de7f8751199da44485682a989a4bebb24,02f5d1ff7c9029a80a4e36b9a5497027ef7f3e73384a4a94fbfe7c4e9164eec8bc,02e41deffd1b7cce11cde209a781adcffdabd1b91c0ba0375857a2bfd9302419f3,02d76625f7956a7fc505ab02556c23ee72d832f1bac391bcd2d3abce5710a13d06,0399eb0a5487515802dc14544cf10b3666623762fbed2ec38a3975716e2c29c232,02bc2feaa536991d269aae46abb8f3772a5b3ad592314945e51543e7da84c4af6e,0318bf32e5217c1eb771a6d5ce1cd39395dff7ff665704f175c9a5451d95a2f2ca,02c681a6243f16208c2004bb81f5a8a67edfdd3e3711534eadeec3dcf0b010c759,0249fdd6b69768b8d84b4893f8ff84b36835c50183de20fcae8f366a45290d01fd)))", "sh(wsh(multi(20,KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy,KwGNz6YCCQtYvFzMtrC6D3tKTKdBBboMrLTsjr2NYVBwapCkn7Mr,KxogYhiNfwxuswvXV66eFyKcCpm7dZ7TqHVqujHAVUjJxyivxQ9X,L2BUNduTSyZwZjwNHynQTF14mv2uz2NRq5n5sYWTb4FkkmqgEE9f,L1okJGHGn1kFjdXHKxXjwVVtmCMR2JA5QsbKCSpSb7ReQjezKeoD,KxDCNSST75HFPaW5QKpzHtAyaCQC7p9Vo3FYfi2u4dXD1vgMiboK,L5edQjFtnkcf5UWURn6UuuoFrabgDQUHdheKCziwN42aLwS3KizU,KzF8UWFcEC7BYTq8Go1xVimMkDmyNYVmXV5PV7RuDicvAocoPB8i,L3nHUboKG2w4VSJ5jYZ5CBM97oeK6YuKvfZxrefdShECcjEYKMWZ,KyjHo36dWkYhimKmVVmQTq3gERv3pnqA4xFCpvUgbGDJad7eS8WE,KwsfyHKRUTZPQtysN7M3tZ4GXTnuov5XRgjdF2XCG8faAPmFruRF,KzCUbGhN9LJhdeFfL9zQgTJMjqxdBKEekRGZX24hXdgCNCijkkap,KzgpMBwwsDLwkaC5UrmBgCYaBD2WgZ7PBoGYXR8KT7gCA9UTN5a3,KyBXTPy4T7YG4q9tcAM3LkvfRpD1ybHMvcJ2ehaWXaSqeGUxEdkP,KzJDe9iwJRPtKP2F2AoN6zBgzS7uiuAwhWCfGdNeYJ3PC1HNJ8M8,L1xbHrxynrqLKkoYc4qtoQPx6uy5qYXR5ZDYVYBSRmCV5piU3JG9,KzRedjSwMggebB3VufhbzpYJnvHfHe9kPJSjCU5QpJdAW3NSZxYS,Kyjtp5858xL7JfeV4PNRCKy2t6XvgqNNepArGY9F9F1SSPqNEMs3,L2D4RLHPiHBidkHS8ftx11jJk1hGFELvxh8LoxNQheaGT58dKenW,KyLPZdwY4td98bKkXqEXTEBX3vwEYTQo1yyLjX2jKXA63GBpmSjv)))","sh(wsh(multi(20,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8,02da72e8b46901a65d4374fe6315538d8f368557dda3a1dcf9ea903f3afe7314c8,0318c82dd0b53fd3a932d16e0ba9e278fcc937c582d5781be626ff16e201f72286,0297ccef1ef99f9d73dec9ad37476ddb232f1238aff877af19e72ba04493361009,02e502cfd5c3f972fe9a3e2a18827820638f96b6f347e54d63deb839011fd5765d,03e687710f0e3ebe81c1037074da939d409c0025f17eb86adb9427d28f0f7ae0e9,02c04d3a5274952acdbc76987f3184b346a483d43be40874624b29e3692c1df5af,02ed06e0f418b5b43a7ec01d1d7d27290fa15f75771cb69b642a51471c29c84acd,036d46073cbb9ffee90473f3da429abc8de7f8751199da44485682a989a4bebb24,02f5d1ff7c9029a80a4e36b9a5497027ef7f3e73384a4a94fbfe7c4e9164eec8bc,02e41deffd1b7cce11cde209a781adcffdabd1b91c0ba0375857a2bfd9302419f3,02d76625f7956a7fc505ab02556c23ee72d832f1bac391bcd2d3abce5710a13d06,0399eb0a5487515802dc14544cf10b3666623762fbed2ec38a3975716e2c29c232,02bc2feaa536991d269aae46abb8f3772a5b3ad592314945e51543e7da84c4af6e,0318bf32e5217c1eb771a6d5ce1cd39395dff7ff665704f175c9a5451d95a2f2ca,02c681a6243f16208c2004bb81f5a8a67edfdd3e3711534eadeec3dcf0b010c759,0249fdd6b69768b8d84b4893f8ff84b36835c50183de20fcae8f366a45290d01fd)))", SIGNABLE, {{"a914c2c9c510e9d7f92fd6131e94803a8d34a8ef675e87"}}, OutputType::P2SH_SEGWIT); // Even if it's wrapped into P2SH
+ Check("wsh(multi(20,KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy,KwGNz6YCCQtYvFzMtrC6D3tKTKdBBboMrLTsjr2NYVBwapCkn7Mr,KxogYhiNfwxuswvXV66eFyKcCpm7dZ7TqHVqujHAVUjJxyivxQ9X,L2BUNduTSyZwZjwNHynQTF14mv2uz2NRq5n5sYWTb4FkkmqgEE9f,L1okJGHGn1kFjdXHKxXjwVVtmCMR2JA5QsbKCSpSb7ReQjezKeoD,KxDCNSST75HFPaW5QKpzHtAyaCQC7p9Vo3FYfi2u4dXD1vgMiboK,L5edQjFtnkcf5UWURn6UuuoFrabgDQUHdheKCziwN42aLwS3KizU,KzF8UWFcEC7BYTq8Go1xVimMkDmyNYVmXV5PV7RuDicvAocoPB8i,L3nHUboKG2w4VSJ5jYZ5CBM97oeK6YuKvfZxrefdShECcjEYKMWZ,KyjHo36dWkYhimKmVVmQTq3gERv3pnqA4xFCpvUgbGDJad7eS8WE,KwsfyHKRUTZPQtysN7M3tZ4GXTnuov5XRgjdF2XCG8faAPmFruRF,KzCUbGhN9LJhdeFfL9zQgTJMjqxdBKEekRGZX24hXdgCNCijkkap,KzgpMBwwsDLwkaC5UrmBgCYaBD2WgZ7PBoGYXR8KT7gCA9UTN5a3,KyBXTPy4T7YG4q9tcAM3LkvfRpD1ybHMvcJ2ehaWXaSqeGUxEdkP,KzJDe9iwJRPtKP2F2AoN6zBgzS7uiuAwhWCfGdNeYJ3PC1HNJ8M8,L1xbHrxynrqLKkoYc4qtoQPx6uy5qYXR5ZDYVYBSRmCV5piU3JG9,KzRedjSwMggebB3VufhbzpYJnvHfHe9kPJSjCU5QpJdAW3NSZxYS,Kyjtp5858xL7JfeV4PNRCKy2t6XvgqNNepArGY9F9F1SSPqNEMs3,L2D4RLHPiHBidkHS8ftx11jJk1hGFELvxh8LoxNQheaGT58dKenW,KyLPZdwY4td98bKkXqEXTEBX3vwEYTQo1yyLjX2jKXA63GBpmSjv))","wsh(multi(20,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8,02da72e8b46901a65d4374fe6315538d8f368557dda3a1dcf9ea903f3afe7314c8,0318c82dd0b53fd3a932d16e0ba9e278fcc937c582d5781be626ff16e201f72286,0297ccef1ef99f9d73dec9ad37476ddb232f1238aff877af19e72ba04493361009,02e502cfd5c3f972fe9a3e2a18827820638f96b6f347e54d63deb839011fd5765d,03e687710f0e3ebe81c1037074da939d409c0025f17eb86adb9427d28f0f7ae0e9,02c04d3a5274952acdbc76987f3184b346a483d43be40874624b29e3692c1df5af,02ed06e0f418b5b43a7ec01d1d7d27290fa15f75771cb69b642a51471c29c84acd,036d46073cbb9ffee90473f3da429abc8de7f8751199da44485682a989a4bebb24,02f5d1ff7c9029a80a4e36b9a5497027ef7f3e73384a4a94fbfe7c4e9164eec8bc,02e41deffd1b7cce11cde209a781adcffdabd1b91c0ba0375857a2bfd9302419f3,02d76625f7956a7fc505ab02556c23ee72d832f1bac391bcd2d3abce5710a13d06,0399eb0a5487515802dc14544cf10b3666623762fbed2ec38a3975716e2c29c232,02bc2feaa536991d269aae46abb8f3772a5b3ad592314945e51543e7da84c4af6e,0318bf32e5217c1eb771a6d5ce1cd39395dff7ff665704f175c9a5451d95a2f2ca,02c681a6243f16208c2004bb81f5a8a67edfdd3e3711534eadeec3dcf0b010c759,0249fdd6b69768b8d84b4893f8ff84b36835c50183de20fcae8f366a45290d01fd))", "wsh(multi(20,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8,02da72e8b46901a65d4374fe6315538d8f368557dda3a1dcf9ea903f3afe7314c8,0318c82dd0b53fd3a932d16e0ba9e278fcc937c582d5781be626ff16e201f72286,0297ccef1ef99f9d73dec9ad37476ddb232f1238aff877af19e72ba04493361009,02e502cfd5c3f972fe9a3e2a18827820638f96b6f347e54d63deb839011fd5765d,03e687710f0e3ebe81c1037074da939d409c0025f17eb86adb9427d28f0f7ae0e9,02c04d3a5274952acdbc76987f3184b346a483d43be40874624b29e3692c1df5af,02ed06e0f418b5b43a7ec01d1d7d27290fa15f75771cb69b642a51471c29c84acd,036d46073cbb9ffee90473f3da429abc8de7f8751199da44485682a989a4bebb24,02f5d1ff7c9029a80a4e36b9a5497027ef7f3e73384a4a94fbfe7c4e9164eec8bc,02e41deffd1b7cce11cde209a781adcffdabd1b91c0ba0375857a2bfd9302419f3,02d76625f7956a7fc505ab02556c23ee72d832f1bac391bcd2d3abce5710a13d06,0399eb0a5487515802dc14544cf10b3666623762fbed2ec38a3975716e2c29c232,02bc2feaa536991d269aae46abb8f3772a5b3ad592314945e51543e7da84c4af6e,0318bf32e5217c1eb771a6d5ce1cd39395dff7ff665704f175c9a5451d95a2f2ca,02c681a6243f16208c2004bb81f5a8a67edfdd3e3711534eadeec3dcf0b010c759,0249fdd6b69768b8d84b4893f8ff84b36835c50183de20fcae8f366a45290d01fd))", SIGNABLE, {{"0020376bd8344b8b6ebe504ff85ef743eaa1aa9272178223bcb6887e9378efb341ac"}}, OutputType::BECH32); // In P2WSH we can have up to 20 keys
+ Check("sh(wsh(multi(20,KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy,KwGNz6YCCQtYvFzMtrC6D3tKTKdBBboMrLTsjr2NYVBwapCkn7Mr,KxogYhiNfwxuswvXV66eFyKcCpm7dZ7TqHVqujHAVUjJxyivxQ9X,L2BUNduTSyZwZjwNHynQTF14mv2uz2NRq5n5sYWTb4FkkmqgEE9f,L1okJGHGn1kFjdXHKxXjwVVtmCMR2JA5QsbKCSpSb7ReQjezKeoD,KxDCNSST75HFPaW5QKpzHtAyaCQC7p9Vo3FYfi2u4dXD1vgMiboK,L5edQjFtnkcf5UWURn6UuuoFrabgDQUHdheKCziwN42aLwS3KizU,KzF8UWFcEC7BYTq8Go1xVimMkDmyNYVmXV5PV7RuDicvAocoPB8i,L3nHUboKG2w4VSJ5jYZ5CBM97oeK6YuKvfZxrefdShECcjEYKMWZ,KyjHo36dWkYhimKmVVmQTq3gERv3pnqA4xFCpvUgbGDJad7eS8WE,KwsfyHKRUTZPQtysN7M3tZ4GXTnuov5XRgjdF2XCG8faAPmFruRF,KzCUbGhN9LJhdeFfL9zQgTJMjqxdBKEekRGZX24hXdgCNCijkkap,KzgpMBwwsDLwkaC5UrmBgCYaBD2WgZ7PBoGYXR8KT7gCA9UTN5a3,KyBXTPy4T7YG4q9tcAM3LkvfRpD1ybHMvcJ2ehaWXaSqeGUxEdkP,KzJDe9iwJRPtKP2F2AoN6zBgzS7uiuAwhWCfGdNeYJ3PC1HNJ8M8,L1xbHrxynrqLKkoYc4qtoQPx6uy5qYXR5ZDYVYBSRmCV5piU3JG9,KzRedjSwMggebB3VufhbzpYJnvHfHe9kPJSjCU5QpJdAW3NSZxYS,Kyjtp5858xL7JfeV4PNRCKy2t6XvgqNNepArGY9F9F1SSPqNEMs3,L2D4RLHPiHBidkHS8ftx11jJk1hGFELvxh8LoxNQheaGT58dKenW,KyLPZdwY4td98bKkXqEXTEBX3vwEYTQo1yyLjX2jKXA63GBpmSjv)))","sh(wsh(multi(20,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8,02da72e8b46901a65d4374fe6315538d8f368557dda3a1dcf9ea903f3afe7314c8,0318c82dd0b53fd3a932d16e0ba9e278fcc937c582d5781be626ff16e201f72286,0297ccef1ef99f9d73dec9ad37476ddb232f1238aff877af19e72ba04493361009,02e502cfd5c3f972fe9a3e2a18827820638f96b6f347e54d63deb839011fd5765d,03e687710f0e3ebe81c1037074da939d409c0025f17eb86adb9427d28f0f7ae0e9,02c04d3a5274952acdbc76987f3184b346a483d43be40874624b29e3692c1df5af,02ed06e0f418b5b43a7ec01d1d7d27290fa15f75771cb69b642a51471c29c84acd,036d46073cbb9ffee90473f3da429abc8de7f8751199da44485682a989a4bebb24,02f5d1ff7c9029a80a4e36b9a5497027ef7f3e73384a4a94fbfe7c4e9164eec8bc,02e41deffd1b7cce11cde209a781adcffdabd1b91c0ba0375857a2bfd9302419f3,02d76625f7956a7fc505ab02556c23ee72d832f1bac391bcd2d3abce5710a13d06,0399eb0a5487515802dc14544cf10b3666623762fbed2ec38a3975716e2c29c232,02bc2feaa536991d269aae46abb8f3772a5b3ad592314945e51543e7da84c4af6e,0318bf32e5217c1eb771a6d5ce1cd39395dff7ff665704f175c9a5451d95a2f2ca,02c681a6243f16208c2004bb81f5a8a67edfdd3e3711534eadeec3dcf0b010c759,0249fdd6b69768b8d84b4893f8ff84b36835c50183de20fcae8f366a45290d01fd)))", "sh(wsh(multi(20,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8,02da72e8b46901a65d4374fe6315538d8f368557dda3a1dcf9ea903f3afe7314c8,0318c82dd0b53fd3a932d16e0ba9e278fcc937c582d5781be626ff16e201f72286,0297ccef1ef99f9d73dec9ad37476ddb232f1238aff877af19e72ba04493361009,02e502cfd5c3f972fe9a3e2a18827820638f96b6f347e54d63deb839011fd5765d,03e687710f0e3ebe81c1037074da939d409c0025f17eb86adb9427d28f0f7ae0e9,02c04d3a5274952acdbc76987f3184b346a483d43be40874624b29e3692c1df5af,02ed06e0f418b5b43a7ec01d1d7d27290fa15f75771cb69b642a51471c29c84acd,036d46073cbb9ffee90473f3da429abc8de7f8751199da44485682a989a4bebb24,02f5d1ff7c9029a80a4e36b9a5497027ef7f3e73384a4a94fbfe7c4e9164eec8bc,02e41deffd1b7cce11cde209a781adcffdabd1b91c0ba0375857a2bfd9302419f3,02d76625f7956a7fc505ab02556c23ee72d832f1bac391bcd2d3abce5710a13d06,0399eb0a5487515802dc14544cf10b3666623762fbed2ec38a3975716e2c29c232,02bc2feaa536991d269aae46abb8f3772a5b3ad592314945e51543e7da84c4af6e,0318bf32e5217c1eb771a6d5ce1cd39395dff7ff665704f175c9a5451d95a2f2ca,02c681a6243f16208c2004bb81f5a8a67edfdd3e3711534eadeec3dcf0b010c759,0249fdd6b69768b8d84b4893f8ff84b36835c50183de20fcae8f366a45290d01fd)))", SIGNABLE, {{"a914c2c9c510e9d7f92fd6131e94803a8d34a8ef675e87"}}, OutputType::P2SH_SEGWIT); // Even if it's wrapped into P2SH
// 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))", "Can only have combo() at top level"); // Old must be top level
@@ -450,8 +451,8 @@ Check("sh(wsh(multi(20,KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy,KwGN
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}});
- Check("sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))", "sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))", DEFAULT, {{"a91445a9a622a8b0a1269944be477640eedc447bbd8487"}}, OutputType::LEGACY, {{0x8000006FUL,222},{0}});
+ 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]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))#tjg09x5t", DEFAULT, {{"a91445a9a622a8b0a1269944be477640eedc447bbd8487"}}, OutputType::LEGACY, {{0x8000006FUL,222},{0}});
+ Check("sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))", DEFAULT, {{"a91445a9a622a8b0a1269944be477640eedc447bbd8487"}}, OutputType::LEGACY, {{0x8000006FUL,222},{0}});
CheckUnparsable("sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))#", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))#", "Expected 8 character checksum, not 0 characters"); // Empty checksum
CheckUnparsable("sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))#ggrsrxfyq", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))#tjg09x5tq", "Expected 8 character checksum, not 9 characters"); // Too long checksum
CheckUnparsable("sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))#ggrsrxf", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))#tjg09x5", "Expected 8 character checksum, not 7 characters"); // Too short checksum
@@ -467,7 +468,6 @@ Check("sh(wsh(multi(20,KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy,KwGN
Check(
"rawtr(xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/86'/1'/0'/1/*)#a5gn3t7k",
"rawtr(xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/86'/1'/0'/1/*)#4ur3xhft",
- "",
"rawtr([5a61ff8e/86'/1'/0']xpub6DtZpc9PRL2B6pwoNGysmHAaBofDmWv5S6KQEKKGPKhf5fV62ywDtSziSApYVK3JnYY5KUSgiCwiXW5wtd8z7LNBxT9Mu5sEro8itdGfTeA/1/*)#llheyd9x",
RANGE | HARDENED | XONLY_KEYS,
{{"51205172af752f057d543ce8e4a6f8dcf15548ec6be44041bfa93b72e191cfc8c1ee"}, {"51201b66f20b86f700c945ecb9ad9b0ad1662b73084e2bfea48bee02126350b8a5b1"}, {"512063e70f66d815218abcc2306aa930aaca07c5cde73b75127eb27b5e8c16b58a25"}},
@@ -478,7 +478,6 @@ Check("sh(wsh(multi(20,KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy,KwGN
Check(
"rawtr(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)",
"rawtr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)",
- "rawtr(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)",
"rawtr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)",
SIGNABLE | XONLY_KEYS,
{{"5120a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd"}},
@@ -529,9 +528,9 @@ Check("sh(wsh(multi(20,KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy,KwGN
CheckUnparsable("wsh(and_b(and_b(older(1),a:older(100000000)),s:pk(L4gM1FBdyHNpkzsFh9ipnofLhpZRp2mwobpeULy1a6dBTvw8Ywtd)))", "wsh(and_b(and_b(older(1),a:older(100000000)),s:pk(03cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204)))", "and_b(older(1),a:older(100000000)) is not sane: contains mixes of timelocks expressed in blocks and seconds");
CheckUnparsable("wsh(and_b(or_b(pkh(L4gM1FBdyHNpkzsFh9ipnofLhpZRp2mwobpeULy1a6dBTvw8Ywtd),s:pk(Kx9HCDjGiwFcgVNhTrS5z5NeZdD6veeam61eDxLDCkGWujvL4Gnn)),s:pk(L4gM1FBdyHNpkzsFh9ipnofLhpZRp2mwobpeULy1a6dBTvw8Ywtd)))", "wsh(and_b(or_b(pkh(03cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204),s:pk(032707170c71d8f75e4ca4e3fce870b9409dcaf12b051d3bcadff74747fa7619c0)),s:pk(03cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204)))", "and_b(or_b(pkh(03cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204),s:pk(032707170c71d8f75e4ca4e3fce870b9409dcaf12b051d3bcadff74747fa7619c0)),s:pk(03cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204)) is not sane: contains duplicate public keys");
// Valid with extended keys.
- Check("wsh(and_v(v:ripemd160(095ff41131e5946f3c85f79e44adbcf8e27e080e),multi(1,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0)))", "wsh(and_v(v:ripemd160(095ff41131e5946f3c85f79e44adbcf8e27e080e),multi(1,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0)))", "wsh(and_v(v:ripemd160(095ff41131e5946f3c85f79e44adbcf8e27e080e),multi(1,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0)))", "wsh(and_v(v:ripemd160(095ff41131e5946f3c85f79e44adbcf8e27e080e),multi(1,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0)))", UNSOLVABLE, {{"0020acf425291b98a1d7e0d4690139442abc289175be32ef1f75945e339924246d73"}}, OutputType::BECH32, {{},{0}});
+ Check("wsh(and_v(v:ripemd160(095ff41131e5946f3c85f79e44adbcf8e27e080e),multi(1,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0)))", "wsh(and_v(v:ripemd160(095ff41131e5946f3c85f79e44adbcf8e27e080e),multi(1,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0)))", "wsh(and_v(v:ripemd160(095ff41131e5946f3c85f79e44adbcf8e27e080e),multi(1,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0)))", UNSOLVABLE, {{"0020acf425291b98a1d7e0d4690139442abc289175be32ef1f75945e339924246d73"}}, OutputType::BECH32, {{},{0}});
// Valid under sh(wsh()) and with a mix of xpubs and raw keys
- Check("sh(wsh(thresh(1,pkh(L4gM1FBdyHNpkzsFh9ipnofLhpZRp2mwobpeULy1a6dBTvw8Ywtd),a:and_n(multi(1,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0),n:older(2)))))", "sh(wsh(thresh(1,pkh(03cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204),a:and_n(multi(1,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0),n:older(2)))))", "sh(wsh(thresh(1,pkh(L4gM1FBdyHNpkzsFh9ipnofLhpZRp2mwobpeULy1a6dBTvw8Ywtd),a:and_n(multi(1,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0),n:older(2)))))", "sh(wsh(thresh(1,pkh(03cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204),a:and_n(multi(1,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0),n:older(2)))))", UNSOLVABLE | MIXED_PUBKEYS, {{"a914767e9119ff3b3ac0cb6dcfe21de1842ccf85f1c487"}}, OutputType::P2SH_SEGWIT, {{},{0}});
+ Check("sh(wsh(thresh(1,pkh(L4gM1FBdyHNpkzsFh9ipnofLhpZRp2mwobpeULy1a6dBTvw8Ywtd),a:and_n(multi(1,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0),n:older(2)))))", "sh(wsh(thresh(1,pkh(03cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204),a:and_n(multi(1,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0),n:older(2)))))", "sh(wsh(thresh(1,pkh(03cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204),a:and_n(multi(1,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0),n:older(2)))))", UNSOLVABLE | MIXED_PUBKEYS, {{"a914767e9119ff3b3ac0cb6dcfe21de1842ccf85f1c487"}}, OutputType::P2SH_SEGWIT, {{},{0}});
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/fuzz/bitdeque.cpp b/src/test/fuzz/bitdeque.cpp
new file mode 100644
index 0000000000..01af8320b5
--- /dev/null
+++ b/src/test/fuzz/bitdeque.cpp
@@ -0,0 +1,542 @@
+// Copyright (c) 2022 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 <util/bitdeque.h>
+
+#include <random.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/util.h>
+
+#include <deque>
+#include <vector>
+
+namespace {
+
+constexpr int LEN_BITS = 16;
+constexpr int RANDDATA_BITS = 20;
+
+using bitdeque_type = bitdeque<128>;
+
+//! Deterministic random vector of bools, for begin/end insertions to draw from.
+std::vector<bool> RANDDATA;
+
+void InitRandData()
+{
+ FastRandomContext ctx(true);
+ RANDDATA.clear();
+ for (size_t i = 0; i < (1U << RANDDATA_BITS) + (1U << LEN_BITS); ++i) {
+ RANDDATA.push_back(ctx.randbool());
+ }
+}
+
+} // namespace
+
+FUZZ_TARGET_INIT(bitdeque, InitRandData)
+{
+ FuzzedDataProvider provider(buffer.data(), buffer.size());
+ FastRandomContext ctx(true);
+
+ size_t maxlen = (1U << provider.ConsumeIntegralInRange<size_t>(0, LEN_BITS)) - 1;
+ size_t limitlen = 4 * maxlen;
+
+ std::deque<bool> deq;
+ bitdeque_type bitdeq;
+
+ const auto& cdeq = deq;
+ const auto& cbitdeq = bitdeq;
+
+ size_t initlen = provider.ConsumeIntegralInRange<size_t>(0, maxlen);
+ while (initlen) {
+ bool val = ctx.randbool();
+ deq.push_back(val);
+ bitdeq.push_back(val);
+ --initlen;
+ }
+
+ while (provider.remaining_bytes()) {
+ {
+ assert(deq.size() == bitdeq.size());
+ auto it = deq.begin();
+ auto bitit = bitdeq.begin();
+ auto itend = deq.end();
+ while (it != itend) {
+ assert(*it == *bitit);
+ ++it;
+ ++bitit;
+ }
+ }
+
+ CallOneOf(provider,
+ [&] {
+ // constructor()
+ deq = std::deque<bool>{};
+ bitdeq = bitdeque_type{};
+ },
+ [&] {
+ // clear()
+ deq.clear();
+ bitdeq.clear();
+ },
+ [&] {
+ // resize()
+ auto count = provider.ConsumeIntegralInRange<size_t>(0, maxlen);
+ deq.resize(count);
+ bitdeq.resize(count);
+ },
+ [&] {
+ // assign(count, val)
+ auto count = provider.ConsumeIntegralInRange<size_t>(0, maxlen);
+ bool val = ctx.randbool();
+ deq.assign(count, val);
+ bitdeq.assign(count, val);
+ },
+ [&] {
+ // constructor(count, val)
+ auto count = provider.ConsumeIntegralInRange<size_t>(0, maxlen);
+ bool val = ctx.randbool();
+ deq = std::deque<bool>(count, val);
+ bitdeq = bitdeque_type(count, val);
+ },
+ [&] {
+ // constructor(count)
+ auto count = provider.ConsumeIntegralInRange<size_t>(0, maxlen);
+ deq = std::deque<bool>(count);
+ bitdeq = bitdeque_type(count);
+ },
+ [&] {
+ // construct(begin, end)
+ auto count = provider.ConsumeIntegralInRange<size_t>(0, maxlen);
+ auto rand_begin = RANDDATA.begin() + ctx.randbits(RANDDATA_BITS);
+ auto rand_end = rand_begin + count;
+ deq = std::deque<bool>(rand_begin, rand_end);
+ bitdeq = bitdeque_type(rand_begin, rand_end);
+ },
+ [&] {
+ // assign(begin, end)
+ auto count = provider.ConsumeIntegralInRange<size_t>(0, maxlen);
+ auto rand_begin = RANDDATA.begin() + ctx.randbits(RANDDATA_BITS);
+ auto rand_end = rand_begin + count;
+ deq.assign(rand_begin, rand_end);
+ bitdeq.assign(rand_begin, rand_end);
+ },
+ [&] {
+ // construct(initializer_list)
+ std::initializer_list<bool> ilist{ctx.randbool(), ctx.randbool(), ctx.randbool(), ctx.randbool(), ctx.randbool()};
+ deq = std::deque<bool>(ilist);
+ bitdeq = bitdeque_type(ilist);
+ },
+ [&] {
+ // assign(initializer_list)
+ std::initializer_list<bool> ilist{ctx.randbool(), ctx.randbool(), ctx.randbool()};
+ deq.assign(ilist);
+ bitdeq.assign(ilist);
+ },
+ [&] {
+ // operator=(const&)
+ auto count = provider.ConsumeIntegralInRange<size_t>(0, maxlen);
+ bool val = ctx.randbool();
+ const std::deque<bool> deq2(count, val);
+ deq = deq2;
+ const bitdeque_type bitdeq2(count, val);
+ bitdeq = bitdeq2;
+ },
+ [&] {
+ // operator=(&&)
+ auto count = provider.ConsumeIntegralInRange<size_t>(0, maxlen);
+ bool val = ctx.randbool();
+ std::deque<bool> deq2(count, val);
+ deq = std::move(deq2);
+ bitdeque_type bitdeq2(count, val);
+ bitdeq = std::move(bitdeq2);
+ },
+ [&] {
+ // deque swap
+ auto count = provider.ConsumeIntegralInRange<size_t>(0, maxlen);
+ auto rand_begin = RANDDATA.begin() + ctx.randbits(RANDDATA_BITS);
+ auto rand_end = rand_begin + count;
+ std::deque<bool> deq2(rand_begin, rand_end);
+ bitdeque_type bitdeq2(rand_begin, rand_end);
+ using std::swap;
+ assert(deq.size() == bitdeq.size());
+ assert(deq2.size() == bitdeq2.size());
+ swap(deq, deq2);
+ swap(bitdeq, bitdeq2);
+ assert(deq.size() == bitdeq.size());
+ assert(deq2.size() == bitdeq2.size());
+ },
+ [&] {
+ // deque.swap
+ auto count = provider.ConsumeIntegralInRange<size_t>(0, maxlen);
+ auto rand_begin = RANDDATA.begin() + ctx.randbits(RANDDATA_BITS);
+ auto rand_end = rand_begin + count;
+ std::deque<bool> deq2(rand_begin, rand_end);
+ bitdeque_type bitdeq2(rand_begin, rand_end);
+ assert(deq.size() == bitdeq.size());
+ assert(deq2.size() == bitdeq2.size());
+ deq.swap(deq2);
+ bitdeq.swap(bitdeq2);
+ assert(deq.size() == bitdeq.size());
+ assert(deq2.size() == bitdeq2.size());
+ },
+ [&] {
+ // operator=(initializer_list)
+ std::initializer_list<bool> ilist{ctx.randbool(), ctx.randbool(), ctx.randbool()};
+ deq = ilist;
+ bitdeq = ilist;
+ },
+ [&] {
+ // iterator arithmetic
+ auto pos1 = provider.ConsumeIntegralInRange<long>(0, cdeq.size());
+ auto pos2 = provider.ConsumeIntegralInRange<long>(0, cdeq.size());
+ auto it = deq.begin() + pos1;
+ auto bitit = bitdeq.begin() + pos1;
+ if ((size_t)pos1 != cdeq.size()) assert(*it == *bitit);
+ assert(it - deq.begin() == pos1);
+ assert(bitit - bitdeq.begin() == pos1);
+ if (provider.ConsumeBool()) {
+ it += pos2 - pos1;
+ bitit += pos2 - pos1;
+ } else {
+ it -= pos1 - pos2;
+ bitit -= pos1 - pos2;
+ }
+ if ((size_t)pos2 != cdeq.size()) assert(*it == *bitit);
+ assert(deq.end() - it == bitdeq.end() - bitit);
+ if (provider.ConsumeBool()) {
+ if ((size_t)pos2 != cdeq.size()) {
+ ++it;
+ ++bitit;
+ }
+ } else {
+ if (pos2 != 0) {
+ --it;
+ --bitit;
+ }
+ }
+ assert(deq.end() - it == bitdeq.end() - bitit);
+ },
+ [&] {
+ // begin() and end()
+ assert(deq.end() - deq.begin() == bitdeq.end() - bitdeq.begin());
+ },
+ [&] {
+ // begin() and end() (const)
+ assert(cdeq.end() - cdeq.begin() == cbitdeq.end() - cbitdeq.begin());
+ },
+ [&] {
+ // rbegin() and rend()
+ assert(deq.rend() - deq.rbegin() == bitdeq.rend() - bitdeq.rbegin());
+ },
+ [&] {
+ // rbegin() and rend() (const)
+ assert(cdeq.rend() - cdeq.rbegin() == cbitdeq.rend() - cbitdeq.rbegin());
+ },
+ [&] {
+ // cbegin() and cend()
+ assert(cdeq.cend() - cdeq.cbegin() == cbitdeq.cend() - cbitdeq.cbegin());
+ },
+ [&] {
+ // crbegin() and crend()
+ assert(cdeq.crend() - cdeq.crbegin() == cbitdeq.crend() - cbitdeq.crbegin());
+ },
+ [&] {
+ // size() and maxsize()
+ assert(cdeq.size() == cbitdeq.size());
+ assert(cbitdeq.size() <= cbitdeq.max_size());
+ },
+ [&] {
+ // empty
+ assert(cdeq.empty() == cbitdeq.empty());
+ },
+ [&] {
+ // at (in range) and flip
+ if (!cdeq.empty()) {
+ size_t pos = provider.ConsumeIntegralInRange<size_t>(0, cdeq.size() - 1);
+ auto& ref = deq.at(pos);
+ auto bitref = bitdeq.at(pos);
+ assert(ref == bitref);
+ if (ctx.randbool()) {
+ ref = !ref;
+ bitref.flip();
+ }
+ }
+ },
+ [&] {
+ // at (maybe out of range) and bit assign
+ size_t pos = provider.ConsumeIntegralInRange<size_t>(0, cdeq.size() + maxlen);
+ bool newval = ctx.randbool();
+ bool throw_deq{false}, throw_bitdeq{false};
+ bool val_deq{false}, val_bitdeq{false};
+ try {
+ auto& ref = deq.at(pos);
+ val_deq = ref;
+ ref = newval;
+ } catch (const std::out_of_range&) {
+ throw_deq = true;
+ }
+ try {
+ auto ref = bitdeq.at(pos);
+ val_bitdeq = ref;
+ ref = newval;
+ } catch (const std::out_of_range&) {
+ throw_bitdeq = true;
+ }
+ assert(throw_deq == throw_bitdeq);
+ assert(throw_bitdeq == (pos >= cdeq.size()));
+ if (!throw_deq) assert(val_deq == val_bitdeq);
+ },
+ [&] {
+ // at (maybe out of range) (const)
+ size_t pos = provider.ConsumeIntegralInRange<size_t>(0, cdeq.size() + maxlen);
+ bool throw_deq{false}, throw_bitdeq{false};
+ bool val_deq{false}, val_bitdeq{false};
+ try {
+ auto& ref = cdeq.at(pos);
+ val_deq = ref;
+ } catch (const std::out_of_range&) {
+ throw_deq = true;
+ }
+ try {
+ auto ref = cbitdeq.at(pos);
+ val_bitdeq = ref;
+ } catch (const std::out_of_range&) {
+ throw_bitdeq = true;
+ }
+ assert(throw_deq == throw_bitdeq);
+ assert(throw_bitdeq == (pos >= cdeq.size()));
+ if (!throw_deq) assert(val_deq == val_bitdeq);
+ },
+ [&] {
+ // operator[]
+ if (!cdeq.empty()) {
+ size_t pos = provider.ConsumeIntegralInRange<size_t>(0, cdeq.size() - 1);
+ assert(deq[pos] == bitdeq[pos]);
+ if (ctx.randbool()) {
+ deq[pos] = !deq[pos];
+ bitdeq[pos].flip();
+ }
+ }
+ },
+ [&] {
+ // operator[] const
+ if (!cdeq.empty()) {
+ size_t pos = provider.ConsumeIntegralInRange<size_t>(0, cdeq.size() - 1);
+ assert(deq[pos] == bitdeq[pos]);
+ }
+ },
+ [&] {
+ // front()
+ if (!cdeq.empty()) {
+ auto& ref = deq.front();
+ auto bitref = bitdeq.front();
+ assert(ref == bitref);
+ if (ctx.randbool()) {
+ ref = !ref;
+ bitref = !bitref;
+ }
+ }
+ },
+ [&] {
+ // front() const
+ if (!cdeq.empty()) {
+ auto& ref = cdeq.front();
+ auto bitref = cbitdeq.front();
+ assert(ref == bitref);
+ }
+ },
+ [&] {
+ // back() and swap(bool, ref)
+ if (!cdeq.empty()) {
+ auto& ref = deq.back();
+ auto bitref = bitdeq.back();
+ assert(ref == bitref);
+ if (ctx.randbool()) {
+ ref = !ref;
+ bitref.flip();
+ }
+ }
+ },
+ [&] {
+ // back() const
+ if (!cdeq.empty()) {
+ const auto& cdeq = deq;
+ const auto& cbitdeq = bitdeq;
+ auto& ref = cdeq.back();
+ auto bitref = cbitdeq.back();
+ assert(ref == bitref);
+ }
+ },
+ [&] {
+ // push_back()
+ if (cdeq.size() < limitlen) {
+ bool val = ctx.randbool();
+ if (cdeq.empty()) {
+ deq.push_back(val);
+ bitdeq.push_back(val);
+ } else {
+ size_t pos = provider.ConsumeIntegralInRange<size_t>(0, cdeq.size() - 1);
+ auto& ref = deq[pos];
+ auto bitref = bitdeq[pos];
+ assert(ref == bitref);
+ deq.push_back(val);
+ bitdeq.push_back(val);
+ assert(ref == bitref); // references are not invalidated
+ }
+ }
+ },
+ [&] {
+ // push_front()
+ if (cdeq.size() < limitlen) {
+ bool val = ctx.randbool();
+ if (cdeq.empty()) {
+ deq.push_front(val);
+ bitdeq.push_front(val);
+ } else {
+ size_t pos = provider.ConsumeIntegralInRange<size_t>(0, cdeq.size() - 1);
+ auto& ref = deq[pos];
+ auto bitref = bitdeq[pos];
+ assert(ref == bitref);
+ deq.push_front(val);
+ bitdeq.push_front(val);
+ assert(ref == bitref); // references are not invalidated
+ }
+ }
+ },
+ [&] {
+ // pop_back()
+ if (!cdeq.empty()) {
+ if (cdeq.size() == 1) {
+ deq.pop_back();
+ bitdeq.pop_back();
+ } else {
+ size_t pos = provider.ConsumeIntegralInRange<size_t>(0, cdeq.size() - 2);
+ auto& ref = deq[pos];
+ auto bitref = bitdeq[pos];
+ assert(ref == bitref);
+ deq.pop_back();
+ bitdeq.pop_back();
+ assert(ref == bitref); // references to other elements are not invalidated
+ }
+ }
+ },
+ [&] {
+ // pop_front()
+ if (!cdeq.empty()) {
+ if (cdeq.size() == 1) {
+ deq.pop_front();
+ bitdeq.pop_front();
+ } else {
+ size_t pos = provider.ConsumeIntegralInRange<size_t>(1, cdeq.size() - 1);
+ auto& ref = deq[pos];
+ auto bitref = bitdeq[pos];
+ assert(ref == bitref);
+ deq.pop_front();
+ bitdeq.pop_front();
+ assert(ref == bitref); // references to other elements are not invalidated
+ }
+ }
+ },
+ [&] {
+ // erase (in middle, single)
+ if (!cdeq.empty()) {
+ size_t before = provider.ConsumeIntegralInRange<size_t>(0, cdeq.size() - 1);
+ size_t after = cdeq.size() - 1 - before;
+ auto it = deq.erase(cdeq.begin() + before);
+ auto bitit = bitdeq.erase(cbitdeq.begin() + before);
+ assert(it == cdeq.begin() + before && it == cdeq.end() - after);
+ assert(bitit == cbitdeq.begin() + before && bitit == cbitdeq.end() - after);
+ }
+ },
+ [&] {
+ // erase (at front, range)
+ size_t count = provider.ConsumeIntegralInRange<size_t>(0, cdeq.size());
+ auto it = deq.erase(cdeq.begin(), cdeq.begin() + count);
+ auto bitit = bitdeq.erase(cbitdeq.begin(), cbitdeq.begin() + count);
+ assert(it == deq.begin());
+ assert(bitit == bitdeq.begin());
+ },
+ [&] {
+ // erase (at back, range)
+ size_t count = provider.ConsumeIntegralInRange<size_t>(0, cdeq.size());
+ auto it = deq.erase(cdeq.end() - count, cdeq.end());
+ auto bitit = bitdeq.erase(cbitdeq.end() - count, cbitdeq.end());
+ assert(it == deq.end());
+ assert(bitit == bitdeq.end());
+ },
+ [&] {
+ // erase (in middle, range)
+ size_t count = provider.ConsumeIntegralInRange<size_t>(0, cdeq.size());
+ size_t before = provider.ConsumeIntegralInRange<size_t>(0, cdeq.size() - count);
+ size_t after = cdeq.size() - count - before;
+ auto it = deq.erase(cdeq.begin() + before, cdeq.end() - after);
+ auto bitit = bitdeq.erase(cbitdeq.begin() + before, cbitdeq.end() - after);
+ assert(it == cdeq.begin() + before && it == cdeq.end() - after);
+ assert(bitit == cbitdeq.begin() + before && bitit == cbitdeq.end() - after);
+ },
+ [&] {
+ // insert/emplace (in middle, single)
+ if (cdeq.size() < limitlen) {
+ size_t before = provider.ConsumeIntegralInRange<size_t>(0, cdeq.size());
+ bool val = ctx.randbool();
+ bool do_emplace = provider.ConsumeBool();
+ auto it = deq.insert(cdeq.begin() + before, val);
+ auto bitit = do_emplace ? bitdeq.emplace(cbitdeq.begin() + before, val)
+ : bitdeq.insert(cbitdeq.begin() + before, val);
+ assert(it == deq.begin() + before);
+ assert(bitit == bitdeq.begin() + before);
+ }
+ },
+ [&] {
+ // insert (at front, begin/end)
+ if (cdeq.size() < limitlen) {
+ size_t count = provider.ConsumeIntegralInRange<size_t>(0, maxlen);
+ auto rand_begin = RANDDATA.begin() + ctx.randbits(RANDDATA_BITS);
+ auto rand_end = rand_begin + count;
+ auto it = deq.insert(cdeq.begin(), rand_begin, rand_end);
+ auto bitit = bitdeq.insert(cbitdeq.begin(), rand_begin, rand_end);
+ assert(it == cdeq.begin());
+ assert(bitit == cbitdeq.begin());
+ }
+ },
+ [&] {
+ // insert (at back, begin/end)
+ if (cdeq.size() < limitlen) {
+ size_t count = provider.ConsumeIntegralInRange<size_t>(0, maxlen);
+ auto rand_begin = RANDDATA.begin() + ctx.randbits(RANDDATA_BITS);
+ auto rand_end = rand_begin + count;
+ auto it = deq.insert(cdeq.end(), rand_begin, rand_end);
+ auto bitit = bitdeq.insert(cbitdeq.end(), rand_begin, rand_end);
+ assert(it == cdeq.end() - count);
+ assert(bitit == cbitdeq.end() - count);
+ }
+ },
+ [&] {
+ // insert (in middle, range)
+ if (cdeq.size() < limitlen) {
+ size_t count = provider.ConsumeIntegralInRange<size_t>(0, maxlen);
+ size_t before = provider.ConsumeIntegralInRange<size_t>(0, cdeq.size());
+ bool val = ctx.randbool();
+ auto it = deq.insert(cdeq.begin() + before, count, val);
+ auto bitit = bitdeq.insert(cbitdeq.begin() + before, count, val);
+ assert(it == deq.begin() + before);
+ assert(bitit == bitdeq.begin() + before);
+ }
+ },
+ [&] {
+ // insert (in middle, begin/end)
+ if (cdeq.size() < limitlen) {
+ size_t count = provider.ConsumeIntegralInRange<size_t>(0, maxlen);
+ size_t before = provider.ConsumeIntegralInRange<size_t>(0, cdeq.size());
+ auto rand_begin = RANDDATA.begin() + ctx.randbits(RANDDATA_BITS);
+ auto rand_end = rand_begin + count;
+ auto it = deq.insert(cdeq.begin() + before, rand_begin, rand_end);
+ auto bitit = bitdeq.insert(cbitdeq.begin() + before, rand_begin, rand_end);
+ assert(it == deq.begin() + before);
+ assert(bitit == bitdeq.begin() + before);
+ }
+ }
+ );
+ }
+
+}
diff --git a/src/test/fuzz/mempool_utils.h b/src/test/fuzz/mempool_utils.h
index bfe12e30ba..c172e8c4b7 100644
--- a/src/test/fuzz/mempool_utils.h
+++ b/src/test/fuzz/mempool_utils.h
@@ -7,7 +7,7 @@
#include <validation.h>
-class DummyChainState final : public CChainState
+class DummyChainState final : public Chainstate
{
public:
void SetMempool(CTxMemPool* mempool)
diff --git a/src/test/fuzz/pow.cpp b/src/test/fuzz/pow.cpp
index 0004d82d66..507ce57ec0 100644
--- a/src/test/fuzz/pow.cpp
+++ b/src/test/fuzz/pow.cpp
@@ -83,3 +83,40 @@ FUZZ_TARGET_INIT(pow, initialize_pow)
}
}
}
+
+
+FUZZ_TARGET_INIT(pow_transition, initialize_pow)
+{
+ FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
+ const Consensus::Params& consensus_params{Params().GetConsensus()};
+ std::vector<std::unique_ptr<CBlockIndex>> blocks;
+
+ const uint32_t old_time{fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
+ const uint32_t new_time{fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
+ const int32_t version{fuzzed_data_provider.ConsumeIntegral<int32_t>()};
+ uint32_t nbits{fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
+
+ const arith_uint256 pow_limit = UintToArith256(consensus_params.powLimit);
+ arith_uint256 old_target;
+ old_target.SetCompact(nbits);
+ if (old_target > pow_limit) {
+ nbits = pow_limit.GetCompact();
+ }
+ // Create one difficulty adjustment period worth of headers
+ for (int height = 0; height < consensus_params.DifficultyAdjustmentInterval(); ++height) {
+ CBlockHeader header;
+ header.nVersion = version;
+ header.nTime = old_time;
+ header.nBits = nbits;
+ if (height == consensus_params.DifficultyAdjustmentInterval() - 1) {
+ header.nTime = new_time;
+ }
+ auto current_block{std::make_unique<CBlockIndex>(header)};
+ current_block->pprev = blocks.empty() ? nullptr : blocks.back().get();
+ current_block->nHeight = height;
+ blocks.emplace_back(std::move(current_block)).get();
+ }
+ auto last_block{blocks.back().get()};
+ unsigned int new_nbits{GetNextWorkRequired(last_block, nullptr, consensus_params)};
+ Assert(PermittedDifficultyTransition(consensus_params, last_block->nHeight + 1, last_block->nBits, new_nbits));
+}
diff --git a/src/test/fuzz/tx_pool.cpp b/src/test/fuzz/tx_pool.cpp
index 3191367870..283a146369 100644
--- a/src/test/fuzz/tx_pool.cpp
+++ b/src/test/fuzz/tx_pool.cpp
@@ -85,7 +85,7 @@ void SetMempoolConstraints(ArgsManager& args, FuzzedDataProvider& fuzzed_data_pr
ToString(fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(0, 999)));
}
-void Finish(FuzzedDataProvider& fuzzed_data_provider, MockedTxPool& tx_pool, CChainState& chainstate)
+void Finish(FuzzedDataProvider& fuzzed_data_provider, MockedTxPool& tx_pool, Chainstate& chainstate)
{
WITH_LOCK(::cs_main, tx_pool.check(chainstate.CoinsTip(), chainstate.m_chain.Height() + 1));
{
@@ -108,7 +108,7 @@ void Finish(FuzzedDataProvider& fuzzed_data_provider, MockedTxPool& tx_pool, CCh
SyncWithValidationInterfaceQueue();
}
-void MockTime(FuzzedDataProvider& fuzzed_data_provider, const CChainState& chainstate)
+void MockTime(FuzzedDataProvider& fuzzed_data_provider, const Chainstate& chainstate)
{
const auto time = ConsumeTime(fuzzed_data_provider,
chainstate.m_chain.Tip()->GetMedianTimePast() + 1,
diff --git a/src/test/fuzz/txorphan.cpp b/src/test/fuzz/txorphan.cpp
index 7580651371..943f3f5fdf 100644
--- a/src/test/fuzz/txorphan.cpp
+++ b/src/test/fuzz/txorphan.cpp
@@ -19,7 +19,6 @@
#include <util/check.h>
#include <util/time.h>
-#include <algorithm>
#include <cstdint>
#include <memory>
#include <set>
diff --git a/src/test/fuzz/util.cpp b/src/test/fuzz/util.cpp
index ba1a634e41..38626d4bcf 100644
--- a/src/test/fuzz/util.cpp
+++ b/src/test/fuzz/util.cpp
@@ -295,7 +295,6 @@ void FillNode(FuzzedDataProvider& fuzzed_data_provider, ConnmanTestMsg& connman,
/*successfully_connected=*/fuzzed_data_provider.ConsumeBool(),
/*remote_services=*/ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS),
/*local_services=*/ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS),
- /*permission_flags=*/ConsumeWeakEnum(fuzzed_data_provider, ALL_NET_PERMISSION_FLAGS),
/*version=*/fuzzed_data_provider.ConsumeIntegralInRange<int32_t>(MIN_PEER_PROTO_VERSION, std::numeric_limits<int32_t>::max()),
/*relay_txs=*/fuzzed_data_provider.ConsumeBool());
}
diff --git a/src/test/fuzz/util.h b/src/test/fuzz/util.h
index 33d9ab3cc3..6d652c922b 100644
--- a/src/test/fuzz/util.h
+++ b/src/test/fuzz/util.h
@@ -301,6 +301,7 @@ auto ConsumeNode(FuzzedDataProvider& fuzzed_data_provider, const std::optional<N
const std::string addr_name = fuzzed_data_provider.ConsumeRandomLengthString(64);
const ConnectionType conn_type = fuzzed_data_provider.PickValueInArray(ALL_CONNECTION_TYPES);
const bool inbound_onion{conn_type == ConnectionType::INBOUND ? fuzzed_data_provider.ConsumeBool() : false};
+ NetPermissionFlags permission_flags = ConsumeWeakEnum(fuzzed_data_provider, ALL_NET_PERMISSION_FLAGS);
if constexpr (ReturnUniquePtr) {
return std::make_unique<CNode>(node_id,
sock,
@@ -310,7 +311,8 @@ auto ConsumeNode(FuzzedDataProvider& fuzzed_data_provider, const std::optional<N
addr_bind,
addr_name,
conn_type,
- inbound_onion);
+ inbound_onion,
+ CNodeOptions{ .permission_flags = permission_flags });
} else {
return CNode{node_id,
sock,
@@ -320,7 +322,8 @@ auto ConsumeNode(FuzzedDataProvider& fuzzed_data_provider, const std::optional<N
addr_bind,
addr_name,
conn_type,
- inbound_onion};
+ inbound_onion,
+ CNodeOptions{ .permission_flags = permission_flags }};
}
}
inline std::unique_ptr<CNode> ConsumeNodeAsUniquePtr(FuzzedDataProvider& fdp, const std::optional<NodeId>& node_id_in = std::nullopt) { return ConsumeNode<true>(fdp, node_id_in); }
diff --git a/src/test/fuzz/utxo_snapshot.cpp b/src/test/fuzz/utxo_snapshot.cpp
index 0b596492be..8abb943266 100644
--- a/src/test/fuzz/utxo_snapshot.cpp
+++ b/src/test/fuzz/utxo_snapshot.cpp
@@ -58,7 +58,7 @@ FUZZ_TARGET_INIT(utxo_snapshot, initialize_chain)
if (fuzzed_data_provider.ConsumeBool()) {
for (const auto& block : *g_chain) {
BlockValidationState dummy;
- bool processed{chainman.ProcessNewBlockHeaders({*block}, dummy)};
+ bool processed{chainman.ProcessNewBlockHeaders({*block}, true, dummy)};
Assert(processed);
const auto* index{WITH_LOCK(::cs_main, return chainman.m_blockman.LookupBlockIndex(block->GetHash()))};
Assert(index);
diff --git a/src/test/headers_sync_chainwork_tests.cpp b/src/test/headers_sync_chainwork_tests.cpp
new file mode 100644
index 0000000000..41241ebee2
--- /dev/null
+++ b/src/test/headers_sync_chainwork_tests.cpp
@@ -0,0 +1,146 @@
+// Copyright (c) 2022 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 <chain.h>
+#include <chainparams.h>
+#include <consensus/params.h>
+#include <headerssync.h>
+#include <pow.h>
+#include <test/util/setup_common.h>
+#include <validation.h>
+#include <vector>
+
+#include <boost/test/unit_test.hpp>
+
+struct HeadersGeneratorSetup : public RegTestingSetup {
+ /** Search for a nonce to meet (regtest) proof of work */
+ void FindProofOfWork(CBlockHeader& starting_header);
+ /**
+ * Generate headers in a chain that build off a given starting hash, using
+ * the given nVersion, advancing time by 1 second from the starting
+ * prev_time, and with a fixed merkle root hash.
+ */
+ void GenerateHeaders(std::vector<CBlockHeader>& headers, size_t count,
+ const uint256& starting_hash, const int nVersion, int prev_time,
+ const uint256& merkle_root, const uint32_t nBits);
+};
+
+void HeadersGeneratorSetup::FindProofOfWork(CBlockHeader& starting_header)
+{
+ while (!CheckProofOfWork(starting_header.GetHash(), starting_header.nBits, Params().GetConsensus())) {
+ ++(starting_header.nNonce);
+ }
+}
+
+void HeadersGeneratorSetup::GenerateHeaders(std::vector<CBlockHeader>& headers,
+ size_t count, const uint256& starting_hash, const int nVersion, int prev_time,
+ const uint256& merkle_root, const uint32_t nBits)
+{
+ uint256 prev_hash = starting_hash;
+
+ while (headers.size() < count) {
+ headers.push_back(CBlockHeader());
+ CBlockHeader& next_header = headers.back();;
+ next_header.nVersion = nVersion;
+ next_header.hashPrevBlock = prev_hash;
+ next_header.hashMerkleRoot = merkle_root;
+ next_header.nTime = prev_time+1;
+ next_header.nBits = nBits;
+
+ FindProofOfWork(next_header);
+ prev_hash = next_header.GetHash();
+ prev_time = next_header.nTime;
+ }
+ return;
+}
+
+BOOST_FIXTURE_TEST_SUITE(headers_sync_chainwork_tests, HeadersGeneratorSetup)
+
+// In this test, we construct two sets of headers from genesis, one with
+// sufficient proof of work and one without.
+// 1. We deliver the first set of headers and verify that the headers sync state
+// updates to the REDOWNLOAD phase successfully.
+// 2. Then we deliver the second set of headers and verify that they fail
+// processing (presumably due to commitments not matching).
+// 3. Finally, we verify that repeating with the first set of headers in both
+// phases is successful.
+BOOST_AUTO_TEST_CASE(headers_sync_state)
+{
+ std::vector<CBlockHeader> first_chain;
+ std::vector<CBlockHeader> second_chain;
+
+ std::unique_ptr<HeadersSyncState> hss;
+
+ const int target_blocks = 15000;
+ arith_uint256 chain_work = target_blocks*2;
+
+ // Generate headers for two different chains (using differing merkle roots
+ // to ensure the headers are different).
+ GenerateHeaders(first_chain, target_blocks-1, Params().GenesisBlock().GetHash(),
+ Params().GenesisBlock().nVersion, Params().GenesisBlock().nTime,
+ ArithToUint256(0), Params().GenesisBlock().nBits);
+
+ GenerateHeaders(second_chain, target_blocks-2, Params().GenesisBlock().GetHash(),
+ Params().GenesisBlock().nVersion, Params().GenesisBlock().nTime,
+ ArithToUint256(1), Params().GenesisBlock().nBits);
+
+ const CBlockIndex* chain_start = WITH_LOCK(::cs_main, return m_node.chainman->m_blockman.LookupBlockIndex(Params().GenesisBlock().GetHash()));
+ std::vector<CBlockHeader> headers_batch;
+
+ // Feed the first chain to HeadersSyncState, by delivering 1 header
+ // initially and then the rest.
+ headers_batch.insert(headers_batch.end(), std::next(first_chain.begin()), first_chain.end());
+
+ hss.reset(new HeadersSyncState(0, Params().GetConsensus(), chain_start, chain_work));
+ (void)hss->ProcessNextHeaders({first_chain.front()}, true);
+ // Pretend the first header is still "full", so we don't abort.
+ auto result = hss->ProcessNextHeaders(headers_batch, true);
+
+ // This chain should look valid, and we should have met the proof-of-work
+ // requirement.
+ BOOST_CHECK(result.success);
+ BOOST_CHECK(result.request_more);
+ BOOST_CHECK(hss->GetState() == HeadersSyncState::State::REDOWNLOAD);
+
+ // Try to sneakily feed back the second chain.
+ result = hss->ProcessNextHeaders(second_chain, true);
+ BOOST_CHECK(!result.success); // foiled!
+ BOOST_CHECK(hss->GetState() == HeadersSyncState::State::FINAL);
+
+ // Now try again, this time feeding the first chain twice.
+ hss.reset(new HeadersSyncState(0, Params().GetConsensus(), chain_start, chain_work));
+ (void)hss->ProcessNextHeaders(first_chain, true);
+ BOOST_CHECK(hss->GetState() == HeadersSyncState::State::REDOWNLOAD);
+
+ result = hss->ProcessNextHeaders(first_chain, true);
+ BOOST_CHECK(result.success);
+ BOOST_CHECK(!result.request_more);
+ // All headers should be ready for acceptance:
+ BOOST_CHECK(result.pow_validated_headers.size() == first_chain.size());
+ // Nothing left for the sync logic to do:
+ BOOST_CHECK(hss->GetState() == HeadersSyncState::State::FINAL);
+
+ // Finally, verify that just trying to process the second chain would not
+ // succeed (too little work)
+ hss.reset(new HeadersSyncState(0, Params().GetConsensus(), chain_start, chain_work));
+ BOOST_CHECK(hss->GetState() == HeadersSyncState::State::PRESYNC);
+ // Pretend just the first message is "full", so we don't abort.
+ (void)hss->ProcessNextHeaders({second_chain.front()}, true);
+ BOOST_CHECK(hss->GetState() == HeadersSyncState::State::PRESYNC);
+
+ headers_batch.clear();
+ headers_batch.insert(headers_batch.end(), std::next(second_chain.begin(), 1), second_chain.end());
+ // Tell the sync logic that the headers message was not full, implying no
+ // more headers can be requested. For a low-work-chain, this should causes
+ // the sync to end with no headers for acceptance.
+ result = hss->ProcessNextHeaders(headers_batch, false);
+ BOOST_CHECK(hss->GetState() == HeadersSyncState::State::FINAL);
+ BOOST_CHECK(result.pow_validated_headers.empty());
+ BOOST_CHECK(!result.request_more);
+ // Nevertheless, no validation errors should have been detected with the
+ // chain:
+ BOOST_CHECK(result.success);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/i2p_tests.cpp b/src/test/i2p_tests.cpp
index bd9ba4b8f7..9da1ee11f9 100644
--- a/src/test/i2p_tests.cpp
+++ b/src/test/i2p_tests.cpp
@@ -3,6 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <i2p.h>
+#include <logging.h>
#include <netaddress.h>
#include <test/util/logging.h>
#include <test/util/net.h>
@@ -19,6 +20,8 @@ BOOST_FIXTURE_TEST_SUITE(i2p_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(unlimited_recv)
{
+ const auto prev_log_level{LogInstance().LogLevel()};
+ LogInstance().SetLogLevel(BCLog::Level::Trace);
auto CreateSockOrig = CreateSock;
// Mock CreateSock() to create MockSock.
@@ -30,7 +33,7 @@ BOOST_AUTO_TEST_CASE(unlimited_recv)
i2p::sam::Session session(gArgs.GetDataDirNet() / "test_i2p_private_key", CService{}, &interrupt);
{
- ASSERT_DEBUG_LOG("Creating SAM session");
+ ASSERT_DEBUG_LOG("Creating persistent SAM session");
ASSERT_DEBUG_LOG("too many bytes without a terminator");
i2p::Connection conn;
@@ -39,6 +42,7 @@ BOOST_AUTO_TEST_CASE(unlimited_recv)
}
CreateSock = CreateSockOrig;
+ LogInstance().SetLogLevel(prev_log_level);
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/logging_tests.cpp b/src/test/logging_tests.cpp
index 5a5e3b3f1f..a6f3a62c71 100644
--- a/src/test/logging_tests.cpp
+++ b/src/test/logging_tests.cpp
@@ -2,6 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <init/common.h>
#include <logging.h>
#include <logging/timer.h>
#include <test/util/setup_common.h>
@@ -10,6 +11,7 @@
#include <chrono>
#include <fstream>
#include <iostream>
+#include <unordered_map>
#include <utility>
#include <vector>
@@ -17,6 +19,12 @@
BOOST_FIXTURE_TEST_SUITE(logging_tests, BasicTestingSetup)
+static void ResetLogger()
+{
+ LogInstance().SetLogLevel(BCLog::DEFAULT_LOG_LEVEL);
+ LogInstance().SetCategoryLogLevel({});
+}
+
struct LogSetup : public BasicTestingSetup {
fs::path prev_log_path;
fs::path tmp_log_path;
@@ -25,6 +33,8 @@ struct LogSetup : public BasicTestingSetup {
bool prev_log_timestamps;
bool prev_log_threadnames;
bool prev_log_sourcelocations;
+ std::unordered_map<BCLog::LogFlags, BCLog::Level> prev_category_levels;
+ BCLog::Level prev_log_level;
LogSetup() : prev_log_path{LogInstance().m_file_path},
tmp_log_path{m_args.GetDataDirBase() / "tmp_debug.log"},
@@ -32,14 +42,21 @@ struct LogSetup : public BasicTestingSetup {
prev_print_to_file{LogInstance().m_print_to_file},
prev_log_timestamps{LogInstance().m_log_timestamps},
prev_log_threadnames{LogInstance().m_log_threadnames},
- prev_log_sourcelocations{LogInstance().m_log_sourcelocations}
+ prev_log_sourcelocations{LogInstance().m_log_sourcelocations},
+ prev_category_levels{LogInstance().CategoryLevels()},
+ prev_log_level{LogInstance().LogLevel()}
{
LogInstance().m_file_path = tmp_log_path;
LogInstance().m_reopen_file = true;
LogInstance().m_print_to_file = true;
LogInstance().m_log_timestamps = false;
LogInstance().m_log_threadnames = false;
- LogInstance().m_log_sourcelocations = true;
+
+ // Prevent tests from failing when the line number of the logs changes.
+ LogInstance().m_log_sourcelocations = false;
+
+ LogInstance().SetLogLevel(BCLog::Level::Debug);
+ LogInstance().SetCategoryLogLevel({});
}
~LogSetup()
@@ -51,6 +68,8 @@ struct LogSetup : public BasicTestingSetup {
LogInstance().m_log_timestamps = prev_log_timestamps;
LogInstance().m_log_threadnames = prev_log_threadnames;
LogInstance().m_log_sourcelocations = prev_log_sourcelocations;
+ LogInstance().SetLogLevel(prev_log_level);
+ LogInstance().SetCategoryLogLevel(prev_category_levels);
}
};
@@ -74,6 +93,7 @@ BOOST_AUTO_TEST_CASE(logging_timer)
BOOST_FIXTURE_TEST_CASE(logging_LogPrintf_, LogSetup)
{
+ LogInstance().m_log_sourcelocations = true;
LogPrintf_("fn1", "src1", 1, BCLog::LogFlags::NET, BCLog::Level::Debug, "foo1: %s", "bar1\n");
LogPrintf_("fn2", "src2", 2, BCLog::LogFlags::NET, BCLog::Level::None, "foo2: %s", "bar2\n");
LogPrintf_("fn3", "src3", 3, BCLog::LogFlags::NONE, BCLog::Level::Debug, "foo3: %s", "bar3\n");
@@ -94,9 +114,6 @@ BOOST_FIXTURE_TEST_CASE(logging_LogPrintf_, LogSetup)
BOOST_FIXTURE_TEST_CASE(logging_LogPrintMacros, LogSetup)
{
- // Prevent tests from failing when the line number of the following log calls changes.
- LogInstance().m_log_sourcelocations = false;
-
LogPrintf("foo5: %s\n", "bar5");
LogPrint(BCLog::NET, "foo6: %s\n", "bar6");
LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "foo7: %s\n", "bar7");
@@ -123,16 +140,14 @@ BOOST_FIXTURE_TEST_CASE(logging_LogPrintMacros, LogSetup)
BOOST_FIXTURE_TEST_CASE(logging_LogPrintMacros_CategoryName, LogSetup)
{
- // Prevent tests from failing when the line number of the following log calls changes.
- LogInstance().m_log_sourcelocations = false;
LogInstance().EnableCategory(BCLog::LogFlags::ALL);
- const auto concated_categery_names = LogInstance().LogCategoriesString();
+ const auto concatenated_category_names = LogInstance().LogCategoriesString();
std::vector<std::pair<BCLog::LogFlags, std::string>> expected_category_names;
- const auto category_names = SplitString(concated_categery_names, ',');
+ const auto category_names = SplitString(concatenated_category_names, ',');
for (const auto& category_name : category_names) {
- BCLog::LogFlags category = BCLog::NONE;
+ BCLog::LogFlags category;
const auto trimmed_category_name = TrimString(category_name);
- BOOST_TEST(GetLogCategory(category, trimmed_category_name));
+ BOOST_REQUIRE(GetLogCategory(category, trimmed_category_name));
expected_category_names.emplace_back(category, trimmed_category_name);
}
@@ -153,4 +168,92 @@ BOOST_FIXTURE_TEST_CASE(logging_LogPrintMacros_CategoryName, LogSetup)
BOOST_CHECK_EQUAL_COLLECTIONS(log_lines.begin(), log_lines.end(), expected.begin(), expected.end());
}
+BOOST_FIXTURE_TEST_CASE(logging_SeverityLevels, LogSetup)
+{
+ LogInstance().EnableCategory(BCLog::LogFlags::ALL);
+
+ LogInstance().SetLogLevel(BCLog::Level::Debug);
+ LogInstance().SetCategoryLogLevel(/*category_str=*/"net", /*level_str=*/"info");
+
+ // Global log level
+ LogPrintLevel(BCLog::HTTP, BCLog::Level::Info, "foo1: %s\n", "bar1");
+ LogPrintLevel(BCLog::MEMPOOL, BCLog::Level::Trace, "foo2: %s. This log level is lower than the global one.\n", "bar2");
+ LogPrintLevel(BCLog::VALIDATION, BCLog::Level::Warning, "foo3: %s\n", "bar3");
+ LogPrintLevel(BCLog::RPC, BCLog::Level::Error, "foo4: %s\n", "bar4");
+
+ // Category-specific log level
+ LogPrintLevel(BCLog::NET, BCLog::Level::Warning, "foo5: %s\n", "bar5");
+ LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "foo6: %s. This log level is the same as the global one but lower than the category-specific one, which takes precedence. \n", "bar6");
+ LogPrintLevel(BCLog::NET, BCLog::Level::Error, "foo7: %s\n", "bar7");
+
+ std::vector<std::string> expected = {
+ "[http:info] foo1: bar1",
+ "[validation:warning] foo3: bar3",
+ "[rpc:error] foo4: bar4",
+ "[net:warning] foo5: bar5",
+ "[net:error] foo7: bar7",
+ };
+ std::ifstream file{tmp_log_path};
+ std::vector<std::string> log_lines;
+ for (std::string log; std::getline(file, log);) {
+ log_lines.push_back(log);
+ }
+ BOOST_CHECK_EQUAL_COLLECTIONS(log_lines.begin(), log_lines.end(), expected.begin(), expected.end());
+}
+
+BOOST_FIXTURE_TEST_CASE(logging_Conf, LogSetup)
+{
+ // Set global log level
+ {
+ ResetLogger();
+ ArgsManager args;
+ args.AddArg("-loglevel", "...", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
+ const char* argv_test[] = {"bitcoind", "-loglevel=debug"};
+ std::string err;
+ BOOST_REQUIRE(args.ParseParameters(2, argv_test, err));
+ init::SetLoggingLevel(args);
+ BOOST_CHECK_EQUAL(LogInstance().LogLevel(), BCLog::Level::Debug);
+ }
+
+ // Set category-specific log level
+ {
+ ResetLogger();
+ ArgsManager args;
+ args.AddArg("-loglevel", "...", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
+ const char* argv_test[] = {"bitcoind", "-loglevel=net:trace"};
+ std::string err;
+ BOOST_REQUIRE(args.ParseParameters(2, argv_test, err));
+ init::SetLoggingLevel(args);
+ BOOST_CHECK_EQUAL(LogInstance().LogLevel(), BCLog::DEFAULT_LOG_LEVEL);
+
+ const auto& category_levels{LogInstance().CategoryLevels()};
+ const auto net_it{category_levels.find(BCLog::LogFlags::NET)};
+ BOOST_REQUIRE(net_it != category_levels.end());
+ BOOST_CHECK_EQUAL(net_it->second, BCLog::Level::Trace);
+ }
+
+ // Set both global log level and category-specific log level
+ {
+ ResetLogger();
+ ArgsManager args;
+ args.AddArg("-loglevel", "...", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
+ const char* argv_test[] = {"bitcoind", "-loglevel=debug", "-loglevel=net:trace", "-loglevel=http:info"};
+ std::string err;
+ BOOST_REQUIRE(args.ParseParameters(4, argv_test, err));
+ init::SetLoggingLevel(args);
+ BOOST_CHECK_EQUAL(LogInstance().LogLevel(), BCLog::Level::Debug);
+
+ const auto& category_levels{LogInstance().CategoryLevels()};
+ BOOST_CHECK_EQUAL(category_levels.size(), 2);
+
+ const auto net_it{category_levels.find(BCLog::LogFlags::NET)};
+ BOOST_CHECK(net_it != category_levels.end());
+ BOOST_CHECK_EQUAL(net_it->second, BCLog::Level::Trace);
+
+ const auto http_it{category_levels.find(BCLog::LogFlags::HTTP)};
+ BOOST_CHECK(http_it != category_levels.end());
+ BOOST_CHECK_EQUAL(http_it->second, BCLog::Level::Info);
+ }
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index d88aed7d4a..9f5fb17b60 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -588,7 +588,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
pblock->nNonce = bi.nonce;
}
std::shared_ptr<const CBlock> shared_pblock = std::make_shared<const CBlock>(*pblock);
- BOOST_CHECK(Assert(m_node.chainman)->ProcessNewBlock(shared_pblock, true, nullptr));
+ BOOST_CHECK(Assert(m_node.chainman)->ProcessNewBlock(shared_pblock, true, true, nullptr));
pblock->hashPrevBlock = pblock->GetHash();
}
diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp
index f6642d3218..12905f6b70 100644
--- a/src/test/net_tests.cpp
+++ b/src/test/net_tests.cpp
@@ -840,7 +840,7 @@ BOOST_AUTO_TEST_CASE(initial_advertise_from_version_message)
const int64_t time{0};
const CNetMsgMaker msg_maker{PROTOCOL_VERSION};
- // Force CChainState::IsInitialBlockDownload() to return false.
+ // Force Chainstate::IsInitialBlockDownload() to return false.
// Otherwise PushAddress() isn't called by PeerManager::ProcessMessage().
TestChainState& chainstate =
*static_cast<TestChainState*>(&m_node.chainman->ActiveChainstate());
diff --git a/src/test/pow_tests.cpp b/src/test/pow_tests.cpp
index 2f43ae52f7..3695ea9d16 100644
--- a/src/test/pow_tests.cpp
+++ b/src/test/pow_tests.cpp
@@ -20,7 +20,14 @@ BOOST_AUTO_TEST_CASE(get_next_work)
pindexLast.nHeight = 32255;
pindexLast.nTime = 1262152739; // Block #32255
pindexLast.nBits = 0x1d00ffff;
- BOOST_CHECK_EQUAL(CalculateNextWorkRequired(&pindexLast, nLastRetargetTime, chainParams->GetConsensus()), 0x1d00d86aU);
+
+ // Here (and below): expected_nbits is calculated in
+ // CalculateNextWorkRequired(); redoing the calculation here would be just
+ // reimplementing the same code that is written in pow.cpp. Rather than
+ // copy that code, we just hardcode the expected result.
+ unsigned int expected_nbits = 0x1d00d86aU;
+ BOOST_CHECK_EQUAL(CalculateNextWorkRequired(&pindexLast, nLastRetargetTime, chainParams->GetConsensus()), expected_nbits);
+ BOOST_CHECK(PermittedDifficultyTransition(chainParams->GetConsensus(), pindexLast.nHeight+1, pindexLast.nBits, expected_nbits));
}
/* Test the constraint on the upper bound for next work */
@@ -32,7 +39,9 @@ BOOST_AUTO_TEST_CASE(get_next_work_pow_limit)
pindexLast.nHeight = 2015;
pindexLast.nTime = 1233061996; // Block #2015
pindexLast.nBits = 0x1d00ffff;
- BOOST_CHECK_EQUAL(CalculateNextWorkRequired(&pindexLast, nLastRetargetTime, chainParams->GetConsensus()), 0x1d00ffffU);
+ unsigned int expected_nbits = 0x1d00ffffU;
+ BOOST_CHECK_EQUAL(CalculateNextWorkRequired(&pindexLast, nLastRetargetTime, chainParams->GetConsensus()), expected_nbits);
+ BOOST_CHECK(PermittedDifficultyTransition(chainParams->GetConsensus(), pindexLast.nHeight+1, pindexLast.nBits, expected_nbits));
}
/* Test the constraint on the lower bound for actual time taken */
@@ -44,7 +53,12 @@ BOOST_AUTO_TEST_CASE(get_next_work_lower_limit_actual)
pindexLast.nHeight = 68543;
pindexLast.nTime = 1279297671; // Block #68543
pindexLast.nBits = 0x1c05a3f4;
- BOOST_CHECK_EQUAL(CalculateNextWorkRequired(&pindexLast, nLastRetargetTime, chainParams->GetConsensus()), 0x1c0168fdU);
+ unsigned int expected_nbits = 0x1c0168fdU;
+ BOOST_CHECK_EQUAL(CalculateNextWorkRequired(&pindexLast, nLastRetargetTime, chainParams->GetConsensus()), expected_nbits);
+ BOOST_CHECK(PermittedDifficultyTransition(chainParams->GetConsensus(), pindexLast.nHeight+1, pindexLast.nBits, expected_nbits));
+ // Test that reducing nbits further would not be a PermittedDifficultyTransition.
+ unsigned int invalid_nbits = expected_nbits-1;
+ BOOST_CHECK(!PermittedDifficultyTransition(chainParams->GetConsensus(), pindexLast.nHeight+1, pindexLast.nBits, invalid_nbits));
}
/* Test the constraint on the upper bound for actual time taken */
@@ -56,7 +70,12 @@ BOOST_AUTO_TEST_CASE(get_next_work_upper_limit_actual)
pindexLast.nHeight = 46367;
pindexLast.nTime = 1269211443; // Block #46367
pindexLast.nBits = 0x1c387f6f;
- BOOST_CHECK_EQUAL(CalculateNextWorkRequired(&pindexLast, nLastRetargetTime, chainParams->GetConsensus()), 0x1d00e1fdU);
+ unsigned int expected_nbits = 0x1d00e1fdU;
+ BOOST_CHECK_EQUAL(CalculateNextWorkRequired(&pindexLast, nLastRetargetTime, chainParams->GetConsensus()), expected_nbits);
+ BOOST_CHECK(PermittedDifficultyTransition(chainParams->GetConsensus(), pindexLast.nHeight+1, pindexLast.nBits, expected_nbits));
+ // Test that increasing nbits further would not be a PermittedDifficultyTransition.
+ unsigned int invalid_nbits = expected_nbits+1;
+ BOOST_CHECK(!PermittedDifficultyTransition(chainParams->GetConsensus(), pindexLast.nHeight+1, pindexLast.nBits, invalid_nbits));
}
BOOST_AUTO_TEST_CASE(CheckProofOfWork_test_negative_target)
diff --git a/src/test/skiplist_tests.cpp b/src/test/skiplist_tests.cpp
index 3d3fd5d93d..9f5e3ab7ae 100644
--- a/src/test/skiplist_tests.cpp
+++ b/src/test/skiplist_tests.cpp
@@ -78,7 +78,7 @@ BOOST_AUTO_TEST_CASE(getlocator_test)
for (int n=0; n<100; n++) {
int r = InsecureRandRange(150000);
CBlockIndex* tip = (r < 100000) ? &vBlocksMain[r] : &vBlocksSide[r - 100000];
- CBlockLocator locator = chain.GetLocator(tip);
+ CBlockLocator locator = GetLocator(tip);
// The first result must be the block itself, the last one must be genesis.
BOOST_CHECK(locator.vHave.front() == tip->GetBlockHash());
diff --git a/src/test/util/chainstate.h b/src/test/util/chainstate.h
index 13e0e684b8..2f0021b114 100644
--- a/src/test/util/chainstate.h
+++ b/src/test/util/chainstate.h
@@ -7,6 +7,7 @@
#include <clientversion.h>
#include <fs.h>
+#include <logging.h>
#include <node/context.h>
#include <node/utxo_snapshot.h>
#include <rpc/blockchain.h>
@@ -14,8 +15,6 @@
#include <univalue.h>
-#include <boost/test/unit_test.hpp>
-
const auto NoMalleation = [](AutoFile& file, node::SnapshotMetadata& meta){};
/**
@@ -36,8 +35,8 @@ CreateAndActivateUTXOSnapshot(node::NodeContext& node, const fs::path root, F ma
UniValue result = CreateUTXOSnapshot(
node, node.chainman->ActiveChainstate(), auto_outfile, snapshot_path, snapshot_path);
- BOOST_TEST_MESSAGE(
- "Wrote UTXO snapshot to " << fs::PathToString(snapshot_path.make_preferred()) << ": " << result.write());
+ LogPrintf(
+ "Wrote UTXO snapshot to %s: %s", fs::PathToString(snapshot_path.make_preferred()), result.write());
// Read the written snapshot in and then activate it.
//
diff --git a/src/test/util/mining.cpp b/src/test/util/mining.cpp
index 88cf9647e7..faa0b2878c 100644
--- a/src/test/util/mining.cpp
+++ b/src/test/util/mining.cpp
@@ -68,7 +68,7 @@ CTxIn MineBlock(const NodeContext& node, const CScript& coinbase_scriptPubKey)
assert(block->nNonce);
}
- bool processed{Assert(node.chainman)->ProcessNewBlock(block, true, nullptr)};
+ bool processed{Assert(node.chainman)->ProcessNewBlock(block, true, true, nullptr)};
assert(processed);
return CTxIn{block->vtx[0]->GetHash(), 0};
diff --git a/src/test/util/net.cpp b/src/test/util/net.cpp
index 223db16c6c..21273ac5c1 100644
--- a/src/test/util/net.cpp
+++ b/src/test/util/net.cpp
@@ -17,7 +17,6 @@ void ConnmanTestMsg::Handshake(CNode& node,
bool successfully_connected,
ServiceFlags remote_services,
ServiceFlags local_services,
- NetPermissionFlags permission_flags,
int32_t version,
bool relay_txs)
{
@@ -56,7 +55,6 @@ void ConnmanTestMsg::Handshake(CNode& node,
assert(peerman.GetNodeStateStats(node.GetId(), statestats));
assert(statestats.m_relay_txs == (relay_txs && !node.IsBlockOnlyConn()));
assert(statestats.their_services == remote_services);
- node.m_permissionFlags = permission_flags;
if (successfully_connected) {
CSerializedNetMsg msg_verack{mm.Make(NetMsgType::VERACK)};
(void)connman.ReceiveMsgFrom(node, msg_verack);
diff --git a/src/test/util/net.h b/src/test/util/net.h
index ec6b4e6e88..b339bee32a 100644
--- a/src/test/util/net.h
+++ b/src/test/util/net.h
@@ -43,7 +43,6 @@ struct ConnmanTestMsg : public CConnman {
bool successfully_connected,
ServiceFlags remote_services,
ServiceFlags local_services,
- NetPermissionFlags permission_flags,
int32_t version,
bool relay_txs);
diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp
index 30d26ecf79..74b055ee45 100644
--- a/src/test/util/setup_common.cpp
+++ b/src/test/util/setup_common.cpp
@@ -108,6 +108,7 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName, const std::ve
"-logsourcelocations",
"-logtimemicros",
"-logthreadnames",
+ "-loglevel=trace",
"-debug",
"-debugexclude=libevent",
"-debugexclude=leveldb",
@@ -295,7 +296,7 @@ void TestChain100Setup::mineBlocks(int num_blocks)
CBlock TestChain100Setup::CreateBlock(
const std::vector<CMutableTransaction>& txns,
const CScript& scriptPubKey,
- CChainState& chainstate)
+ Chainstate& chainstate)
{
CBlock block = BlockAssembler{chainstate, nullptr}.CreateNewBlock(scriptPubKey)->block;
@@ -313,7 +314,7 @@ CBlock TestChain100Setup::CreateBlock(
CBlock TestChain100Setup::CreateAndProcessBlock(
const std::vector<CMutableTransaction>& txns,
const CScript& scriptPubKey,
- CChainState* chainstate)
+ Chainstate* chainstate)
{
if (!chainstate) {
chainstate = &Assert(m_node.chainman)->ActiveChainstate();
@@ -321,7 +322,7 @@ CBlock TestChain100Setup::CreateAndProcessBlock(
const CBlock block = this->CreateBlock(txns, scriptPubKey, *chainstate);
std::shared_ptr<const CBlock> shared_pblock = std::make_shared<const CBlock>(block);
- Assert(m_node.chainman)->ProcessNewBlock(shared_pblock, true, nullptr);
+ Assert(m_node.chainman)->ProcessNewBlock(shared_pblock, true, true, nullptr);
return block;
}
diff --git a/src/test/util/setup_common.h b/src/test/util/setup_common.h
index ed2c5db7e6..136ee1fd62 100644
--- a/src/test/util/setup_common.h
+++ b/src/test/util/setup_common.h
@@ -134,7 +134,7 @@ struct TestChain100Setup : public TestingSetup {
*/
CBlock CreateAndProcessBlock(const std::vector<CMutableTransaction>& txns,
const CScript& scriptPubKey,
- CChainState* chainstate = nullptr);
+ Chainstate* chainstate = nullptr);
/**
* Create a new block with just given transactions, coinbase paying to
@@ -143,7 +143,7 @@ struct TestChain100Setup : public TestingSetup {
CBlock CreateBlock(
const std::vector<CMutableTransaction>& txns,
const CScript& scriptPubKey,
- CChainState& chainstate);
+ Chainstate& chainstate);
//! Mine a series of new blocks on the active chain.
void mineBlocks(int num_blocks);
diff --git a/src/test/util/validation.h b/src/test/util/validation.h
index b0bc717b6c..cbe7745b81 100644
--- a/src/test/util/validation.h
+++ b/src/test/util/validation.h
@@ -9,7 +9,7 @@
class CValidationInterface;
-struct TestChainState : public CChainState {
+struct TestChainState : public Chainstate {
/** Reset the ibd cache to its initial state */
void ResetIbd();
/** Toggle IsInitialBlockDownload from true to false */
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index 70e2f89e0b..0f9f332dc6 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -23,6 +23,7 @@
#include <util/string.h>
#include <util/time.h>
#include <util/vector.h>
+#include <util/bitdeque.h>
#include <array>
#include <fstream>
@@ -238,15 +239,15 @@ BOOST_AUTO_TEST_CASE(span_write_bytes)
BOOST_AUTO_TEST_CASE(util_Join)
{
// Normal version
- BOOST_CHECK_EQUAL(Join({}, ", "), "");
- BOOST_CHECK_EQUAL(Join({"foo"}, ", "), "foo");
- BOOST_CHECK_EQUAL(Join({"foo", "bar"}, ", "), "foo, bar");
+ BOOST_CHECK_EQUAL(Join(std::vector<std::string>{}, ", "), "");
+ BOOST_CHECK_EQUAL(Join(std::vector<std::string>{"foo"}, ", "), "foo");
+ BOOST_CHECK_EQUAL(Join(std::vector<std::string>{"foo", "bar"}, ", "), "foo, bar");
// Version with unary operator
const auto op_upper = [](const std::string& s) { return ToUpper(s); };
- BOOST_CHECK_EQUAL(Join<std::string>({}, ", ", op_upper), "");
- BOOST_CHECK_EQUAL(Join<std::string>({"foo"}, ", ", op_upper), "FOO");
- BOOST_CHECK_EQUAL(Join<std::string>({"foo", "bar"}, ", ", op_upper), "FOO, BAR");
+ BOOST_CHECK_EQUAL(Join(std::list<std::string>{}, ", ", op_upper), "");
+ BOOST_CHECK_EQUAL(Join(std::list<std::string>{"foo"}, ", ", op_upper), "FOO");
+ BOOST_CHECK_EQUAL(Join(std::list<std::string>{"foo", "bar"}, ", ", op_upper), "FOO, BAR");
}
BOOST_AUTO_TEST_CASE(util_ReplaceAll)
@@ -2510,13 +2511,13 @@ BOOST_AUTO_TEST_CASE(test_tracked_vector)
auto v2 = Vector(std::move(t2));
BOOST_CHECK_EQUAL(v2.size(), 1U);
- BOOST_CHECK(v2[0].origin == &t2);
+ BOOST_CHECK(v2[0].origin == &t2); // NOLINT(*-use-after-move)
BOOST_CHECK_EQUAL(v2[0].copies, 0);
auto v3 = Vector(t1, std::move(t2));
BOOST_CHECK_EQUAL(v3.size(), 2U);
BOOST_CHECK(v3[0].origin == &t1);
- BOOST_CHECK(v3[1].origin == &t2);
+ BOOST_CHECK(v3[1].origin == &t2); // NOLINT(*-use-after-move)
BOOST_CHECK_EQUAL(v3[0].copies, 1);
BOOST_CHECK_EQUAL(v3[1].copies, 0);
@@ -2524,7 +2525,7 @@ BOOST_AUTO_TEST_CASE(test_tracked_vector)
BOOST_CHECK_EQUAL(v4.size(), 3U);
BOOST_CHECK(v4[0].origin == &t1);
BOOST_CHECK(v4[1].origin == &t2);
- BOOST_CHECK(v4[2].origin == &t3);
+ BOOST_CHECK(v4[2].origin == &t3); // NOLINT(*-use-after-move)
BOOST_CHECK_EQUAL(v4[0].copies, 1);
BOOST_CHECK_EQUAL(v4[1].copies, 1);
BOOST_CHECK_EQUAL(v4[2].copies, 0);
diff --git a/src/test/validation_block_tests.cpp b/src/test/validation_block_tests.cpp
index 1c5ca18759..bb1ade153a 100644
--- a/src/test/validation_block_tests.cpp
+++ b/src/test/validation_block_tests.cpp
@@ -100,7 +100,7 @@ std::shared_ptr<CBlock> MinerTestingSetup::FinalizeBlock(std::shared_ptr<CBlock>
// submit block header, so that miner can get the block height from the
// global state and the node has the topology of the chain
BlockValidationState ignored;
- BOOST_CHECK(Assert(m_node.chainman)->ProcessNewBlockHeaders({pblock->GetBlockHeader()}, ignored));
+ BOOST_CHECK(Assert(m_node.chainman)->ProcessNewBlockHeaders({pblock->GetBlockHeader()}, true, ignored));
return pblock;
}
@@ -157,7 +157,7 @@ BOOST_AUTO_TEST_CASE(processnewblock_signals_ordering)
bool ignored;
// Connect the genesis block and drain any outstanding events
- BOOST_CHECK(Assert(m_node.chainman)->ProcessNewBlock(std::make_shared<CBlock>(Params().GenesisBlock()), true, &ignored));
+ BOOST_CHECK(Assert(m_node.chainman)->ProcessNewBlock(std::make_shared<CBlock>(Params().GenesisBlock()), true, true, &ignored));
SyncWithValidationInterfaceQueue();
// subscribe to events (this subscriber will validate event ordering)
@@ -179,13 +179,13 @@ BOOST_AUTO_TEST_CASE(processnewblock_signals_ordering)
FastRandomContext insecure;
for (int i = 0; i < 1000; i++) {
auto block = blocks[insecure.randrange(blocks.size() - 1)];
- Assert(m_node.chainman)->ProcessNewBlock(block, true, &ignored);
+ Assert(m_node.chainman)->ProcessNewBlock(block, true, true, &ignored);
}
// to make sure that eventually we process the full chain - do it here
for (const auto& block : blocks) {
if (block->vtx.size() == 1) {
- bool processed = Assert(m_node.chainman)->ProcessNewBlock(block, true, &ignored);
+ bool processed = Assert(m_node.chainman)->ProcessNewBlock(block, true, true, &ignored);
assert(processed);
}
}
@@ -224,7 +224,7 @@ BOOST_AUTO_TEST_CASE(mempool_locks_reorg)
{
bool ignored;
auto ProcessBlock = [&](std::shared_ptr<const CBlock> block) -> bool {
- return Assert(m_node.chainman)->ProcessNewBlock(block, /*force_processing=*/true, /*new_block=*/&ignored);
+ return Assert(m_node.chainman)->ProcessNewBlock(block, /*force_processing=*/true, /*min_pow_checked=*/true, /*new_block=*/&ignored);
};
// Process all mined blocks
diff --git a/src/test/validation_chainstate_tests.cpp b/src/test/validation_chainstate_tests.cpp
index ee60f9aa4d..347a967b33 100644
--- a/src/test/validation_chainstate_tests.cpp
+++ b/src/test/validation_chainstate_tests.cpp
@@ -18,7 +18,7 @@
BOOST_FIXTURE_TEST_SUITE(validation_chainstate_tests, ChainTestingSetup)
-//! Test resizing coins-related CChainState caches during runtime.
+//! Test resizing coins-related Chainstate caches during runtime.
//!
BOOST_AUTO_TEST_CASE(validation_chainstate_resize_caches)
{
@@ -38,7 +38,7 @@ BOOST_AUTO_TEST_CASE(validation_chainstate_resize_caches)
return outp;
};
- CChainState& c1 = WITH_LOCK(cs_main, return manager.InitializeChainstate(&mempool));
+ Chainstate& c1 = WITH_LOCK(cs_main, return manager.InitializeChainstate(&mempool));
c1.InitCoinsDB(
/*cache_size_bytes=*/1 << 23, /*in_memory=*/true, /*should_wipe=*/false);
WITH_LOCK(::cs_main, c1.InitCoinsCache(1 << 23));
@@ -106,8 +106,8 @@ BOOST_FIXTURE_TEST_CASE(chainstate_update_tip, TestChain100Setup)
BOOST_CHECK_EQUAL(chainman.GetAll().size(), 2);
- CChainState& background_cs{*[&] {
- for (CChainState* cs : chainman.GetAll()) {
+ Chainstate& background_cs{*[&] {
+ for (Chainstate* cs : chainman.GetAll()) {
if (cs != &chainman.ActiveChainstate()) {
return cs;
}
@@ -132,7 +132,7 @@ BOOST_FIXTURE_TEST_CASE(chainstate_update_tip, TestChain100Setup)
bool checked = CheckBlock(*pblock, state, chainparams.GetConsensus());
BOOST_CHECK(checked);
bool accepted = background_cs.AcceptBlock(
- pblock, state, &pindex, true, nullptr, &newblock);
+ pblock, state, &pindex, true, nullptr, &newblock, true);
BOOST_CHECK(accepted);
}
// UpdateTip is called here
diff --git a/src/test/validation_chainstatemanager_tests.cpp b/src/test/validation_chainstatemanager_tests.cpp
index 7b7bd05b5c..24ad9458c9 100644
--- a/src/test/validation_chainstatemanager_tests.cpp
+++ b/src/test/validation_chainstatemanager_tests.cpp
@@ -32,13 +32,13 @@ BOOST_AUTO_TEST_CASE(chainstatemanager)
ChainstateManager& manager = *m_node.chainman;
CTxMemPool& mempool = *m_node.mempool;
- std::vector<CChainState*> chainstates;
+ std::vector<Chainstate*> chainstates;
BOOST_CHECK(!manager.SnapshotBlockhash().has_value());
// Create a legacy (IBD) chainstate.
//
- CChainState& c1 = WITH_LOCK(::cs_main, return manager.InitializeChainstate(&mempool));
+ Chainstate& c1 = WITH_LOCK(::cs_main, return manager.InitializeChainstate(&mempool));
chainstates.push_back(&c1);
c1.InitCoinsDB(
/*cache_size_bytes=*/1 << 23, /*in_memory=*/true, /*should_wipe=*/false);
@@ -63,7 +63,7 @@ BOOST_AUTO_TEST_CASE(chainstatemanager)
// Create a snapshot-based chainstate.
//
const uint256 snapshot_blockhash = GetRandHash();
- CChainState& c2 = WITH_LOCK(::cs_main, return manager.InitializeChainstate(
+ Chainstate& c2 = WITH_LOCK(::cs_main, return manager.InitializeChainstate(
&mempool, snapshot_blockhash));
chainstates.push_back(&c2);
@@ -111,11 +111,11 @@ BOOST_AUTO_TEST_CASE(chainstatemanager_rebalance_caches)
manager.m_total_coinsdb_cache = max_cache;
manager.m_total_coinstip_cache = max_cache;
- std::vector<CChainState*> chainstates;
+ std::vector<Chainstate*> chainstates;
// Create a legacy (IBD) chainstate.
//
- CChainState& c1 = WITH_LOCK(cs_main, return manager.InitializeChainstate(&mempool));
+ Chainstate& c1 = WITH_LOCK(cs_main, return manager.InitializeChainstate(&mempool));
chainstates.push_back(&c1);
c1.InitCoinsDB(
/*cache_size_bytes=*/1 << 23, /*in_memory=*/true, /*should_wipe=*/false);
@@ -133,7 +133,7 @@ BOOST_AUTO_TEST_CASE(chainstatemanager_rebalance_caches)
// Create a snapshot-based chainstate.
//
- CChainState& c2 = WITH_LOCK(cs_main, return manager.InitializeChainstate(&mempool, GetRandHash()));
+ Chainstate& c2 = WITH_LOCK(cs_main, return manager.InitializeChainstate(&mempool, GetRandHash()));
chainstates.push_back(&c2);
c2.InitCoinsDB(
/*cache_size_bytes=*/1 << 23, /*in_memory=*/true, /*should_wipe=*/false);
@@ -250,7 +250,7 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_activate_snapshot, TestChain100Setup)
LOCK(::cs_main);
int chains_tested{0};
- for (CChainState* chainstate : chainman.GetAll()) {
+ for (Chainstate* chainstate : chainman.GetAll()) {
BOOST_TEST_MESSAGE("Checking coins in " << chainstate->ToString());
CCoinsViewCache& coinscache = chainstate->CoinsTip();
@@ -283,7 +283,7 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_activate_snapshot, TestChain100Setup)
size_t coins_in_background{0};
size_t coins_missing_from_background{0};
- for (CChainState* chainstate : chainman.GetAll()) {
+ for (Chainstate* chainstate : chainman.GetAll()) {
BOOST_TEST_MESSAGE("Checking coins in " << chainstate->ToString());
CCoinsViewCache& coinscache = chainstate->CoinsTip();
bool is_background = chainstate != &chainman.ActiveChainstate();
@@ -326,7 +326,7 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_loadblockindex, TestChain100Setup)
{
ChainstateManager& chainman = *Assert(m_node.chainman);
CTxMemPool& mempool = *m_node.mempool;
- CChainState& cs1 = chainman.ActiveChainstate();
+ Chainstate& cs1 = chainman.ActiveChainstate();
int num_indexes{0};
int num_assumed_valid{0};
@@ -338,7 +338,7 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_loadblockindex, TestChain100Setup)
CBlockIndex* assumed_tip{WITH_LOCK(chainman.GetMutex(), return chainman.ActiveChain().Tip())};
auto reload_all_block_indexes = [&]() {
- for (CChainState* cs : chainman.GetAll()) {
+ for (Chainstate* cs : chainman.GetAll()) {
LOCK(::cs_main);
cs->UnloadBlockIndex();
BOOST_CHECK(cs->setBlockIndexCandidates.empty());
@@ -373,7 +373,7 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_loadblockindex, TestChain100Setup)
BOOST_CHECK_EQUAL(expected_assumed_valid, num_assumed_valid);
- CChainState& cs2 = WITH_LOCK(::cs_main,
+ Chainstate& cs2 = WITH_LOCK(::cs_main,
return chainman.InitializeChainstate(&mempool, GetRandHash()));
reload_all_block_indexes();
diff --git a/src/test/validation_flush_tests.cpp b/src/test/validation_flush_tests.cpp
index 74b2af6858..c06e6c8d3b 100644
--- a/src/test/validation_flush_tests.cpp
+++ b/src/test/validation_flush_tests.cpp
@@ -13,11 +13,11 @@ BOOST_FIXTURE_TEST_SUITE(validation_flush_tests, TestingSetup)
//! Test utilities for detecting when we need to flush the coins cache based
//! on estimated memory usage.
//!
-//! @sa CChainState::GetCoinsCacheSizeState()
+//! @sa Chainstate::GetCoinsCacheSizeState()
//!
BOOST_AUTO_TEST_CASE(getcoinscachesizestate)
{
- CChainState& chainstate{m_node.chainman->ActiveChainstate()};
+ Chainstate& chainstate{m_node.chainman->ActiveChainstate()};
constexpr bool is_64_bit = sizeof(void*) == 8;
diff --git a/src/threadinterrupt.h b/src/threadinterrupt.h
index 363aab39ce..979bc2ee3e 100644
--- a/src/threadinterrupt.h
+++ b/src/threadinterrupt.h
@@ -6,6 +6,7 @@
#define BITCOIN_THREADINTERRUPT_H
#include <sync.h>
+#include <threadsafety.h>
#include <atomic>
#include <chrono>
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index b151953d0d..e1288b7346 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -24,38 +24,6 @@
#include <cmath>
#include <optional>
-// Helpers for modifying CTxMemPool::mapTx, which is a boost multi_index.
-struct update_descendant_state
-{
- update_descendant_state(int64_t _modifySize, CAmount _modifyFee, int64_t _modifyCount) :
- modifySize(_modifySize), modifyFee(_modifyFee), modifyCount(_modifyCount)
- {}
-
- void operator() (CTxMemPoolEntry &e)
- { e.UpdateDescendantState(modifySize, modifyFee, modifyCount); }
-
- private:
- int64_t modifySize;
- CAmount modifyFee;
- int64_t modifyCount;
-};
-
-struct update_ancestor_state
-{
- update_ancestor_state(int64_t _modifySize, CAmount _modifyFee, int64_t _modifyCount, int64_t _modifySigOpsCost) :
- modifySize(_modifySize), modifyFee(_modifyFee), modifyCount(_modifyCount), modifySigOpsCost(_modifySigOpsCost)
- {}
-
- void operator() (CTxMemPoolEntry &e)
- { e.UpdateAncestorState(modifySize, modifyFee, modifyCount, modifySigOpsCost); }
-
- private:
- int64_t modifySize;
- CAmount modifyFee;
- int64_t modifyCount;
- int64_t modifySigOpsCost;
-};
-
bool TestLockPointValidity(CChain& active_chain, const LockPoints& lp)
{
AssertLockHeld(cs_main);
@@ -146,7 +114,9 @@ void CTxMemPool::UpdateForDescendants(txiter updateIt, cacheMap& cachedDescendan
modifyCount++;
cachedDescendants[updateIt].insert(mapTx.iterator_to(descendant));
// Update ancestor state for each descendant
- mapTx.modify(mapTx.iterator_to(descendant), update_ancestor_state(updateIt->GetTxSize(), updateIt->GetModifiedFee(), 1, updateIt->GetSigOpCost()));
+ mapTx.modify(mapTx.iterator_to(descendant), [=](CTxMemPoolEntry& e) {
+ e.UpdateAncestorState(updateIt->GetTxSize(), updateIt->GetModifiedFee(), 1, updateIt->GetSigOpCost());
+ });
// Don't directly remove the transaction here -- doing so would
// invalidate iterators in cachedDescendants. Mark it for removal
// by inserting into descendants_to_remove.
@@ -155,7 +125,7 @@ void CTxMemPool::UpdateForDescendants(txiter updateIt, cacheMap& cachedDescendan
}
}
}
- mapTx.modify(updateIt, update_descendant_state(modifySize, modifyFee, modifyCount));
+ mapTx.modify(updateIt, [=](CTxMemPoolEntry& e) { e.UpdateDescendantState(modifySize, modifyFee, modifyCount); });
}
void CTxMemPool::UpdateTransactionsFromBlock(const std::vector<uint256>& vHashesToUpdate)
@@ -347,7 +317,7 @@ void CTxMemPool::UpdateAncestorsOf(bool add, txiter it, setEntries &setAncestors
const int64_t updateSize = updateCount * it->GetTxSize();
const CAmount updateFee = updateCount * it->GetModifiedFee();
for (txiter ancestorIt : setAncestors) {
- mapTx.modify(ancestorIt, update_descendant_state(updateSize, updateFee, updateCount));
+ mapTx.modify(ancestorIt, [=](CTxMemPoolEntry& e) { e.UpdateDescendantState(updateSize, updateFee, updateCount); });
}
}
@@ -362,7 +332,7 @@ void CTxMemPool::UpdateEntryForAncestors(txiter it, const setEntries &setAncesto
updateFee += ancestorIt->GetModifiedFee();
updateSigOpsCost += ancestorIt->GetSigOpCost();
}
- mapTx.modify(it, update_ancestor_state(updateSize, updateFee, updateCount, updateSigOpsCost));
+ mapTx.modify(it, [=](CTxMemPoolEntry& e){ e.UpdateAncestorState(updateSize, updateFee, updateCount, updateSigOpsCost); });
}
void CTxMemPool::UpdateChildrenForRemoval(txiter it)
@@ -393,7 +363,7 @@ void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove, b
CAmount modifyFee = -removeIt->GetModifiedFee();
int modifySigOps = -removeIt->GetSigOpCost();
for (txiter dit : setDescendants) {
- mapTx.modify(dit, update_ancestor_state(modifySize, modifyFee, -1, modifySigOps));
+ mapTx.modify(dit, [=](CTxMemPoolEntry& e){ e.UpdateAncestorState(modifySize, modifyFee, -1, modifySigOps); });
}
}
}
@@ -942,14 +912,14 @@ void CTxMemPool::PrioritiseTransaction(const uint256& hash, const CAmount& nFeeD
std::string dummy;
CalculateMemPoolAncestors(*it, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy, false);
for (txiter ancestorIt : setAncestors) {
- mapTx.modify(ancestorIt, update_descendant_state(0, nFeeDelta, 0));
+ mapTx.modify(ancestorIt, [=](CTxMemPoolEntry& e){ e.UpdateDescendantState(0, nFeeDelta, 0);});
}
// Now update all descendants' modified fees with ancestors
setEntries setDescendants;
CalculateDescendants(it, setDescendants);
setDescendants.erase(it);
for (txiter descendantIt : setDescendants) {
- mapTx.modify(descendantIt, update_ancestor_state(0, nFeeDelta, 0, 0));
+ mapTx.modify(descendantIt, [=](CTxMemPoolEntry& e){ e.UpdateAncestorState(0, nFeeDelta, 0, 0); });
}
++nTransactionsUpdated;
}
diff --git a/src/txmempool.h b/src/txmempool.h
index d06816ba97..cd15d069b1 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -35,7 +35,7 @@
class CBlockIndex;
class CChain;
-class CChainState;
+class Chainstate;
extern RecursiveMutex cs_main;
/** Fake height value used in Coin to signify they are only in the memory pool (since 0.8) */
diff --git a/src/uint256.h b/src/uint256.h
index 5c3a2f5409..e74b9ff7b1 100644
--- a/src/uint256.h
+++ b/src/uint256.h
@@ -6,6 +6,7 @@
#ifndef BITCOIN_UINT256_H
#define BITCOIN_UINT256_H
+#include <crypto/common.h>
#include <span.h>
#include <assert.h>
@@ -84,15 +85,7 @@ public:
uint64_t GetUint64(int pos) const
{
- const uint8_t* ptr = m_data + pos * 8;
- return ((uint64_t)ptr[0]) | \
- ((uint64_t)ptr[1]) << 8 | \
- ((uint64_t)ptr[2]) << 16 | \
- ((uint64_t)ptr[3]) << 24 | \
- ((uint64_t)ptr[4]) << 32 | \
- ((uint64_t)ptr[5]) << 40 | \
- ((uint64_t)ptr[6]) << 48 | \
- ((uint64_t)ptr[7]) << 56;
+ return ReadLE64(m_data + pos * 8);
}
template<typename Stream>
diff --git a/src/univalue/include/univalue.h b/src/univalue/include/univalue.h
index 8ba6fd5425..ccaf56a271 100644
--- a/src/univalue/include/univalue.h
+++ b/src/univalue/include/univalue.h
@@ -80,14 +80,14 @@ public:
bool isArray() const { return (typ == VARR); }
bool isObject() const { return (typ == VOBJ); }
- void push_back(const UniValue& val);
+ void push_back(UniValue val);
void push_backV(const std::vector<UniValue>& vec);
template <class It>
void push_backV(It first, It last);
- void __pushKV(const std::string& key, const UniValue& val);
- void pushKV(const std::string& key, const UniValue& val);
- void pushKVs(const UniValue& obj);
+ void __pushKV(std::string key, UniValue val);
+ void pushKV(std::string key, UniValue val);
+ void pushKVs(UniValue obj);
std::string write(unsigned int prettyIndent = 0,
unsigned int indentLevel = 0) const;
diff --git a/src/univalue/lib/univalue.cpp b/src/univalue/lib/univalue.cpp
index 55e777b8ae..12a434dd0e 100644
--- a/src/univalue/lib/univalue.cpp
+++ b/src/univalue/lib/univalue.cpp
@@ -101,11 +101,11 @@ void UniValue::setObject()
typ = VOBJ;
}
-void UniValue::push_back(const UniValue& val_)
+void UniValue::push_back(UniValue val)
{
checkType(VARR);
- values.push_back(val_);
+ values.push_back(std::move(val));
}
void UniValue::push_backV(const std::vector<UniValue>& vec)
@@ -115,32 +115,32 @@ void UniValue::push_backV(const std::vector<UniValue>& vec)
values.insert(values.end(), vec.begin(), vec.end());
}
-void UniValue::__pushKV(const std::string& key, const UniValue& val_)
+void UniValue::__pushKV(std::string key, UniValue val)
{
checkType(VOBJ);
- keys.push_back(key);
- values.push_back(val_);
+ keys.push_back(std::move(key));
+ values.push_back(std::move(val));
}
-void UniValue::pushKV(const std::string& key, const UniValue& val_)
+void UniValue::pushKV(std::string key, UniValue val)
{
checkType(VOBJ);
size_t idx;
if (findKey(key, idx))
- values[idx] = val_;
+ values[idx] = std::move(val);
else
- __pushKV(key, val_);
+ __pushKV(std::move(key), std::move(val));
}
-void UniValue::pushKVs(const UniValue& obj)
+void UniValue::pushKVs(UniValue obj)
{
checkType(VOBJ);
obj.checkType(VOBJ);
for (size_t i = 0; i < obj.keys.size(); i++)
- __pushKV(obj.keys[i], obj.values.at(i));
+ __pushKV(std::move(obj.keys.at(i)), std::move(obj.values.at(i)));
}
void UniValue::getObjMap(std::map<std::string,UniValue>& kv) const
diff --git a/src/util/bip32.cpp b/src/util/bip32.cpp
index 39e43eeb31..796af4a544 100644
--- a/src/util/bip32.cpp
+++ b/src/util/bip32.cpp
@@ -6,12 +6,10 @@
#include <util/bip32.h>
#include <util/strencodings.h>
-#include <algorithm>
#include <cstdint>
#include <cstdio>
#include <sstream>
-
bool ParseHDKeypath(const std::string& keypath_str, std::vector<uint32_t>& keypath)
{
std::stringstream ss(keypath_str);
diff --git a/src/util/bitdeque.h b/src/util/bitdeque.h
new file mode 100644
index 0000000000..1e34b72475
--- /dev/null
+++ b/src/util/bitdeque.h
@@ -0,0 +1,469 @@
+// Copyright (c) 2022 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_UTIL_BITDEQUE_H
+#define BITCOIN_UTIL_BITDEQUE_H
+
+#include <bitset>
+#include <cstddef>
+#include <deque>
+#include <limits>
+#include <stdexcept>
+#include <tuple>
+
+/** Class that mimics std::deque<bool>, but with std::vector<bool>'s bit packing.
+ *
+ * BlobSize selects the (minimum) number of bits that are allocated at once.
+ * Larger values reduce the asymptotic memory usage overhead, at the cost of
+ * needing larger up-front allocations. The default is 4096 bytes.
+ */
+template<int BlobSize = 4096 * 8>
+class bitdeque
+{
+ // Internal definitions
+ using word_type = std::bitset<BlobSize>;
+ using deque_type = std::deque<word_type>;
+ static_assert(BlobSize > 0);
+ static constexpr int BITS_PER_WORD = BlobSize;
+
+ // Forward and friend declarations of iterator types.
+ template<bool Const> class Iterator;
+ template<bool Const> friend class Iterator;
+
+ /** Iterator to a bitdeque element, const or not. */
+ template<bool Const>
+ class Iterator
+ {
+ using deque_iterator = std::conditional_t<Const, typename deque_type::const_iterator, typename deque_type::iterator>;
+
+ deque_iterator m_it;
+ int m_bitpos{0};
+ Iterator(const deque_iterator& it, int bitpos) : m_it(it), m_bitpos(bitpos) {}
+ friend class bitdeque;
+
+ public:
+ using iterator_category = std::random_access_iterator_tag;
+ using value_type = bool;
+ using pointer = void;
+ using const_pointer = void;
+ using reference = std::conditional_t<Const, bool, typename word_type::reference>;
+ using const_reference = bool;
+ using difference_type = std::ptrdiff_t;
+
+ /** Default constructor. */
+ Iterator() = default;
+
+ /** Default copy constructor. */
+ Iterator(const Iterator&) = default;
+
+ /** Conversion from non-const to const iterator. */
+ template<bool ConstArg = Const, typename = std::enable_if_t<Const && ConstArg>>
+ Iterator(const Iterator<false>& x) : m_it(x.m_it), m_bitpos(x.m_bitpos) {}
+
+ Iterator& operator+=(difference_type dist)
+ {
+ if (dist > 0) {
+ if (dist + m_bitpos >= BITS_PER_WORD) {
+ ++m_it;
+ dist -= BITS_PER_WORD - m_bitpos;
+ m_bitpos = 0;
+ }
+ auto jump = dist / BITS_PER_WORD;
+ m_it += jump;
+ m_bitpos += dist - jump * BITS_PER_WORD;
+ } else if (dist < 0) {
+ dist = -dist;
+ if (dist > m_bitpos) {
+ --m_it;
+ dist -= m_bitpos + 1;
+ m_bitpos = BITS_PER_WORD - 1;
+ }
+ auto jump = dist / BITS_PER_WORD;
+ m_it -= jump;
+ m_bitpos -= dist - jump * BITS_PER_WORD;
+ }
+ return *this;
+ }
+
+ friend difference_type operator-(const Iterator& x, const Iterator& y)
+ {
+ return BITS_PER_WORD * (x.m_it - y.m_it) + x.m_bitpos - y.m_bitpos;
+ }
+
+ Iterator& operator=(const Iterator&) = default;
+ Iterator& operator-=(difference_type dist) { return operator+=(-dist); }
+ Iterator& operator++() { ++m_bitpos; if (m_bitpos == BITS_PER_WORD) { m_bitpos = 0; ++m_it; }; return *this; }
+ Iterator operator++(int) { auto ret{*this}; operator++(); return ret; }
+ Iterator& operator--() { if (m_bitpos == 0) { m_bitpos = BITS_PER_WORD; --m_it; }; --m_bitpos; return *this; }
+ Iterator operator--(int) { auto ret{*this}; operator--(); return ret; }
+ friend Iterator operator+(Iterator x, difference_type dist) { x += dist; return x; }
+ friend Iterator operator+(difference_type dist, Iterator x) { x += dist; return x; }
+ friend Iterator operator-(Iterator x, difference_type dist) { x -= dist; return x; }
+ friend bool operator<(const Iterator& x, const Iterator& y) { return std::tie(x.m_it, x.m_bitpos) < std::tie(y.m_it, y.m_bitpos); }
+ friend bool operator>(const Iterator& x, const Iterator& y) { return std::tie(x.m_it, x.m_bitpos) > std::tie(y.m_it, y.m_bitpos); }
+ friend bool operator<=(const Iterator& x, const Iterator& y) { return std::tie(x.m_it, x.m_bitpos) <= std::tie(y.m_it, y.m_bitpos); }
+ friend bool operator>=(const Iterator& x, const Iterator& y) { return std::tie(x.m_it, x.m_bitpos) >= std::tie(y.m_it, y.m_bitpos); }
+ friend bool operator==(const Iterator& x, const Iterator& y) { return x.m_it == y.m_it && x.m_bitpos == y.m_bitpos; }
+ friend bool operator!=(const Iterator& x, const Iterator& y) { return x.m_it != y.m_it || x.m_bitpos != y.m_bitpos; }
+ reference operator*() const { return (*m_it)[m_bitpos]; }
+ reference operator[](difference_type pos) const { return *(*this + pos); }
+ };
+
+public:
+ using value_type = bool;
+ using size_type = std::size_t;
+ using difference_type = typename deque_type::difference_type;
+ using reference = typename word_type::reference;
+ using const_reference = bool;
+ using iterator = Iterator<false>;
+ using const_iterator = Iterator<true>;
+ using pointer = void;
+ using const_pointer = void;
+ using reverse_iterator = std::reverse_iterator<iterator>;
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+
+private:
+ /** Deque of bitsets storing the actual bit data. */
+ deque_type m_deque;
+
+ /** Number of unused bits at the front of m_deque.front(). */
+ int m_pad_begin;
+
+ /** Number of unused bits at the back of m_deque.back(). */
+ int m_pad_end;
+
+ /** Shrink the container by n bits, removing from the end. */
+ void erase_back(size_type n)
+ {
+ if (n >= static_cast<size_type>(BITS_PER_WORD - m_pad_end)) {
+ n -= BITS_PER_WORD - m_pad_end;
+ m_pad_end = 0;
+ m_deque.erase(m_deque.end() - 1 - (n / BITS_PER_WORD), m_deque.end());
+ n %= BITS_PER_WORD;
+ }
+ if (n) {
+ auto& last = m_deque.back();
+ while (n) {
+ last.reset(BITS_PER_WORD - 1 - m_pad_end);
+ ++m_pad_end;
+ --n;
+ }
+ }
+ }
+
+ /** Extend the container by n bits, adding at the end. */
+ void extend_back(size_type n)
+ {
+ if (n > static_cast<size_type>(m_pad_end)) {
+ n -= m_pad_end + 1;
+ m_pad_end = BITS_PER_WORD - 1;
+ m_deque.insert(m_deque.end(), 1 + (n / BITS_PER_WORD), {});
+ n %= BITS_PER_WORD;
+ }
+ m_pad_end -= n;
+ }
+
+ /** Shrink the container by n bits, removing from the beginning. */
+ void erase_front(size_type n)
+ {
+ if (n >= static_cast<size_type>(BITS_PER_WORD - m_pad_begin)) {
+ n -= BITS_PER_WORD - m_pad_begin;
+ m_pad_begin = 0;
+ m_deque.erase(m_deque.begin(), m_deque.begin() + 1 + (n / BITS_PER_WORD));
+ n %= BITS_PER_WORD;
+ }
+ if (n) {
+ auto& first = m_deque.front();
+ while (n) {
+ first.reset(m_pad_begin);
+ ++m_pad_begin;
+ --n;
+ }
+ }
+ }
+
+ /** Extend the container by n bits, adding at the beginning. */
+ void extend_front(size_type n)
+ {
+ if (n > static_cast<size_type>(m_pad_begin)) {
+ n -= m_pad_begin + 1;
+ m_pad_begin = BITS_PER_WORD - 1;
+ m_deque.insert(m_deque.begin(), 1 + (n / BITS_PER_WORD), {});
+ n %= BITS_PER_WORD;
+ }
+ m_pad_begin -= n;
+ }
+
+ /** Insert a sequence of falses anywhere in the container. */
+ void insert_zeroes(size_type before, size_type count)
+ {
+ size_type after = size() - before;
+ if (before < after) {
+ extend_front(count);
+ std::move(begin() + count, begin() + count + before, begin());
+ } else {
+ extend_back(count);
+ std::move_backward(begin() + before, begin() + before + after, end());
+ }
+ }
+
+public:
+ /** Construct an empty container. */
+ explicit bitdeque() : m_pad_begin{0}, m_pad_end{0} {}
+
+ /** Set the container equal to count times the value of val. */
+ void assign(size_type count, bool val)
+ {
+ m_deque.clear();
+ m_deque.resize((count + BITS_PER_WORD - 1) / BITS_PER_WORD);
+ m_pad_begin = 0;
+ m_pad_end = 0;
+ if (val) {
+ for (auto& elem : m_deque) elem.flip();
+ }
+ if (count % BITS_PER_WORD) {
+ erase_back(BITS_PER_WORD - (count % BITS_PER_WORD));
+ }
+ }
+
+ /** Construct a container containing count times the value of val. */
+ bitdeque(size_type count, bool val) { assign(count, val); }
+
+ /** Construct a container containing count false values. */
+ explicit bitdeque(size_t count) { assign(count, false); }
+
+ /** Copy constructor. */
+ bitdeque(const bitdeque&) = default;
+
+ /** Move constructor. */
+ bitdeque(bitdeque&&) noexcept = default;
+
+ /** Copy assignment operator. */
+ bitdeque& operator=(const bitdeque& other) = default;
+
+ /** Move assignment operator. */
+ bitdeque& operator=(bitdeque&& other) noexcept = default;
+
+ // Iterator functions.
+ iterator begin() noexcept { return {m_deque.begin(), m_pad_begin}; }
+ iterator end() noexcept { return iterator{m_deque.end(), 0} - m_pad_end; }
+ const_iterator begin() const noexcept { return const_iterator{m_deque.cbegin(), m_pad_begin}; }
+ const_iterator cbegin() const noexcept { return const_iterator{m_deque.cbegin(), m_pad_begin}; }
+ const_iterator end() const noexcept { return const_iterator{m_deque.cend(), 0} - m_pad_end; }
+ const_iterator cend() const noexcept { return const_iterator{m_deque.cend(), 0} - m_pad_end; }
+ reverse_iterator rbegin() noexcept { return reverse_iterator{end()}; }
+ reverse_iterator rend() noexcept { return reverse_iterator{begin()}; }
+ const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator{cend()}; }
+ const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator{cend()}; }
+ const_reverse_iterator rend() const noexcept { return const_reverse_iterator{cbegin()}; }
+ const_reverse_iterator crend() const noexcept { return const_reverse_iterator{cbegin()}; }
+
+ /** Count the number of bits in the container. */
+ size_type size() const noexcept { return m_deque.size() * BITS_PER_WORD - m_pad_begin - m_pad_end; }
+
+ /** Determine whether the container is empty. */
+ bool empty() const noexcept
+ {
+ return m_deque.size() == 0 || (m_deque.size() == 1 && (m_pad_begin + m_pad_end == BITS_PER_WORD));
+ }
+
+ /** Return the maximum size of the container. */
+ size_type max_size() const noexcept
+ {
+ if (m_deque.max_size() < std::numeric_limits<difference_type>::max() / BITS_PER_WORD) {
+ return m_deque.max_size() * BITS_PER_WORD;
+ } else {
+ return std::numeric_limits<difference_type>::max();
+ }
+ }
+
+ /** Set the container equal to the bits in [first,last). */
+ template<typename It>
+ void assign(It first, It last)
+ {
+ size_type count = std::distance(first, last);
+ assign(count, false);
+ auto it = begin();
+ while (first != last) {
+ *(it++) = *(first++);
+ }
+ }
+
+ /** Set the container equal to the bits in ilist. */
+ void assign(std::initializer_list<bool> ilist)
+ {
+ assign(ilist.size(), false);
+ auto it = begin();
+ auto init = ilist.begin();
+ while (init != ilist.end()) {
+ *(it++) = *(init++);
+ }
+ }
+
+ /** Set the container equal to the bits in ilist. */
+ bitdeque& operator=(std::initializer_list<bool> ilist)
+ {
+ assign(ilist);
+ return *this;
+ }
+
+ /** Construct a container containing the bits in [first,last). */
+ template<typename It>
+ bitdeque(It first, It last) { assign(first, last); }
+
+ /** Construct a container containing the bits in ilist. */
+ bitdeque(std::initializer_list<bool> ilist) { assign(ilist); }
+
+ // Access an element of the container, with bounds checking.
+ reference at(size_type position)
+ {
+ if (position >= size()) throw std::out_of_range("bitdeque::at() out of range");
+ return begin()[position];
+ }
+ const_reference at(size_type position) const
+ {
+ if (position >= size()) throw std::out_of_range("bitdeque::at() out of range");
+ return cbegin()[position];
+ }
+
+ // Access elements of the container without bounds checking.
+ reference operator[](size_type position) { return begin()[position]; }
+ const_reference operator[](size_type position) const { return cbegin()[position]; }
+ reference front() { return *begin(); }
+ const_reference front() const { return *cbegin(); }
+ reference back() { return end()[-1]; }
+ const_reference back() const { return cend()[-1]; }
+
+ /** Release unused memory. */
+ void shrink_to_fit()
+ {
+ m_deque.shrink_to_fit();
+ }
+
+ /** Empty the container. */
+ void clear() noexcept
+ {
+ m_deque.clear();
+ m_pad_begin = m_pad_end = 0;
+ }
+
+ // Append an element to the container.
+ void push_back(bool val)
+ {
+ extend_back(1);
+ back() = val;
+ }
+ reference emplace_back(bool val)
+ {
+ extend_back(1);
+ auto ref = back();
+ ref = val;
+ return ref;
+ }
+
+ // Prepend an element to the container.
+ void push_front(bool val)
+ {
+ extend_front(1);
+ front() = val;
+ }
+ reference emplace_front(bool val)
+ {
+ extend_front(1);
+ auto ref = front();
+ ref = val;
+ return ref;
+ }
+
+ // Remove the last element from the container.
+ void pop_back()
+ {
+ erase_back(1);
+ }
+
+ // Remove the first element from the container.
+ void pop_front()
+ {
+ erase_front(1);
+ }
+
+ /** Resize the container. */
+ void resize(size_type n)
+ {
+ if (n < size()) {
+ erase_back(size() - n);
+ } else {
+ extend_back(n - size());
+ }
+ }
+
+ // Swap two containers.
+ void swap(bitdeque& other) noexcept
+ {
+ std::swap(m_deque, other.m_deque);
+ std::swap(m_pad_begin, other.m_pad_begin);
+ std::swap(m_pad_end, other.m_pad_end);
+ }
+ friend void swap(bitdeque& b1, bitdeque& b2) noexcept { b1.swap(b2); }
+
+ // Erase elements from the container.
+ iterator erase(const_iterator first, const_iterator last)
+ {
+ size_type before = std::distance(cbegin(), first);
+ size_type dist = std::distance(first, last);
+ size_type after = std::distance(last, cend());
+ if (before < after) {
+ std::move_backward(begin(), begin() + before, end() - after);
+ erase_front(dist);
+ return begin() + before;
+ } else {
+ std::move(end() - after, end(), begin() + before);
+ erase_back(dist);
+ return end() - after;
+ }
+ }
+
+ iterator erase(iterator first, iterator last) { return erase(const_iterator{first}, const_iterator{last}); }
+ iterator erase(const_iterator pos) { return erase(pos, pos + 1); }
+ iterator erase(iterator pos) { return erase(const_iterator{pos}, const_iterator{pos} + 1); }
+
+ // Insert elements into the container.
+ iterator insert(const_iterator pos, bool val)
+ {
+ size_type before = pos - cbegin();
+ insert_zeroes(before, 1);
+ auto it = begin() + before;
+ *it = val;
+ return it;
+ }
+
+ iterator emplace(const_iterator pos, bool val) { return insert(pos, val); }
+
+ iterator insert(const_iterator pos, size_type count, bool val)
+ {
+ size_type before = pos - cbegin();
+ insert_zeroes(before, count);
+ auto it_begin = begin() + before;
+ auto it = it_begin;
+ auto it_end = it + count;
+ while (it != it_end) *(it++) = val;
+ return it_begin;
+ }
+
+ template<typename It>
+ iterator insert(const_iterator pos, It first, It last)
+ {
+ size_type before = pos - cbegin();
+ size_type count = std::distance(first, last);
+ insert_zeroes(before, count);
+ auto it_begin = begin() + before;
+ auto it = it_begin;
+ while (first != last) {
+ *(it++) = *(first++);
+ }
+ return it_begin;
+ }
+};
+
+#endif // BITCOIN_UTIL_BITDEQUE_H
diff --git a/src/util/message.cpp b/src/util/message.cpp
index 028251a5a8..7d6f3403f4 100644
--- a/src/util/message.cpp
+++ b/src/util/message.cpp
@@ -8,7 +8,6 @@
#include <key_io.h>
#include <pubkey.h>
#include <script/standard.h>
-#include <serialize.h>
#include <uint256.h>
#include <util/message.h>
#include <util/strencodings.h>
diff --git a/src/util/strencodings.cpp b/src/util/strencodings.cpp
index 303e19beec..b5ac151374 100644
--- a/src/util/strencodings.cpp
+++ b/src/util/strencodings.cpp
@@ -6,7 +6,6 @@
#include <span.h>
#include <util/strencodings.h>
-#include <algorithm>
#include <array>
#include <cassert>
#include <cstring>
diff --git a/src/util/string.cpp b/src/util/string.cpp
index db6dbe4135..e994c85f1c 100644
--- a/src/util/string.cpp
+++ b/src/util/string.cpp
@@ -6,10 +6,9 @@
#include <regex>
#include <string>
-#include <utility>
void ReplaceAll(std::string& in_out, const std::string& search, const std::string& substitute)
{
if (search.empty()) return;
- in_out = std::regex_replace(in_out, std::regex(std::move(search)), substitute);
+ in_out = std::regex_replace(in_out, std::regex(search), substitute);
}
diff --git a/src/util/string.h b/src/util/string.h
index dd4de888bb..9b4c9a7e28 100644
--- a/src/util/string.h
+++ b/src/util/string.h
@@ -7,7 +7,6 @@
#include <util/spanparsing.h>
-#include <algorithm>
#include <array>
#include <cstdint>
#include <cstring>
@@ -58,34 +57,30 @@ void ReplaceAll(std::string& in_out, const std::string& search, const std::strin
}
/**
- * Join a list of items
+ * Join all container items. Typically used to concatenate strings but accepts
+ * containers with elements of any type.
*
- * @param list The list to join
- * @param separator The separator
- * @param unary_op Apply this operator to each item in the list
+ * @param container The items to join
+ * @param separator The separator
+ * @param unary_op Apply this operator to each item
*/
-template <typename T, typename BaseType, typename UnaryOp>
-auto Join(const std::vector<T>& list, const BaseType& separator, UnaryOp unary_op)
- -> decltype(unary_op(list.at(0)))
+template <typename C, typename S, typename UnaryOp>
+auto Join(const C& container, const S& separator, UnaryOp unary_op)
{
- decltype(unary_op(list.at(0))) ret;
- for (size_t i = 0; i < list.size(); ++i) {
- if (i > 0) ret += separator;
- ret += unary_op(list.at(i));
+ decltype(unary_op(*container.begin())) ret;
+ bool first{true};
+ for (const auto& item : container) {
+ if (!first) ret += separator;
+ ret += unary_op(item);
+ first = false;
}
return ret;
}
-template <typename T, typename T2>
-T Join(const std::vector<T>& list, const T2& separator)
+template <typename C, typename S>
+auto Join(const C& container, const S& separator)
{
- return Join(list, separator, [](const T& i) { return i; });
-}
-
-// Explicit overload needed for c_str arguments, which would otherwise cause a substitution failure in the template above.
-inline std::string Join(const std::vector<std::string>& list, std::string_view separator)
-{
- return Join<std::string>(list, separator);
+ return Join(container, separator, [](const auto& i) { return i; });
}
/**
diff --git a/src/util/system.cpp b/src/util/system.cpp
index 1953a9f836..c3c6cbfef6 100644
--- a/src/util/system.cpp
+++ b/src/util/system.cpp
@@ -831,7 +831,7 @@ std::string HelpMessageOpt(const std::string &option, const std::string &message
std::string("\n\n");
}
-static std::string FormatException(const std::exception* pex, const char* pszThread)
+static std::string FormatException(const std::exception* pex, std::string_view thread_name)
{
#ifdef WIN32
char pszModule[MAX_PATH] = "";
@@ -841,15 +841,15 @@ static std::string FormatException(const std::exception* pex, const char* pszThr
#endif
if (pex)
return strprintf(
- "EXCEPTION: %s \n%s \n%s in %s \n", typeid(*pex).name(), pex->what(), pszModule, pszThread);
+ "EXCEPTION: %s \n%s \n%s in %s \n", typeid(*pex).name(), pex->what(), pszModule, thread_name);
else
return strprintf(
- "UNKNOWN EXCEPTION \n%s in %s \n", pszModule, pszThread);
+ "UNKNOWN EXCEPTION \n%s in %s \n", pszModule, thread_name);
}
-void PrintExceptionContinue(const std::exception* pex, const char* pszThread)
+void PrintExceptionContinue(const std::exception* pex, std::string_view thread_name)
{
- std::string message = FormatException(pex, pszThread);
+ std::string message = FormatException(pex, thread_name);
LogPrintf("\n\n************************\n%s\n", message);
tfm::format(std::cerr, "\n\n************************\n%s\n", message);
}
diff --git a/src/util/system.h b/src/util/system.h
index 756e6642f2..c8e1de6700 100644
--- a/src/util/system.h
+++ b/src/util/system.h
@@ -51,7 +51,7 @@ bool error(const char* fmt, const Args&... args)
return false;
}
-void PrintExceptionContinue(const std::exception *pex, const char* pszThread);
+void PrintExceptionContinue(const std::exception* pex, std::string_view thread_name);
/**
* Ensure file contents are fully committed to disk, using a platform-specific
diff --git a/src/util/thread.cpp b/src/util/thread.cpp
index f9f427ba20..ae98abdb3d 100644
--- a/src/util/thread.cpp
+++ b/src/util/thread.cpp
@@ -10,10 +10,12 @@
#include <exception>
#include <functional>
+#include <string>
+#include <utility>
-void util::TraceThread(const char* thread_name, std::function<void()> thread_func)
+void util::TraceThread(std::string_view thread_name, std::function<void()> thread_func)
{
- util::ThreadRename(thread_name);
+ util::ThreadRename(std::string{thread_name});
try {
LogPrintf("%s thread start\n", thread_name);
thread_func();
diff --git a/src/util/thread.h b/src/util/thread.h
index ca2eccc0c3..b80bf046a0 100644
--- a/src/util/thread.h
+++ b/src/util/thread.h
@@ -6,12 +6,13 @@
#define BITCOIN_UTIL_THREAD_H
#include <functional>
+#include <string>
namespace util {
/**
* A wrapper for do-something-once thread functions.
*/
-void TraceThread(const char* thread_name, std::function<void()> thread_func);
+void TraceThread(std::string_view thread_name, std::function<void()> thread_func);
} // namespace util
diff --git a/src/validation.cpp b/src/validation.cpp
index f4cae07b9e..fb29ca3ae7 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -131,7 +131,7 @@ int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE;
uint256 hashAssumeValid;
arith_uint256 nMinimumChainWork;
-const CBlockIndex* CChainState::FindForkInGlobalIndex(const CBlockLocator& locator) const
+const CBlockIndex* Chainstate::FindForkInGlobalIndex(const CBlockLocator& locator) const
{
AssertLockHeld(cs_main);
@@ -273,7 +273,7 @@ static void LimitMempoolSize(CTxMemPool& pool, CCoinsViewCache& coins_cache)
coins_cache.Uncache(removed);
}
-static bool IsCurrentForFeeEstimation(CChainState& active_chainstate) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+static bool IsCurrentForFeeEstimation(Chainstate& active_chainstate) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
AssertLockHeld(cs_main);
if (active_chainstate.IsInitialBlockDownload())
@@ -286,7 +286,7 @@ static bool IsCurrentForFeeEstimation(CChainState& active_chainstate) EXCLUSIVE_
return true;
}
-void CChainState::MaybeUpdateMempoolForReorg(
+void Chainstate::MaybeUpdateMempoolForReorg(
DisconnectedBlockTransactions& disconnectpool,
bool fAddToMempool)
{
@@ -424,7 +424,7 @@ namespace {
class MemPoolAccept
{
public:
- explicit MemPoolAccept(CTxMemPool& mempool, CChainState& active_chainstate) : m_pool(mempool), m_view(&m_dummy), m_viewmempool(&active_chainstate.CoinsTip(), m_pool), m_active_chainstate(active_chainstate),
+ explicit MemPoolAccept(CTxMemPool& mempool, Chainstate& active_chainstate) : m_pool(mempool), m_view(&m_dummy), m_viewmempool(&active_chainstate.CoinsTip(), m_pool), m_active_chainstate(active_chainstate),
m_limit_ancestors(m_pool.m_limits.ancestor_count),
m_limit_ancestor_size(m_pool.m_limits.ancestor_size_vbytes),
m_limit_descendants(m_pool.m_limits.descendant_count),
@@ -658,7 +658,7 @@ private:
CCoinsViewMemPool m_viewmempool;
CCoinsView m_dummy;
- CChainState& m_active_chainstate;
+ Chainstate& m_active_chainstate;
// The package limits in effect at the time of invocation.
const size_t m_limit_ancestors;
@@ -1411,7 +1411,7 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package,
} // anon namespace
-MempoolAcceptResult AcceptToMemoryPool(CChainState& active_chainstate, const CTransactionRef& tx,
+MempoolAcceptResult AcceptToMemoryPool(Chainstate& active_chainstate, const CTransactionRef& tx,
int64_t accept_time, bool bypass_limits, bool test_accept)
EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
{
@@ -1438,7 +1438,7 @@ MempoolAcceptResult AcceptToMemoryPool(CChainState& active_chainstate, const CTr
return result;
}
-PackageMempoolAcceptResult ProcessNewPackage(CChainState& active_chainstate, CTxMemPool& pool,
+PackageMempoolAcceptResult ProcessNewPackage(Chainstate& active_chainstate, CTxMemPool& pool,
const Package& package, bool test_accept)
{
AssertLockHeld(cs_main);
@@ -1497,7 +1497,7 @@ void CoinsViews::InitCache()
m_cacheview = std::make_unique<CCoinsViewCache>(&m_catcherview);
}
-CChainState::CChainState(
+Chainstate::Chainstate(
CTxMemPool* mempool,
BlockManager& blockman,
ChainstateManager& chainman,
@@ -1508,7 +1508,7 @@ CChainState::CChainState(
m_chainman(chainman),
m_from_snapshot_blockhash(from_snapshot_blockhash) {}
-void CChainState::InitCoinsDB(
+void Chainstate::InitCoinsDB(
size_t cache_size_bytes,
bool in_memory,
bool should_wipe,
@@ -1522,7 +1522,7 @@ void CChainState::InitCoinsDB(
leveldb_name, cache_size_bytes, in_memory, should_wipe);
}
-void CChainState::InitCoinsCache(size_t cache_size_bytes)
+void Chainstate::InitCoinsCache(size_t cache_size_bytes)
{
AssertLockHeld(::cs_main);
assert(m_coins_views != nullptr);
@@ -1532,10 +1532,10 @@ void CChainState::InitCoinsCache(size_t cache_size_bytes)
// Note that though this is marked const, we may end up modifying `m_cached_finished_ibd`, which
// is a performance-related implementation detail. This function must be marked
-// `const` so that `CValidationInterface` clients (which are given a `const CChainState*`)
+// `const` so that `CValidationInterface` clients (which are given a `const Chainstate*`)
// can call it.
//
-bool CChainState::IsInitialBlockDownload() const
+bool Chainstate::IsInitialBlockDownload() const
{
// Optimization: pre-test latch before taking the lock.
if (m_cached_finished_ibd.load(std::memory_order_relaxed))
@@ -1577,7 +1577,7 @@ static void AlertNotify(const std::string& strMessage)
#endif
}
-void CChainState::CheckForkWarningConditions()
+void Chainstate::CheckForkWarningConditions()
{
AssertLockHeld(cs_main);
@@ -1596,7 +1596,7 @@ void CChainState::CheckForkWarningConditions()
}
// Called both upon regular invalid block discovery *and* InvalidateBlock
-void CChainState::InvalidChainFound(CBlockIndex* pindexNew)
+void Chainstate::InvalidChainFound(CBlockIndex* pindexNew)
{
AssertLockHeld(cs_main);
if (!m_chainman.m_best_invalid || pindexNew->nChainWork > m_chainman.m_best_invalid->nChainWork) {
@@ -1619,7 +1619,7 @@ void CChainState::InvalidChainFound(CBlockIndex* pindexNew)
// Same as InvalidChainFound, above, except not called directly from InvalidateBlock,
// which does its own setBlockIndexCandidates management.
-void CChainState::InvalidBlockFound(CBlockIndex* pindex, const BlockValidationState& state)
+void Chainstate::InvalidBlockFound(CBlockIndex* pindex, const BlockValidationState& state)
{
AssertLockHeld(cs_main);
if (state.GetResult() != BlockValidationResult::BLOCK_MUTATED) {
@@ -1824,7 +1824,7 @@ int ApplyTxInUndo(Coin&& undo, CCoinsViewCache& view, const COutPoint& out)
/** Undo the effects of this block (with given index) on the UTXO set represented by coins.
* When FAILED is returned, view is left in an indeterminate state. */
-DisconnectResult CChainState::DisconnectBlock(const CBlock& block, const CBlockIndex* pindex, CCoinsViewCache& view)
+DisconnectResult Chainstate::DisconnectBlock(const CBlock& block, const CBlockIndex* pindex, CCoinsViewCache& view)
{
AssertLockHeld(::cs_main);
bool fClean = true;
@@ -1977,7 +1977,7 @@ static int64_t nBlocksTotal = 0;
/** Apply the effects of this block (with given index) on the UTXO set represented by coins.
* Validity checks that depend on the UTXO set are also done; ConnectBlock()
* can fail if those validity checks fail (among other reasons). */
-bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state, CBlockIndex* pindex,
+bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state, CBlockIndex* pindex,
CCoinsViewCache& view, bool fJustCheck)
{
AssertLockHeld(cs_main);
@@ -2289,7 +2289,7 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
return true;
}
-CoinsCacheSizeState CChainState::GetCoinsCacheSizeState()
+CoinsCacheSizeState Chainstate::GetCoinsCacheSizeState()
{
AssertLockHeld(::cs_main);
return this->GetCoinsCacheSizeState(
@@ -2297,7 +2297,7 @@ CoinsCacheSizeState CChainState::GetCoinsCacheSizeState()
m_mempool ? m_mempool->m_max_size_bytes : 0);
}
-CoinsCacheSizeState CChainState::GetCoinsCacheSizeState(
+CoinsCacheSizeState Chainstate::GetCoinsCacheSizeState(
size_t max_coins_cache_size_bytes,
size_t max_mempool_size_bytes)
{
@@ -2321,7 +2321,7 @@ CoinsCacheSizeState CChainState::GetCoinsCacheSizeState(
return CoinsCacheSizeState::OK;
}
-bool CChainState::FlushStateToDisk(
+bool Chainstate::FlushStateToDisk(
BlockValidationState &state,
FlushStateMode mode,
int nManualPruneHeight)
@@ -2464,7 +2464,7 @@ bool CChainState::FlushStateToDisk(
return true;
}
-void CChainState::ForceFlushStateToDisk()
+void Chainstate::ForceFlushStateToDisk()
{
BlockValidationState state;
if (!this->FlushStateToDisk(state, FlushStateMode::ALWAYS)) {
@@ -2472,7 +2472,7 @@ void CChainState::ForceFlushStateToDisk()
}
}
-void CChainState::PruneAndFlush()
+void Chainstate::PruneAndFlush()
{
BlockValidationState state;
m_blockman.m_check_for_pruning = true;
@@ -2519,7 +2519,7 @@ static void UpdateTipLog(
!warning_messages.empty() ? strprintf(" warning='%s'", warning_messages) : "");
}
-void CChainState::UpdateTip(const CBlockIndex* pindexNew)
+void Chainstate::UpdateTip(const CBlockIndex* pindexNew)
{
AssertLockHeld(::cs_main);
const auto& coins_tip = this->CoinsTip();
@@ -2575,7 +2575,7 @@ void CChainState::UpdateTip(const CBlockIndex* pindexNew)
* disconnectpool (note that the caller is responsible for mempool consistency
* in any case).
*/
-bool CChainState::DisconnectTip(BlockValidationState& state, DisconnectedBlockTransactions* disconnectpool)
+bool Chainstate::DisconnectTip(BlockValidationState& state, DisconnectedBlockTransactions* disconnectpool)
{
AssertLockHeld(cs_main);
if (m_mempool) AssertLockHeld(m_mempool->cs);
@@ -2691,7 +2691,7 @@ public:
*
* The block is added to connectTrace if connection succeeds.
*/
-bool CChainState::ConnectTip(BlockValidationState& state, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions& disconnectpool)
+bool Chainstate::ConnectTip(BlockValidationState& state, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions& disconnectpool)
{
AssertLockHeld(cs_main);
if (m_mempool) AssertLockHeld(m_mempool->cs);
@@ -2759,7 +2759,7 @@ bool CChainState::ConnectTip(BlockValidationState& state, CBlockIndex* pindexNew
* Return the tip of the chain with the most work in it, that isn't
* known to be invalid (it's however far from certain to be valid).
*/
-CBlockIndex* CChainState::FindMostWorkChain()
+CBlockIndex* Chainstate::FindMostWorkChain()
{
AssertLockHeld(::cs_main);
do {
@@ -2818,7 +2818,7 @@ CBlockIndex* CChainState::FindMostWorkChain()
}
/** Delete all entries in setBlockIndexCandidates that are worse than the current tip. */
-void CChainState::PruneBlockIndexCandidates() {
+void Chainstate::PruneBlockIndexCandidates() {
// Note that we can't delete the current block itself, as we may need to return to it later in case a
// reorganization to a better block fails.
std::set<CBlockIndex*, CBlockIndexWorkComparator>::iterator it = setBlockIndexCandidates.begin();
@@ -2835,7 +2835,7 @@ void CChainState::PruneBlockIndexCandidates() {
*
* @returns true unless a system error occurred
*/
-bool CChainState::ActivateBestChainStep(BlockValidationState& state, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace)
+bool Chainstate::ActivateBestChainStep(BlockValidationState& state, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace)
{
AssertLockHeld(cs_main);
if (m_mempool) AssertLockHeld(m_mempool->cs);
@@ -2927,7 +2927,7 @@ static SynchronizationState GetSynchronizationState(bool init)
return SynchronizationState::INIT_DOWNLOAD;
}
-static bool NotifyHeaderTip(CChainState& chainstate) LOCKS_EXCLUDED(cs_main) {
+static bool NotifyHeaderTip(Chainstate& chainstate) LOCKS_EXCLUDED(cs_main) {
bool fNotify = false;
bool fInitialBlockDownload = false;
static CBlockIndex* pindexHeaderOld = nullptr;
@@ -2944,7 +2944,7 @@ static bool NotifyHeaderTip(CChainState& chainstate) LOCKS_EXCLUDED(cs_main) {
}
// Send block tip changed notifications without cs_main
if (fNotify) {
- uiInterface.NotifyHeaderTip(GetSynchronizationState(fInitialBlockDownload), pindexHeader);
+ uiInterface.NotifyHeaderTip(GetSynchronizationState(fInitialBlockDownload), pindexHeader->nHeight, pindexHeader->nTime, false);
}
return fNotify;
}
@@ -2957,7 +2957,7 @@ static void LimitValidationInterfaceQueue() LOCKS_EXCLUDED(cs_main) {
}
}
-bool CChainState::ActivateBestChain(BlockValidationState& state, std::shared_ptr<const CBlock> pblock)
+bool Chainstate::ActivateBestChain(BlockValidationState& state, std::shared_ptr<const CBlock> pblock)
{
AssertLockNotHeld(m_chainstate_mutex);
@@ -3059,7 +3059,7 @@ bool CChainState::ActivateBestChain(BlockValidationState& state, std::shared_ptr
return true;
}
-bool CChainState::PreciousBlock(BlockValidationState& state, CBlockIndex* pindex)
+bool Chainstate::PreciousBlock(BlockValidationState& state, CBlockIndex* pindex)
{
AssertLockNotHeld(m_chainstate_mutex);
AssertLockNotHeld(::cs_main);
@@ -3090,7 +3090,7 @@ bool CChainState::PreciousBlock(BlockValidationState& state, CBlockIndex* pindex
return ActivateBestChain(state, std::shared_ptr<const CBlock>());
}
-bool CChainState::InvalidateBlock(BlockValidationState& state, CBlockIndex* pindex)
+bool Chainstate::InvalidateBlock(BlockValidationState& state, CBlockIndex* pindex)
{
AssertLockNotHeld(m_chainstate_mutex);
AssertLockNotHeld(::cs_main);
@@ -3233,7 +3233,7 @@ bool CChainState::InvalidateBlock(BlockValidationState& state, CBlockIndex* pind
return true;
}
-void CChainState::ResetBlockFailureFlags(CBlockIndex *pindex) {
+void Chainstate::ResetBlockFailureFlags(CBlockIndex *pindex) {
AssertLockHeld(cs_main);
int nHeight = pindex->nHeight;
@@ -3266,7 +3266,7 @@ void CChainState::ResetBlockFailureFlags(CBlockIndex *pindex) {
}
/** Mark a block as having its data received and checked (up to BLOCK_VALID_TRANSACTIONS). */
-void CChainState::ReceivedBlockTransactions(const CBlock& block, CBlockIndex* pindexNew, const FlatFilePos& pos)
+void Chainstate::ReceivedBlockTransactions(const CBlock& block, CBlockIndex* pindexNew, const FlatFilePos& pos)
{
AssertLockHeld(cs_main);
pindexNew->nTx = block.vtx.size();
@@ -3432,6 +3432,22 @@ std::vector<unsigned char> ChainstateManager::GenerateCoinbaseCommitment(CBlock&
return commitment;
}
+bool HasValidProofOfWork(const std::vector<CBlockHeader>& headers, const Consensus::Params& consensusParams)
+{
+ return std::all_of(headers.cbegin(), headers.cend(),
+ [&](const auto& header) { return CheckProofOfWork(header.GetHash(), header.nBits, consensusParams);});
+}
+
+arith_uint256 CalculateHeadersWork(const std::vector<CBlockHeader>& headers)
+{
+ arith_uint256 total_work{0};
+ for (const CBlockHeader& header : headers) {
+ CBlockIndex dummy(header);
+ total_work += GetBlockProof(dummy);
+ }
+ return total_work;
+}
+
/** Context-dependent validity checks.
* By "context", we mean only the previous block headers, but not the UTXO
* set; UTXO-related validity checks are done in ConnectBlock().
@@ -3572,9 +3588,10 @@ static bool ContextualCheckBlock(const CBlock& block, BlockValidationState& stat
return true;
}
-bool ChainstateManager::AcceptBlockHeader(const CBlockHeader& block, BlockValidationState& state, CBlockIndex** ppindex)
+bool ChainstateManager::AcceptBlockHeader(const CBlockHeader& block, BlockValidationState& state, CBlockIndex** ppindex, bool min_pow_checked)
{
AssertLockHeld(cs_main);
+
// Check for duplicate
uint256 hash = block.GetHash();
BlockMap::iterator miSelf{m_blockman.m_block_index.find(hash)};
@@ -3608,7 +3625,7 @@ bool ChainstateManager::AcceptBlockHeader(const CBlockHeader& block, BlockValida
LogPrint(BCLog::VALIDATION, "%s: %s prev block invalid\n", __func__, hash.ToString());
return state.Invalid(BlockValidationResult::BLOCK_INVALID_PREV, "bad-prevblk");
}
- if (!ContextualCheckBlockHeader(block, state, m_blockman, *this, pindexPrev, m_adjusted_time_callback())) {
+ if (!ContextualCheckBlockHeader(block, state, m_blockman, *this, pindexPrev, m_options.adjusted_time_callback())) {
LogPrint(BCLog::VALIDATION, "%s: Consensus::ContextualCheckBlockHeader: %s, %s\n", __func__, hash.ToString(), state.ToString());
return false;
}
@@ -3652,6 +3669,10 @@ bool ChainstateManager::AcceptBlockHeader(const CBlockHeader& block, BlockValida
}
}
}
+ if (!min_pow_checked) {
+ LogPrint(BCLog::VALIDATION, "%s: not adding new block header %s, missing anti-dos proof-of-work validation\n", __func__, hash.ToString());
+ return state.Invalid(BlockValidationResult::BLOCK_HEADER_LOW_WORK, "too-little-chainwork");
+ }
CBlockIndex* pindex{m_blockman.AddToBlockIndex(block, m_best_header)};
if (ppindex)
@@ -3661,14 +3682,14 @@ bool ChainstateManager::AcceptBlockHeader(const CBlockHeader& block, BlockValida
}
// Exposed wrapper for AcceptBlockHeader
-bool ChainstateManager::ProcessNewBlockHeaders(const std::vector<CBlockHeader>& headers, BlockValidationState& state, const CBlockIndex** ppindex)
+bool ChainstateManager::ProcessNewBlockHeaders(const std::vector<CBlockHeader>& headers, bool min_pow_checked, BlockValidationState& state, const CBlockIndex** ppindex)
{
AssertLockNotHeld(cs_main);
{
LOCK(cs_main);
for (const CBlockHeader& header : headers) {
CBlockIndex *pindex = nullptr; // Use a temp pindex instead of ppindex to avoid a const_cast
- bool accepted{AcceptBlockHeader(header, state, &pindex)};
+ bool accepted{AcceptBlockHeader(header, state, &pindex, min_pow_checked)};
ActiveChainstate().CheckBlockIndex();
if (!accepted) {
@@ -3690,8 +3711,33 @@ bool ChainstateManager::ProcessNewBlockHeaders(const std::vector<CBlockHeader>&
return true;
}
+void ChainstateManager::ReportHeadersPresync(const arith_uint256& work, int64_t height, int64_t timestamp)
+{
+ AssertLockNotHeld(cs_main);
+ const auto& chainstate = ActiveChainstate();
+ {
+ LOCK(cs_main);
+ // Don't report headers presync progress if we already have a post-minchainwork header chain.
+ // This means we lose reporting for potentially legitimate, but unlikely, deep reorgs, but
+ // prevent attackers that spam low-work headers from filling our logs.
+ if (m_best_header->nChainWork >= UintToArith256(GetConsensus().nMinimumChainWork)) return;
+ // Rate limit headers presync updates to 4 per second, as these are not subject to DoS
+ // protection.
+ auto now = std::chrono::steady_clock::now();
+ if (now < m_last_presync_update + std::chrono::milliseconds{250}) return;
+ m_last_presync_update = now;
+ }
+ bool initial_download = chainstate.IsInitialBlockDownload();
+ uiInterface.NotifyHeaderTip(GetSynchronizationState(initial_download), height, timestamp, /*presync=*/true);
+ if (initial_download) {
+ const int64_t blocks_left{(GetTime() - timestamp) / GetConsensus().nPowTargetSpacing};
+ const double progress{100.0 * height / (height + blocks_left)};
+ LogPrintf("Pre-synchronizing blockheaders, height: %d (~%.2f%%)\n", height, progress);
+ }
+}
+
/** 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, CBlockIndex** ppindex, bool fRequested, const FlatFilePos* dbp, bool* fNewBlock)
+bool Chainstate::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, BlockValidationState& state, CBlockIndex** ppindex, bool fRequested, const FlatFilePos* dbp, bool* fNewBlock, bool min_pow_checked)
{
const CBlock& block = *pblock;
@@ -3701,7 +3747,7 @@ bool CChainState::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, Block
CBlockIndex *pindexDummy = nullptr;
CBlockIndex *&pindex = ppindex ? *ppindex : pindexDummy;
- bool accepted_header{m_chainman.AcceptBlockHeader(block, state, &pindex)};
+ bool accepted_header{m_chainman.AcceptBlockHeader(block, state, &pindex, min_pow_checked)};
CheckBlockIndex();
if (!accepted_header)
@@ -3774,7 +3820,7 @@ bool CChainState::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, Block
return true;
}
-bool ChainstateManager::ProcessNewBlock(const std::shared_ptr<const CBlock>& block, bool force_processing, bool* new_block)
+bool ChainstateManager::ProcessNewBlock(const std::shared_ptr<const CBlock>& block, bool force_processing, bool min_pow_checked, bool* new_block)
{
AssertLockNotHeld(cs_main);
@@ -3795,7 +3841,7 @@ bool ChainstateManager::ProcessNewBlock(const std::shared_ptr<const CBlock>& blo
bool ret = CheckBlock(*block, state, GetConsensus());
if (ret) {
// Store to disk
- ret = ActiveChainstate().AcceptBlock(block, state, &pindex, force_processing, nullptr, new_block);
+ ret = ActiveChainstate().AcceptBlock(block, state, &pindex, force_processing, nullptr, new_block, min_pow_checked);
}
if (!ret) {
GetMainSignals().BlockChecked(*block, state);
@@ -3816,7 +3862,7 @@ bool ChainstateManager::ProcessNewBlock(const std::shared_ptr<const CBlock>& blo
MempoolAcceptResult ChainstateManager::ProcessTransaction(const CTransactionRef& tx, bool test_accept)
{
AssertLockHeld(cs_main);
- CChainState& active_chainstate = ActiveChainstate();
+ Chainstate& active_chainstate = ActiveChainstate();
if (!active_chainstate.GetMempool()) {
TxValidationState state;
state.Invalid(TxValidationResult::TX_NO_MEMPOOL, "no-mempool");
@@ -3829,7 +3875,7 @@ MempoolAcceptResult ChainstateManager::ProcessTransaction(const CTransactionRef&
bool TestBlockValidity(BlockValidationState& state,
const CChainParams& chainparams,
- CChainState& chainstate,
+ Chainstate& chainstate,
const CBlock& block,
CBlockIndex* pindexPrev,
const std::function<NodeClock::time_point()>& adjusted_time_callback,
@@ -3861,7 +3907,7 @@ bool TestBlockValidity(BlockValidationState& state,
}
/* This function is called from the RPC code for pruneblockchain */
-void PruneBlockFilesManual(CChainState& active_chainstate, int nManualPruneHeight)
+void PruneBlockFilesManual(Chainstate& active_chainstate, int nManualPruneHeight)
{
BlockValidationState state;
if (!active_chainstate.FlushStateToDisk(
@@ -3870,14 +3916,14 @@ void PruneBlockFilesManual(CChainState& active_chainstate, int nManualPruneHeigh
}
}
-void CChainState::LoadMempool(const fs::path& load_path, FopenFn mockable_fopen_function)
+void Chainstate::LoadMempool(const fs::path& load_path, FopenFn mockable_fopen_function)
{
if (!m_mempool) return;
::LoadMempool(*m_mempool, load_path, *this, mockable_fopen_function);
m_mempool->SetLoadTried(!ShutdownRequested());
}
-bool CChainState::LoadChainTip()
+bool Chainstate::LoadChainTip()
{
AssertLockHeld(cs_main);
const CCoinsViewCache& coins_cache = CoinsTip();
@@ -3916,7 +3962,7 @@ CVerifyDB::~CVerifyDB()
}
bool CVerifyDB::VerifyDB(
- CChainState& chainstate,
+ Chainstate& chainstate,
const Consensus::Params& consensus_params,
CCoinsView& coinsview,
int nCheckLevel, int nCheckDepth)
@@ -4032,7 +4078,7 @@ bool CVerifyDB::VerifyDB(
}
/** Apply the effects of a block on the utxo cache, ignoring that it may already have been applied. */
-bool CChainState::RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& inputs)
+bool Chainstate::RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& inputs)
{
AssertLockHeld(cs_main);
// TODO: merge with ConnectBlock
@@ -4053,7 +4099,7 @@ bool CChainState::RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& i
return true;
}
-bool CChainState::ReplayBlocks()
+bool Chainstate::ReplayBlocks()
{
LOCK(cs_main);
@@ -4121,7 +4167,7 @@ bool CChainState::ReplayBlocks()
return true;
}
-bool CChainState::NeedsRedownload() const
+bool Chainstate::NeedsRedownload() const
{
AssertLockHeld(cs_main);
@@ -4139,7 +4185,7 @@ bool CChainState::NeedsRedownload() const
return false;
}
-void CChainState::UnloadBlockIndex()
+void Chainstate::UnloadBlockIndex()
{
AssertLockHeld(::cs_main);
nBlockSequenceId = 1;
@@ -4208,7 +4254,7 @@ bool ChainstateManager::LoadBlockIndex()
// detecting "holistically" whether the block index under consideration
// relied on an assumed-valid ancestor, but this proved to be too slow to
// be practical.
- for (CChainState* chainstate : GetAll()) {
+ for (Chainstate* chainstate : GetAll()) {
if (chainstate->reliesOnAssumedValid() ||
pindex->nHeight < first_assumed_valid_height) {
chainstate->setBlockIndexCandidates.insert(pindex);
@@ -4237,7 +4283,7 @@ bool ChainstateManager::LoadBlockIndex()
return true;
}
-bool CChainState::LoadGenesisBlock()
+bool Chainstate::LoadGenesisBlock()
{
LOCK(cs_main);
@@ -4263,7 +4309,7 @@ bool CChainState::LoadGenesisBlock()
return true;
}
-void CChainState::LoadExternalBlockFile(
+void Chainstate::LoadExternalBlockFile(
FILE* fileIn,
FlatFilePos* dbp,
std::multimap<uint256, FlatFilePos>* blocks_with_unknown_parent)
@@ -4273,7 +4319,7 @@ void CChainState::LoadExternalBlockFile(
// Either both should be specified (-reindex), or neither (-loadblock).
assert(!dbp == !blocks_with_unknown_parent);
- int64_t nStart = GetTimeMillis();
+ const auto start{SteadyClock::now()};
int nLoaded = 0;
try {
@@ -4332,7 +4378,7 @@ void CChainState::LoadExternalBlockFile(
const CBlockIndex* pindex = m_blockman.LookupBlockIndex(hash);
if (!pindex || (pindex->nStatus & BLOCK_HAVE_DATA) == 0) {
BlockValidationState state;
- if (AcceptBlock(pblock, state, nullptr, true, dbp, nullptr)) {
+ if (AcceptBlock(pblock, state, nullptr, true, dbp, nullptr, true)) {
nLoaded++;
}
if (state.IsError()) {
@@ -4370,7 +4416,7 @@ void CChainState::LoadExternalBlockFile(
head.ToString());
LOCK(cs_main);
BlockValidationState dummy;
- if (AcceptBlock(pblockrecursive, dummy, nullptr, true, &it->second, nullptr)) {
+ if (AcceptBlock(pblockrecursive, dummy, nullptr, true, &it->second, nullptr, true)) {
nLoaded++;
queue.push_back(pblockrecursive->GetHash());
}
@@ -4387,10 +4433,10 @@ void CChainState::LoadExternalBlockFile(
} catch (const std::runtime_error& e) {
AbortNode(std::string("System error: ") + e.what());
}
- LogPrintf("Loaded %i blocks from external file in %dms\n", nLoaded, GetTimeMillis() - nStart);
+ LogPrintf("Loaded %i blocks from external file in %dms\n", nLoaded, Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
}
-void CChainState::CheckBlockIndex()
+void Chainstate::CheckBlockIndex()
{
if (!fCheckBlockIndex) {
return;
@@ -4612,7 +4658,7 @@ void CChainState::CheckBlockIndex()
assert(nNodes == forward.size());
}
-std::string CChainState::ToString()
+std::string Chainstate::ToString()
{
AssertLockHeld(::cs_main);
CBlockIndex* tip = m_chain.Tip();
@@ -4621,7 +4667,7 @@ std::string CChainState::ToString()
tip ? tip->nHeight : -1, tip ? tip->GetBlockHash().ToString() : "null");
}
-bool CChainState::ResizeCoinsCaches(size_t coinstip_size, size_t coinsdb_size)
+bool Chainstate::ResizeCoinsCaches(size_t coinstip_size, size_t coinsdb_size)
{
AssertLockHeld(::cs_main);
if (coinstip_size == m_coinstip_cache_size_bytes &&
@@ -4682,10 +4728,10 @@ std::optional<uint256> ChainstateManager::SnapshotBlockhash() const
return std::nullopt;
}
-std::vector<CChainState*> ChainstateManager::GetAll()
+std::vector<Chainstate*> ChainstateManager::GetAll()
{
LOCK(::cs_main);
- std::vector<CChainState*> out;
+ std::vector<Chainstate*> out;
if (!IsSnapshotValidated() && m_ibd_chainstate) {
out.push_back(m_ibd_chainstate.get());
@@ -4698,18 +4744,18 @@ std::vector<CChainState*> ChainstateManager::GetAll()
return out;
}
-CChainState& ChainstateManager::InitializeChainstate(
+Chainstate& ChainstateManager::InitializeChainstate(
CTxMemPool* mempool, const std::optional<uint256>& snapshot_blockhash)
{
AssertLockHeld(::cs_main);
bool is_snapshot = snapshot_blockhash.has_value();
- std::unique_ptr<CChainState>& to_modify =
+ std::unique_ptr<Chainstate>& to_modify =
is_snapshot ? m_snapshot_chainstate : m_ibd_chainstate;
if (to_modify) {
throw std::logic_error("should not be overwriting a chainstate");
}
- to_modify.reset(new CChainState(mempool, m_blockman, *this, snapshot_blockhash));
+ to_modify.reset(new Chainstate(mempool, m_blockman, *this, snapshot_blockhash));
// Snapshot chainstates and initial IBD chaintates always become active.
if (is_snapshot || (!is_snapshot && !m_active_chainstate)) {
@@ -4779,7 +4825,7 @@ bool ChainstateManager::ActivateSnapshot(
}
auto snapshot_chainstate = WITH_LOCK(::cs_main,
- return std::make_unique<CChainState>(
+ return std::make_unique<Chainstate>(
/*mempool=*/nullptr, m_blockman, *this, base_blockhash));
{
@@ -4829,7 +4875,7 @@ static void FlushSnapshotToDisk(CCoinsViewCache& coins_cache, bool snapshot_load
}
bool ChainstateManager::PopulateAndValidateSnapshot(
- CChainState& snapshot_chainstate,
+ Chainstate& snapshot_chainstate,
AutoFile& coins_file,
const SnapshotMetadata& metadata)
{
@@ -4923,7 +4969,7 @@ bool ChainstateManager::PopulateAndValidateSnapshot(
// Important that we set this. This and the coins_cache accesses above are
// sort of a layer violation, but either we reach into the innards of
- // CCoinsViewCache here or we have to invert some of the CChainState to
+ // CCoinsViewCache here or we have to invert some of the Chainstate to
// embed them in a snapshot-activation-specific CCoinsViewCache bulk load
// method.
coins_cache.SetBestBlock(base_blockhash);
@@ -5002,7 +5048,7 @@ bool ChainstateManager::PopulateAndValidateSnapshot(
index->nStatus |= BLOCK_ASSUMED_VALID;
}
- // Fake BLOCK_OPT_WITNESS so that CChainState::NeedsRedownload()
+ // Fake BLOCK_OPT_WITNESS so that Chainstate::NeedsRedownload()
// won't ask to rewind the entire assumed-valid chain on startup.
if (DeploymentActiveAt(*index, *this, Consensus::DEPLOYMENT_SEGWIT)) {
index->nStatus |= BLOCK_OPT_WITNESS;
@@ -5025,7 +5071,7 @@ bool ChainstateManager::PopulateAndValidateSnapshot(
return true;
}
-CChainState& ChainstateManager::ActiveChainstate() const
+Chainstate& ChainstateManager::ActiveChainstate() const
{
LOCK(::cs_main);
assert(m_active_chainstate);
diff --git a/src/validation.h b/src/validation.h
index b1b6689c46..9ba206855f 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -43,7 +43,7 @@
#include <utility>
#include <vector>
-class CChainState;
+class Chainstate;
class CBlockTreeDB;
class CTxMemPool;
class ChainstateManager;
@@ -127,7 +127,7 @@ bool AbortNode(BlockValidationState& state, const std::string& strMessage, const
double GuessVerificationProgress(const ChainTxData& data, const CBlockIndex* pindex);
/** Prune block files up to a given height */
-void PruneBlockFilesManual(CChainState& active_chainstate, int nManualPruneHeight);
+void PruneBlockFilesManual(Chainstate& active_chainstate, int nManualPruneHeight);
/**
* Validation result for a single transaction mempool acceptance.
@@ -240,7 +240,7 @@ struct PackageMempoolAcceptResult
*
* @returns a MempoolAcceptResult indicating whether the transaction was accepted/rejected with reason.
*/
-MempoolAcceptResult AcceptToMemoryPool(CChainState& active_chainstate, const CTransactionRef& tx,
+MempoolAcceptResult AcceptToMemoryPool(Chainstate& active_chainstate, const CTransactionRef& tx,
int64_t accept_time, bool bypass_limits, bool test_accept)
EXCLUSIVE_LOCKS_REQUIRED(cs_main);
@@ -252,7 +252,7 @@ MempoolAcceptResult AcceptToMemoryPool(CChainState& active_chainstate, const CTr
* If a transaction fails, validation will exit early and some results may be missing. It is also
* possible for the package to be partially submitted.
*/
-PackageMempoolAcceptResult ProcessNewPackage(CChainState& active_chainstate, CTxMemPool& pool,
+PackageMempoolAcceptResult ProcessNewPackage(Chainstate& active_chainstate, CTxMemPool& pool,
const Package& txns, bool test_accept)
EXCLUSIVE_LOCKS_REQUIRED(cs_main);
@@ -333,20 +333,26 @@ bool CheckBlock(const CBlock& block, BlockValidationState& state, const Consensu
/** Check a block is completely valid from start to finish (only works on top of our current best block) */
bool TestBlockValidity(BlockValidationState& state,
const CChainParams& chainparams,
- CChainState& chainstate,
+ Chainstate& chainstate,
const CBlock& block,
CBlockIndex* pindexPrev,
const std::function<NodeClock::time_point()>& adjusted_time_callback,
bool fCheckPOW = true,
bool fCheckMerkleRoot = true) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+/** Check with the proof of work on each blockheader matches the value in nBits */
+bool HasValidProofOfWork(const std::vector<CBlockHeader>& headers, const Consensus::Params& consensusParams);
+
+/** Return the sum of the work on a given set of headers */
+arith_uint256 CalculateHeadersWork(const std::vector<CBlockHeader>& headers);
+
/** RAII wrapper for VerifyDB: Verify consistency of the block and coin databases */
class CVerifyDB {
public:
CVerifyDB();
~CVerifyDB();
bool VerifyDB(
- CChainState& chainstate,
+ Chainstate& chainstate,
const Consensus::Params& consensus_params,
CCoinsView& coinsview,
int nCheckLevel,
@@ -362,7 +368,7 @@ enum DisconnectResult
class ConnectTrace;
-/** @see CChainState::FlushStateToDisk */
+/** @see Chainstate::FlushStateToDisk */
enum class FlushStateMode {
NONE,
IF_NEEDED,
@@ -415,7 +421,7 @@ enum class CoinsCacheSizeState
};
/**
- * CChainState stores and provides an API to update our local knowledge of the
+ * Chainstate stores and provides an API to update our local knowledge of the
* current best chain.
*
* Eventually, the API here is targeted at being exposed externally as a
@@ -428,7 +434,7 @@ enum class CoinsCacheSizeState
* whereas block information and metadata independent of the current tip is
* kept in `BlockManager`.
*/
-class CChainState
+class Chainstate
{
protected:
/**
@@ -466,7 +472,7 @@ protected:
public:
//! Reference to a BlockManager instance which itself is shared across all
- //! CChainState instances.
+ //! Chainstate instances.
node::BlockManager& m_blockman;
/** Chain parameters for this chainstate */
@@ -478,7 +484,7 @@ public:
//! chainstate within deeply nested method calls.
ChainstateManager& m_chainman;
- explicit CChainState(
+ explicit Chainstate(
CTxMemPool* mempool,
node::BlockManager& blockman,
ChainstateManager& chainman,
@@ -650,7 +656,7 @@ public:
EXCLUSIVE_LOCKS_REQUIRED(!m_chainstate_mutex)
LOCKS_EXCLUDED(::cs_main);
- bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, BlockValidationState& state, CBlockIndex** ppindex, bool fRequested, const FlatFilePos* dbp, bool* fNewBlock) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, BlockValidationState& state, CBlockIndex** ppindex, bool fRequested, const FlatFilePos* dbp, bool* fNewBlock, bool min_pow_checked) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
// Block (dis)connection on a given view:
DisconnectResult DisconnectBlock(const CBlock& block, const CBlockIndex* pindex, CCoinsViewCache& view)
@@ -808,7 +814,7 @@ private:
//! This is especially important when, e.g., calling ActivateBestChain()
//! on all chainstates because we are not able to hold ::cs_main going into
//! that call.
- std::unique_ptr<CChainState> m_ibd_chainstate GUARDED_BY(::cs_main);
+ std::unique_ptr<Chainstate> m_ibd_chainstate GUARDED_BY(::cs_main);
//! A chainstate initialized on the basis of a UTXO snapshot. If this is
//! non-null, it is always our active chainstate.
@@ -819,7 +825,7 @@ private:
//! This is especially important when, e.g., calling ActivateBestChain()
//! on all chainstates because we are not able to hold ::cs_main going into
//! that call.
- std::unique_ptr<CChainState> m_snapshot_chainstate GUARDED_BY(::cs_main);
+ std::unique_ptr<Chainstate> m_snapshot_chainstate GUARDED_BY(::cs_main);
//! Points to either the ibd or snapshot chainstate; indicates our
//! most-work chain.
@@ -830,7 +836,7 @@ private:
//! This is especially important when, e.g., calling ActivateBestChain()
//! on all chainstates because we are not able to hold ::cs_main going into
//! that call.
- CChainState* m_active_chainstate GUARDED_BY(::cs_main) {nullptr};
+ Chainstate* m_active_chainstate GUARDED_BY(::cs_main) {nullptr};
//! If true, the assumed-valid chainstate has been fully validated
//! by the background validation chainstate.
@@ -838,35 +844,39 @@ private:
CBlockIndex* m_best_invalid GUARDED_BY(::cs_main){nullptr};
- const CChainParams m_chainparams;
-
- const std::function<NodeClock::time_point()> m_adjusted_time_callback;
-
//! Internal helper for ActivateSnapshot().
[[nodiscard]] bool PopulateAndValidateSnapshot(
- CChainState& snapshot_chainstate,
+ Chainstate& snapshot_chainstate,
AutoFile& coins_file,
const node::SnapshotMetadata& metadata);
/**
* If a block header hasn't already been seen, call CheckBlockHeader on it, ensure
* that it doesn't descend from an invalid block, and then add it to m_block_index.
+ * Caller must set min_pow_checked=true in order to add a new header to the
+ * block index (permanent memory storage), indicating that the header is
+ * known to be part of a sufficiently high-work chain (anti-dos check).
*/
bool AcceptBlockHeader(
const CBlockHeader& block,
BlockValidationState& state,
- CBlockIndex** ppindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
- friend CChainState;
+ CBlockIndex** ppindex,
+ bool min_pow_checked) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ friend Chainstate;
+
+ /** Most recent headers presync progress update, for rate-limiting. */
+ std::chrono::time_point<std::chrono::steady_clock> m_last_presync_update GUARDED_BY(::cs_main) {};
public:
using Options = kernel::ChainstateManagerOpts;
- explicit ChainstateManager(const Options& opts)
- : m_chainparams{opts.chainparams},
- m_adjusted_time_callback{Assert(opts.adjusted_time_callback)} {};
+ explicit ChainstateManager(Options options) : m_options{std::move(options)}
+ {
+ Assert(m_options.adjusted_time_callback);
+ }
- const CChainParams& GetParams() const { return m_chainparams; }
- const Consensus::Params& GetConsensus() const { return m_chainparams.GetConsensus(); }
+ const CChainParams& GetParams() const { return m_options.chainparams; }
+ const Consensus::Params& GetConsensus() const { return m_options.chainparams.GetConsensus(); }
/**
* Alias for ::cs_main.
@@ -881,6 +891,7 @@ public:
*/
RecursiveMutex& GetMutex() const LOCK_RETURNED(::cs_main) { return ::cs_main; }
+ const Options m_options;
std::thread m_load_block;
//! A single BlockManager instance is shared across each constructed
//! chainstate to avoid duplicating block metadata.
@@ -925,19 +936,19 @@ public:
// constructor
//! @param[in] snapshot_blockhash If given, signify that this chainstate
//! is based on a snapshot.
- CChainState& InitializeChainstate(
+ Chainstate& InitializeChainstate(
CTxMemPool* mempool,
const std::optional<uint256>& snapshot_blockhash = std::nullopt)
LIFETIMEBOUND EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
//! Get all chainstates currently being used.
- std::vector<CChainState*> GetAll();
+ std::vector<Chainstate*> GetAll();
//! Construct and activate a Chainstate on the basis of UTXO snapshot data.
//!
//! Steps:
//!
- //! - Initialize an unused CChainState.
+ //! - Initialize an unused Chainstate.
//! - Load its `CoinsViews` contents from `coins_file`.
//! - Verify that the hash of the resulting coinsdb matches the expected hash
//! per assumeutxo chain parameters.
@@ -950,7 +961,7 @@ public:
AutoFile& coins_file, const node::SnapshotMetadata& metadata, bool in_memory);
//! The most-work chain.
- CChainState& ActiveChainstate() const;
+ Chainstate& ActiveChainstate() const;
CChain& ActiveChain() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex()) { return ActiveChainstate().m_chain; }
int ActiveHeight() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex()) { return ActiveChain().Height(); }
CBlockIndex* ActiveTip() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex()) { return ActiveChain().Tip(); }
@@ -991,10 +1002,15 @@ public:
*
* @param[in] block The block we want to process.
* @param[in] force_processing Process this block even if unrequested; used for non-network block sources.
+ * @param[in] min_pow_checked True if proof-of-work anti-DoS checks have
+ * been done by caller for headers chain
+ * (note: only affects headers acceptance; if
+ * block header is already present in block
+ * index then this parameter has no effect)
* @param[out] new_block A boolean which is set to indicate if the block was first received via this call
* @returns If the block was processed, independently of block validity
*/
- bool ProcessNewBlock(const std::shared_ptr<const CBlock>& block, bool force_processing, bool* new_block) LOCKS_EXCLUDED(cs_main);
+ bool ProcessNewBlock(const std::shared_ptr<const CBlock>& block, bool force_processing, bool min_pow_checked, bool* new_block) LOCKS_EXCLUDED(cs_main);
/**
* Process incoming block headers.
@@ -1003,10 +1019,11 @@ public:
* validationinterface callback.
*
* @param[in] block The block headers themselves
+ * @param[in] min_pow_checked True if proof-of-work anti-DoS checks have been done by caller for headers chain
* @param[out] state This may be set to an Error state if any error occurred processing them
* @param[out] ppindex If set, the pointer will be set to point to the last new block index object for the given headers
*/
- bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& block, BlockValidationState& state, const CBlockIndex** ppindex = nullptr) LOCKS_EXCLUDED(cs_main);
+ bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& block, bool min_pow_checked, BlockValidationState& state, const CBlockIndex** ppindex = nullptr) LOCKS_EXCLUDED(cs_main);
/**
* Try to add a transaction to the memory pool.
@@ -1030,6 +1047,12 @@ public:
/** Produce the necessary coinbase commitment for a block (modifies the hash, don't call for mined blocks). */
std::vector<unsigned char> GenerateCoinbaseCommitment(CBlock& block, const CBlockIndex* pindexPrev) const;
+ /** This is used by net_processing to report pre-synchronization progress of headers, as
+ * headers are not yet fed to validation during that time, but validation is (for now)
+ * responsible for logging and signalling through NotifyHeaderTip, so it needs this
+ * information. */
+ void ReportHeadersPresync(const arith_uint256& work, int64_t height, int64_t timestamp);
+
~ChainstateManager();
};
diff --git a/src/wallet/bdb.cpp b/src/wallet/bdb.cpp
index deb1293cd4..3a9d277f65 100644
--- a/src/wallet/bdb.cpp
+++ b/src/wallet/bdb.cpp
@@ -533,7 +533,7 @@ bool BerkeleyDatabase::Rewrite(const char* pszSkip)
void BerkeleyEnvironment::Flush(bool fShutdown)
{
- int64_t nStart = GetTimeMillis();
+ const auto start{SteadyClock::now()};
// Flush log data to the actual data file on all files that are not in use
LogPrint(BCLog::WALLETDB, "BerkeleyEnvironment::Flush: [%s] Flush(%s)%s\n", strPath, fShutdown ? "true" : "false", fDbEnvInit ? "" : " database not started");
if (!fDbEnvInit)
@@ -561,7 +561,7 @@ void BerkeleyEnvironment::Flush(bool fShutdown)
no_dbs_accessed = false;
}
}
- LogPrint(BCLog::WALLETDB, "BerkeleyEnvironment::Flush: Flush(%s)%s took %15dms\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " database not started", GetTimeMillis() - nStart);
+ LogPrint(BCLog::WALLETDB, "BerkeleyEnvironment::Flush: Flush(%s)%s took %15dms\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " database not started", Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
if (fShutdown) {
char** listp;
if (no_dbs_accessed) {
@@ -591,14 +591,14 @@ bool BerkeleyDatabase::PeriodicFlush()
const std::string strFile = fs::PathToString(m_filename);
LogPrint(BCLog::WALLETDB, "Flushing %s\n", strFile);
- int64_t nStart = GetTimeMillis();
+ const auto start{SteadyClock::now()};
// Flush wallet file so it's self contained
env->CloseDb(m_filename);
env->CheckpointLSN(strFile);
m_refcount = -1;
- LogPrint(BCLog::WALLETDB, "Flushed %s %dms\n", strFile, GetTimeMillis() - nStart);
+ LogPrint(BCLog::WALLETDB, "Flushed %s %dms\n", strFile, Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
return true;
}
diff --git a/src/wallet/load.cpp b/src/wallet/load.cpp
index c06513588b..6eb0ef5e7a 100644
--- a/src/wallet/load.cpp
+++ b/src/wallet/load.cpp
@@ -151,7 +151,7 @@ void StartWallets(WalletContext& context, CScheduler& scheduler)
if (context.args->GetBoolArg("-flushwallet", DEFAULT_FLUSHWALLET)) {
scheduler.scheduleEvery([&context] { MaybeCompactWalletDB(context); }, std::chrono::milliseconds{500});
}
- scheduler.scheduleEvery([&context] { MaybeResendWalletTxs(context); }, std::chrono::milliseconds{1000});
+ scheduler.scheduleEvery([&context] { MaybeResendWalletTxs(context); }, 1min);
}
void FlushWallets(WalletContext& context)
diff --git a/src/wallet/rpc/backup.cpp b/src/wallet/rpc/backup.cpp
index 306053fd0c..35df151e84 100644
--- a/src/wallet/rpc/backup.cpp
+++ b/src/wallet/rpc/backup.cpp
@@ -101,7 +101,7 @@ RPCHelpMan importprivkey()
"\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n"
"may report that the imported key exists but related transactions are still missing, leading to temporarily incorrect/bogus balances and unspent outputs until rescan completes.\n"
"The rescan parameter can be set to false if the key was never used to create transactions. If it is set to false,\n"
- "but the key was used to create transactions, rescanwallet needs to be called with the appropriate block range.\n"
+ "but the key was used to create transactions, rescanblockchain needs to be called with the appropriate block range.\n"
"Note: Use \"getwalletinfo\" to query the scanning progress.\n",
{
{"privkey", RPCArg::Type::STR, RPCArg::Optional::NO, "The private key (see dumpprivkey)"},
@@ -204,7 +204,7 @@ RPCHelpMan importaddress()
"\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n"
"may report that the imported address exists but related transactions are still missing, leading to temporarily incorrect/bogus balances and unspent outputs until rescan completes.\n"
"The rescan parameter can be set to false if the key was never used to create transactions. If it is set to false,\n"
- "but the key was used to create transactions, rescanwallet needs to be called with the appropriate block range.\n"
+ "but the key was used to create transactions, rescanblockchain needs to be called with the appropriate block range.\n"
"If you have the full public key, you should call importpubkey instead of this.\n"
"Hint: use importmulti to import more than one address.\n"
"\nNote: If you import a non-standard raw script in hex form, outputs sending to it will be treated\n"
@@ -295,7 +295,7 @@ RPCHelpMan importaddress()
RescanWallet(*pwallet, reserver);
{
LOCK(pwallet->cs_wallet);
- pwallet->ReacceptWalletTransactions();
+ pwallet->ResubmitWalletTransactions(/*relay=*/false, /*force=*/true);
}
}
@@ -406,7 +406,7 @@ RPCHelpMan importpubkey()
"\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n"
"may report that the imported pubkey exists but related transactions are still missing, leading to temporarily incorrect/bogus balances and unspent outputs until rescan completes.\n"
"The rescan parameter can be set to false if the key was never used to create transactions. If it is set to false,\n"
- "but the key was used to create transactions, rescanwallet needs to be called with the appropriate block range.\n"
+ "but the key was used to create transactions, rescanblockchain needs to be called with the appropriate block range.\n"
"Note: Use \"getwalletinfo\" to query the scanning progress.\n",
{
{"pubkey", RPCArg::Type::STR, RPCArg::Optional::NO, "The hex-encoded public key"},
@@ -476,7 +476,7 @@ RPCHelpMan importpubkey()
RescanWallet(*pwallet, reserver);
{
LOCK(pwallet->cs_wallet);
- pwallet->ReacceptWalletTransactions();
+ pwallet->ResubmitWalletTransactions(/*relay=*/false, /*force=*/true);
}
}
@@ -1257,7 +1257,7 @@ RPCHelpMan importmulti()
"\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n"
"may report that the imported keys, addresses or scripts exist but related transactions are still missing.\n"
"The rescan parameter can be set to false if the key was never used to create transactions. If it is set to false,\n"
- "but the key was used to create transactions, rescanwallet needs to be called with the appropriate block range.\n"
+ "but the key was used to create transactions, rescanblockchain needs to be called with the appropriate block range.\n"
"Note: Use \"getwalletinfo\" to query the scanning progress.\n",
{
{"requests", RPCArg::Type::ARR, RPCArg::Optional::NO, "Data to be imported",
@@ -1397,7 +1397,7 @@ RPCHelpMan importmulti()
int64_t scannedTime = pwallet->RescanFromTime(nLowestTimestamp, reserver, true /* update */);
{
LOCK(pwallet->cs_wallet);
- pwallet->ReacceptWalletTransactions();
+ pwallet->ResubmitWalletTransactions(/*relay=*/false, /*force=*/true);
}
if (pwallet->IsAbortingRescan()) {
@@ -1691,7 +1691,7 @@ RPCHelpMan importdescriptors()
int64_t scanned_time = pwallet->RescanFromTime(lowest_timestamp, reserver, true /* update */);
{
LOCK(pwallet->cs_wallet);
- pwallet->ReacceptWalletTransactions();
+ pwallet->ResubmitWalletTransactions(/*relay=*/false, /*force=*/true);
}
if (pwallet->IsAbortingRescan()) {
@@ -1784,34 +1784,59 @@ RPCHelpMan listdescriptors()
LOCK(wallet->cs_wallet);
- UniValue descriptors(UniValue::VARR);
const auto active_spk_mans = wallet->GetActiveScriptPubKeyMans();
+
+ struct WalletDescInfo {
+ std::string descriptor;
+ uint64_t creation_time;
+ bool active;
+ std::optional<bool> internal;
+ std::optional<std::pair<int64_t,int64_t>> range;
+ int64_t next_index;
+ };
+
+ std::vector<WalletDescInfo> wallet_descriptors;
for (const auto& spk_man : wallet->GetAllScriptPubKeyMans()) {
const auto desc_spk_man = dynamic_cast<DescriptorScriptPubKeyMan*>(spk_man);
if (!desc_spk_man) {
throw JSONRPCError(RPC_WALLET_ERROR, "Unexpected ScriptPubKey manager type.");
}
- UniValue spk(UniValue::VOBJ);
LOCK(desc_spk_man->cs_desc_man);
const auto& wallet_descriptor = desc_spk_man->GetWalletDescriptor();
std::string descriptor;
-
if (!desc_spk_man->GetDescriptorString(descriptor, priv)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Can't get descriptor string.");
}
- spk.pushKV("desc", descriptor);
- spk.pushKV("timestamp", wallet_descriptor.creation_time);
- spk.pushKV("active", active_spk_mans.count(desc_spk_man) != 0);
- const auto internal = wallet->IsInternalScriptPubKeyMan(desc_spk_man);
- if (internal.has_value()) {
- spk.pushKV("internal", *internal);
+ const bool is_range = wallet_descriptor.descriptor->IsRange();
+ wallet_descriptors.push_back({
+ descriptor,
+ wallet_descriptor.creation_time,
+ active_spk_mans.count(desc_spk_man) != 0,
+ wallet->IsInternalScriptPubKeyMan(desc_spk_man),
+ is_range ? std::optional(std::make_pair(wallet_descriptor.range_start, wallet_descriptor.range_end)) : std::nullopt,
+ wallet_descriptor.next_index
+ });
+ }
+
+ std::sort(wallet_descriptors.begin(), wallet_descriptors.end(), [](const auto& a, const auto& b) {
+ return a.descriptor < b.descriptor;
+ });
+
+ UniValue descriptors(UniValue::VARR);
+ for (const WalletDescInfo& info : wallet_descriptors) {
+ UniValue spk(UniValue::VOBJ);
+ spk.pushKV("desc", info.descriptor);
+ spk.pushKV("timestamp", info.creation_time);
+ spk.pushKV("active", info.active);
+ if (info.internal.has_value()) {
+ spk.pushKV("internal", info.internal.value());
}
- if (wallet_descriptor.descriptor->IsRange()) {
+ if (info.range.has_value()) {
UniValue range(UniValue::VARR);
- range.push_back(wallet_descriptor.range_start);
- range.push_back(wallet_descriptor.range_end - 1);
+ range.push_back(info.range->first);
+ range.push_back(info.range->second - 1);
spk.pushKV("range", range);
- spk.pushKV("next", wallet_descriptor.next_index);
+ spk.pushKV("next", info.next_index);
}
descriptors.push_back(spk);
}
diff --git a/src/wallet/rpc/spend.cpp b/src/wallet/rpc/spend.cpp
index 18136c8e25..e38b13624c 100644
--- a/src/wallet/rpc/spend.cpp
+++ b/src/wallet/rpc/spend.cpp
@@ -1137,7 +1137,7 @@ RPCHelpMan send()
{"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "",
Cat<std::vector<RPCArg>>(
{
- {"add_inputs", RPCArg::Type::BOOL, RPCArg::Default{false}, "If inputs are specified, automatically include more if they are not enough."},
+ {"add_inputs", RPCArg::Type::BOOL, RPCArg::DefaultHint{"false when \"inputs\" are specified, true otherwise"},"Automatically include coins from the wallet to cover the target amount.\n"},
{"include_unsafe", RPCArg::Type::BOOL, RPCArg::Default{false}, "Include inputs that are not safe to spend (unconfirmed transactions from outside keys and unconfirmed replacement transactions).\n"
"Warning: the resulting transaction may become invalid if one of the unsafe inputs disappears.\n"
"If that happens, you will need to fund the transaction with different inputs and republish it."},
@@ -1264,11 +1264,15 @@ RPCHelpMan sendall()
{"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, RPCArg::Default{UniValue::VARR}, "Use exactly the specified inputs to build the transaction. Specifying inputs is incompatible with send_max. A JSON array of JSON objects",
+ {"inputs", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "Use exactly the specified inputs to build the transaction. Specifying inputs is incompatible with send_max.",
{
- {"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"},
+ {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
+ {
+ {"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::DefaultHint{"depends on the value of the 'replaceable' and 'locktime' arguments"}, "The sequence number"},
+ },
+ },
},
},
{"locktime", RPCArg::Type::NUM, RPCArg::Default{0}, "Raw locktime. Non-0 value also locktime-activates inputs"},
@@ -1398,6 +1402,10 @@ RPCHelpMan sendall()
const CAmount fee_from_size{fee_rate.GetFee(tx_size.vsize)};
const CAmount effective_value{total_input_value - fee_from_size};
+ if (fee_from_size > pwallet->m_default_max_tx_fee) {
+ throw JSONRPCError(RPC_WALLET_ERROR, TransactionErrorString(TransactionError::MAX_FEE_EXCEEDED).original);
+ }
+
if (effective_value <= 0) {
if (send_max) {
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Total value of UTXO pool too low to pay for transaction, try using lower feerate.");
@@ -1406,6 +1414,11 @@ RPCHelpMan sendall()
}
}
+ // If this transaction is too large, e.g. because the wallet has many UTXOs, it will be rejected by the node's mempool.
+ if (tx_size.weight > MAX_STANDARD_TX_WEIGHT) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Transaction too large.");
+ }
+
CAmount output_amounts_claimed{0};
for (const CTxOut& out : rawTx.vout) {
output_amounts_claimed += out.nValue;
@@ -1578,7 +1591,7 @@ RPCHelpMan walletcreatefundedpsbt()
{"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "",
Cat<std::vector<RPCArg>>(
{
- {"add_inputs", RPCArg::Type::BOOL, RPCArg::Default{false}, "If inputs are specified, automatically include more if they are not enough."},
+ {"add_inputs", RPCArg::Type::BOOL, RPCArg::DefaultHint{"false when \"inputs\" are specified, true otherwise"}, "Automatically include coins from the wallet to cover the target amount.\n"},
{"include_unsafe", RPCArg::Type::BOOL, RPCArg::Default{false}, "Include inputs that are not safe to spend (unconfirmed transactions from outside keys and unconfirmed replacement transactions).\n"
"Warning: the resulting transaction may become invalid if one of the unsafe inputs disappears.\n"
"If that happens, you will need to fund the transaction with different inputs and republish it."},
diff --git a/src/wallet/rpc/wallet.cpp b/src/wallet/rpc/wallet.cpp
index eb275f9951..675c4a759d 100644
--- a/src/wallet/rpc/wallet.cpp
+++ b/src/wallet/rpc/wallet.cpp
@@ -701,6 +701,59 @@ RPCHelpMan simulaterawtransaction()
};
}
+static RPCHelpMan migratewallet()
+{
+ return RPCHelpMan{"migratewallet",
+ "EXPERIMENTAL warning: This call may not work as expected and may be changed in future releases\n"
+ "\nMigrate the wallet to a descriptor wallet.\n"
+ "A new wallet backup will need to be made.\n"
+ "\nThe migration process will create a backup of the wallet before migrating. This backup\n"
+ "file will be named <wallet name>-<timestamp>.legacy.bak and can be found in the directory\n"
+ "for this wallet. In the event of an incorrect migration, the backup can be restored using restorewallet." +
+ HELP_REQUIRING_PASSPHRASE,
+ {},
+ RPCResult{
+ RPCResult::Type::OBJ, "", "",
+ {
+ {RPCResult::Type::STR, "wallet_name", "The name of the primary migrated wallet"},
+ {RPCResult::Type::STR, "watchonly_name", /*optional=*/true, "The name of the migrated wallet containing the watchonly scripts"},
+ {RPCResult::Type::STR, "solvables_name", /*optional=*/true, "The name of the migrated wallet containing solvable but not watched scripts"},
+ {RPCResult::Type::STR, "backup_path", "The location of the backup of the original wallet"},
+ }
+ },
+ RPCExamples{
+ HelpExampleCli("migratewallet", "")
+ + HelpExampleRpc("migratewallet", "")
+ },
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+ {
+ std::shared_ptr<CWallet> wallet = GetWalletForJSONRPCRequest(request);
+ if (!wallet) return NullUniValue;
+
+ EnsureWalletIsUnlocked(*wallet);
+
+ WalletContext& context = EnsureWalletContext(request.context);
+
+ util::Result<MigrationResult> res = MigrateLegacyToDescriptor(std::move(wallet), context);
+ if (!res) {
+ throw JSONRPCError(RPC_WALLET_ERROR, util::ErrorString(res).original);
+ }
+
+ UniValue r{UniValue::VOBJ};
+ r.pushKV("wallet_name", res->wallet_name);
+ if (res->watchonly_wallet) {
+ r.pushKV("watchonly_name", res->watchonly_wallet->GetName());
+ }
+ if (res->solvables_wallet) {
+ r.pushKV("solvables_name", res->solvables_wallet->GetName());
+ }
+ r.pushKV("backup_path", res->backup_path.u8string());
+
+ return r;
+ },
+ };
+}
+
// addresses
RPCHelpMan getaddressinfo();
RPCHelpMan getnewaddress();
@@ -820,6 +873,7 @@ Span<const CRPCCommand> GetWalletRPCCommands()
{"wallet", &listwallets},
{"wallet", &loadwallet},
{"wallet", &lockunspent},
+ {"wallet", &migratewallet},
{"wallet", &newkeypool},
{"wallet", &removeprunedfunds},
{"wallet", &rescanblockchain},
diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp
index 40d5ecd755..41654579c6 100644
--- a/src/wallet/scriptpubkeyman.cpp
+++ b/src/wallet/scriptpubkeyman.cpp
@@ -999,9 +999,10 @@ bool LegacyScriptPubKeyMan::GetKeyOrigin(const CKeyID& keyID, KeyOriginInfo& inf
{
LOCK(cs_KeyStore);
auto it = mapKeyMetadata.find(keyID);
- if (it != mapKeyMetadata.end()) {
- meta = it->second;
+ if (it == mapKeyMetadata.end()) {
+ return false;
}
+ meta = it->second;
}
if (meta.has_key_origin) {
std::copy(meta.key_origin.fingerprint, meta.key_origin.fingerprint + 4, info.fingerprint);
@@ -1658,6 +1659,318 @@ std::set<CKeyID> LegacyScriptPubKeyMan::GetKeys() const
return set_address;
}
+const std::unordered_set<CScript, SaltedSipHasher> LegacyScriptPubKeyMan::GetScriptPubKeys() const
+{
+ LOCK(cs_KeyStore);
+ std::unordered_set<CScript, SaltedSipHasher> spks;
+
+ // All keys have at least P2PK and P2PKH
+ for (const auto& key_pair : mapKeys) {
+ const CPubKey& pub = key_pair.second.GetPubKey();
+ spks.insert(GetScriptForRawPubKey(pub));
+ spks.insert(GetScriptForDestination(PKHash(pub)));
+ }
+ for (const auto& key_pair : mapCryptedKeys) {
+ const CPubKey& pub = key_pair.second.first;
+ spks.insert(GetScriptForRawPubKey(pub));
+ spks.insert(GetScriptForDestination(PKHash(pub)));
+ }
+
+ // For every script in mapScript, only the ISMINE_SPENDABLE ones are being tracked.
+ // The watchonly ones will be in setWatchOnly which we deal with later
+ // For all keys, if they have segwit scripts, those scripts will end up in mapScripts
+ for (const auto& script_pair : mapScripts) {
+ const CScript& script = script_pair.second;
+ if (IsMine(script) == ISMINE_SPENDABLE) {
+ // Add ScriptHash for scripts that are not already P2SH
+ if (!script.IsPayToScriptHash()) {
+ spks.insert(GetScriptForDestination(ScriptHash(script)));
+ }
+ // For segwit scripts, we only consider them spendable if we have the segwit spk
+ int wit_ver = -1;
+ std::vector<unsigned char> witprog;
+ if (script.IsWitnessProgram(wit_ver, witprog) && wit_ver == 0) {
+ spks.insert(script);
+ }
+ } else {
+ // Multisigs are special. They don't show up as ISMINE_SPENDABLE unless they are in a P2SH
+ // So check the P2SH of a multisig to see if we should insert it
+ std::vector<std::vector<unsigned char>> sols;
+ TxoutType type = Solver(script, sols);
+ if (type == TxoutType::MULTISIG) {
+ CScript ms_spk = GetScriptForDestination(ScriptHash(script));
+ if (IsMine(ms_spk) != ISMINE_NO) {
+ spks.insert(ms_spk);
+ }
+ }
+ }
+ }
+
+ // All watchonly scripts are raw
+ spks.insert(setWatchOnly.begin(), setWatchOnly.end());
+
+ return spks;
+}
+
+std::optional<MigrationData> LegacyScriptPubKeyMan::MigrateToDescriptor()
+{
+ LOCK(cs_KeyStore);
+ if (m_storage.IsLocked()) {
+ return std::nullopt;
+ }
+
+ MigrationData out;
+
+ std::unordered_set<CScript, SaltedSipHasher> spks{GetScriptPubKeys()};
+
+ // Get all key ids
+ std::set<CKeyID> keyids;
+ for (const auto& key_pair : mapKeys) {
+ keyids.insert(key_pair.first);
+ }
+ for (const auto& key_pair : mapCryptedKeys) {
+ keyids.insert(key_pair.first);
+ }
+
+ // Get key metadata and figure out which keys don't have a seed
+ // Note that we do not ignore the seeds themselves because they are considered IsMine!
+ for (auto keyid_it = keyids.begin(); keyid_it != keyids.end();) {
+ const CKeyID& keyid = *keyid_it;
+ const auto& it = mapKeyMetadata.find(keyid);
+ if (it != mapKeyMetadata.end()) {
+ const CKeyMetadata& meta = it->second;
+ if (meta.hdKeypath == "s" || meta.hdKeypath == "m") {
+ keyid_it++;
+ continue;
+ }
+ if (m_hd_chain.seed_id == meta.hd_seed_id || m_inactive_hd_chains.count(meta.hd_seed_id) > 0) {
+ keyid_it = keyids.erase(keyid_it);
+ continue;
+ }
+ }
+ keyid_it++;
+ }
+
+ // keyids is now all non-HD keys. Each key will have its own combo descriptor
+ for (const CKeyID& keyid : keyids) {
+ CKey key;
+ if (!GetKey(keyid, key)) {
+ assert(false);
+ }
+
+ // Get birthdate from key meta
+ uint64_t creation_time = 0;
+ const auto& it = mapKeyMetadata.find(keyid);
+ if (it != mapKeyMetadata.end()) {
+ creation_time = it->second.nCreateTime;
+ }
+
+ // Get the key origin
+ // Maybe this doesn't matter because floating keys here shouldn't have origins
+ KeyOriginInfo info;
+ bool has_info = GetKeyOrigin(keyid, info);
+ std::string origin_str = has_info ? "[" + HexStr(info.fingerprint) + FormatHDKeypath(info.path) + "]" : "";
+
+ // Construct the combo descriptor
+ std::string desc_str = "combo(" + origin_str + HexStr(key.GetPubKey()) + ")";
+ FlatSigningProvider keys;
+ std::string error;
+ std::unique_ptr<Descriptor> desc = Parse(desc_str, keys, error, false);
+ WalletDescriptor w_desc(std::move(desc), creation_time, 0, 0, 0);
+
+ // Make the DescriptorScriptPubKeyMan and get the scriptPubKeys
+ auto desc_spk_man = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(m_storage, w_desc));
+ desc_spk_man->AddDescriptorKey(key, key.GetPubKey());
+ desc_spk_man->TopUp();
+ auto desc_spks = desc_spk_man->GetScriptPubKeys();
+
+ // Remove the scriptPubKeys from our current set
+ for (const CScript& spk : desc_spks) {
+ size_t erased = spks.erase(spk);
+ assert(erased == 1);
+ assert(IsMine(spk) == ISMINE_SPENDABLE);
+ }
+
+ out.desc_spkms.push_back(std::move(desc_spk_man));
+ }
+
+ // Handle HD keys by using the CHDChains
+ std::vector<CHDChain> chains;
+ chains.push_back(m_hd_chain);
+ for (const auto& chain_pair : m_inactive_hd_chains) {
+ chains.push_back(chain_pair.second);
+ }
+ for (const CHDChain& chain : chains) {
+ for (int i = 0; i < 2; ++i) {
+ // Skip if doing internal chain and split chain is not supported
+ if (chain.seed_id.IsNull() || (i == 1 && !m_storage.CanSupportFeature(FEATURE_HD_SPLIT))) {
+ continue;
+ }
+ // Get the master xprv
+ CKey seed_key;
+ if (!GetKey(chain.seed_id, seed_key)) {
+ assert(false);
+ }
+ CExtKey master_key;
+ master_key.SetSeed(seed_key);
+
+ // Make the combo descriptor
+ std::string xpub = EncodeExtPubKey(master_key.Neuter());
+ std::string desc_str = "combo(" + xpub + "/0'/" + ToString(i) + "'/*')";
+ FlatSigningProvider keys;
+ std::string error;
+ std::unique_ptr<Descriptor> desc = Parse(desc_str, keys, error, false);
+ uint32_t chain_counter = std::max((i == 1 ? chain.nInternalChainCounter : chain.nExternalChainCounter), (uint32_t)0);
+ WalletDescriptor w_desc(std::move(desc), 0, 0, chain_counter, 0);
+
+ // Make the DescriptorScriptPubKeyMan and get the scriptPubKeys
+ auto desc_spk_man = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(m_storage, w_desc));
+ desc_spk_man->AddDescriptorKey(master_key.key, master_key.key.GetPubKey());
+ desc_spk_man->TopUp();
+ auto desc_spks = desc_spk_man->GetScriptPubKeys();
+
+ // Remove the scriptPubKeys from our current set
+ for (const CScript& spk : desc_spks) {
+ size_t erased = spks.erase(spk);
+ assert(erased == 1);
+ assert(IsMine(spk) == ISMINE_SPENDABLE);
+ }
+
+ out.desc_spkms.push_back(std::move(desc_spk_man));
+ }
+ }
+ // Add the current master seed to the migration data
+ if (!m_hd_chain.seed_id.IsNull()) {
+ CKey seed_key;
+ if (!GetKey(m_hd_chain.seed_id, seed_key)) {
+ assert(false);
+ }
+ out.master_key.SetSeed(seed_key);
+ }
+
+ // Handle the rest of the scriptPubKeys which must be imports and may not have all info
+ for (auto it = spks.begin(); it != spks.end();) {
+ const CScript& spk = *it;
+
+ // Get birthdate from script meta
+ uint64_t creation_time = 0;
+ const auto& mit = m_script_metadata.find(CScriptID(spk));
+ if (mit != m_script_metadata.end()) {
+ creation_time = mit->second.nCreateTime;
+ }
+
+ // InferDescriptor as that will get us all the solving info if it is there
+ std::unique_ptr<Descriptor> desc = InferDescriptor(spk, *GetSolvingProvider(spk));
+ // Get the private keys for this descriptor
+ std::vector<CScript> scripts;
+ FlatSigningProvider keys;
+ if (!desc->Expand(0, DUMMY_SIGNING_PROVIDER, scripts, keys)) {
+ assert(false);
+ }
+ std::set<CKeyID> privkeyids;
+ for (const auto& key_orig_pair : keys.origins) {
+ privkeyids.insert(key_orig_pair.first);
+ }
+
+ std::vector<CScript> desc_spks;
+
+ // Make the descriptor string with private keys
+ std::string desc_str;
+ bool watchonly = !desc->ToPrivateString(*this, desc_str);
+ if (watchonly && !m_storage.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
+ out.watch_descs.push_back({desc->ToString(), creation_time});
+
+ // Get the scriptPubKeys without writing this to the wallet
+ FlatSigningProvider provider;
+ desc->Expand(0, provider, desc_spks, provider);
+ } else {
+ // Make the DescriptorScriptPubKeyMan and get the scriptPubKeys
+ WalletDescriptor w_desc(std::move(desc), creation_time, 0, 0, 0);
+ auto desc_spk_man = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(m_storage, w_desc));
+ for (const auto& keyid : privkeyids) {
+ CKey key;
+ if (!GetKey(keyid, key)) {
+ continue;
+ }
+ desc_spk_man->AddDescriptorKey(key, key.GetPubKey());
+ }
+ desc_spk_man->TopUp();
+ auto desc_spks_set = desc_spk_man->GetScriptPubKeys();
+ desc_spks.insert(desc_spks.end(), desc_spks_set.begin(), desc_spks_set.end());
+
+ out.desc_spkms.push_back(std::move(desc_spk_man));
+ }
+
+ // Remove the scriptPubKeys from our current set
+ for (const CScript& desc_spk : desc_spks) {
+ auto del_it = spks.find(desc_spk);
+ assert(del_it != spks.end());
+ assert(IsMine(desc_spk) != ISMINE_NO);
+ it = spks.erase(del_it);
+ }
+ }
+
+ // Multisigs are special. They don't show up as ISMINE_SPENDABLE unless they are in a P2SH
+ // So we have to check if any of our scripts are a multisig and if so, add the P2SH
+ for (const auto& script_pair : mapScripts) {
+ const CScript script = script_pair.second;
+
+ // Get birthdate from script meta
+ uint64_t creation_time = 0;
+ const auto& it = m_script_metadata.find(CScriptID(script));
+ if (it != m_script_metadata.end()) {
+ creation_time = it->second.nCreateTime;
+ }
+
+ std::vector<std::vector<unsigned char>> sols;
+ TxoutType type = Solver(script, sols);
+ if (type == TxoutType::MULTISIG) {
+ CScript sh_spk = GetScriptForDestination(ScriptHash(script));
+ CTxDestination witdest = WitnessV0ScriptHash(script);
+ CScript witprog = GetScriptForDestination(witdest);
+ CScript sh_wsh_spk = GetScriptForDestination(ScriptHash(witprog));
+
+ // We only want the multisigs that we have not already seen, i.e. they are not watchonly and not spendable
+ // For P2SH, a multisig is not ISMINE_NO when:
+ // * All keys are in the wallet
+ // * The multisig itself is watch only
+ // * The P2SH is watch only
+ // For P2SH-P2WSH, if the script is in the wallet, then it will have the same conditions as P2SH.
+ // For P2WSH, a multisig is not ISMINE_NO when, other than the P2SH conditions:
+ // * The P2WSH script is in the wallet and it is being watched
+ std::vector<std::vector<unsigned char>> keys(sols.begin() + 1, sols.begin() + sols.size() - 1);
+ if (HaveWatchOnly(sh_spk) || HaveWatchOnly(script) || HaveKeys(keys, *this) || (HaveCScript(CScriptID(witprog)) && HaveWatchOnly(witprog))) {
+ // The above emulates IsMine for these 3 scriptPubKeys, so double check that by running IsMine
+ assert(IsMine(sh_spk) != ISMINE_NO || IsMine(witprog) != ISMINE_NO || IsMine(sh_wsh_spk) != ISMINE_NO);
+ continue;
+ }
+ assert(IsMine(sh_spk) == ISMINE_NO && IsMine(witprog) == ISMINE_NO && IsMine(sh_wsh_spk) == ISMINE_NO);
+
+ std::unique_ptr<Descriptor> sh_desc = InferDescriptor(sh_spk, *GetSolvingProvider(sh_spk));
+ out.solvable_descs.push_back({sh_desc->ToString(), creation_time});
+
+ const auto desc = InferDescriptor(witprog, *this);
+ if (desc->IsSolvable()) {
+ std::unique_ptr<Descriptor> wsh_desc = InferDescriptor(witprog, *GetSolvingProvider(witprog));
+ out.solvable_descs.push_back({wsh_desc->ToString(), creation_time});
+ std::unique_ptr<Descriptor> sh_wsh_desc = InferDescriptor(sh_wsh_spk, *GetSolvingProvider(sh_wsh_spk));
+ out.solvable_descs.push_back({sh_wsh_desc->ToString(), creation_time});
+ }
+ }
+ }
+
+ // Make sure that we have accounted for all scriptPubKeys
+ assert(spks.size() == 0);
+ return out;
+}
+
+bool LegacyScriptPubKeyMan::DeleteRecords()
+{
+ LOCK(cs_KeyStore);
+ WalletBatch batch(m_storage.GetDatabase());
+ return batch.EraseRecords(DBKeys::LEGACY_TYPES);
+}
+
util::Result<CTxDestination> DescriptorScriptPubKeyMan::GetNewDestination(const OutputType type)
{
// Returns true if this descriptor supports getting new addresses. Conditions where we may be unable to fetch them (e.g. locked) are caught later
@@ -2327,14 +2640,14 @@ const WalletDescriptor DescriptorScriptPubKeyMan::GetWalletDescriptor() const
return m_wallet_descriptor;
}
-const std::vector<CScript> DescriptorScriptPubKeyMan::GetScriptPubKeys() const
+const std::unordered_set<CScript, SaltedSipHasher> DescriptorScriptPubKeyMan::GetScriptPubKeys() const
{
LOCK(cs_desc_man);
- std::vector<CScript> script_pub_keys;
+ std::unordered_set<CScript, SaltedSipHasher> script_pub_keys;
script_pub_keys.reserve(m_map_script_pub_keys.size());
for (auto const& script_pub_key: m_map_script_pub_keys) {
- script_pub_keys.push_back(script_pub_key.first);
+ script_pub_keys.insert(script_pub_key.first);
}
return script_pub_keys;
}
diff --git a/src/wallet/scriptpubkeyman.h b/src/wallet/scriptpubkeyman.h
index 408d162eba..3ab489c374 100644
--- a/src/wallet/scriptpubkeyman.h
+++ b/src/wallet/scriptpubkeyman.h
@@ -242,6 +242,9 @@ public:
virtual uint256 GetID() const { return uint256(); }
+ /** Returns a set of all the scriptPubKeys that this ScriptPubKeyMan watches */
+ virtual const std::unordered_set<CScript, SaltedSipHasher> GetScriptPubKeys() const { return {}; };
+
/** Prepends the wallet name in logging output to ease debugging in multi-wallet use cases */
template<typename... Params>
void WalletLogPrintf(std::string fmt, Params... parameters) const {
@@ -262,6 +265,8 @@ static const std::unordered_set<OutputType> LEGACY_OUTPUT_TYPES {
OutputType::BECH32,
};
+class DescriptorScriptPubKeyMan;
+
class LegacyScriptPubKeyMan : public ScriptPubKeyMan, public FillableSigningProvider
{
private:
@@ -507,6 +512,13 @@ public:
const std::map<CKeyID, int64_t>& GetAllReserveKeys() const { return m_pool_key_to_index; }
std::set<CKeyID> GetKeys() const override;
+ const std::unordered_set<CScript, SaltedSipHasher> GetScriptPubKeys() const override;
+
+ /** Get the DescriptorScriptPubKeyMans (with private keys) that have the same scriptPubKeys as this LegacyScriptPubKeyMan.
+ * Does not modify this ScriptPubKeyMan. */
+ std::optional<MigrationData> MigrateToDescriptor();
+ /** Delete all the records ofthis LegacyScriptPubKeyMan from disk*/
+ bool DeleteRecords();
};
/** Wraps a LegacyScriptPubKeyMan so that it can be returned in a new unique_ptr. Does not provide privkeys */
@@ -630,7 +642,7 @@ public:
void WriteDescriptor();
const WalletDescriptor GetWalletDescriptor() const EXCLUSIVE_LOCKS_REQUIRED(cs_desc_man);
- const std::vector<CScript> GetScriptPubKeys() const;
+ const std::unordered_set<CScript, SaltedSipHasher> GetScriptPubKeys() const override;
bool GetDescriptorString(std::string& out, const bool priv) const;
diff --git a/src/wallet/spend.cpp b/src/wallet/spend.cpp
index 92cf771358..d84310c323 100644
--- a/src/wallet/spend.cpp
+++ b/src/wallet/spend.cpp
@@ -353,7 +353,7 @@ std::map<CTxDestination, std::vector<COutput>> ListCoins(const CWallet& wallet)
std::map<CTxDestination, std::vector<COutput>> result;
- for (const COutput& coin : AvailableCoinsListUnspent(wallet).All()) {
+ for (COutput& coin : AvailableCoinsListUnspent(wallet).All()) {
CTxDestination address;
if ((coin.spendable || (wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && coin.solvable)) &&
ExtractDestination(FindNonChangeParentOutput(wallet, coin.outpoint).scriptPubKey, address)) {
diff --git a/src/wallet/test/ismine_tests.cpp b/src/wallet/test/ismine_tests.cpp
index dd5cd0af46..68146eb079 100644
--- a/src/wallet/test/ismine_tests.cpp
+++ b/src/wallet/test/ismine_tests.cpp
@@ -43,11 +43,13 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// Keystore does not have key
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
// Keystore has key
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1);
}
// P2PK uncompressed
@@ -60,11 +62,13 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// Keystore does not have key
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
// Keystore has key
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey));
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1);
}
// P2PKH compressed
@@ -77,11 +81,13 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// Keystore does not have key
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
// Keystore has key
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1);
}
// P2PKH uncompressed
@@ -94,11 +100,13 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// Keystore does not have key
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
// Keystore has key
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey));
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1);
}
// P2SH
@@ -113,16 +121,19 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// Keystore does not have redeemScript or key
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
// Keystore has redeemScript but no key
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(redeemScript));
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
// Keystore has redeemScript and key
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1);
}
// (P2PKH inside) P2SH inside P2SH (invalid)
@@ -141,6 +152,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
}
// (P2PKH inside) P2SH inside P2WSH (invalid)
@@ -159,6 +171,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
}
// P2WPKH inside P2WSH (invalid)
@@ -175,6 +188,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
}
// (P2PKH inside) P2WSH inside P2WSH (invalid)
@@ -193,6 +207,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
}
// P2WPKH compressed
@@ -208,6 +223,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(scriptPubKey));
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1);
}
// P2WPKH uncompressed
@@ -222,11 +238,13 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// Keystore has key, but no P2SH redeemScript
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
// Keystore has key and P2SH redeemScript
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(scriptPubKey));
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
}
// scriptPubKey multisig
@@ -240,24 +258,28 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// Keystore does not have any keys
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
// Keystore has 1/2 keys
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey));
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
// Keystore has 2/2 keys
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[1]));
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
// Keystore has 2/2 keys and the script
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(scriptPubKey));
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
}
// P2SH multisig
@@ -274,11 +296,13 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// Keystore has no redeemScript
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
// Keystore has redeemScript
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(redeemScript));
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1);
}
// P2WSH multisig with compressed keys
@@ -295,16 +319,19 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// Keystore has keys, but no witnessScript or P2SH redeemScript
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
// Keystore has keys and witnessScript, but no P2SH redeemScript
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(witnessScript));
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
// Keystore has keys, witnessScript, P2SH redeemScript
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(scriptPubKey));
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1);
}
// P2WSH multisig with uncompressed key
@@ -321,16 +348,19 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// Keystore has keys, but no witnessScript or P2SH redeemScript
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
// Keystore has keys and witnessScript, but no P2SH redeemScript
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(witnessScript));
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
// Keystore has keys, witnessScript, P2SH redeemScript
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(scriptPubKey));
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
}
// P2WSH multisig wrapped in P2SH
@@ -346,18 +376,21 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// Keystore has no witnessScript, P2SH redeemScript, or keys
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
// Keystore has witnessScript and P2SH redeemScript, but no keys
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(redeemScript));
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(witnessScript));
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
// Keystore has keys, witnessScript, P2SH redeemScript
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[1]));
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1);
}
// OP_RETURN
@@ -372,6 +405,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
}
// witness unspendable
@@ -386,6 +420,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
}
// witness unknown
@@ -400,6 +435,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
}
// Nonstandard
@@ -414,6 +450,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
}
}
diff --git a/src/wallet/test/walletload_tests.cpp b/src/wallet/test/walletload_tests.cpp
new file mode 100644
index 0000000000..f45b69a418
--- /dev/null
+++ b/src/wallet/test/walletload_tests.cpp
@@ -0,0 +1,54 @@
+// Copyright (c) 2022 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or https://www.opensource.org/licenses/mit-license.php.
+
+#include <wallet/wallet.h>
+#include <test/util/setup_common.h>
+
+#include <boost/test/unit_test.hpp>
+
+namespace wallet {
+
+BOOST_AUTO_TEST_SUITE(walletload_tests)
+
+class DummyDescriptor final : public Descriptor {
+private:
+ std::string desc;
+public:
+ explicit DummyDescriptor(const std::string& descriptor) : desc(descriptor) {};
+ ~DummyDescriptor() = default;
+
+ std::string ToString() const override { return desc; }
+ std::optional<OutputType> GetOutputType() const override { return OutputType::UNKNOWN; }
+
+ bool IsRange() const override { return false; }
+ bool IsSolvable() const override { return false; }
+ bool IsSingleType() const override { return true; }
+ bool ToPrivateString(const SigningProvider& provider, std::string& out) const override { return false; }
+ bool ToNormalizedString(const SigningProvider& provider, std::string& out, const DescriptorCache* cache = nullptr) const override { return false; }
+ bool Expand(int pos, const SigningProvider& provider, std::vector<CScript>& output_scripts, FlatSigningProvider& out, DescriptorCache* write_cache = nullptr) const override { return false; };
+ bool ExpandFromCache(int pos, const DescriptorCache& read_cache, std::vector<CScript>& output_scripts, FlatSigningProvider& out) const override { return false; }
+ void ExpandPrivate(int pos, const SigningProvider& provider, FlatSigningProvider& out) const override {}
+};
+
+BOOST_FIXTURE_TEST_CASE(wallet_load_unknown_descriptor, TestingSetup)
+{
+ std::unique_ptr<WalletDatabase> database = CreateMockWalletDatabase();
+ {
+ // Write unknown active descriptor
+ WalletBatch batch(*database, false);
+ std::string unknown_desc = "trx(tpubD6NzVbkrYhZ4Y4S7m6Y5s9GD8FqEMBy56AGphZXuagajudVZEnYyBahZMgHNCTJc2at82YX6s8JiL1Lohu5A3v1Ur76qguNH4QVQ7qYrBQx/86'/1'/0'/0/*)#8pn8tzdt";
+ WalletDescriptor wallet_descriptor(std::make_shared<DummyDescriptor>(unknown_desc), 0, 0, 0, 0);
+ BOOST_CHECK(batch.WriteDescriptor(uint256(), wallet_descriptor));
+ BOOST_CHECK(batch.WriteActiveScriptPubKeyMan(static_cast<uint8_t>(OutputType::UNKNOWN), uint256(), false));
+ }
+
+ {
+ // Now try to load the wallet and verify the error.
+ const std::shared_ptr<CWallet> wallet(new CWallet(m_node.chain.get(), "", m_args, std::move(database)));
+ BOOST_CHECK_EQUAL(wallet->LoadWallet(), DBErrors::UNKNOWN_DESCRIPTOR);
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+} // namespace wallet
diff --git a/src/wallet/transaction.h b/src/wallet/transaction.h
index 271d698e56..27983e356d 100644
--- a/src/wallet/transaction.h
+++ b/src/wallet/transaction.h
@@ -305,6 +305,13 @@ public:
CWalletTx(CWalletTx const &) = delete;
void operator=(CWalletTx const &x) = delete;
};
+
+struct WalletTxOrderComparator {
+ bool operator()(const CWalletTx* a, const CWalletTx* b) const
+ {
+ return a->nOrderPos < b->nOrderPos;
+ }
+};
} // namespace wallet
#endif // BITCOIN_WALLET_TRANSACTION_H
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 3d989d90f8..c084ef10ec 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -542,6 +542,7 @@ void CWallet::SetMinVersion(enum WalletFeature nVersion, WalletBatch* batch_in)
LOCK(cs_wallet);
if (nWalletVersion >= nVersion)
return;
+ WalletLogPrintf("Setting minversion to %d\n", nVersion);
nWalletVersion = nVersion;
{
@@ -881,7 +882,7 @@ bool CWallet::MarkReplaced(const uint256& originalHash, const uint256& newHash)
wtx.mapValue["replaced_by_txid"] = newHash.ToString();
- // Refresh mempool status without waiting for transactionRemovedFromMempool
+ // Refresh mempool status without waiting for transactionRemovedFromMempool or transactionAddedToMempool
RefreshMempoolStatus(wtx, chain());
WalletBatch batch(GetDatabase());
@@ -1856,34 +1857,6 @@ CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_bloc
return result;
}
-void CWallet::ReacceptWalletTransactions()
-{
- // If transactions aren't being broadcasted, don't let them into local mempool either
- if (!fBroadcastTransactions)
- return;
- std::map<int64_t, CWalletTx*> mapSorted;
-
- // Sort pending wallet transactions based on their initial wallet insertion order
- for (std::pair<const uint256, CWalletTx>& item : mapWallet) {
- const uint256& wtxid = item.first;
- CWalletTx& wtx = item.second;
- assert(wtx.GetHash() == wtxid);
-
- int nDepth = GetTxDepthInMainChain(wtx);
-
- if (!wtx.IsCoinBase() && (nDepth == 0 && !wtx.isAbandoned())) {
- mapSorted.insert(std::make_pair(wtx.nOrderPos, &wtx));
- }
- }
-
- // Try to add wallet transactions to memory pool
- for (const std::pair<const int64_t, CWalletTx*>& item : mapSorted) {
- CWalletTx& wtx = *(item.second);
- std::string unused_err_string;
- SubmitTxMemoryPoolAndRelay(wtx, unused_err_string, false);
- }
-}
-
bool CWallet::SubmitTxMemoryPoolAndRelay(CWalletTx& wtx, std::string& err_string, bool relay) const
{
AssertLockHeld(cs_wallet);
@@ -1924,43 +1897,69 @@ std::set<uint256> CWallet::GetTxConflicts(const CWalletTx& wtx) const
return result;
}
-// Rebroadcast transactions from the wallet. We do this on a random timer
-// to slightly obfuscate which transactions come from our wallet.
+// Resubmit transactions from the wallet to the mempool, optionally asking the
+// mempool to relay them. On startup, we will do this for all unconfirmed
+// transactions but will not ask the mempool to relay them. We do this on startup
+// to ensure that our own mempool is aware of our transactions, and to also
+// initialize nNextResend so that the actual rebroadcast is scheduled. There
+// is a privacy side effect here as not broadcasting on startup also means that we won't
+// inform the world of our wallet's state, particularly if the wallet (or node) is not
+// yet synced.
+//
+// Otherwise this function is called periodically in order to relay our unconfirmed txs.
+// We do this on a random timer to slightly obfuscate which transactions
+// come from our wallet.
//
-// Ideally, we'd only resend transactions that we think should have been
+// TODO: Ideally, we'd only resend transactions that we think should have been
// mined in the most recent block. Any transaction that wasn't in the top
// blockweight of transactions in the mempool shouldn't have been mined,
// and so is probably just sitting in the mempool waiting to be confirmed.
// Rebroadcasting does nothing to speed up confirmation and only damages
// privacy.
-void CWallet::ResendWalletTransactions()
+//
+// The `force` option results in all unconfirmed transactions being submitted to
+// the mempool. This does not necessarily result in those transactions being relayed,
+// that depends on the `relay` option. Periodic rebroadcast uses the pattern
+// relay=true force=false, while loading into the mempool
+// (on start, or after import) uses relay=false force=true.
+void CWallet::ResubmitWalletTransactions(bool relay, bool force)
{
+ // Don't attempt to resubmit if the wallet is configured to not broadcast,
+ // even if forcing.
+ if (!fBroadcastTransactions) return;
+
// During reindex, importing and IBD, old wallet transactions become
// unconfirmed. Don't resend them as that would spam other nodes.
- if (!chain().isReadyToBroadcast()) return;
+ // We only allow forcing mempool submission when not relaying to avoid this spam.
+ if (!force && relay && !chain().isReadyToBroadcast()) return;
// Do this infrequently and randomly to avoid giving away
// that these are our transactions.
- if (GetTime() < nNextResend || !fBroadcastTransactions) return;
- bool fFirst = (nNextResend == 0);
+ if (!force && GetTime() < nNextResend) return;
// resend 12-36 hours from now, ~1 day on average.
nNextResend = GetTime() + (12 * 60 * 60) + GetRand(24 * 60 * 60);
- if (fFirst) return;
int submitted_tx_count = 0;
{ // cs_wallet scope
LOCK(cs_wallet);
- // Relay transactions
- for (std::pair<const uint256, CWalletTx>& item : mapWallet) {
- CWalletTx& wtx = item.second;
- // Attempt to rebroadcast all txes more than 5 minutes older than
- // the last block. SubmitTxMemoryPoolAndRelay() will not rebroadcast
- // any confirmed or conflicting txs.
- if (wtx.nTimeReceived > m_best_block_time - 5 * 60) continue;
+ // First filter for the transactions we want to rebroadcast.
+ // We use a set with WalletTxOrderComparator so that rebroadcasting occurs in insertion order
+ std::set<CWalletTx*, WalletTxOrderComparator> to_submit;
+ for (auto& [txid, wtx] : mapWallet) {
+ // Only rebroadcast unconfirmed txs
+ if (!wtx.isUnconfirmed()) continue;
+
+ // attempt to rebroadcast all txes more than 5 minutes older than
+ // the last block, or all txs if forcing.
+ if (!force && wtx.nTimeReceived > m_best_block_time - 5 * 60) continue;
+ to_submit.insert(&wtx);
+ }
+ // Now try submitting the transactions to the memory pool and (optionally) relay them.
+ for (auto wtx : to_submit) {
std::string unused_err_string;
- if (SubmitTxMemoryPoolAndRelay(wtx, unused_err_string, true)) ++submitted_tx_count;
+ if (SubmitTxMemoryPoolAndRelay(*wtx, unused_err_string, relay)) ++submitted_tx_count;
}
} // cs_wallet
@@ -1974,7 +1973,7 @@ void CWallet::ResendWalletTransactions()
void MaybeResendWalletTxs(WalletContext& context)
{
for (const std::shared_ptr<CWallet>& pwallet : GetWallets(context)) {
- pwallet->ResendWalletTransactions();
+ pwallet->ResubmitWalletTransactions(/*relay=*/true, /*force=*/false);
}
}
@@ -2787,7 +2786,7 @@ std::shared_ptr<CWallet> CWallet::Create(WalletContext& context, const std::stri
ArgsManager& args = *Assert(context.args);
const std::string& walletFile = database->Filename();
- int64_t nStart = GetTimeMillis();
+ const auto start{SteadyClock::now()};
// TODO: Can't use std::make_shared because we need a custom deleter but
// should be possible to use std::allocate_shared.
const std::shared_ptr<CWallet> walletInstance(new CWallet(chain, name, args, std::move(database)), ReleaseWallet);
@@ -2820,8 +2819,12 @@ std::shared_ptr<CWallet> CWallet::Create(WalletContext& context, const std::stri
warnings.push_back(strprintf(_("Error reading %s! Transaction data may be missing or incorrect."
" Rescanning wallet."), walletFile));
rescan_required = true;
- }
- else {
+ } else if (nLoadWalletRet == DBErrors::UNKNOWN_DESCRIPTOR) {
+ error = strprintf(_("Unrecognized descriptor found. Loading wallet %s\n\n"
+ "The wallet might had been created on a newer version.\n"
+ "Please try running the latest software version.\n"), walletFile);
+ return nullptr;
+ } else {
error = strprintf(_("Error loading %s"), walletFile);
return nullptr;
}
@@ -3004,7 +3007,7 @@ std::shared_ptr<CWallet> CWallet::Create(WalletContext& context, const std::stri
walletInstance->m_spend_zero_conf_change = args.GetBoolArg("-spendzeroconfchange", DEFAULT_SPEND_ZEROCONF_CHANGE);
walletInstance->m_signal_rbf = args.GetBoolArg("-walletrbf", DEFAULT_WALLET_RBF);
- walletInstance->WalletLogPrintf("Wallet completed loading in %15dms\n", GetTimeMillis() - nStart);
+ walletInstance->WalletLogPrintf("Wallet completed loading in %15dms\n", Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
// Try to top up keypool. No-op if the wallet is locked.
walletInstance->TopUpKeyPool();
@@ -3190,7 +3193,7 @@ void CWallet::postInitProcess()
// Add wallet transactions that aren't already in a block to mempool
// Do this here as mempool requires genesis block to be loaded
- ReacceptWalletTransactions();
+ ResubmitWalletTransactions(/*relay=*/false, /*force=*/true);
// Update wallet transactions with current mempool transactions.
chain().requestMempoolTransactions(*this);
@@ -3433,6 +3436,29 @@ void CWallet::LoadDescriptorScriptPubKeyMan(uint256 id, WalletDescriptor& desc)
}
}
+void CWallet::SetupDescriptorScriptPubKeyMans(const CExtKey& master_key)
+{
+ AssertLockHeld(cs_wallet);
+
+ for (bool internal : {false, true}) {
+ for (OutputType t : OUTPUT_TYPES) {
+ auto spk_manager = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this));
+ if (IsCrypted()) {
+ if (IsLocked()) {
+ throw std::runtime_error(std::string(__func__) + ": Wallet is locked, cannot setup new descriptors");
+ }
+ if (!spk_manager->CheckDecryptionKey(vMasterKey) && !spk_manager->Encrypt(vMasterKey, nullptr)) {
+ throw std::runtime_error(std::string(__func__) + ": Could not encrypt new descriptors");
+ }
+ }
+ spk_manager->SetupDescriptorGeneration(master_key, t, internal);
+ uint256 id = spk_manager->GetID();
+ m_spk_managers[id] = std::move(spk_manager);
+ AddActiveScriptPubKeyMan(id, t, internal);
+ }
+ }
+}
+
void CWallet::SetupDescriptorScriptPubKeyMans()
{
AssertLockHeld(cs_wallet);
@@ -3448,23 +3474,7 @@ void CWallet::SetupDescriptorScriptPubKeyMans()
CExtKey master_key;
master_key.SetSeed(seed_key);
- for (bool internal : {false, true}) {
- for (OutputType t : OUTPUT_TYPES) {
- auto spk_manager = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this));
- if (IsCrypted()) {
- if (IsLocked()) {
- throw std::runtime_error(std::string(__func__) + ": Wallet is locked, cannot setup new descriptors");
- }
- if (!spk_manager->CheckDecryptionKey(vMasterKey) && !spk_manager->Encrypt(vMasterKey, nullptr)) {
- throw std::runtime_error(std::string(__func__) + ": Could not encrypt new descriptors");
- }
- }
- spk_manager->SetupDescriptorGeneration(master_key, t, internal);
- uint256 id = spk_manager->GetID();
- m_spk_managers[id] = std::move(spk_manager);
- AddActiveScriptPubKeyMan(id, t, internal);
- }
- }
+ SetupDescriptorScriptPubKeyMans(master_key);
} else {
ExternalSigner signer = ExternalSignerScriptPubKeyMan::GetExternalSigner();
@@ -3632,9 +3642,13 @@ ScriptPubKeyMan* CWallet::AddWalletDescriptor(WalletDescriptor& desc, const Flat
return nullptr;
}
- CTxDestination dest;
- if (!internal && ExtractDestination(script_pub_keys.at(0), dest)) {
- SetAddressBook(dest, label, "receive");
+ if (!internal) {
+ for (const auto& script : script_pub_keys) {
+ CTxDestination dest;
+ if (ExtractDestination(script, dest)) {
+ SetAddressBook(dest, label, "receive");
+ }
+ }
}
}
@@ -3643,4 +3657,472 @@ ScriptPubKeyMan* CWallet::AddWalletDescriptor(WalletDescriptor& desc, const Flat
return spk_man;
}
+
+bool CWallet::MigrateToSQLite(bilingual_str& error)
+{
+ AssertLockHeld(cs_wallet);
+
+ WalletLogPrintf("Migrating wallet storage database from BerkeleyDB to SQLite.\n");
+
+ if (m_database->Format() == "sqlite") {
+ error = _("Error: This wallet already uses SQLite");
+ return false;
+ }
+
+ // Get all of the records for DB type migration
+ std::unique_ptr<DatabaseBatch> batch = m_database->MakeBatch();
+ std::vector<std::pair<SerializeData, SerializeData>> records;
+ if (!batch->StartCursor()) {
+ error = _("Error: Unable to begin reading all records in the database");
+ return false;
+ }
+ bool complete = false;
+ while (true) {
+ CDataStream ss_key(SER_DISK, CLIENT_VERSION);
+ CDataStream ss_value(SER_DISK, CLIENT_VERSION);
+ bool ret = batch->ReadAtCursor(ss_key, ss_value, complete);
+ if (!ret) {
+ break;
+ }
+ SerializeData key(ss_key.begin(), ss_key.end());
+ SerializeData value(ss_value.begin(), ss_value.end());
+ records.emplace_back(key, value);
+ }
+ batch->CloseCursor();
+ batch.reset();
+ if (!complete) {
+ error = _("Error: Unable to read all records in the database");
+ return false;
+ }
+
+ // Close this database and delete the file
+ fs::path db_path = fs::PathFromString(m_database->Filename());
+ fs::path db_dir = db_path.parent_path();
+ m_database->Close();
+ fs::remove(db_path);
+
+ // Make new DB
+ DatabaseOptions opts;
+ opts.require_create = true;
+ opts.require_format = DatabaseFormat::SQLITE;
+ DatabaseStatus db_status;
+ std::unique_ptr<WalletDatabase> new_db = MakeDatabase(db_dir, opts, db_status, error);
+ assert(new_db); // This is to prevent doing anything further with this wallet. The original file was deleted, but a backup exists.
+ m_database.reset();
+ m_database = std::move(new_db);
+
+ // Write existing records into the new DB
+ batch = m_database->MakeBatch();
+ bool began = batch->TxnBegin();
+ assert(began); // This is a critical error, the new db could not be written to. The original db exists as a backup, but we should not continue execution.
+ for (const auto& [key, value] : records) {
+ CDataStream ss_key(key, SER_DISK, CLIENT_VERSION);
+ CDataStream ss_value(value, SER_DISK, CLIENT_VERSION);
+ if (!batch->Write(ss_key, ss_value)) {
+ batch->TxnAbort();
+ m_database->Close();
+ fs::remove(m_database->Filename());
+ assert(false); // This is a critical error, the new db could not be written to. The original db exists as a backup, but we should not continue execution.
+ }
+ }
+ bool committed = batch->TxnCommit();
+ assert(committed); // This is a critical error, the new db could not be written to. The original db exists as a backup, but we should not continue execution.
+ return true;
+}
+
+std::optional<MigrationData> CWallet::GetDescriptorsForLegacy(bilingual_str& error) const
+{
+ AssertLockHeld(cs_wallet);
+
+ LegacyScriptPubKeyMan* legacy_spkm = GetLegacyScriptPubKeyMan();
+ if (!legacy_spkm) {
+ error = _("Error: This wallet is already a descriptor wallet");
+ return std::nullopt;
+ }
+
+ std::optional<MigrationData> res = legacy_spkm->MigrateToDescriptor();
+ if (res == std::nullopt) {
+ error = _("Error: Unable to produce descriptors for this legacy wallet. Make sure the wallet is unlocked first");
+ return std::nullopt;
+ }
+ return res;
+}
+
+bool CWallet::ApplyMigrationData(MigrationData& data, bilingual_str& error)
+{
+ AssertLockHeld(cs_wallet);
+
+ LegacyScriptPubKeyMan* legacy_spkm = GetLegacyScriptPubKeyMan();
+ if (!legacy_spkm) {
+ error = _("Error: This wallet is already a descriptor wallet");
+ return false;
+ }
+
+ for (auto& desc_spkm : data.desc_spkms) {
+ if (m_spk_managers.count(desc_spkm->GetID()) > 0) {
+ error = _("Error: Duplicate descriptors created during migration. Your wallet may be corrupted.");
+ return false;
+ }
+ m_spk_managers[desc_spkm->GetID()] = std::move(desc_spkm);
+ }
+
+ // Remove the LegacyScriptPubKeyMan from disk
+ if (!legacy_spkm->DeleteRecords()) {
+ return false;
+ }
+
+ // Remove the LegacyScriptPubKeyMan from memory
+ m_spk_managers.erase(legacy_spkm->GetID());
+ m_external_spk_managers.clear();
+ m_internal_spk_managers.clear();
+
+ // Setup new descriptors
+ SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
+ if (!IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
+ // Use the existing master key if we have it
+ if (data.master_key.key.IsValid()) {
+ SetupDescriptorScriptPubKeyMans(data.master_key);
+ } else {
+ // Setup with a new seed if we don't.
+ SetupDescriptorScriptPubKeyMans();
+ }
+ }
+
+ // Check if the transactions in the wallet are still ours. Either they belong here, or they belong in the watchonly wallet.
+ // We need to go through these in the tx insertion order so that lookups to spends works.
+ std::vector<uint256> txids_to_delete;
+ for (const auto& [_pos, wtx] : wtxOrdered) {
+ if (!IsMine(*wtx->tx) && !IsFromMe(*wtx->tx)) {
+ // Check it is the watchonly wallet's
+ // solvable_wallet doesn't need to be checked because transactions for those scripts weren't being watched for
+ if (data.watchonly_wallet) {
+ LOCK(data.watchonly_wallet->cs_wallet);
+ if (data.watchonly_wallet->IsMine(*wtx->tx) || data.watchonly_wallet->IsFromMe(*wtx->tx)) {
+ // Add to watchonly wallet
+ if (!data.watchonly_wallet->AddToWallet(wtx->tx, wtx->m_state)) {
+ error = _("Error: Could not add watchonly tx to watchonly wallet");
+ return false;
+ }
+ // Mark as to remove from this wallet
+ txids_to_delete.push_back(wtx->GetHash());
+ continue;
+ }
+ }
+ // Both not ours and not in the watchonly wallet
+ error = strprintf(_("Error: Transaction %s in wallet cannot be identified to belong to migrated wallets"), wtx->GetHash().GetHex());
+ return false;
+ }
+ }
+ // Do the removes
+ if (txids_to_delete.size() > 0) {
+ std::vector<uint256> deleted_txids;
+ if (ZapSelectTx(txids_to_delete, deleted_txids) != DBErrors::LOAD_OK) {
+ error = _("Error: Could not delete watchonly transactions");
+ return false;
+ }
+ if (deleted_txids != txids_to_delete) {
+ error = _("Error: Not all watchonly txs could be deleted");
+ return false;
+ }
+ // Tell the GUI of each tx
+ for (const uint256& txid : deleted_txids) {
+ NotifyTransactionChanged(txid, CT_UPDATED);
+ }
+ }
+
+ // Check the address book data in the same way we did for transactions
+ std::vector<CTxDestination> dests_to_delete;
+ for (const auto& addr_pair : m_address_book) {
+ // Labels applied to receiving addresses should go based on IsMine
+ if (addr_pair.second.purpose == "receive") {
+ if (!IsMine(addr_pair.first)) {
+ // Check the address book data is the watchonly wallet's
+ if (data.watchonly_wallet) {
+ LOCK(data.watchonly_wallet->cs_wallet);
+ if (data.watchonly_wallet->IsMine(addr_pair.first)) {
+ // Add to the watchonly. Preserve the labels, purpose, and change-ness
+ std::string label = addr_pair.second.GetLabel();
+ std::string purpose = addr_pair.second.purpose;
+ if (!purpose.empty()) {
+ data.watchonly_wallet->m_address_book[addr_pair.first].purpose = purpose;
+ }
+ if (!addr_pair.second.IsChange()) {
+ data.watchonly_wallet->m_address_book[addr_pair.first].SetLabel(label);
+ }
+ dests_to_delete.push_back(addr_pair.first);
+ continue;
+ }
+ }
+ if (data.solvable_wallet) {
+ LOCK(data.solvable_wallet->cs_wallet);
+ if (data.solvable_wallet->IsMine(addr_pair.first)) {
+ // Add to the solvable. Preserve the labels, purpose, and change-ness
+ std::string label = addr_pair.second.GetLabel();
+ std::string purpose = addr_pair.second.purpose;
+ if (!purpose.empty()) {
+ data.solvable_wallet->m_address_book[addr_pair.first].purpose = purpose;
+ }
+ if (!addr_pair.second.IsChange()) {
+ data.solvable_wallet->m_address_book[addr_pair.first].SetLabel(label);
+ }
+ dests_to_delete.push_back(addr_pair.first);
+ continue;
+ }
+ }
+ // Not ours, not in watchonly wallet, and not in solvable
+ error = _("Error: Address book data in wallet cannot be identified to belong to migrated wallets");
+ return false;
+ }
+ } else {
+ // Labels for everything else (send) should be cloned to all
+ if (data.watchonly_wallet) {
+ LOCK(data.watchonly_wallet->cs_wallet);
+ // Add to the watchonly. Preserve the labels, purpose, and change-ness
+ std::string label = addr_pair.second.GetLabel();
+ std::string purpose = addr_pair.second.purpose;
+ if (!purpose.empty()) {
+ data.watchonly_wallet->m_address_book[addr_pair.first].purpose = purpose;
+ }
+ if (!addr_pair.second.IsChange()) {
+ data.watchonly_wallet->m_address_book[addr_pair.first].SetLabel(label);
+ }
+ continue;
+ }
+ if (data.solvable_wallet) {
+ LOCK(data.solvable_wallet->cs_wallet);
+ // Add to the solvable. Preserve the labels, purpose, and change-ness
+ std::string label = addr_pair.second.GetLabel();
+ std::string purpose = addr_pair.second.purpose;
+ if (!purpose.empty()) {
+ data.solvable_wallet->m_address_book[addr_pair.first].purpose = purpose;
+ }
+ if (!addr_pair.second.IsChange()) {
+ data.solvable_wallet->m_address_book[addr_pair.first].SetLabel(label);
+ }
+ continue;
+ }
+ }
+ }
+ // Remove the things to delete
+ if (dests_to_delete.size() > 0) {
+ for (const auto& dest : dests_to_delete) {
+ if (!DelAddressBook(dest)) {
+ error = _("Error: Unable to remove watchonly address book data");
+ return false;
+ }
+ }
+ }
+
+ // Connect the SPKM signals
+ ConnectScriptPubKeyManNotifiers();
+ NotifyCanGetAddressesChanged();
+
+ WalletLogPrintf("Wallet migration complete.\n");
+
+ return true;
+}
+
+bool DoMigration(CWallet& wallet, WalletContext& context, bilingual_str& error, MigrationResult& res) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
+{
+ AssertLockHeld(wallet.cs_wallet);
+
+ // Get all of the descriptors from the legacy wallet
+ std::optional<MigrationData> data = wallet.GetDescriptorsForLegacy(error);
+ if (data == std::nullopt) return false;
+
+ // Create the watchonly and solvable wallets if necessary
+ if (data->watch_descs.size() > 0 || data->solvable_descs.size() > 0) {
+ DatabaseOptions options;
+ options.require_existing = false;
+ options.require_create = true;
+
+ // Make the wallets
+ options.create_flags = WALLET_FLAG_DISABLE_PRIVATE_KEYS | WALLET_FLAG_BLANK_WALLET | WALLET_FLAG_DESCRIPTORS;
+ if (wallet.IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE)) {
+ options.create_flags |= WALLET_FLAG_AVOID_REUSE;
+ }
+ if (wallet.IsWalletFlagSet(WALLET_FLAG_KEY_ORIGIN_METADATA)) {
+ options.create_flags |= WALLET_FLAG_KEY_ORIGIN_METADATA;
+ }
+ if (data->watch_descs.size() > 0) {
+ wallet.WalletLogPrintf("Making a new watchonly wallet containing the watched scripts\n");
+
+ DatabaseStatus status;
+ std::vector<bilingual_str> warnings;
+ std::string wallet_name = wallet.GetName() + "_watchonly";
+ data->watchonly_wallet = CreateWallet(context, wallet_name, std::nullopt, options, status, error, warnings);
+ if (status != DatabaseStatus::SUCCESS) {
+ error = _("Error: Failed to create new watchonly wallet");
+ return false;
+ }
+ res.watchonly_wallet = data->watchonly_wallet;
+ LOCK(data->watchonly_wallet->cs_wallet);
+
+ // Parse the descriptors and add them to the new wallet
+ for (const auto& [desc_str, creation_time] : data->watch_descs) {
+ // Parse the descriptor
+ FlatSigningProvider keys;
+ std::string parse_err;
+ std::unique_ptr<Descriptor> desc = Parse(desc_str, keys, parse_err, /* require_checksum */ true);
+ assert(desc); // It shouldn't be possible to have the LegacyScriptPubKeyMan make an invalid descriptor
+ assert(!desc->IsRange()); // It shouldn't be possible to have LegacyScriptPubKeyMan make a ranged watchonly descriptor
+
+ // Add to the wallet
+ WalletDescriptor w_desc(std::move(desc), creation_time, 0, 0, 0);
+ data->watchonly_wallet->AddWalletDescriptor(w_desc, keys, "", false);
+ }
+
+ // Add the wallet to settings
+ UpdateWalletSetting(*context.chain, wallet_name, /*load_on_startup=*/true, warnings);
+ }
+ if (data->solvable_descs.size() > 0) {
+ wallet.WalletLogPrintf("Making a new watchonly wallet containing the unwatched solvable scripts\n");
+
+ DatabaseStatus status;
+ std::vector<bilingual_str> warnings;
+ std::string wallet_name = wallet.GetName() + "_solvables";
+ data->solvable_wallet = CreateWallet(context, wallet_name, std::nullopt, options, status, error, warnings);
+ if (status != DatabaseStatus::SUCCESS) {
+ error = _("Error: Failed to create new watchonly wallet");
+ return false;
+ }
+ res.solvables_wallet = data->solvable_wallet;
+ LOCK(data->solvable_wallet->cs_wallet);
+
+ // Parse the descriptors and add them to the new wallet
+ for (const auto& [desc_str, creation_time] : data->solvable_descs) {
+ // Parse the descriptor
+ FlatSigningProvider keys;
+ std::string parse_err;
+ std::unique_ptr<Descriptor> desc = Parse(desc_str, keys, parse_err, /* require_checksum */ true);
+ assert(desc); // It shouldn't be possible to have the LegacyScriptPubKeyMan make an invalid descriptor
+ assert(!desc->IsRange()); // It shouldn't be possible to have LegacyScriptPubKeyMan make a ranged watchonly descriptor
+
+ // Add to the wallet
+ WalletDescriptor w_desc(std::move(desc), creation_time, 0, 0, 0);
+ data->solvable_wallet->AddWalletDescriptor(w_desc, keys, "", false);
+ }
+
+ // Add the wallet to settings
+ UpdateWalletSetting(*context.chain, wallet_name, /*load_on_startup=*/true, warnings);
+ }
+ }
+
+ // Add the descriptors to wallet, remove LegacyScriptPubKeyMan, and cleanup txs and address book data
+ if (!wallet.ApplyMigrationData(*data, error)) {
+ return false;
+ }
+ return true;
+}
+
+util::Result<MigrationResult> MigrateLegacyToDescriptor(std::shared_ptr<CWallet>&& wallet, WalletContext& context)
+{
+ MigrationResult res;
+ bilingual_str error;
+ std::vector<bilingual_str> warnings;
+
+ // Make a backup of the DB
+ std::string wallet_name = wallet->GetName();
+ fs::path this_wallet_dir = fs::absolute(fs::PathFromString(wallet->GetDatabase().Filename())).parent_path();
+ fs::path backup_filename = fs::PathFromString(strprintf("%s-%d.legacy.bak", wallet_name, GetTime()));
+ fs::path backup_path = this_wallet_dir / backup_filename;
+ if (!wallet->BackupWallet(fs::PathToString(backup_path))) {
+ return util::Error{_("Error: Unable to make a backup of your wallet")};
+ }
+ res.backup_path = backup_path;
+
+ // Unload the wallet so that nothing else tries to use it while we're changing it
+ if (!RemoveWallet(context, wallet, /*load_on_start=*/std::nullopt, warnings)) {
+ return util::Error{_("Unable to unload the wallet before migrating")};
+ }
+ UnloadWallet(std::move(wallet));
+
+ // Load the wallet but only in the context of this function.
+ // No signals should be connected nor should anything else be aware of this wallet
+ WalletContext empty_context;
+ empty_context.args = context.args;
+ DatabaseOptions options;
+ options.require_existing = true;
+ DatabaseStatus status;
+ std::unique_ptr<WalletDatabase> database = MakeWalletDatabase(wallet_name, options, status, error);
+ if (!database) {
+ return util::Error{Untranslated("Wallet file verification failed.") + Untranslated(" ") + error};
+ }
+
+ std::shared_ptr<CWallet> local_wallet = CWallet::Create(empty_context, wallet_name, std::move(database), options.create_flags, error, warnings);
+ if (!local_wallet) {
+ return util::Error{Untranslated("Wallet loading failed.") + Untranslated(" ") + error};
+ }
+
+ bool success = false;
+ {
+ LOCK(local_wallet->cs_wallet);
+
+ // First change to using SQLite
+ if (!local_wallet->MigrateToSQLite(error)) return util::Error{error};
+
+ // Do the migration, and cleanup if it fails
+ success = DoMigration(*local_wallet, context, error, res);
+ }
+
+ if (success) {
+ // Migration successful, unload the wallet locally, then reload it.
+ assert(local_wallet.use_count() == 1);
+ local_wallet.reset();
+ LoadWallet(context, wallet_name, /*load_on_start=*/std::nullopt, options, status, error, warnings);
+ res.wallet_name = wallet_name;
+ } else {
+ // Migration failed, cleanup
+ // Copy the backup to the actual wallet dir
+ fs::path temp_backup_location = fsbridge::AbsPathJoin(GetWalletDir(), backup_filename);
+ fs::copy_file(backup_path, temp_backup_location, fs::copy_options::none);
+
+ // Remember this wallet's walletdir to remove after unloading
+ std::vector<fs::path> wallet_dirs;
+ wallet_dirs.push_back(fs::PathFromString(local_wallet->GetDatabase().Filename()).parent_path());
+
+ // Unload the wallet locally
+ assert(local_wallet.use_count() == 1);
+ local_wallet.reset();
+
+ // Make list of wallets to cleanup
+ std::vector<std::shared_ptr<CWallet>> created_wallets;
+ created_wallets.push_back(std::move(res.watchonly_wallet));
+ created_wallets.push_back(std::move(res.solvables_wallet));
+
+ // Get the directories to remove after unloading
+ for (std::shared_ptr<CWallet>& w : created_wallets) {
+ wallet_dirs.push_back(fs::PathFromString(w->GetDatabase().Filename()).parent_path());
+ }
+
+ // Unload the wallets
+ for (std::shared_ptr<CWallet>& w : created_wallets) {
+ if (!RemoveWallet(context, w, /*load_on_start=*/false)) {
+ error += _("\nUnable to cleanup failed migration");
+ return util::Error{error};
+ }
+ UnloadWallet(std::move(w));
+ }
+
+ // Delete the wallet directories
+ for (fs::path& dir : wallet_dirs) {
+ fs::remove_all(dir);
+ }
+
+ // Restore the backup
+ DatabaseStatus status;
+ std::vector<bilingual_str> warnings;
+ if (!RestoreWallet(context, temp_backup_location, wallet_name, /*load_on_start=*/std::nullopt, status, error, warnings)) {
+ error += _("\nUnable to restore backup of wallet.");
+ return util::Error{error};
+ }
+
+ // Move the backup to the wallet dir
+ fs::copy_file(temp_backup_location, backup_path, fs::copy_options::none);
+ fs::remove(temp_backup_location);
+
+ return util::Error{error};
+ }
+ return res;
+}
} // namespace wallet
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 9281045c21..f4ea5f1920 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -316,7 +316,7 @@ private:
std::string m_name;
/** Internal database handle. */
- std::unique_ptr<WalletDatabase> const m_database;
+ std::unique_ptr<WalletDatabase> m_database;
/**
* The following is used to keep track of how far behind the wallet is
@@ -537,8 +537,7 @@ public:
};
ScanResult ScanForWalletTransactions(const uint256& start_block, int start_height, std::optional<int> max_height, const WalletRescanReserver& reserver, bool fUpdate, const bool save_progress);
void transactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason, uint64_t mempool_sequence) override;
- void ReacceptWalletTransactions() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
- void ResendWalletTransactions();
+ void ResubmitWalletTransactions(bool relay, bool force);
OutputType TransactionChangeType(const std::optional<OutputType>& change_type, const std::vector<CRecipient>& vecSend) const;
@@ -907,6 +906,7 @@ public:
void DeactivateScriptPubKeyMan(uint256 id, OutputType type, bool internal);
//! Create new DescriptorScriptPubKeyMans and add them to the wallet
+ void SetupDescriptorScriptPubKeyMans(const CExtKey& master_key) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
void SetupDescriptorScriptPubKeyMans() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
//! Return the DescriptorScriptPubKeyMan for a WalletDescriptor if it is already in the wallet
@@ -919,6 +919,20 @@ public:
//! Add a descriptor to the wallet, return a ScriptPubKeyMan & associated output type
ScriptPubKeyMan* AddWalletDescriptor(WalletDescriptor& desc, const FlatSigningProvider& signing_provider, const std::string& label, bool internal) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+
+ /** Move all records from the BDB database to a new SQLite database for storage.
+ * The original BDB file will be deleted and replaced with a new SQLite file.
+ * A backup is not created.
+ * May crash if something unexpected happens in the filesystem.
+ */
+ bool MigrateToSQLite(bilingual_str& error) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+
+ //! Get all of the descriptors from a legacy wallet
+ std::optional<MigrationData> GetDescriptorsForLegacy(bilingual_str& error) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+
+ //! Adds the ScriptPubKeyMans given in MigrationData to this wallet, removes LegacyScriptPubKeyMan,
+ //! and where needed, moves tx and address book entries to watchonly_wallet or solvable_wallet
+ bool ApplyMigrationData(MigrationData& data, bilingual_str& error) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
};
/**
@@ -977,6 +991,16 @@ bool RemoveWalletSetting(interfaces::Chain& chain, const std::string& wallet_nam
bool DummySignInput(const SigningProvider& provider, CTxIn &tx_in, const CTxOut &txout, const CCoinControl* coin_control = nullptr);
bool FillInputToWeight(CTxIn& txin, int64_t target_weight);
+
+struct MigrationResult {
+ std::string wallet_name;
+ std::shared_ptr<CWallet> watchonly_wallet;
+ std::shared_ptr<CWallet> solvables_wallet;
+ fs::path backup_path;
+};
+
+//! Do all steps to migrate a legacy wallet to a descriptor wallet
+util::Result<MigrationResult> MigrateLegacyToDescriptor(std::shared_ptr<CWallet>&& wallet, WalletContext& context);
} // namespace wallet
#endif // BITCOIN_WALLET_WALLET_H
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index 0d85652c0c..6a8f0d2481 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -59,6 +59,7 @@ const std::string WALLETDESCRIPTORCKEY{"walletdescriptorckey"};
const std::string WALLETDESCRIPTORKEY{"walletdescriptorkey"};
const std::string WATCHMETA{"watchmeta"};
const std::string WATCHS{"watchs"};
+const std::unordered_set<std::string> LEGACY_TYPES{CRYPTED_KEY, CSCRIPT, DEFAULTKEY, HDCHAIN, KEYMETA, KEY, OLD_KEY, POOL, WATCHMETA, WATCHS};
} // namespace DBKeys
//
@@ -313,6 +314,7 @@ public:
std::map<std::pair<uint256, CKeyID>, std::pair<CPubKey, std::vector<unsigned char>>> m_descriptor_crypt_keys;
std::map<uint160, CHDChain> m_hd_chains;
bool tx_corrupt{false};
+ bool descriptor_unknown{false};
CWalletScanState() = default;
};
@@ -626,7 +628,13 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
uint256 id;
ssKey >> id;
WalletDescriptor desc;
- ssValue >> desc;
+ try {
+ ssValue >> desc;
+ } catch (const std::ios_base::failure& e) {
+ strErr = e.what();
+ wss.descriptor_unknown = true;
+ return false;
+ }
if (wss.m_descriptor_caches.count(id) == 0) {
wss.m_descriptor_caches[id] = DescriptorCache();
}
@@ -766,6 +774,12 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
DBErrors result = DBErrors::LOAD_OK;
LOCK(pwallet->cs_wallet);
+
+ // Last client version to open this wallet
+ int last_client = CLIENT_VERSION;
+ bool has_last_client = m_batch->Read(DBKeys::VERSION, last_client);
+ pwallet->WalletLogPrintf("Wallet file version = %d, last client version = %d\n", pwallet->GetVersion(), last_client);
+
try {
int nMinVersion = 0;
if (m_batch->Read(DBKeys::MINVERSION, nMinVersion)) {
@@ -831,6 +845,13 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
// Set tx_corrupt back to false so that the error is only printed once (per corrupt tx)
wss.tx_corrupt = false;
result = DBErrors::CORRUPT;
+ } else if (wss.descriptor_unknown) {
+ strErr = strprintf("Error: Unrecognized descriptor found in wallet %s. ", pwallet->GetName());
+ strErr += (last_client > CLIENT_VERSION) ? "The wallet might had been created on a newer version. " :
+ "The database might be corrupted or the software version is not compatible with one of your wallet descriptors. ";
+ strErr += "Please try running the latest software version";
+ pwallet->WalletLogPrintf("%s\n", strErr);
+ return DBErrors::UNKNOWN_DESCRIPTOR;
} else {
// Leave other errors alone, if we try to fix them we might make things worse.
fNoncriticalErrors = true; // ... but do warn the user there is something wrong.
@@ -883,11 +904,6 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
if (result != DBErrors::LOAD_OK)
return result;
- // Last client version to open this wallet
- int last_client = CLIENT_VERSION;
- bool has_last_client = m_batch->Read(DBKeys::VERSION, last_client);
- pwallet->WalletLogPrintf("Wallet file version = %d, last client version = %d\n", pwallet->GetVersion(), last_client);
-
pwallet->WalletLogPrintf("Keys: %u plaintext, %u encrypted, %u w/ metadata, %u total. Unknown wallet records: %u\n",
wss.nKeys, wss.nCKeys, wss.nKeyMeta, wss.nKeys + wss.nCKeys, wss.m_unknown_records);
@@ -1083,6 +1099,45 @@ bool WalletBatch::WriteWalletFlags(const uint64_t flags)
return WriteIC(DBKeys::FLAGS, flags);
}
+bool WalletBatch::EraseRecords(const std::unordered_set<std::string>& types)
+{
+ // Get cursor
+ if (!m_batch->StartCursor())
+ {
+ return false;
+ }
+
+ // Iterate the DB and look for any records that have the type prefixes
+ while (true)
+ {
+ // Read next record
+ CDataStream key(SER_DISK, CLIENT_VERSION);
+ CDataStream value(SER_DISK, CLIENT_VERSION);
+ bool complete;
+ bool ret = m_batch->ReadAtCursor(key, value, complete);
+ if (complete) {
+ break;
+ }
+ else if (!ret)
+ {
+ m_batch->CloseCursor();
+ return false;
+ }
+
+ // Make a copy of key to avoid data being deleted by the following read of the type
+ Span<const unsigned char> key_data = MakeUCharSpan(key);
+
+ std::string type;
+ key >> type;
+
+ if (types.count(type) > 0) {
+ m_batch->Erase(key_data);
+ }
+ }
+ m_batch->CloseCursor();
+ return true;
+}
+
bool WalletBatch::TxnBegin()
{
return m_batch->TxnBegin();
diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h
index a04ea598b6..da6efe534b 100644
--- a/src/wallet/walletdb.h
+++ b/src/wallet/walletdb.h
@@ -51,7 +51,8 @@ enum class DBErrors
EXTERNAL_SIGNER_SUPPORT_REQUIRED,
LOAD_FAIL,
NEED_REWRITE,
- NEED_RESCAN
+ NEED_RESCAN,
+ UNKNOWN_DESCRIPTOR
};
namespace DBKeys {
@@ -84,6 +85,9 @@ extern const std::string WALLETDESCRIPTORCKEY;
extern const std::string WALLETDESCRIPTORKEY;
extern const std::string WATCHMETA;
extern const std::string WATCHS;
+
+// Keys in this set pertain only to the legacy wallet (LegacyScriptPubKeyMan) and are removed during migration from legacy to descriptors.
+extern const std::unordered_set<std::string> LEGACY_TYPES;
} // namespace DBKeys
/* simple HD chain data model */
@@ -276,6 +280,9 @@ public:
//! write the hdchain model (external chain child index counter)
bool WriteHDChain(const CHDChain& chain);
+ //! Delete records of the given types
+ bool EraseRecords(const std::unordered_set<std::string>& types);
+
bool WriteWalletFlags(const uint64_t flags);
//! Begin a new transaction
bool TxnBegin();
diff --git a/src/wallet/walletutil.h b/src/wallet/walletutil.h
index 788d41ceb7..8434d64fb5 100644
--- a/src/wallet/walletutil.h
+++ b/src/wallet/walletutil.h
@@ -104,6 +104,20 @@ public:
WalletDescriptor() {}
WalletDescriptor(std::shared_ptr<Descriptor> descriptor, uint64_t creation_time, int32_t range_start, int32_t range_end, int32_t next_index) : descriptor(descriptor), creation_time(creation_time), range_start(range_start), range_end(range_end), next_index(next_index) {}
};
+
+class CWallet;
+class DescriptorScriptPubKeyMan;
+
+/** struct containing information needed for migrating legacy wallets to descriptor wallets */
+struct MigrationData
+{
+ CExtKey master_key;
+ std::vector<std::pair<std::string, int64_t>> watch_descs;
+ std::vector<std::pair<std::string, int64_t>> solvable_descs;
+ std::vector<std::unique_ptr<DescriptorScriptPubKeyMan>> desc_spkms;
+ std::shared_ptr<CWallet> watchonly_wallet{nullptr};
+ std::shared_ptr<CWallet> solvable_wallet{nullptr};
+};
} // namespace wallet
#endif // BITCOIN_WALLET_WALLETUTIL_H
diff --git a/test/functional/feature_block.py b/test/functional/feature_block.py
index 462deeae32..850cb8334c 100755
--- a/test/functional/feature_block.py
+++ b/test/functional/feature_block.py
@@ -1297,7 +1297,7 @@ class FullBlockTest(BitcoinTestFramework):
blocks2 = []
for i in range(89, LARGE_REORG_SIZE + 89):
blocks2.append(self.next_block("alt" + str(i)))
- self.send_blocks(blocks2, False, force_send=True)
+ self.send_blocks(blocks2, False, force_send=False)
# extend alt chain to trigger re-org
block = self.next_block("alt" + str(chain1_tip + 1))
diff --git a/test/functional/feature_config_args.py b/test/functional/feature_config_args.py
index 6c51a5ac31..eb31bca29a 100755
--- a/test/functional/feature_config_args.py
+++ b/test/functional/feature_config_args.py
@@ -186,11 +186,12 @@ class ConfArgsTest(BitcoinTestFramework):
with self.nodes[0].assert_debug_log(expected_msgs=[
"Loaded 0 addresses from peers.dat",
"DNS seeding disabled",
- "Adding fixed seeds as -dnsseed=0, -addnode is not provided and all -seednode(s) attempted\n",
+ "Adding fixed seeds as -dnsseed=0 (or IPv4/IPv6 connections are disabled via -onlynet), -addnode is not provided and all -seednode(s) attempted\n",
]):
self.start_node(0, extra_args=['-dnsseed=0', '-fixedseeds=1'])
assert time.time() - start < 60
self.stop_node(0)
+ self.nodes[0].assert_start_raises_init_error(['-dnsseed=1', '-onlynet=i2p', '-i2psam=127.0.0.1:7656'], "Error: Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6")
# No peers.dat exists and dns seeds are disabled.
# We expect the node will not add fixed seeds when explicitly disabled.
diff --git a/test/functional/feature_proxy.py b/test/functional/feature_proxy.py
index dd3cdc96ca..d02d56d068 100755
--- a/test/functional/feature_proxy.py
+++ b/test/functional/feature_proxy.py
@@ -332,20 +332,27 @@ class ProxyTest(BitcoinTestFramework):
msg = "Error: Invalid -i2psam address or hostname: 'def:xyz'"
self.nodes[1].assert_start_raises_init_error(expected_msg=msg)
+ self.log.info("Test passing -onlynet=onion with -onion=0/-noonion raises expected init error")
msg = (
"Error: Outbound connections restricted to Tor (-onlynet=onion) but "
- "the proxy for reaching the Tor network is not provided (no -proxy= "
- "and no -onion= given) or it is explicitly forbidden (-onion=0)"
+ "the proxy for reaching the Tor network is explicitly forbidden: -onion=0"
)
- self.log.info("Test passing -onlynet=onion without -proxy or -onion raises expected init error")
- self.nodes[1].extra_args = ["-onlynet=onion"]
- self.nodes[1].assert_start_raises_init_error(expected_msg=msg)
-
- self.log.info("Test passing -onlynet=onion with -onion=0/-noonion raises expected init error")
for arg in ["-onion=0", "-noonion"]:
self.nodes[1].extra_args = ["-onlynet=onion", arg]
self.nodes[1].assert_start_raises_init_error(expected_msg=msg)
+ self.log.info("Test passing -onlynet=onion without -proxy, -onion or -listenonion raises expected init error")
+ self.nodes[1].extra_args = ["-onlynet=onion", "-listenonion=0"]
+ msg = (
+ "Error: Outbound connections restricted to Tor (-onlynet=onion) but the proxy for "
+ "reaching the Tor network is not provided: none of -proxy, -onion or -listenonion is given"
+ )
+ self.nodes[1].assert_start_raises_init_error(expected_msg=msg)
+
+ self.log.info("Test passing -onlynet=onion without -proxy or -onion but with -listenonion=1 is ok")
+ self.start_node(1, extra_args=["-onlynet=onion", "-listenonion=1"])
+ self.stop_node(1)
+
self.log.info("Test passing unknown network to -onlynet raises expected init error")
self.nodes[1].extra_args = ["-onlynet=abc"]
msg = "Error: Unknown network specified in -onlynet: 'abc'"
diff --git a/test/functional/mempool_accept.py b/test/functional/mempool_accept.py
index 65b37a4975..02ec18140c 100755
--- a/test/functional/mempool_accept.py
+++ b/test/functional/mempool_accept.py
@@ -65,7 +65,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
assert_equal(node.getmempoolinfo()['size'], self.mempool_size)
self.log.info('Should not accept garbage to testmempoolaccept')
- assert_raises_rpc_error(-3, 'Expected type array, got string', lambda: node.testmempoolaccept(rawtxs='ff00baar'))
+ assert_raises_rpc_error(-3, 'JSON value of type string is not of expected type array', lambda: node.testmempoolaccept(rawtxs='ff00baar'))
assert_raises_rpc_error(-8, 'Array must contain between 1 and 25 transactions.', lambda: node.testmempoolaccept(rawtxs=['ff22']*26))
assert_raises_rpc_error(-8, 'Array must contain between 1 and 25 transactions.', lambda: node.testmempoolaccept(rawtxs=[]))
assert_raises_rpc_error(-22, 'TX decode failed', lambda: node.testmempoolaccept(rawtxs=['ff00baar']))
diff --git a/test/functional/mempool_expiry.py b/test/functional/mempool_expiry.py
index 47ae0c762b..21721177e6 100755
--- a/test/functional/mempool_expiry.py
+++ b/test/functional/mempool_expiry.py
@@ -13,6 +13,7 @@ definable expiry timeout via the '-mempoolexpiry=<n>' command line argument
from datetime import timedelta
from test_framework.blocktools import COINBASE_MATURITY
+from test_framework.messages import DEFAULT_MEMPOOL_EXPIRY_HOURS
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
@@ -20,7 +21,6 @@ from test_framework.util import (
)
from test_framework.wallet import MiniWallet
-DEFAULT_MEMPOOL_EXPIRY_HOURS = 336 # hours
CUSTOM_MEMPOOL_EXPIRY = 10 # hours
diff --git a/test/functional/p2p_compactblocks.py b/test/functional/p2p_compactblocks.py
index 5e50e1ebce..3cbb948e3c 100755
--- a/test/functional/p2p_compactblocks.py
+++ b/test/functional/p2p_compactblocks.py
@@ -615,6 +615,27 @@ class CompactBlocksTest(BitcoinTestFramework):
bad_peer.send_message(msg)
bad_peer.wait_for_disconnect()
+ def test_low_work_compactblocks(self, test_node):
+ # A compactblock with insufficient work won't get its header included
+ node = self.nodes[0]
+ hashPrevBlock = int(node.getblockhash(node.getblockcount() - 150), 16)
+ block = self.build_block_on_tip(node)
+ block.hashPrevBlock = hashPrevBlock
+ block.solve()
+
+ comp_block = HeaderAndShortIDs()
+ comp_block.initialize_from_block(block)
+ with self.nodes[0].assert_debug_log(['[net] Ignoring low-work compact block from peer 0']):
+ test_node.send_and_ping(msg_cmpctblock(comp_block.to_p2p()))
+
+ tips = node.getchaintips()
+ found = False
+ for x in tips:
+ if x["hash"] == block.hash:
+ found = True
+ break
+ assert not found
+
def test_compactblocks_not_at_tip(self, test_node):
node = self.nodes[0]
# Test that requesting old compactblocks doesn't work.
@@ -833,6 +854,9 @@ class CompactBlocksTest(BitcoinTestFramework):
self.log.info("Testing compactblock requests/announcements not at chain tip...")
self.test_compactblocks_not_at_tip(self.segwit_node)
+ self.log.info("Testing handling of low-work compact blocks...")
+ self.test_low_work_compactblocks(self.segwit_node)
+
self.log.info("Testing handling of incorrect blocktxn responses...")
self.test_incorrect_blocktxn_response(self.segwit_node)
diff --git a/test/functional/p2p_dos_header_tree.py b/test/functional/p2p_dos_header_tree.py
index fde1e4bfa2..7e26994511 100755
--- a/test/functional/p2p_dos_header_tree.py
+++ b/test/functional/p2p_dos_header_tree.py
@@ -22,6 +22,7 @@ class RejectLowDifficultyHeadersTest(BitcoinTestFramework):
self.setup_clean_chain = True
self.chain = 'testnet3' # Use testnet chain because it has an early checkpoint
self.num_nodes = 2
+ self.extra_args = [["-minimumchainwork=0x0"], ["-minimumchainwork=0x0"]]
def add_options(self, parser):
parser.add_argument(
@@ -62,7 +63,7 @@ class RejectLowDifficultyHeadersTest(BitcoinTestFramework):
self.log.info("Feed all fork headers (succeeds without checkpoint)")
# On node 0 it succeeds because checkpoints are disabled
- self.restart_node(0, extra_args=['-nocheckpoints'])
+ self.restart_node(0, extra_args=['-nocheckpoints', "-minimumchainwork=0x0"])
peer_no_checkpoint = self.nodes[0].add_p2p_connection(P2PInterface())
peer_no_checkpoint.send_and_ping(msg_headers(self.headers_fork))
assert {
diff --git a/test/functional/p2p_headers_sync_with_minchainwork.py b/test/functional/p2p_headers_sync_with_minchainwork.py
new file mode 100755
index 0000000000..991e3348ed
--- /dev/null
+++ b/test/functional/p2p_headers_sync_with_minchainwork.py
@@ -0,0 +1,164 @@
+#!/usr/bin/env python3
+# Copyright (c) 2019-2021 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""Test that we reject low difficulty headers to prevent our block tree from filling up with useless bloat"""
+
+from test_framework.test_framework import BitcoinTestFramework
+
+from test_framework.p2p import (
+ P2PInterface,
+)
+
+from test_framework.messages import (
+ msg_headers,
+)
+
+from test_framework.blocktools import (
+ NORMAL_GBT_REQUEST_PARAMS,
+ create_block,
+)
+
+from test_framework.util import assert_equal
+
+NODE1_BLOCKS_REQUIRED = 15
+NODE2_BLOCKS_REQUIRED = 2047
+
+
+class RejectLowDifficultyHeadersTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.setup_clean_chain = True
+ self.num_nodes = 4
+ # Node0 has no required chainwork; node1 requires 15 blocks on top of the genesis block; node2 requires 2047
+ self.extra_args = [["-minimumchainwork=0x0", "-checkblockindex=0"], ["-minimumchainwork=0x1f", "-checkblockindex=0"], ["-minimumchainwork=0x1000", "-checkblockindex=0"], ["-minimumchainwork=0x1000", "-checkblockindex=0", "-whitelist=noban@127.0.0.1"]]
+
+ def setup_network(self):
+ self.setup_nodes()
+ self.reconnect_all()
+ self.sync_all()
+
+ def disconnect_all(self):
+ self.disconnect_nodes(0, 1)
+ self.disconnect_nodes(0, 2)
+ self.disconnect_nodes(0, 3)
+
+ def reconnect_all(self):
+ self.connect_nodes(0, 1)
+ self.connect_nodes(0, 2)
+ self.connect_nodes(0, 3)
+
+ def test_chains_sync_when_long_enough(self):
+ self.log.info("Generate blocks on the node with no required chainwork, and verify nodes 1 and 2 have no new headers in their headers tree")
+ with self.nodes[1].assert_debug_log(expected_msgs=["[net] Ignoring low-work chain (height=14)"]), self.nodes[2].assert_debug_log(expected_msgs=["[net] Ignoring low-work chain (height=14)"]), self.nodes[3].assert_debug_log(expected_msgs=["Synchronizing blockheaders, height: 14"]):
+ self.generate(self.nodes[0], NODE1_BLOCKS_REQUIRED-1, sync_fun=self.no_op)
+
+ # Node3 should always allow headers due to noban permissions
+ self.log.info("Check that node3 will sync headers (due to noban permissions)")
+
+ def check_node3_chaintips(num_tips, tip_hash, height):
+ node3_chaintips = self.nodes[3].getchaintips()
+ assert(len(node3_chaintips) == num_tips)
+ assert {
+ 'height': height,
+ 'hash': tip_hash,
+ 'branchlen': height,
+ 'status': 'headers-only',
+ } in node3_chaintips
+
+ check_node3_chaintips(2, self.nodes[0].getbestblockhash(), NODE1_BLOCKS_REQUIRED-1)
+
+ for node in self.nodes[1:3]:
+ chaintips = node.getchaintips()
+ assert(len(chaintips) == 1)
+ assert {
+ 'height': 0,
+ 'hash': '0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206',
+ 'branchlen': 0,
+ 'status': 'active',
+ } in chaintips
+
+ self.log.info("Generate more blocks to satisfy node1's minchainwork requirement, and verify node2 still has no new headers in headers tree")
+ with self.nodes[2].assert_debug_log(expected_msgs=["[net] Ignoring low-work chain (height=15)"]), self.nodes[3].assert_debug_log(expected_msgs=["Synchronizing blockheaders, height: 15"]):
+ self.generate(self.nodes[0], NODE1_BLOCKS_REQUIRED - self.nodes[0].getblockcount(), sync_fun=self.no_op)
+ self.sync_blocks(self.nodes[0:2]) # node3 will sync headers (noban permissions) but not blocks (due to minchainwork)
+
+ assert {
+ 'height': 0,
+ 'hash': '0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206',
+ 'branchlen': 0,
+ 'status': 'active',
+ } in self.nodes[2].getchaintips()
+
+ assert(len(self.nodes[2].getchaintips()) == 1)
+
+ self.log.info("Check that node3 accepted these headers as well")
+ check_node3_chaintips(2, self.nodes[0].getbestblockhash(), NODE1_BLOCKS_REQUIRED)
+
+ self.log.info("Generate long chain for node0/node1/node3")
+ self.generate(self.nodes[0], NODE2_BLOCKS_REQUIRED-self.nodes[0].getblockcount(), sync_fun=self.no_op)
+
+ self.log.info("Verify that node2 and node3 will sync the chain when it gets long enough")
+ self.sync_blocks()
+
+ def test_peerinfo_includes_headers_presync_height(self):
+ self.log.info("Test that getpeerinfo() includes headers presync height")
+
+ # Disconnect network, so that we can find our own peer connection more
+ # easily
+ self.disconnect_all()
+
+ p2p = self.nodes[0].add_p2p_connection(P2PInterface())
+ node = self.nodes[0]
+
+ # Ensure we have a long chain already
+ current_height = self.nodes[0].getblockcount()
+ if (current_height < 3000):
+ self.generate(node, 3000-current_height, sync_fun=self.no_op)
+
+ # Send a group of 2000 headers, forking from genesis.
+ new_blocks = []
+ hashPrevBlock = int(node.getblockhash(0), 16)
+ for i in range(2000):
+ block = create_block(hashprev = hashPrevBlock, tmpl=node.getblocktemplate(NORMAL_GBT_REQUEST_PARAMS))
+ block.solve()
+ new_blocks.append(block)
+ hashPrevBlock = block.sha256
+
+ headers_message = msg_headers(headers=new_blocks)
+ p2p.send_and_ping(headers_message)
+
+ # getpeerinfo should show a sync in progress
+ assert_equal(node.getpeerinfo()[0]['presynced_headers'], 2000)
+
+ def test_large_reorgs_can_succeed(self):
+ self.log.info("Test that a 2000+ block reorg, starting from a point that is more than 2000 blocks before a locator entry, can succeed")
+
+ self.sync_all() # Ensure all nodes are synced.
+ self.disconnect_all()
+
+ # locator(block at height T) will have heights:
+ # [T, T-1, ..., T-10, T-12, T-16, T-24, T-40, T-72, T-136, T-264,
+ # T-520, T-1032, T-2056, T-4104, ...]
+ # So mine a number of blocks > 4104 to ensure that the first window of
+ # received headers during a sync are fully between locator entries.
+ BLOCKS_TO_MINE = 4110
+
+ self.generate(self.nodes[0], BLOCKS_TO_MINE, sync_fun=self.no_op)
+ self.generate(self.nodes[1], BLOCKS_TO_MINE+2, sync_fun=self.no_op)
+
+ self.reconnect_all()
+
+ self.sync_blocks(timeout=300) # Ensure tips eventually agree
+
+
+ def run_test(self):
+ self.test_chains_sync_when_long_enough()
+
+ self.test_large_reorgs_can_succeed()
+
+ self.test_peerinfo_includes_headers_presync_height()
+
+
+
+if __name__ == '__main__':
+ RejectLowDifficultyHeadersTest().main()
diff --git a/test/functional/p2p_i2p_sessions.py b/test/functional/p2p_i2p_sessions.py
new file mode 100755
index 0000000000..4e52522b81
--- /dev/null
+++ b/test/functional/p2p_i2p_sessions.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python3
+# Copyright (c) 2022-2022 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""
+Test whether persistent or transient I2P sessions are being used, based on `-i2pacceptincoming`.
+"""
+
+from test_framework.test_framework import BitcoinTestFramework
+
+
+class I2PSessions(BitcoinTestFramework):
+ def set_test_params(self):
+ self.num_nodes = 2
+ # The test assumes that an I2P SAM proxy is not listening here.
+ self.extra_args = [
+ ["-i2psam=127.0.0.1:60000", "-i2pacceptincoming=1"],
+ ["-i2psam=127.0.0.1:60000", "-i2pacceptincoming=0"],
+ ]
+
+ def run_test(self):
+ addr = "zsxwyo6qcn3chqzwxnseusqgsnuw3maqnztkiypyfxtya4snkoka.b32.i2p"
+
+ self.log.info("Ensure we create a persistent session when -i2pacceptincoming=1")
+ node0 = self.nodes[0]
+ with node0.assert_debug_log(expected_msgs=[f"Creating persistent SAM session"]):
+ node0.addnode(node=addr, command="onetry")
+
+ self.log.info("Ensure we create a transient session when -i2pacceptincoming=0")
+ node1 = self.nodes[1]
+ with node1.assert_debug_log(expected_msgs=[f"Creating transient SAM session"]):
+ node1.addnode(node=addr, command="onetry")
+
+
+if __name__ == '__main__':
+ I2PSessions().main()
diff --git a/test/functional/p2p_leak.py b/test/functional/p2p_leak.py
index af8e45d578..936c22197c 100755
--- a/test/functional/p2p_leak.py
+++ b/test/functional/p2p_leak.py
@@ -138,6 +138,9 @@ class P2PLeakTest(BitcoinTestFramework):
# Give the node enough time to possibly leak out a message
time.sleep(PEER_TIMEOUT + 2)
+ self.log.info("Connect peer to ensure the net thread runs the disconnect logic at least once")
+ self.nodes[0].add_p2p_connection(P2PInterface())
+
# Make sure only expected messages came in
assert not no_version_idle_peer.unexpected_msg
assert not no_version_idle_peer.got_wtxidrelay
@@ -169,7 +172,7 @@ class P2PLeakTest(BitcoinTestFramework):
self.log.info('Check that old peers are disconnected')
p2p_old_peer = self.nodes[0].add_p2p_connection(P2PInterface(), send_version=False, wait_for_verack=False)
- with self.nodes[0].assert_debug_log(['peer=4 using obsolete version 31799; disconnecting']):
+ with self.nodes[0].assert_debug_log(["using obsolete version 31799; disconnecting"]):
p2p_old_peer.send_message(self.create_old_version(31799))
p2p_old_peer.wait_for_disconnect()
diff --git a/test/functional/p2p_unrequested_blocks.py b/test/functional/p2p_unrequested_blocks.py
index 76d9b045ce..5030e7af26 100755
--- a/test/functional/p2p_unrequested_blocks.py
+++ b/test/functional/p2p_unrequested_blocks.py
@@ -72,6 +72,13 @@ class AcceptBlockTest(BitcoinTestFramework):
def setup_network(self):
self.setup_nodes()
+ def check_hash_in_chaintips(self, node, blockhash):
+ tips = node.getchaintips()
+ for x in tips:
+ if x["hash"] == blockhash:
+ return True
+ return False
+
def run_test(self):
test_node = self.nodes[0].add_p2p_connection(P2PInterface())
min_work_node = self.nodes[1].add_p2p_connection(P2PInterface())
@@ -89,10 +96,15 @@ class AcceptBlockTest(BitcoinTestFramework):
blocks_h2[i].solve()
block_time += 1
test_node.send_and_ping(msg_block(blocks_h2[0]))
- min_work_node.send_and_ping(msg_block(blocks_h2[1]))
+
+ with self.nodes[1].assert_debug_log(expected_msgs=[f"AcceptBlockHeader: not adding new block header {blocks_h2[1].hash}, missing anti-dos proof-of-work validation"]):
+ min_work_node.send_and_ping(msg_block(blocks_h2[1]))
assert_equal(self.nodes[0].getblockcount(), 2)
assert_equal(self.nodes[1].getblockcount(), 1)
+
+ # Ensure that the header of the second block was also not accepted by node1
+ assert_equal(self.check_hash_in_chaintips(self.nodes[1], blocks_h2[1].hash), False)
self.log.info("First height 2 block accepted by node0; correctly rejected by node1")
# 3. Send another block that builds on genesis.
diff --git a/test/functional/rpc_blockchain.py b/test/functional/rpc_blockchain.py
index d07b144905..d8147b3355 100755
--- a/test/functional/rpc_blockchain.py
+++ b/test/functional/rpc_blockchain.py
@@ -38,6 +38,7 @@ from test_framework.messages import (
msg_block,
)
from test_framework.p2p import P2PInterface
+from test_framework.script import hash256
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
@@ -452,8 +453,9 @@ class BlockchainTest(BitcoinTestFramework):
# (Previously this was broken based on setting
# `rpc/blockchain.cpp:latestblock` incorrectly.)
#
- b20hash = node.getblockhash(20)
- b20 = node.getblock(b20hash)
+ fork_height = current_height - 100 # choose something vaguely near our tip
+ fork_hash = node.getblockhash(fork_height)
+ fork_block = node.getblock(fork_hash)
def solve_and_send_block(prevhash, height, time):
b = create_block(prevhash, create_coinbase(height), time)
@@ -461,10 +463,10 @@ class BlockchainTest(BitcoinTestFramework):
peer.send_and_ping(msg_block(b))
return b
- b21f = solve_and_send_block(int(b20hash, 16), 21, b20['time'] + 1)
- b22f = solve_and_send_block(b21f.sha256, 22, b21f.nTime + 1)
+ b1 = solve_and_send_block(int(fork_hash, 16), fork_height+1, fork_block['time'] + 1)
+ b2 = solve_and_send_block(b1.sha256, fork_height+2, b1.nTime + 1)
- node.invalidateblock(b22f.hash)
+ node.invalidateblock(b2.hash)
def assert_waitforheight(height, timeout=2):
assert_equal(
@@ -484,6 +486,10 @@ class BlockchainTest(BitcoinTestFramework):
self.wallet.send_self_transfer(fee_rate=fee_per_kb, from_node=node)
blockhash = self.generate(node, 1)[0]
+ def assert_hexblock_hashes(verbosity):
+ block = node.getblock(blockhash, verbosity)
+ assert_equal(blockhash, hash256(bytes.fromhex(block[:160]))[::-1].hex())
+
def assert_fee_not_in_block(verbosity):
block = node.getblock(blockhash, verbosity)
assert 'fee' not in block['tx'][1]
@@ -518,8 +524,13 @@ class BlockchainTest(BitcoinTestFramework):
for vin in tx["vin"]:
assert "prevout" not in vin
+ self.log.info("Test that getblock with verbosity 0 hashes to expected value")
+ assert_hexblock_hashes(0)
+ assert_hexblock_hashes(False)
+
self.log.info("Test that getblock with verbosity 1 doesn't include fee")
assert_fee_not_in_block(1)
+ assert_fee_not_in_block(True)
self.log.info('Test that getblock with verbosity 2 and 3 includes expected fee')
assert_fee_in_block(2)
diff --git a/test/functional/rpc_estimatefee.py b/test/functional/rpc_estimatefee.py
index 51b7efb4c3..b057400887 100755
--- a/test/functional/rpc_estimatefee.py
+++ b/test/functional/rpc_estimatefee.py
@@ -22,15 +22,15 @@ class EstimateFeeTest(BitcoinTestFramework):
assert_raises_rpc_error(-1, "estimaterawfee", self.nodes[0].estimaterawfee)
# wrong type for conf_target
- assert_raises_rpc_error(-3, "Expected type number, got string", self.nodes[0].estimatesmartfee, 'foo')
- assert_raises_rpc_error(-3, "Expected type number, got string", self.nodes[0].estimaterawfee, 'foo')
+ assert_raises_rpc_error(-3, "JSON value of type string is not of expected type number", self.nodes[0].estimatesmartfee, 'foo')
+ assert_raises_rpc_error(-3, "JSON value of type string is not of expected type number", self.nodes[0].estimaterawfee, 'foo')
# wrong type for estimatesmartfee(estimate_mode)
- assert_raises_rpc_error(-3, "Expected type string, got number", self.nodes[0].estimatesmartfee, 1, 1)
+ assert_raises_rpc_error(-3, "JSON value of type number is not of expected type string", self.nodes[0].estimatesmartfee, 1, 1)
assert_raises_rpc_error(-8, 'Invalid estimate_mode parameter, must be one of: "unset", "economical", "conservative"', self.nodes[0].estimatesmartfee, 1, 'foo')
# wrong type for estimaterawfee(threshold)
- assert_raises_rpc_error(-3, "Expected type number, got string", self.nodes[0].estimaterawfee, 1, 'foo')
+ assert_raises_rpc_error(-3, "JSON value of type string is not of expected type number", self.nodes[0].estimaterawfee, 1, 'foo')
# extra params
assert_raises_rpc_error(-1, "estimatesmartfee", self.nodes[0].estimatesmartfee, 1, 'ECONOMICAL', 1)
diff --git a/test/functional/rpc_fundrawtransaction.py b/test/functional/rpc_fundrawtransaction.py
index 5a870de6c7..a963bb5e2d 100755
--- a/test/functional/rpc_fundrawtransaction.py
+++ b/test/functional/rpc_fundrawtransaction.py
@@ -106,6 +106,7 @@ class RawTransactionsTest(BitcoinTestFramework):
self.generate(self.nodes[2], 1)
self.generate(self.nodes[0], 121)
+ self.test_add_inputs_default_value()
self.test_weight_calculation()
self.test_change_position()
self.test_simple()
@@ -635,7 +636,7 @@ class RawTransactionsTest(BitcoinTestFramework):
self.log.info("Test fundrawtxn fee with many inputs")
# Empty node1, send some small coins from node0 to node1.
- self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), self.nodes[1].getbalance(), "", "", True)
+ self.nodes[1].sendall(recipients=[self.nodes[0].getnewaddress()])
self.generate(self.nodes[1], 1)
for _ in range(20):
@@ -661,7 +662,7 @@ class RawTransactionsTest(BitcoinTestFramework):
self.log.info("Test fundrawtxn sign+send with many inputs")
# Again, empty node1, send some small coins from node0 to node1.
- self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), self.nodes[1].getbalance(), "", "", True)
+ self.nodes[1].sendall(recipients=[self.nodes[0].getnewaddress()])
self.generate(self.nodes[1], 1)
for _ in range(20):
@@ -1073,6 +1074,121 @@ class RawTransactionsTest(BitcoinTestFramework):
self.nodes[2].unloadwallet("extfund")
+ def test_add_inputs_default_value(self):
+ self.log.info("Test 'add_inputs' default value")
+
+ # Create and fund the wallet with 5 BTC
+ self.nodes[2].createwallet("test_preset_inputs")
+ wallet = self.nodes[2].get_wallet_rpc("test_preset_inputs")
+ addr1 = wallet.getnewaddress(address_type="bech32")
+ self.nodes[0].sendtoaddress(addr1, 5)
+ self.generate(self.nodes[0], 1)
+
+ # Covered cases:
+ # 1. Default add_inputs value with no preset inputs (add_inputs=true):
+ # Expect: automatically add coins from the wallet to the tx.
+ # 2. Default add_inputs value with preset inputs (add_inputs=false):
+ # Expect: disallow automatic coin selection.
+ # 3. Explicit add_inputs=true and preset inputs (with preset inputs not-covering the target amount).
+ # Expect: include inputs from the wallet.
+ # 4. Explicit add_inputs=true and preset inputs (with preset inputs covering the target amount).
+ # Expect: only preset inputs are used.
+ # 5. Explicit add_inputs=true, no preset inputs (same as (1) but with an explicit set):
+ # Expect: include inputs from the wallet.
+
+ # Case (1), 'send' command
+ # 'add_inputs' value is true unless "inputs" are specified, in such case, add_inputs=false.
+ # So, the wallet will automatically select coins and create the transaction if only the outputs are provided.
+ tx = wallet.send(outputs=[{addr1: 3}])
+ assert tx["complete"]
+
+ # Case (2), 'send' command
+ # Select an input manually, which doesn't cover the entire output amount and
+ # verify that the dynamically set 'add_inputs=false' value works.
+
+ # Fund wallet with 2 outputs, 5 BTC each.
+ addr2 = wallet.getnewaddress(address_type="bech32")
+ source_tx = self.nodes[0].send(outputs=[{addr1: 5}, {addr2: 5}], options={"change_position": 0})
+ self.generate(self.nodes[0], 1)
+
+ # Select only one input.
+ options = {
+ "inputs": [
+ {
+ "txid": source_tx["txid"],
+ "vout": 1 # change position was hardcoded to index 0
+ }
+ ]
+ }
+ assert_raises_rpc_error(-4, "Insufficient funds", wallet.send, outputs=[{addr1: 8}], options=options)
+
+ # Case (3), Explicit add_inputs=true and preset inputs (with preset inputs not-covering the target amount)
+ options["add_inputs"] = True
+ options["add_to_wallet"] = False
+ tx = wallet.send(outputs=[{addr1: 8}], options=options)
+ assert tx["complete"]
+
+ # Case (4), Explicit add_inputs=true and preset inputs (with preset inputs covering the target amount)
+ options["inputs"].append({
+ "txid": source_tx["txid"],
+ "vout": 2 # change position was hardcoded to index 0
+ })
+ tx = wallet.send(outputs=[{addr1: 8}], options=options)
+ assert tx["complete"]
+ # Check that only the preset inputs were added to the tx
+ decoded_psbt_inputs = self.nodes[0].decodepsbt(tx["psbt"])['tx']['vin']
+ assert_equal(len(decoded_psbt_inputs), 2)
+ for input in decoded_psbt_inputs:
+ assert_equal(input["txid"], source_tx["txid"])
+
+ # Case (5), assert that inputs are added to the tx by explicitly setting add_inputs=true
+ options = {"add_inputs": True, "add_to_wallet": True}
+ tx = wallet.send(outputs=[{addr1: 8}], options=options)
+ assert tx["complete"]
+
+ ################################################
+
+ # Case (1), 'walletcreatefundedpsbt' command
+ # Default add_inputs value with no preset inputs (add_inputs=true)
+ inputs = []
+ outputs = {self.nodes[1].getnewaddress(): 8}
+ assert "psbt" in wallet.walletcreatefundedpsbt(inputs=inputs, outputs=outputs)
+
+ # Case (2), 'walletcreatefundedpsbt' command
+ # Default add_inputs value with preset inputs (add_inputs=false).
+ inputs = [{
+ "txid": source_tx["txid"],
+ "vout": 1 # change position was hardcoded to index 0
+ }]
+ outputs = {self.nodes[1].getnewaddress(): 8}
+ assert_raises_rpc_error(-4, "Insufficient funds", wallet.walletcreatefundedpsbt, inputs=inputs, outputs=outputs)
+
+ # Case (3), Explicit add_inputs=true and preset inputs (with preset inputs not-covering the target amount)
+ options["add_inputs"] = True
+ options["add_to_wallet"] = False
+ assert "psbt" in wallet.walletcreatefundedpsbt(outputs=[{addr1: 8}], inputs=inputs, options=options)
+
+ # Case (4), Explicit add_inputs=true and preset inputs (with preset inputs covering the target amount)
+ inputs.append({
+ "txid": source_tx["txid"],
+ "vout": 2 # change position was hardcoded to index 0
+ })
+ psbt_tx = wallet.walletcreatefundedpsbt(outputs=[{addr1: 8}], inputs=inputs, options=options)
+ # Check that only the preset inputs were added to the tx
+ decoded_psbt_inputs = self.nodes[0].decodepsbt(psbt_tx["psbt"])['tx']['vin']
+ assert_equal(len(decoded_psbt_inputs), 2)
+ for input in decoded_psbt_inputs:
+ assert_equal(input["txid"], source_tx["txid"])
+
+ # Case (5), 'walletcreatefundedpsbt' command
+ # Explicit add_inputs=true, no preset inputs
+ options = {
+ "add_inputs": True
+ }
+ assert "psbt" in wallet.walletcreatefundedpsbt(inputs=[], outputs=outputs, options=options)
+
+ self.nodes[2].unloadwallet("test_preset_inputs")
+
def test_weight_calculation(self):
self.log.info("Test weight calculation with external inputs")
diff --git a/test/functional/rpc_getblockfrompeer.py b/test/functional/rpc_getblockfrompeer.py
index 41e430d87e..278a343b2b 100755
--- a/test/functional/rpc_getblockfrompeer.py
+++ b/test/functional/rpc_getblockfrompeer.py
@@ -56,8 +56,8 @@ class GetBlockFromPeerTest(BitcoinTestFramework):
self.log.info("Arguments must be valid")
assert_raises_rpc_error(-8, "hash must be of length 64 (not 4, for '1234')", self.nodes[0].getblockfrompeer, "1234", peer_0_peer_1_id)
- assert_raises_rpc_error(-3, "Expected type string, got number", self.nodes[0].getblockfrompeer, 1234, peer_0_peer_1_id)
- assert_raises_rpc_error(-3, "Expected type number, got string", self.nodes[0].getblockfrompeer, short_tip, "0")
+ assert_raises_rpc_error(-3, "JSON value of type number is not of expected type string", self.nodes[0].getblockfrompeer, 1234, peer_0_peer_1_id)
+ assert_raises_rpc_error(-3, "JSON value of type string is not of expected type number", self.nodes[0].getblockfrompeer, short_tip, "0")
self.log.info("We must already have the header")
assert_raises_rpc_error(-1, "Block header missing", self.nodes[0].getblockfrompeer, "00" * 32, 0)
diff --git a/test/functional/rpc_getdescriptorinfo.py b/test/functional/rpc_getdescriptorinfo.py
index 5e6fd66aab..1b0f411e52 100755
--- a/test/functional/rpc_getdescriptorinfo.py
+++ b/test/functional/rpc_getdescriptorinfo.py
@@ -29,7 +29,7 @@ class DescriptorTest(BitcoinTestFramework):
def run_test(self):
assert_raises_rpc_error(-1, 'getdescriptorinfo', self.nodes[0].getdescriptorinfo)
- assert_raises_rpc_error(-3, 'Expected type string', self.nodes[0].getdescriptorinfo, 1)
+ assert_raises_rpc_error(-3, 'JSON value of type number is not of expected type string', self.nodes[0].getdescriptorinfo, 1)
assert_raises_rpc_error(-5, "'' is not a valid descriptor function", self.nodes[0].getdescriptorinfo, "")
# P2PK output with the specified public key.
diff --git a/test/functional/rpc_invalidateblock.py b/test/functional/rpc_invalidateblock.py
index f1c2537ef9..1e33e7ca9c 100755
--- a/test/functional/rpc_invalidateblock.py
+++ b/test/functional/rpc_invalidateblock.py
@@ -8,6 +8,7 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.address import ADDRESS_BCRT1_UNSPENDABLE_DESCRIPTOR
from test_framework.util import (
assert_equal,
+ assert_raises_rpc_error,
)
@@ -83,6 +84,10 @@ class InvalidateTest(BitcoinTestFramework):
# Should be back at the tip by now
assert_equal(self.nodes[1].getbestblockhash(), blocks[-1])
+ self.log.info("Verify that invalidating an unknown block throws an error")
+ assert_raises_rpc_error(-5, "Block not found", self.nodes[1].invalidateblock, "00" * 32)
+ assert_equal(self.nodes[1].getbestblockhash(), blocks[-1])
+
if __name__ == '__main__':
InvalidateTest().main()
diff --git a/test/functional/rpc_rawtransaction.py b/test/functional/rpc_rawtransaction.py
index a858292dd4..f1fae13b4a 100755
--- a/test/functional/rpc_rawtransaction.py
+++ b/test/functional/rpc_rawtransaction.py
@@ -180,7 +180,7 @@ class RawTransactionsTest(BitcoinTestFramework):
assert_raises_rpc_error(-1, "createrawtransaction", self.nodes[0].createrawtransaction, [], {}, 0, False, 'foo')
# Test `createrawtransaction` invalid `inputs`
- assert_raises_rpc_error(-3, "Expected type array", self.nodes[0].createrawtransaction, 'foo', {})
+ assert_raises_rpc_error(-3, "JSON value of type string is not of expected type array", self.nodes[0].createrawtransaction, 'foo', {})
assert_raises_rpc_error(-1, "JSON value of type string is not of expected type object", self.nodes[0].createrawtransaction, ['foo'], {})
assert_raises_rpc_error(-1, "JSON value of type null is not of expected type string", self.nodes[0].createrawtransaction, [{}], {})
assert_raises_rpc_error(-8, "txid must be of length 64 (not 3, for 'foo')", self.nodes[0].createrawtransaction, [{'txid': 'foo'}], {})
@@ -226,12 +226,12 @@ class RawTransactionsTest(BitcoinTestFramework):
self.nodes[0].createrawtransaction, [{'txid': TXID, 'vout': 0, 'sequence': MAX_BIP125_RBF_SEQUENCE+1}], {}, 0, True)
# Test `createrawtransaction` invalid `locktime`
- assert_raises_rpc_error(-3, "Expected type number", self.nodes[0].createrawtransaction, [], {}, 'foo')
+ assert_raises_rpc_error(-3, "JSON value of type string is not of expected type number", self.nodes[0].createrawtransaction, [], {}, 'foo')
assert_raises_rpc_error(-8, "Invalid parameter, locktime out of range", self.nodes[0].createrawtransaction, [], {}, -1)
assert_raises_rpc_error(-8, "Invalid parameter, locktime out of range", self.nodes[0].createrawtransaction, [], {}, 4294967296)
# Test `createrawtransaction` invalid `replaceable`
- assert_raises_rpc_error(-3, "Expected type bool", self.nodes[0].createrawtransaction, [], {}, 0, 'foo')
+ assert_raises_rpc_error(-3, "JSON value of type string is not of expected type bool", self.nodes[0].createrawtransaction, [], {}, 0, 'foo')
# Test that createrawtransaction accepts an array and object as outputs
# One output
diff --git a/test/functional/test_framework/messages.py b/test/functional/test_framework/messages.py
index 4e757b64ca..8a928a1e50 100755
--- a/test/functional/test_framework/messages.py
+++ b/test/functional/test_framework/messages.py
@@ -71,6 +71,7 @@ DEFAULT_DESCENDANT_LIMIT = 25 # default max number of in-mempool descendants
# Default setting for -datacarriersize. 80 bytes of data, +1 for OP_RETURN, +2 for the pushdata opcodes.
MAX_OP_RETURN_RELAY = 83
+DEFAULT_MEMPOOL_EXPIRY_HOURS = 336 # hours
def sha256(s):
return hashlib.sha256(s).digest()
diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py
index 03f6c8adea..e35cae006f 100755
--- a/test/functional/test_framework/test_node.py
+++ b/test/functional/test_framework/test_node.py
@@ -118,6 +118,8 @@ class TestNode():
self.args.append("-logthreadnames")
if self.version_is_at_least(219900):
self.args.append("-logsourcelocations")
+ if self.version_is_at_least(239000):
+ self.args.append("-loglevel=trace")
self.cli = TestNodeCLI(bitcoin_cli, self.datadir)
self.use_cli = use_cli
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index 37d0c4f87e..c47e4d9b84 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -186,6 +186,7 @@ BASE_SCRIPTS = [
'wallet_signrawtransactionwithwallet.py --legacy-wallet',
'wallet_signrawtransactionwithwallet.py --descriptors',
'rpc_signrawtransactionwithkey.py',
+ 'p2p_headers_sync_with_minchainwork.py',
'rpc_rawtransaction.py --legacy-wallet',
'wallet_groups.py --legacy-wallet',
'wallet_transactiontime_rescan.py --descriptors',
@@ -330,6 +331,7 @@ BASE_SCRIPTS = [
'feature_blocksdir.py',
'wallet_startup.py',
'p2p_i2p_ports.py',
+ 'p2p_i2p_sessions.py',
'feature_config_args.py',
'feature_presegwit_node_upgrade.py',
'feature_settings.py',
@@ -339,6 +341,7 @@ BASE_SCRIPTS = [
'feature_dirsymlinks.py',
'feature_help.py',
'feature_shutdown.py',
+ 'wallet_migration.py',
'p2p_ibd_txrelay.py',
# Don't append tests at the end to avoid merge conflicts
# Put them in a random line within the section that fits their approximate run-time
@@ -552,14 +555,14 @@ def run_tests(*, test_list, src_dir, build_dir, tmpdir, jobs=1, enable_coverage=
while i < test_count:
if failfast and not all_passed:
break
- for test_result, testdir, stdout, stderr in job_queue.get_next():
+ for test_result, testdir, stdout, stderr, skip_reason in job_queue.get_next():
test_results.append(test_result)
i += 1
done_str = "{}/{} - {}{}{}".format(i, test_count, BOLD[1], test_result.name, BOLD[0])
if test_result.status == "Passed":
logging.debug("%s passed, Duration: %s s" % (done_str, test_result.time))
elif test_result.status == "Skipped":
- logging.debug("%s skipped" % (done_str))
+ logging.debug(f"{done_str} skipped ({skip_reason})")
else:
all_passed = False
print("%s failed, Duration: %s s\n" % (done_str, test_result.time))
@@ -683,10 +686,12 @@ class TestHandler:
log_out.seek(0), log_err.seek(0)
[stdout, stderr] = [log_file.read().decode('utf-8') for log_file in (log_out, log_err)]
log_out.close(), log_err.close()
+ skip_reason = None
if proc.returncode == TEST_EXIT_PASSED and stderr == "":
status = "Passed"
elif proc.returncode == TEST_EXIT_SKIPPED:
status = "Skipped"
+ skip_reason = re.search(r"Test Skipped: (.*)", stdout).group(1)
else:
status = "Failed"
self.num_running -= 1
@@ -695,7 +700,7 @@ class TestHandler:
clearline = '\r' + (' ' * dot_count) + '\r'
print(clearline, end='', flush=True)
dot_count = 0
- ret.append((TestResult(name, status, int(time.time() - start_time)), testdir, stdout, stderr))
+ ret.append((TestResult(name, status, int(time.time() - start_time)), testdir, stdout, stderr, skip_reason))
if ret:
return ret
if self.use_term_control:
diff --git a/test/functional/tool_wallet.py b/test/functional/tool_wallet.py
index 2cb9dc4523..1e5ce513cb 100755
--- a/test/functional/tool_wallet.py
+++ b/test/functional/tool_wallet.py
@@ -68,7 +68,7 @@ class ToolWalletTest(BitcoinTestFramework):
result = 'unchanged' if new == old else 'increased!'
self.log.debug('Wallet file timestamp {}'.format(result))
- def get_expected_info_output(self, name="", transactions=0, keypool=2, address=0):
+ def get_expected_info_output(self, name="", transactions=0, keypool=2, address=0, imported_privs=0):
wallet_name = self.default_wallet_name if name == "" else name
if self.options.descriptors:
output_types = 4 # p2pkh, p2sh, segwit, bech32m
@@ -83,7 +83,7 @@ class ToolWalletTest(BitcoinTestFramework):
Keypool Size: %d
Transactions: %d
Address Book: %d
- ''' % (wallet_name, keypool * output_types, transactions, address))
+ ''' % (wallet_name, keypool * output_types, transactions, imported_privs * 3 + address))
else:
output_types = 3 # p2pkh, p2sh, segwit. Legacy wallets do not support bech32m.
return textwrap.dedent('''\
@@ -97,7 +97,7 @@ class ToolWalletTest(BitcoinTestFramework):
Keypool Size: %d
Transactions: %d
Address Book: %d
- ''' % (wallet_name, keypool, transactions, address * output_types))
+ ''' % (wallet_name, keypool, transactions, (address + imported_privs) * output_types))
def read_dump(self, filename):
dump = OrderedDict()
@@ -219,7 +219,7 @@ class ToolWalletTest(BitcoinTestFramework):
# shasum_before = self.wallet_shasum()
timestamp_before = self.wallet_timestamp()
self.log.debug('Wallet file timestamp before calling info: {}'.format(timestamp_before))
- out = self.get_expected_info_output(address=1)
+ out = self.get_expected_info_output(imported_privs=1)
self.assert_tool_output(out, '-wallet=' + self.default_wallet_name, 'info')
timestamp_after = self.wallet_timestamp()
self.log.debug('Wallet file timestamp after calling info: {}'.format(timestamp_after))
@@ -250,7 +250,7 @@ class ToolWalletTest(BitcoinTestFramework):
shasum_before = self.wallet_shasum()
timestamp_before = self.wallet_timestamp()
self.log.debug('Wallet file timestamp before calling info: {}'.format(timestamp_before))
- out = self.get_expected_info_output(transactions=1, address=1)
+ out = self.get_expected_info_output(transactions=1, imported_privs=1)
self.assert_tool_output(out, '-wallet=' + self.default_wallet_name, 'info')
shasum_after = self.wallet_shasum()
timestamp_after = self.wallet_timestamp()
diff --git a/test/functional/wallet_balance.py b/test/functional/wallet_balance.py
index d2ed97ca76..ec58ace4a2 100755
--- a/test/functional/wallet_balance.py
+++ b/test/functional/wallet_balance.py
@@ -266,7 +266,6 @@ class WalletTest(BitcoinTestFramework):
self.nodes[1].invalidateblock(block_reorg)
assert_equal(self.nodes[0].getbalance(minconf=0), 0) # wallet txs not in the mempool are untrusted
self.generatetoaddress(self.nodes[0], 1, ADDRESS_WATCHONLY, sync_fun=self.no_op)
- assert_equal(self.nodes[0].getbalance(minconf=0), 0) # wallet txs not in the mempool are untrusted
# Now confirm tx_orig
self.restart_node(1, ['-persistmempool=0'])
diff --git a/test/functional/wallet_basic.py b/test/functional/wallet_basic.py
index ed603a2857..917721fef8 100755
--- a/test/functional/wallet_basic.py
+++ b/test/functional/wallet_basic.py
@@ -585,15 +585,9 @@ class WalletTest(BitcoinTestFramework):
# ==Check that wallet prefers to use coins that don't exceed mempool limits =====
- # Get all non-zero utxos together
+ # Get all non-zero utxos together and split into two chains
chain_addrs = [self.nodes[0].getnewaddress(), self.nodes[0].getnewaddress()]
- singletxid = self.nodes[0].sendtoaddress(chain_addrs[0], self.nodes[0].getbalance(), "", "", True)
- self.generate(self.nodes[0], 1, sync_fun=self.no_op)
- node0_balance = self.nodes[0].getbalance()
- # Split into two chains
- rawtx = self.nodes[0].createrawtransaction([{"txid": singletxid, "vout": 0}], {chain_addrs[0]: node0_balance / 2 - Decimal('0.01'), chain_addrs[1]: node0_balance / 2 - Decimal('0.01')})
- signedtx = self.nodes[0].signrawtransactionwithwallet(rawtx)
- singletxid = self.nodes[0].sendrawtransaction(hexstring=signedtx["hex"], maxfeerate=0)
+ self.nodes[0].sendall(recipients=chain_addrs)
self.generate(self.nodes[0], 1, sync_fun=self.no_op)
# Make a long chain of unconfirmed payments without hitting mempool limit
@@ -701,37 +695,38 @@ class WalletTest(BitcoinTestFramework):
txid_feeReason_four = self.nodes[2].sendmany(dummy='', amounts={address: 5}, verbose=False)
assert_equal(self.nodes[2].gettransaction(txid_feeReason_four)['txid'], txid_feeReason_four)
- self.log.info("Testing 'listunspent' outputs the parent descriptor(s) of coins")
- # Create two multisig descriptors, and send a UTxO each.
- multi_a = descsum_create("wsh(multi(1,tpubD6NzVbkrYhZ4YBNjUo96Jxd1u4XKWgnoc7LsA1jz3Yc2NiDbhtfBhaBtemB73n9V5vtJHwU6FVXwggTbeoJWQ1rzdz8ysDuQkpnaHyvnvzR/*,tpubD6NzVbkrYhZ4YHdDGMAYGaWxMSC1B6tPRTHuU5t3BcfcS3nrF523iFm5waFd1pP3ZvJt4Jr8XmCmsTBNx5suhcSgtzpGjGMASR3tau1hJz4/*))")
- multi_b = descsum_create("wsh(multi(1,tpubD6NzVbkrYhZ4YHdDGMAYGaWxMSC1B6tPRTHuU5t3BcfcS3nrF523iFm5waFd1pP3ZvJt4Jr8XmCmsTBNx5suhcSgtzpGjGMASR3tau1hJz4/*,tpubD6NzVbkrYhZ4Y2RLiuEzNQkntjmsLpPYDm3LTRBYynUQtDtpzeUKAcb9sYthSFL3YR74cdFgF5mW8yKxv2W2CWuZDFR2dUpE5PF9kbrVXNZ/*))")
- addr_a = self.nodes[0].deriveaddresses(multi_a, 0)[0]
- addr_b = self.nodes[0].deriveaddresses(multi_b, 0)[0]
- txid_a = self.nodes[0].sendtoaddress(addr_a, 0.01)
- txid_b = self.nodes[0].sendtoaddress(addr_b, 0.01)
- self.generate(self.nodes[0], 1, sync_fun=self.no_op)
- # Now import the descriptors, make sure we can identify on which descriptor each coin was received.
- self.nodes[0].createwallet(wallet_name="wo", descriptors=True, disable_private_keys=True)
- wo_wallet = self.nodes[0].get_wallet_rpc("wo")
- wo_wallet.importdescriptors([
- {
- "desc": multi_a,
- "active": False,
- "timestamp": "now",
- },
- {
- "desc": multi_b,
- "active": False,
- "timestamp": "now",
- },
- ])
- coins = wo_wallet.listunspent(minconf=0)
- assert_equal(len(coins), 2)
- coin_a = next(c for c in coins if c["txid"] == txid_a)
- assert_equal(coin_a["parent_descs"][0], multi_a)
- coin_b = next(c for c in coins if c["txid"] == txid_b)
- assert_equal(coin_b["parent_descs"][0], multi_b)
- self.nodes[0].unloadwallet("wo")
+ if self.options.descriptors:
+ self.log.info("Testing 'listunspent' outputs the parent descriptor(s) of coins")
+ # Create two multisig descriptors, and send a UTxO each.
+ multi_a = descsum_create("wsh(multi(1,tpubD6NzVbkrYhZ4YBNjUo96Jxd1u4XKWgnoc7LsA1jz3Yc2NiDbhtfBhaBtemB73n9V5vtJHwU6FVXwggTbeoJWQ1rzdz8ysDuQkpnaHyvnvzR/*,tpubD6NzVbkrYhZ4YHdDGMAYGaWxMSC1B6tPRTHuU5t3BcfcS3nrF523iFm5waFd1pP3ZvJt4Jr8XmCmsTBNx5suhcSgtzpGjGMASR3tau1hJz4/*))")
+ multi_b = descsum_create("wsh(multi(1,tpubD6NzVbkrYhZ4YHdDGMAYGaWxMSC1B6tPRTHuU5t3BcfcS3nrF523iFm5waFd1pP3ZvJt4Jr8XmCmsTBNx5suhcSgtzpGjGMASR3tau1hJz4/*,tpubD6NzVbkrYhZ4Y2RLiuEzNQkntjmsLpPYDm3LTRBYynUQtDtpzeUKAcb9sYthSFL3YR74cdFgF5mW8yKxv2W2CWuZDFR2dUpE5PF9kbrVXNZ/*))")
+ addr_a = self.nodes[0].deriveaddresses(multi_a, 0)[0]
+ addr_b = self.nodes[0].deriveaddresses(multi_b, 0)[0]
+ txid_a = self.nodes[0].sendtoaddress(addr_a, 0.01)
+ txid_b = self.nodes[0].sendtoaddress(addr_b, 0.01)
+ self.generate(self.nodes[0], 1, sync_fun=self.no_op)
+ # Now import the descriptors, make sure we can identify on which descriptor each coin was received.
+ self.nodes[0].createwallet(wallet_name="wo", descriptors=True, disable_private_keys=True)
+ wo_wallet = self.nodes[0].get_wallet_rpc("wo")
+ wo_wallet.importdescriptors([
+ {
+ "desc": multi_a,
+ "active": False,
+ "timestamp": "now",
+ },
+ {
+ "desc": multi_b,
+ "active": False,
+ "timestamp": "now",
+ },
+ ])
+ coins = wo_wallet.listunspent(minconf=0)
+ assert_equal(len(coins), 2)
+ coin_a = next(c for c in coins if c["txid"] == txid_a)
+ assert_equal(coin_a["parent_descs"][0], multi_a)
+ coin_b = next(c for c in coins if c["txid"] == txid_b)
+ assert_equal(coin_b["parent_descs"][0], multi_b)
+ self.nodes[0].unloadwallet("wo")
if __name__ == '__main__':
diff --git a/test/functional/wallet_bumpfee.py b/test/functional/wallet_bumpfee.py
index bd3943d66b..f4ae697292 100755
--- a/test/functional/wallet_bumpfee.py
+++ b/test/functional/wallet_bumpfee.py
@@ -624,7 +624,7 @@ def test_no_more_inputs_fails(self, rbf_node, dest_address):
# feerate rbf requires confirmed outputs when change output doesn't exist or is insufficient
self.generatetoaddress(rbf_node, 1, dest_address)
# spend all funds, no change output
- rbfid = rbf_node.sendtoaddress(rbf_node.getnewaddress(), rbf_node.getbalance(), "", "", True)
+ rbfid = rbf_node.sendall(recipients=[rbf_node.getnewaddress()])['txid']
assert_raises_rpc_error(-4, "Unable to create transaction. Insufficient funds", rbf_node.bumpfee, rbfid)
self.clear_mempool()
diff --git a/test/functional/wallet_groups.py b/test/functional/wallet_groups.py
index 866c411dba..e5e4cf03bf 100755
--- a/test/functional/wallet_groups.py
+++ b/test/functional/wallet_groups.py
@@ -26,9 +26,10 @@ class WalletGroupTest(BitcoinTestFramework):
["-maxapsfee=0.00002719"],
["-maxapsfee=0.00002720"],
]
- # whitelist peers to speed up tx relay / mempool sync
+
for args in self.extra_args:
- args.append("-whitelist=noban@127.0.0.1")
+ args.append("-whitelist=noban@127.0.0.1") # whitelist peers to speed up tx relay / mempool sync
+ args.append(f"-paytxfee={20 * 1e3 / 1e8}") # apply feerate of 20 sats/vB across all nodes
self.rpc_timeout = 480
@@ -154,7 +155,7 @@ class WalletGroupTest(BitcoinTestFramework):
assert_equal(2, len(tx6["vout"]))
# Empty out node2's wallet
- self.nodes[2].sendtoaddress(address=self.nodes[0].getnewaddress(), amount=self.nodes[2].getbalance(), subtractfeefromamount=True)
+ self.nodes[2].sendall(recipients=[self.nodes[0].getnewaddress()])
self.sync_all()
self.generate(self.nodes[0], 1)
diff --git a/test/functional/wallet_listsinceblock.py b/test/functional/wallet_listsinceblock.py
index 204bd67fb1..f259449bef 100755
--- a/test/functional/wallet_listsinceblock.py
+++ b/test/functional/wallet_listsinceblock.py
@@ -42,7 +42,8 @@ class ListSinceBlockTest(BitcoinTestFramework):
self.test_double_send()
self.double_spends_filtered()
self.test_targetconfirmations()
- self.test_desc()
+ if self.options.descriptors:
+ self.test_desc()
self.test_send_to_self()
def test_no_blockhash(self):
diff --git a/test/functional/wallet_migration.py b/test/functional/wallet_migration.py
new file mode 100755
index 0000000000..3c1cb6ac32
--- /dev/null
+++ b/test/functional/wallet_migration.py
@@ -0,0 +1,407 @@
+#!/usr/bin/env python3
+# Copyright (c) 2020 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""Test Migrating a wallet from legacy to descriptor."""
+
+import os
+import random
+from test_framework.descriptors import descsum_create
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (
+ assert_equal,
+ assert_raises_rpc_error,
+ find_vout_for_address,
+)
+from test_framework.wallet_util import (
+ get_generate_key,
+)
+
+
+class WalletMigrationTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.setup_clean_chain = True
+ self.num_nodes = 1
+ self.extra_args = [[]]
+ self.supports_cli = False
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+ self.skip_if_no_sqlite()
+ self.skip_if_no_bdb()
+
+ def assert_is_sqlite(self, wallet_name):
+ wallet_file_path = os.path.join(self.nodes[0].datadir, "regtest/wallets", wallet_name, self.wallet_data_filename)
+ with open(wallet_file_path, 'rb') as f:
+ file_magic = f.read(16)
+ assert_equal(file_magic, b'SQLite format 3\x00')
+ assert_equal(self.nodes[0].get_wallet_rpc(wallet_name).getwalletinfo()["format"], "sqlite")
+
+ def create_legacy_wallet(self, wallet_name):
+ self.nodes[0].createwallet(wallet_name=wallet_name)
+ wallet = self.nodes[0].get_wallet_rpc(wallet_name)
+ assert_equal(wallet.getwalletinfo()["descriptors"], False)
+ assert_equal(wallet.getwalletinfo()["format"], "bdb")
+ return wallet
+
+ def assert_addr_info_equal(self, addr_info, addr_info_old):
+ assert_equal(addr_info["address"], addr_info_old["address"])
+ assert_equal(addr_info["scriptPubKey"], addr_info_old["scriptPubKey"])
+ assert_equal(addr_info["ismine"], addr_info_old["ismine"])
+ assert_equal(addr_info["hdkeypath"], addr_info_old["hdkeypath"])
+ assert_equal(addr_info["solvable"], addr_info_old["solvable"])
+ assert_equal(addr_info["ischange"], addr_info_old["ischange"])
+ assert_equal(addr_info["hdmasterfingerprint"], addr_info_old["hdmasterfingerprint"])
+
+ def assert_list_txs_equal(self, received_list_txs, expected_list_txs):
+ for d in received_list_txs:
+ if "parent_descs" in d:
+ del d["parent_descs"]
+ for d in expected_list_txs:
+ if "parent_descs" in d:
+ del d["parent_descs"]
+ assert_equal(received_list_txs, expected_list_txs)
+
+ def test_basic(self):
+ default = self.nodes[0].get_wallet_rpc(self.default_wallet_name)
+
+ self.log.info("Test migration of a basic keys only wallet without balance")
+ basic0 = self.create_legacy_wallet("basic0")
+
+ addr = basic0.getnewaddress()
+ change = basic0.getrawchangeaddress()
+
+ old_addr_info = basic0.getaddressinfo(addr)
+ old_change_addr_info = basic0.getaddressinfo(change)
+ assert_equal(old_addr_info["ismine"], True)
+ assert_equal(old_addr_info["hdkeypath"], "m/0'/0'/0'")
+ assert_equal(old_change_addr_info["ismine"], True)
+ assert_equal(old_change_addr_info["hdkeypath"], "m/0'/1'/0'")
+
+ # Note: migration could take a while.
+ basic0.migratewallet()
+
+ # Verify created descriptors
+ assert_equal(basic0.getwalletinfo()["descriptors"], True)
+ self.assert_is_sqlite("basic0")
+
+ # The wallet should create the following descriptors:
+ # * BIP32 descriptors in the form of "0'/0'/*" and "0'/1'/*" (2 descriptors)
+ # * BIP44 descriptors in the form of "44'/1'/0'/0/*" and "44'/1'/0'/1/*" (2 descriptors)
+ # * BIP49 descriptors, P2SH(P2WPKH), in the form of "86'/1'/0'/0/*" and "86'/1'/0'/1/*" (2 descriptors)
+ # * BIP84 descriptors, P2WPKH, in the form of "84'/1'/0'/1/*" and "84'/1'/0'/1/*" (2 descriptors)
+ # * BIP86 descriptors, P2TR, in the form of "86'/1'/0'/0/*" and "86'/1'/0'/1/*" (2 descriptors)
+ # * A combo(PK) descriptor for the wallet master key.
+ # So, should have a total of 11 descriptors on it.
+ assert_equal(len(basic0.listdescriptors()["descriptors"]), 11)
+
+ # Compare addresses info
+ addr_info = basic0.getaddressinfo(addr)
+ change_addr_info = basic0.getaddressinfo(change)
+ self.assert_addr_info_equal(addr_info, old_addr_info)
+ self.assert_addr_info_equal(change_addr_info, old_change_addr_info)
+
+ addr_info = basic0.getaddressinfo(basic0.getnewaddress("", "bech32"))
+ assert_equal(addr_info["hdkeypath"], "m/84'/1'/0'/0/0")
+
+ self.log.info("Test migration of a basic keys only wallet with a balance")
+ basic1 = self.create_legacy_wallet("basic1")
+
+ for _ in range(0, 10):
+ default.sendtoaddress(basic1.getnewaddress(), 1)
+
+ self.generate(self.nodes[0], 1)
+
+ for _ in range(0, 5):
+ basic1.sendtoaddress(default.getnewaddress(), 0.5)
+
+ self.generate(self.nodes[0], 1)
+ bal = basic1.getbalance()
+ txs = basic1.listtransactions()
+
+ basic1.migratewallet()
+ assert_equal(basic1.getwalletinfo()["descriptors"], True)
+ self.assert_is_sqlite("basic1")
+ assert_equal(basic1.getbalance(), bal)
+ self.assert_list_txs_equal(basic1.listtransactions(), txs)
+
+ # restart node and verify that everything is still there
+ self.restart_node(0)
+ default = self.nodes[0].get_wallet_rpc(self.default_wallet_name)
+ self.nodes[0].loadwallet("basic1")
+ basic1 = self.nodes[0].get_wallet_rpc("basic1")
+ assert_equal(basic1.getwalletinfo()["descriptors"], True)
+ self.assert_is_sqlite("basic1")
+ assert_equal(basic1.getbalance(), bal)
+ self.assert_list_txs_equal(basic1.listtransactions(), txs)
+
+ self.log.info("Test migration of a wallet with balance received on the seed")
+ basic2 = self.create_legacy_wallet("basic2")
+ basic2_seed = get_generate_key()
+ basic2.sethdseed(True, basic2_seed.privkey)
+ assert_equal(basic2.getbalance(), 0)
+
+ # Receive coins on different output types for the same seed
+ basic2_balance = 0
+ for addr in [basic2_seed.p2pkh_addr, basic2_seed.p2wpkh_addr, basic2_seed.p2sh_p2wpkh_addr]:
+ send_value = random.randint(1, 4)
+ default.sendtoaddress(addr, send_value)
+ basic2_balance += send_value
+ self.generate(self.nodes[0], 1)
+ assert_equal(basic2.getbalance(), basic2_balance)
+ basic2_txs = basic2.listtransactions()
+
+ # Now migrate and test that we still see have the same balance/transactions
+ basic2.migratewallet()
+ assert_equal(basic2.getwalletinfo()["descriptors"], True)
+ self.assert_is_sqlite("basic2")
+ assert_equal(basic2.getbalance(), basic2_balance)
+ self.assert_list_txs_equal(basic2.listtransactions(), basic2_txs)
+
+ def test_multisig(self):
+ default = self.nodes[0].get_wallet_rpc(self.default_wallet_name)
+
+ # Contrived case where all the multisig keys are in a single wallet
+ self.log.info("Test migration of a wallet with all keys for a multisig")
+ multisig0 = self.create_legacy_wallet("multisig0")
+ addr1 = multisig0.getnewaddress()
+ addr2 = multisig0.getnewaddress()
+ addr3 = multisig0.getnewaddress()
+
+ ms_info = multisig0.addmultisigaddress(2, [addr1, addr2, addr3])
+
+ multisig0.migratewallet()
+ assert_equal(multisig0.getwalletinfo()["descriptors"], True)
+ self.assert_is_sqlite("multisig0")
+ ms_addr_info = multisig0.getaddressinfo(ms_info["address"])
+ assert_equal(ms_addr_info["ismine"], True)
+ assert_equal(ms_addr_info["desc"], ms_info["descriptor"])
+ assert_equal("multisig0_watchonly" in self.nodes[0].listwallets(), False)
+ assert_equal("multisig0_solvables" in self.nodes[0].listwallets(), False)
+
+ pub1 = multisig0.getaddressinfo(addr1)["pubkey"]
+ pub2 = multisig0.getaddressinfo(addr2)["pubkey"]
+
+ # Some keys in multisig do not belong to this wallet
+ self.log.info("Test migration of a wallet that has some keys in a multisig")
+ self.nodes[0].createwallet(wallet_name="multisig1")
+ multisig1 = self.nodes[0].get_wallet_rpc("multisig1")
+ ms_info = multisig1.addmultisigaddress(2, [multisig1.getnewaddress(), pub1, pub2])
+ ms_info2 = multisig1.addmultisigaddress(2, [multisig1.getnewaddress(), pub1, pub2])
+ assert_equal(multisig1.getwalletinfo()["descriptors"], False)
+
+ addr1 = ms_info["address"]
+ addr2 = ms_info2["address"]
+ txid = default.sendtoaddress(addr1, 10)
+ multisig1.importaddress(addr1)
+ assert_equal(multisig1.getaddressinfo(addr1)["ismine"], False)
+ assert_equal(multisig1.getaddressinfo(addr1)["iswatchonly"], True)
+ assert_equal(multisig1.getaddressinfo(addr1)["solvable"], True)
+ self.generate(self.nodes[0], 1)
+ multisig1.gettransaction(txid)
+ assert_equal(multisig1.getbalances()["watchonly"]["trusted"], 10)
+ assert_equal(multisig1.getaddressinfo(addr2)["ismine"], False)
+ assert_equal(multisig1.getaddressinfo(addr2)["iswatchonly"], False)
+ assert_equal(multisig1.getaddressinfo(addr2)["solvable"], True)
+
+ # Migrating multisig1 should see the multisig is no longer part of multisig1
+ # A new wallet multisig1_watchonly is created which has the multisig address
+ # Transaction to multisig is in multisig1_watchonly and not multisig1
+ multisig1.migratewallet()
+ assert_equal(multisig1.getwalletinfo()["descriptors"], True)
+ self.assert_is_sqlite("multisig1")
+ assert_equal(multisig1.getaddressinfo(addr1)["ismine"], False)
+ assert_equal(multisig1.getaddressinfo(addr1)["iswatchonly"], False)
+ assert_equal(multisig1.getaddressinfo(addr1)["solvable"], False)
+ assert_raises_rpc_error(-5, "Invalid or non-wallet transaction id", multisig1.gettransaction, txid)
+ assert_equal(multisig1.getbalance(), 0)
+ assert_equal(multisig1.listtransactions(), [])
+
+ assert_equal("multisig1_watchonly" in self.nodes[0].listwallets(), True)
+ ms1_watchonly = self.nodes[0].get_wallet_rpc("multisig1_watchonly")
+ ms1_wallet_info = ms1_watchonly.getwalletinfo()
+ assert_equal(ms1_wallet_info['descriptors'], True)
+ assert_equal(ms1_wallet_info['private_keys_enabled'], False)
+ self.assert_is_sqlite("multisig1_watchonly")
+ assert_equal(ms1_watchonly.getaddressinfo(addr1)["ismine"], True)
+ assert_equal(ms1_watchonly.getaddressinfo(addr1)["solvable"], True)
+ # Because addr2 was not being watched, it isn't in multisig1_watchonly but rather multisig1_solvables
+ assert_equal(ms1_watchonly.getaddressinfo(addr2)["ismine"], False)
+ assert_equal(ms1_watchonly.getaddressinfo(addr2)["solvable"], False)
+ ms1_watchonly.gettransaction(txid)
+ assert_equal(ms1_watchonly.getbalance(), 10)
+
+ # Migrating multisig1 should see the second multisig is no longer part of multisig1
+ # A new wallet multisig1_solvables is created which has the second address
+ # This should have no transactions
+ assert_equal("multisig1_solvables" in self.nodes[0].listwallets(), True)
+ ms1_solvable = self.nodes[0].get_wallet_rpc("multisig1_solvables")
+ ms1_wallet_info = ms1_solvable.getwalletinfo()
+ assert_equal(ms1_wallet_info['descriptors'], True)
+ assert_equal(ms1_wallet_info['private_keys_enabled'], False)
+ self.assert_is_sqlite("multisig1_solvables")
+ assert_equal(ms1_solvable.getaddressinfo(addr1)["ismine"], False)
+ assert_equal(ms1_solvable.getaddressinfo(addr1)["solvable"], False)
+ assert_equal(ms1_solvable.getaddressinfo(addr2)["ismine"], True)
+ assert_equal(ms1_solvable.getaddressinfo(addr2)["solvable"], True)
+ assert_equal(ms1_solvable.getbalance(), 0)
+ assert_equal(ms1_solvable.listtransactions(), [])
+
+
+ def test_other_watchonly(self):
+ default = self.nodes[0].get_wallet_rpc(self.default_wallet_name)
+
+ # Wallet with an imported address. Should be the same thing as the multisig test
+ self.log.info("Test migration of a wallet with watchonly imports")
+ self.nodes[0].createwallet(wallet_name="imports0")
+ imports0 = self.nodes[0].get_wallet_rpc("imports0")
+ assert_equal(imports0.getwalletinfo()["descriptors"], False)
+
+ # Exteranl address label
+ imports0.setlabel(default.getnewaddress(), "external")
+
+ # Normal non-watchonly tx
+ received_addr = imports0.getnewaddress()
+ imports0.setlabel(received_addr, "Receiving")
+ received_txid = default.sendtoaddress(received_addr, 10)
+
+ # Watchonly tx
+ import_addr = default.getnewaddress()
+ imports0.importaddress(import_addr)
+ imports0.setlabel(import_addr, "imported")
+ received_watchonly_txid = default.sendtoaddress(import_addr, 10)
+
+ # Received watchonly tx that is then spent
+ import_sent_addr = default.getnewaddress()
+ imports0.importaddress(import_sent_addr)
+ received_sent_watchonly_txid = default.sendtoaddress(import_sent_addr, 10)
+ received_sent_watchonly_vout = find_vout_for_address(self.nodes[0], received_sent_watchonly_txid, import_sent_addr)
+ send = default.sendall(recipients=[default.getnewaddress()], options={"inputs": [{"txid": received_sent_watchonly_txid, "vout": received_sent_watchonly_vout}]})
+ sent_watchonly_txid = send["txid"]
+
+ self.generate(self.nodes[0], 1)
+
+ balances = imports0.getbalances()
+ spendable_bal = balances["mine"]["trusted"]
+ watchonly_bal = balances["watchonly"]["trusted"]
+ assert_equal(len(imports0.listtransactions(include_watchonly=True)), 4)
+
+ # Migrate
+ imports0.migratewallet()
+ assert_equal(imports0.getwalletinfo()["descriptors"], True)
+ self.assert_is_sqlite("imports0")
+ assert_raises_rpc_error(-5, "Invalid or non-wallet transaction id", imports0.gettransaction, received_watchonly_txid)
+ assert_raises_rpc_error(-5, "Invalid or non-wallet transaction id", imports0.gettransaction, received_sent_watchonly_txid)
+ assert_raises_rpc_error(-5, "Invalid or non-wallet transaction id", imports0.gettransaction, sent_watchonly_txid)
+ assert_equal(len(imports0.listtransactions(include_watchonly=True)), 1)
+ imports0.gettransaction(received_txid)
+ assert_equal(imports0.getbalance(), spendable_bal)
+
+ assert_equal("imports0_watchonly" in self.nodes[0].listwallets(), True)
+ watchonly = self.nodes[0].get_wallet_rpc("imports0_watchonly")
+ watchonly_info = watchonly.getwalletinfo()
+ assert_equal(watchonly_info["descriptors"], True)
+ self.assert_is_sqlite("imports0_watchonly")
+ assert_equal(watchonly_info["private_keys_enabled"], False)
+ watchonly.gettransaction(received_watchonly_txid)
+ watchonly.gettransaction(received_sent_watchonly_txid)
+ watchonly.gettransaction(sent_watchonly_txid)
+ assert_equal(watchonly.getbalance(), watchonly_bal)
+ assert_raises_rpc_error(-5, "Invalid or non-wallet transaction id", watchonly.gettransaction, received_txid)
+ assert_equal(len(watchonly.listtransactions(include_watchonly=True)), 3)
+
+ def test_no_privkeys(self):
+ default = self.nodes[0].get_wallet_rpc(self.default_wallet_name)
+
+ # Migrating an actual watchonly wallet should not create a new watchonly wallet
+ self.log.info("Test migration of a pure watchonly wallet")
+ self.nodes[0].createwallet(wallet_name="watchonly0", disable_private_keys=True)
+ watchonly0 = self.nodes[0].get_wallet_rpc("watchonly0")
+ info = watchonly0.getwalletinfo()
+ assert_equal(info["descriptors"], False)
+ assert_equal(info["private_keys_enabled"], False)
+
+ addr = default.getnewaddress()
+ desc = default.getaddressinfo(addr)["desc"]
+ res = watchonly0.importmulti([
+ {
+ "desc": desc,
+ "watchonly": True,
+ "timestamp": "now",
+ }])
+ assert_equal(res[0]['success'], True)
+ default.sendtoaddress(addr, 10)
+ self.generate(self.nodes[0], 1)
+
+ watchonly0.migratewallet()
+ assert_equal("watchonly0_watchonly" in self.nodes[0].listwallets(), False)
+ info = watchonly0.getwalletinfo()
+ assert_equal(info["descriptors"], True)
+ assert_equal(info["private_keys_enabled"], False)
+ self.assert_is_sqlite("watchonly0")
+
+ # Migrating a wallet with pubkeys added to the keypool
+ self.log.info("Test migration of a pure watchonly wallet with pubkeys in keypool")
+ self.nodes[0].createwallet(wallet_name="watchonly1", disable_private_keys=True)
+ watchonly1 = self.nodes[0].get_wallet_rpc("watchonly1")
+ info = watchonly1.getwalletinfo()
+ assert_equal(info["descriptors"], False)
+ assert_equal(info["private_keys_enabled"], False)
+
+ addr1 = default.getnewaddress(address_type="bech32")
+ addr2 = default.getnewaddress(address_type="bech32")
+ desc1 = default.getaddressinfo(addr1)["desc"]
+ desc2 = default.getaddressinfo(addr2)["desc"]
+ res = watchonly1.importmulti([
+ {
+ "desc": desc1,
+ "keypool": True,
+ "timestamp": "now",
+ },
+ {
+ "desc": desc2,
+ "keypool": True,
+ "timestamp": "now",
+ }
+ ])
+ assert_equal(res[0]["success"], True)
+ assert_equal(res[1]["success"], True)
+ # Before migrating, we can fetch addr1 from the keypool
+ assert_equal(watchonly1.getnewaddress(address_type="bech32"), addr1)
+
+ watchonly1.migratewallet()
+ info = watchonly1.getwalletinfo()
+ assert_equal(info["descriptors"], True)
+ assert_equal(info["private_keys_enabled"], False)
+ self.assert_is_sqlite("watchonly1")
+ # After migrating, the "keypool" is empty
+ assert_raises_rpc_error(-4, "Error: This wallet has no available keys", watchonly1.getnewaddress)
+
+ def test_pk_coinbases(self):
+ self.log.info("Test migration of a wallet using old pk() coinbases")
+ wallet = self.create_legacy_wallet("pkcb")
+
+ addr = wallet.getnewaddress()
+ addr_info = wallet.getaddressinfo(addr)
+ desc = descsum_create("pk(" + addr_info["pubkey"] + ")")
+
+ self.nodes[0].generatetodescriptor(1, desc, invalid_call=False)
+
+ bals = wallet.getbalances()
+
+ wallet.migratewallet()
+
+ assert_equal(bals, wallet.getbalances())
+
+ def run_test(self):
+ self.generate(self.nodes[0], 101)
+
+ # TODO: Test the actual records in the wallet for these tests too. The behavior may be correct, but the data written may not be what we actually want
+ self.test_basic()
+ self.test_multisig()
+ self.test_other_watchonly()
+ self.test_no_privkeys()
+ self.test_pk_coinbases()
+
+if __name__ == '__main__':
+ WalletMigrationTest().main()
diff --git a/test/functional/wallet_resendwallettransactions.py b/test/functional/wallet_resendwallettransactions.py
index 6552bfe60c..b3d02fbfc9 100755
--- a/test/functional/wallet_resendwallettransactions.py
+++ b/test/functional/wallet_resendwallettransactions.py
@@ -9,10 +9,13 @@ from test_framework.blocktools import (
create_block,
create_coinbase,
)
+from test_framework.messages import DEFAULT_MEMPOOL_EXPIRY_HOURS
from test_framework.p2p import P2PTxInvStore
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import assert_equal
-
+from test_framework.util import (
+ assert_equal,
+ assert_raises_rpc_error,
+)
class ResendWalletTransactionsTest(BitcoinTestFramework):
def set_test_params(self):
@@ -27,13 +30,9 @@ class ResendWalletTransactionsTest(BitcoinTestFramework):
peer_first = node.add_p2p_connection(P2PTxInvStore())
self.log.info("Create a new transaction and wait until it's broadcast")
- txid = node.sendtoaddress(node.getnewaddress(), 1)
-
- # Wallet rebroadcast is first scheduled 1 sec after startup (see
- # nNextResend in ResendWalletTransactions()). Tell scheduler to call
- # MaybeResendWalletTxn now to initialize nNextResend before the first
- # setmocktime call below.
- node.mockscheduler(1)
+ parent_utxo, indep_utxo = node.listunspent()[:2]
+ addr = node.getnewaddress()
+ txid = node.send(outputs=[{addr: 1}], options={"inputs": [parent_utxo]})["txid"]
# Can take a few seconds due to transaction trickling
peer_first.wait_for_broadcast([txid])
@@ -51,7 +50,7 @@ class ResendWalletTransactionsTest(BitcoinTestFramework):
block.solve()
node.submitblock(block.serialize().hex())
- # Set correct m_best_block_time, which is used in ResendWalletTransactions
+ # Set correct m_best_block_time, which is used in ResubmitWalletTransactions
node.syncwithvalidationinterfacequeue()
now = int(time.time())
@@ -60,20 +59,67 @@ class ResendWalletTransactionsTest(BitcoinTestFramework):
twelve_hrs = 12 * 60 * 60
two_min = 2 * 60
node.setmocktime(now + twelve_hrs - two_min)
- node.mockscheduler(1) # Tell scheduler to call MaybeResendWalletTxn now
+ node.mockscheduler(60) # Tell scheduler to call MaybeResendWalletTxs now
assert_equal(int(txid, 16) in peer_second.get_invs(), False)
self.log.info("Bump time & check that transaction is rebroadcast")
# Transaction should be rebroadcast approximately 24 hours in the future,
# but can range from 12-36. So bump 36 hours to be sure.
- with node.assert_debug_log(['ResendWalletTransactions: resubmit 1 unconfirmed transactions']):
+ with node.assert_debug_log(['resubmit 1 unconfirmed transactions']):
node.setmocktime(now + 36 * 60 * 60)
- # Tell scheduler to call MaybeResendWalletTxn now.
- node.mockscheduler(1)
+ # Tell scheduler to call MaybeResendWalletTxs now.
+ node.mockscheduler(60)
# Give some time for trickle to occur
node.setmocktime(now + 36 * 60 * 60 + 600)
peer_second.wait_for_broadcast([txid])
+ self.log.info("Chain of unconfirmed not-in-mempool txs are rebroadcast")
+ # This tests that the node broadcasts the parent transaction before the child transaction.
+ # To test that scenario, we need a method to reliably get a child transaction placed
+ # in mapWallet positioned before the parent. We cannot predict the position in mapWallet,
+ # but we can observe it using listreceivedbyaddress and other related RPCs.
+ #
+ # So we will create the child transaction, use listreceivedbyaddress to see what the
+ # ordering of mapWallet is, if the child is not before the parent, we will create a new
+ # child (via bumpfee) and remove the old child (via removeprunedfunds) until we get the
+ # ordering of child before parent.
+ child_txid = node.send(outputs=[{addr: 0.5}], options={"inputs": [{"txid":txid, "vout":0}]})["txid"]
+ while True:
+ txids = node.listreceivedbyaddress(minconf=0, address_filter=addr)[0]["txids"]
+ if txids == [child_txid, txid]:
+ break
+ bumped = node.bumpfee(child_txid)
+ # The scheduler queue creates a copy of the added tx after
+ # send/bumpfee and re-adds it to the wallet (undoing the next
+ # removeprunedfunds). So empty the scheduler queue:
+ node.syncwithvalidationinterfacequeue()
+ node.removeprunedfunds(child_txid)
+ child_txid = bumped["txid"]
+ entry_time = node.getmempoolentry(child_txid)["time"]
+
+ block_time = entry_time + 6 * 60
+ node.setmocktime(block_time)
+ block = create_block(int(node.getbestblockhash(), 16), create_coinbase(node.getblockcount() + 1), block_time)
+ block.solve()
+ node.submitblock(block.serialize().hex())
+ # Set correct m_best_block_time, which is used in ResubmitWalletTransactions
+ node.syncwithvalidationinterfacequeue()
+
+ # Evict these txs from the mempool
+ evict_time = block_time + 60 * 60 * DEFAULT_MEMPOOL_EXPIRY_HOURS + 5
+ node.setmocktime(evict_time)
+ indep_send = node.send(outputs=[{node.getnewaddress(): 1}], options={"inputs": [indep_utxo]})
+ node.getmempoolentry(indep_send["txid"])
+ assert_raises_rpc_error(-5, "Transaction not in mempool", node.getmempoolentry, txid)
+ assert_raises_rpc_error(-5, "Transaction not in mempool", node.getmempoolentry, child_txid)
+
+ # Rebroadcast and check that parent and child are both in the mempool
+ with node.assert_debug_log(['resubmit 2 unconfirmed transactions']):
+ node.setmocktime(evict_time + 36 * 60 * 60) # 36 hrs is the upper limit of the resend timer
+ node.mockscheduler(60)
+ node.getmempoolentry(txid)
+ node.getmempoolentry(child_txid)
+
if __name__ == '__main__':
ResendWalletTransactionsTest().main()
diff --git a/test/functional/wallet_sendall.py b/test/functional/wallet_sendall.py
index aa8d2a9d2c..db4f32fe16 100755
--- a/test/functional/wallet_sendall.py
+++ b/test/functional/wallet_sendall.py
@@ -264,6 +264,32 @@ class SendallTest(BitcoinTestFramework):
recipients=[self.remainder_target],
options={"inputs": [utxo], "send_max": True})
+ @cleanup
+ def sendall_fails_on_high_fee(self):
+ self.log.info("Test sendall fails if the transaction fee exceeds the maxtxfee")
+ self.add_utxos([21])
+
+ assert_raises_rpc_error(
+ -4,
+ "Fee exceeds maximum configured by user",
+ self.wallet.sendall,
+ recipients=[self.remainder_target],
+ fee_rate=100000)
+
+ # This tests needs to be the last one otherwise @cleanup will fail with "Transaction too large" error
+ def sendall_fails_with_transaction_too_large(self):
+ self.log.info("Test that sendall fails if resulting transaction is too large")
+ # create many inputs
+ outputs = {self.wallet.getnewaddress(): 0.000025 for _ in range(1600)}
+ self.def_wallet.sendmany(amounts=outputs)
+ self.generate(self.nodes[0], 1)
+
+ assert_raises_rpc_error(
+ -4,
+ "Transaction too large.",
+ self.wallet.sendall,
+ recipients=[self.remainder_target])
+
def run_test(self):
self.nodes[0].createwallet("activewallet")
self.wallet = self.nodes[0].get_wallet_rpc("activewallet")
@@ -312,5 +338,11 @@ class SendallTest(BitcoinTestFramework):
# Sendall fails when using send_max while specifying inputs
self.sendall_fails_on_specific_inputs_with_send_max()
+ # Sendall fails when providing a fee that is too high
+ self.sendall_fails_on_high_fee()
+
+ # Sendall fails when many inputs result to too large transaction
+ self.sendall_fails_with_transaction_too_large()
+
if __name__ == '__main__':
SendallTest().main()
diff --git a/test/sanitizer_suppressions/tsan b/test/sanitizer_suppressions/tsan
index 3acf575d07..d331991273 100644
--- a/test/sanitizer_suppressions/tsan
+++ b/test/sanitizer_suppressions/tsan
@@ -13,7 +13,7 @@ race:zmq::*
race:bitcoin-qt
# deadlock (TODO fix)
-deadlock:CChainState::ConnectTip
+deadlock:Chainstate::ConnectTip
# Intentional deadlock in tests
deadlock:sync_tests::potential_deadlock_detected