aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am2
-rw-r--r--configure.ac1
-rw-r--r--contrib/devtools/README.md6
-rwxr-xr-xcontrib/devtools/optimize-pngs.py76
-rwxr-xr-xcontrib/gitian-descriptors/assign_DISTNAME12
-rw-r--r--contrib/gitian-descriptors/gitian-linux.yml12
-rw-r--r--contrib/gitian-descriptors/gitian-osx.yml12
-rw-r--r--contrib/gitian-descriptors/gitian-win.yml15
-rwxr-xr-xcontrib/gitian-descriptors/make_git_archive20
-rw-r--r--contrib/guix/README.md1
-rwxr-xr-xcontrib/guix/guix-build.sh1
-rw-r--r--contrib/guix/libexec/build.sh37
-rw-r--r--contrib/guix/manifest.scm3
-rw-r--r--contrib/valgrind.supp13
-rw-r--r--share/setup.nsi.in1
-rw-r--r--src/Makefile.test.include7
-rw-r--r--src/bench/ccoins_caching.cpp2
-rw-r--r--src/bloom.cpp26
-rw-r--r--src/bloom.h7
-rw-r--r--src/coins.cpp12
-rw-r--r--src/coins.h14
-rw-r--r--src/dummywallet.cpp5
-rw-r--r--src/init.cpp8
-rw-r--r--src/interfaces/node.cpp8
-rw-r--r--src/interfaces/node.h7
-rw-r--r--src/interfaces/wallet.cpp6
-rw-r--r--src/interfaces/wallet.h7
-rw-r--r--src/logging/timer.h10
-rw-r--r--src/net_processing.cpp1
-rw-r--r--src/prevector.h24
-rw-r--r--src/primitives/transaction.h2
-rw-r--r--src/qt/addressbookpage.cpp2
-rw-r--r--src/qt/askpassphrasedialog.cpp3
-rw-r--r--src/qt/bitcoingui.cpp2
-rw-r--r--src/qt/coincontroldialog.cpp2
-rw-r--r--src/qt/editaddressdialog.cpp2
-rw-r--r--src/qt/guiutil.cpp6
-rw-r--r--src/qt/guiutil.h3
-rw-r--r--src/qt/openuridialog.cpp2
-rw-r--r--src/qt/optionsdialog.cpp2
-rw-r--r--src/qt/receiverequestdialog.cpp2
-rw-r--r--src/qt/rpcconsole.cpp2
-rw-r--r--src/qt/signverifymessagedialog.cpp2
-rw-r--r--src/qt/splashscreen.cpp2
-rw-r--r--src/qt/transactiondescdialog.cpp3
-rw-r--r--src/qt/utilitydialog.cpp6
-rw-r--r--src/qt/walletcontroller.cpp13
-rw-r--r--src/qt/walletcontroller.h5
-rw-r--r--src/qt/walletmodel.cpp19
-rw-r--r--src/support/lockedpool.cpp4
-rw-r--r--src/test/fuzz/bloom_filter.cpp5
-rw-r--r--src/test/fuzz/message.cpp48
-rw-r--r--src/test/transaction_tests.cpp1
-rw-r--r--src/util/translation.h14
-rw-r--r--src/validation.cpp18
-rw-r--r--src/validation.h2
-rw-r--r--src/wallet/db.cpp10
-rw-r--r--src/wallet/db.h6
-rw-r--r--src/wallet/feebumper.cpp52
-rw-r--r--src/wallet/feebumper.h21
-rw-r--r--src/wallet/load.cpp20
-rw-r--r--src/wallet/rpcdump.cpp7
-rw-r--r--src/wallet/rpcwallet.cpp71
-rw-r--r--src/wallet/scriptpubkeyman.cpp5
-rw-r--r--src/wallet/scriptpubkeyman.h7
-rw-r--r--src/wallet/test/coinselector_tests.cpp9
-rw-r--r--src/wallet/test/psbt_wallet_tests.cpp6
-rw-r--r--src/wallet/test/wallet_tests.cpp24
-rw-r--r--src/wallet/wallet.cpp255
-rw-r--r--src/wallet/wallet.h55
-rw-r--r--src/wallet/walletdb.cpp74
-rw-r--r--src/wallet/walletdb.h8
-rw-r--r--src/wallet/wallettool.cpp5
-rw-r--r--src/wallet/walletutil.h8
-rwxr-xr-xtest/functional/feature_backwards_compatibility.py29
-rwxr-xr-xtest/functional/p2p_leak.py7
-rwxr-xr-xtest/functional/p2p_segwit.py4
-rwxr-xr-xtest/functional/tool_wallet.py14
-rwxr-xr-xtest/functional/wallet_bumpfee.py4
-rwxr-xr-xtest/functional/wallet_multiwallet.py6
-rwxr-xr-xtest/lint/lint-shell.sh6
81 files changed, 626 insertions, 615 deletions
diff --git a/Makefile.am b/Makefile.am
index c35f5080aa..43790f1c23 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -80,7 +80,7 @@ $(BITCOIN_WIN_INSTALLER): all-recursive
STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $(BITCOIN_CLI_BIN) $(top_builddir)/release
STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $(BITCOIN_TX_BIN) $(top_builddir)/release
STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $(BITCOIN_WALLET_BIN) $(top_builddir)/release
- @test -f $(MAKENSIS) && $(MAKENSIS) -V2 $(top_builddir)/share/setup.nsi || \
+ @test -f $(MAKENSIS) && echo 'OutFile "$@"' | cat $(top_builddir)/share/setup.nsi - | $(MAKENSIS) -V2 - || \
echo error: could not build $@
@echo built $@
diff --git a/configure.ac b/configure.ac
index 821563440f..e853bf80a0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -350,6 +350,7 @@ fi
if test "x$CXXFLAGS_overridden" = "xno"; then
AX_CHECK_COMPILE_FLAG([-Wall],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wall"],,[[$CXXFLAG_WERROR]])
AX_CHECK_COMPILE_FLAG([-Wextra],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wextra"],,[[$CXXFLAG_WERROR]])
+ AX_CHECK_COMPILE_FLAG([-Wgnu],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wgnu"],,[[$CXXFLAG_WERROR]])
AX_CHECK_COMPILE_FLAG([-Wformat],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wformat"],,[[$CXXFLAG_WERROR]])
AX_CHECK_COMPILE_FLAG([-Wvla],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wvla"],,[[$CXXFLAG_WERROR]])
AX_CHECK_COMPILE_FLAG([-Wswitch],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wswitch"],,[[$CXXFLAG_WERROR]])
diff --git a/contrib/devtools/README.md b/contrib/devtools/README.md
index f5533719c0..bdff7a84b0 100644
--- a/contrib/devtools/README.md
+++ b/contrib/devtools/README.md
@@ -89,12 +89,6 @@ example:
BUILDDIR=$PWD/build contrib/devtools/gen-manpages.sh
```
-optimize-pngs.py
-================
-
-A script to optimize png files in the bitcoin
-repository (requires pngcrush).
-
security-check.py and test-security-check.py
============================================
diff --git a/contrib/devtools/optimize-pngs.py b/contrib/devtools/optimize-pngs.py
deleted file mode 100755
index e9481dbbcf..0000000000
--- a/contrib/devtools/optimize-pngs.py
+++ /dev/null
@@ -1,76 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (c) 2014-2018 The Bitcoin Core developers
-# Distributed under the MIT software license, see the accompanying
-# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-'''
-Run this script every time you change one of the png files. Using pngcrush, it will optimize the png files, remove various color profiles, remove ancillary chunks (alla) and text chunks (text).
-#pngcrush -brute -ow -rem gAMA -rem cHRM -rem iCCP -rem sRGB -rem alla -rem text
-'''
-import os
-import sys
-import subprocess
-import hashlib
-from PIL import Image # pip3 install Pillow
-
-def file_hash(filename):
- '''Return hash of raw file contents'''
- with open(filename, 'rb') as f:
- return hashlib.sha256(f.read()).hexdigest()
-
-def content_hash(filename):
- '''Return hash of RGBA contents of image'''
- i = Image.open(filename)
- i = i.convert('RGBA')
- data = i.tobytes()
- return hashlib.sha256(data).hexdigest()
-
-pngcrush = 'pngcrush'
-git = 'git'
-folders = ["src/qt/res/movies", "src/qt/res/icons", "share/pixmaps"]
-basePath = subprocess.check_output([git, 'rev-parse', '--show-toplevel'], universal_newlines=True, encoding='utf8').rstrip('\n')
-totalSaveBytes = 0
-noHashChange = True
-
-outputArray = []
-for folder in folders:
- absFolder=os.path.join(basePath, folder)
- for file in os.listdir(absFolder):
- extension = os.path.splitext(file)[1]
- if extension.lower() == '.png':
- print("optimizing {}...".format(file), end =' ')
- file_path = os.path.join(absFolder, file)
- fileMetaMap = {'file' : file, 'osize': os.path.getsize(file_path), 'sha256Old' : file_hash(file_path)}
- fileMetaMap['contentHashPre'] = content_hash(file_path)
-
- try:
- subprocess.call([pngcrush, "-brute", "-ow", "-rem", "gAMA", "-rem", "cHRM", "-rem", "iCCP", "-rem", "sRGB", "-rem", "alla", "-rem", "text", file_path],
- stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
- except:
- print("pngcrush is not installed, aborting...")
- sys.exit(0)
-
- #verify
- if "Not a PNG file" in subprocess.check_output([pngcrush, "-n", "-v", file_path], stderr=subprocess.STDOUT, universal_newlines=True, encoding='utf8'):
- print("PNG file "+file+" is corrupted after crushing, check out pngcursh version")
- sys.exit(1)
-
- fileMetaMap['sha256New'] = file_hash(file_path)
- fileMetaMap['contentHashPost'] = content_hash(file_path)
-
- if fileMetaMap['contentHashPre'] != fileMetaMap['contentHashPost']:
- print("Image contents of PNG file {} before and after crushing don't match".format(file))
- sys.exit(1)
-
- fileMetaMap['psize'] = os.path.getsize(file_path)
- outputArray.append(fileMetaMap)
- print("done")
-
-print("summary:\n+++++++++++++++++")
-for fileDict in outputArray:
- oldHash = fileDict['sha256Old']
- newHash = fileDict['sha256New']
- totalSaveBytes += fileDict['osize'] - fileDict['psize']
- noHashChange = noHashChange and (oldHash == newHash)
- print(fileDict['file']+"\n size diff from: "+str(fileDict['osize'])+" to: "+str(fileDict['psize'])+"\n old sha256: "+oldHash+"\n new sha256: "+newHash+"\n")
-
-print("completed. Checksum stable: "+str(noHashChange)+". Total reduction: "+str(totalSaveBytes)+" bytes")
diff --git a/contrib/gitian-descriptors/assign_DISTNAME b/contrib/gitian-descriptors/assign_DISTNAME
new file mode 100755
index 0000000000..a2ca768aaa
--- /dev/null
+++ b/contrib/gitian-descriptors/assign_DISTNAME
@@ -0,0 +1,12 @@
+# 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.
+#
+# A helper script to be sourced into the gitian descriptors
+
+if RECENT_TAG="$(git describe --exact-match HEAD)"; then
+ VERSION="${RECENT_TAG#v}"
+else
+ VERSION="$(git rev-parse --short=12 HEAD)"
+fi
+DISTNAME="bitcoin-${VERSION}"
diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml
index f421372e10..0ed1e16f7e 100644
--- a/contrib/gitian-descriptors/gitian-linux.yml
+++ b/contrib/gitian-descriptors/gitian-linux.yml
@@ -140,9 +140,15 @@ script: |
create_per-host_faketime_wrappers "${REFERENCE_DATETIME}"
export PATH=${WRAP_DIR}:${PATH}
- # Create the git archive, and define DISTNAME and GIT_ARCHIVE variables.
- # shellcheck source=contrib/gitian-descriptors/make_git_archive
- source contrib/gitian-descriptors/make_git_archive
+ # Define DISTNAME variable.
+ # shellcheck source=contrib/gitian-descriptors/assign_DISTNAME
+ source contrib/gitian-descriptors/assign_DISTNAME
+
+ GIT_ARCHIVE="${OUTDIR}/src/${DISTNAME}.tar.gz"
+
+ # Create the source tarball
+ mkdir -p "$(dirname "$GIT_ARCHIVE")"
+ git archive --output="$GIT_ARCHIVE" HEAD
ORIGPATH="$PATH"
# Extract the git archive into a dir for each host and build
diff --git a/contrib/gitian-descriptors/gitian-osx.yml b/contrib/gitian-descriptors/gitian-osx.yml
index 82f8f194fc..bbae7201e5 100644
--- a/contrib/gitian-descriptors/gitian-osx.yml
+++ b/contrib/gitian-descriptors/gitian-osx.yml
@@ -103,9 +103,15 @@ script: |
create_per-host_faketime_wrappers "${REFERENCE_DATETIME}"
export PATH=${WRAP_DIR}:${PATH}
- # Create the git archive, and define DISTNAME and GIT_ARCHIVE variables.
- # shellcheck source=contrib/gitian-descriptors/make_git_archive
- source contrib/gitian-descriptors/make_git_archive
+ # Define DISTNAME variable.
+ # shellcheck source=contrib/gitian-descriptors/assign_DISTNAME
+ source contrib/gitian-descriptors/assign_DISTNAME
+
+ GIT_ARCHIVE="${OUTDIR}/src/${DISTNAME}.tar.gz"
+
+ # Create the source tarball
+ mkdir -p "$(dirname "$GIT_ARCHIVE")"
+ git archive --output="$GIT_ARCHIVE" HEAD
ORIGPATH="$PATH"
# Extract the git archive into a dir for each host and build
diff --git a/contrib/gitian-descriptors/gitian-win.yml b/contrib/gitian-descriptors/gitian-win.yml
index 54ad68a2a3..d05b6d426d 100644
--- a/contrib/gitian-descriptors/gitian-win.yml
+++ b/contrib/gitian-descriptors/gitian-win.yml
@@ -108,9 +108,15 @@ script: |
create_per-host_compiler_wrapper "${REFERENCE_DATETIME}"
export PATH=${WRAP_DIR}:${PATH}
- # Create the git archive, and define DISTNAME and GIT_ARCHIVE variables.
- # shellcheck source=contrib/gitian-descriptors/make_git_archive
- source contrib/gitian-descriptors/make_git_archive
+ # Define DISTNAME variable.
+ # shellcheck source=contrib/gitian-descriptors/assign_DISTNAME
+ source contrib/gitian-descriptors/assign_DISTNAME
+
+ GIT_ARCHIVE="${OUTDIR}/src/${DISTNAME}.tar.gz"
+
+ # Create the source tarball
+ mkdir -p "$(dirname "$GIT_ARCHIVE")"
+ git archive --output="$GIT_ARCHIVE" HEAD
ORIGPATH="$PATH"
# Extract the git archive into a dir for each host and build
@@ -127,9 +133,8 @@ script: |
make ${MAKEOPTS}
make ${MAKEOPTS} -C src check-security
make ${MAKEOPTS} -C src check-symbols
- make deploy
+ make deploy BITCOIN_WIN_INSTALLER="${OUTDIR}/${DISTNAME}-win64-setup-unsigned.exe"
make install DESTDIR=${INSTALLPATH}
- cp -f ./bitcoin-*-win64-setup-unsigned.exe ${OUTDIR}/${DISTNAME}-win64-setup-unsigned.exe
cd installed
mv ${DISTNAME}/bin/*.dll ${DISTNAME}/lib/
find . -name "lib*.la" -delete
diff --git a/contrib/gitian-descriptors/make_git_archive b/contrib/gitian-descriptors/make_git_archive
deleted file mode 100755
index d922c94c60..0000000000
--- a/contrib/gitian-descriptors/make_git_archive
+++ /dev/null
@@ -1,20 +0,0 @@
-# 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.
-#
-# A helper script to be sourced into the gitian descriptors
-
-mkdir -p ${OUTDIR}/src
-RECENT_TAG=$(git describe --abbrev=0 HEAD)
-if [ $RECENT_TAG = $(git describe HEAD) ]; then
- if [[ $RECENT_TAG == v* ]]; then
- VERSION=${RECENT_TAG:1}
- else
- VERSION=$RECENT_TAG
- fi
-else
- VERSION=$(git rev-parse --short HEAD)
-fi
-DISTNAME=bitcoin-${VERSION}
-GIT_ARCHIVE="${OUTDIR}/src/${DISTNAME}.tar.gz"
-git archive --output=$GIT_ARCHIVE HEAD
diff --git a/contrib/guix/README.md b/contrib/guix/README.md
index 9f99b36f88..8ce8cb97a0 100644
--- a/contrib/guix/README.md
+++ b/contrib/guix/README.md
@@ -13,7 +13,6 @@ We achieve bootstrappability by using Guix as a functional package manager.
Conservatively, a x86_64 machine with:
-- 2 or more logical cores
- 4GB of free disk space on the partition that /gnu/store will reside in
- 24GB of free disk space on the partition that the Bitcoin Core git repository
resides in
diff --git a/contrib/guix/guix-build.sh b/contrib/guix/guix-build.sh
index e20b2a048d..11d2c8b867 100755
--- a/contrib/guix/guix-build.sh
+++ b/contrib/guix/guix-build.sh
@@ -105,6 +105,7 @@ for host in ${HOSTS=x86_64-linux-gnu arm-linux-gnueabihf aarch64-linux-gnu riscv
--pure \
--no-cwd \
--share="$PWD"=/bitcoin \
+ --expose="$(git rev-parse --git-common-dir)" \
${SOURCES_PATH:+--share="$SOURCES_PATH"} \
${ADDITIONAL_GUIX_ENVIRONMENT_FLAGS} \
-- env HOST="$host" \
diff --git a/contrib/guix/libexec/build.sh b/contrib/guix/libexec/build.sh
index 550b1b8f40..01f4518c73 100644
--- a/contrib/guix/libexec/build.sh
+++ b/contrib/guix/libexec/build.sh
@@ -141,19 +141,17 @@ make -C depends --jobs="$MAX_JOBS" HOST="$HOST" \
# Source Tarball Building #
###########################
-# Create the source tarball and move it to "${OUTDIR}/src" if not already there
-if [ -z "$(find "${OUTDIR}/src" -name 'bitcoin-*.tar.gz')" ]; then
- ./autogen.sh
- env CONFIG_SITE="${BASEPREFIX}/${HOST}/share/config.site" ./configure --prefix=/
- make dist GZIP_ENV='-9n' ${V:+V=1}
- mkdir -p "${OUTDIR}/src"
- mv "$(find "${PWD}" -name 'bitcoin-*.tar.gz')" "${OUTDIR}/src/"
-fi
+# Define DISTNAME variable.
+# shellcheck source=contrib/gitian-descriptors/assign_DISTNAME
+source contrib/gitian-descriptors/assign_DISTNAME
-# Determine the full path to our source tarball
-SOURCEDIST="$(find "${OUTDIR}/src" -name 'bitcoin-*.tar.gz')"
-# Determine our distribution name (e.g. bitcoin-0.18.0)
-DISTNAME="$(basename "$SOURCEDIST" '.tar.gz')"
+GIT_ARCHIVE="${OUTDIR}/src/${DISTNAME}.tar.gz"
+
+# Create the source tarball if not already there
+if [ ! -e "$GIT_ARCHIVE" ]; then
+ mkdir -p "$(dirname "$GIT_ARCHIVE")"
+ git archive --output="$GIT_ARCHIVE" HEAD
+fi
###########################
# Binary Tarball Building #
@@ -187,7 +185,9 @@ export PATH="${BASEPREFIX}/${HOST}/native/bin:${PATH}"
cd "$DISTSRC"
# Extract the source tarball
- tar --strip-components=1 -xf "${SOURCEDIST}"
+ tar -xf "${GIT_ARCHIVE}"
+
+ ./autogen.sh
# Configure this DISTSRC for $HOST
# shellcheck disable=SC2086
@@ -220,7 +220,7 @@ export PATH="${BASEPREFIX}/${HOST}/native/bin:${PATH}"
# Make the os-specific installers
case "$HOST" in
*mingw*)
- make deploy ${V:+V=1}
+ make deploy ${V:+V=1} BITCOIN_WIN_INSTALLER="${OUTDIR}/${DISTNAME}-win64-setup-unsigned.exe"
;;
esac
@@ -232,11 +232,6 @@ export PATH="${BASEPREFIX}/${HOST}/native/bin:${PATH}"
# Install built Bitcoin Core to $INSTALLPATH
make install DESTDIR="${INSTALLPATH}" ${V:+V=1}
- case "$HOST" in
- *mingw*)
- cp -f --target-directory="$OUTDIR" ./*-setup-unsigned.exe
- ;;
- esac
(
cd installed
@@ -264,7 +259,7 @@ export PATH="${BASEPREFIX}/${HOST}/native/bin:${PATH}"
cp "${DISTSRC}/doc/README_windows.txt" "${DISTNAME}/readme.txt"
;;
*linux*)
- cp "${DISTSRC}/doc/README.md" "${DISTNAME}/"
+ cp "${DISTSRC}/README.md" "${DISTNAME}/"
;;
esac
@@ -307,7 +302,7 @@ case "$HOST" in
(
cd ./windeploy
mkdir unsigned
- cp --target-directory=unsigned/ "$OUTDIR"/bitcoin-*-setup-unsigned.exe
+ cp --target-directory=unsigned/ "${OUTDIR}/${DISTNAME}-win64-setup-unsigned.exe"
find . -print0 \
| sort --zero-terminated \
| tar --create --no-recursion --mode='u+rw,go+r-w,a+X' --null --files-from=- \
diff --git a/contrib/guix/manifest.scm b/contrib/guix/manifest.scm
index 86c1a8d27f..5e011ea184 100644
--- a/contrib/guix/manifest.scm
+++ b/contrib/guix/manifest.scm
@@ -17,6 +17,7 @@
(gnu packages pkg-config)
(gnu packages python)
(gnu packages shells)
+ (gnu packages version-control)
(guix build-system gnu)
(guix build-system trivial)
(guix gexp)
@@ -181,6 +182,8 @@ chain for " target " development."))
;; Scripting
perl
python-3.7
+ ;; Git
+ git
;; Native gcc 9 toolchain targeting glibc 2.27
(make-gcc-toolchain gcc-9 glibc-2.27))
(let ((target (getenv "HOST")))
diff --git a/contrib/valgrind.supp b/contrib/valgrind.supp
index 744b8ee70f..f232bb62c2 100644
--- a/contrib/valgrind.supp
+++ b/contrib/valgrind.supp
@@ -184,16 +184,3 @@
...
fun:_ZN5BCLog6Logger12StartLoggingEv
}
-{
- Suppress BCLog::Logger::StartLogging() still reachable memory warning
- Memcheck:Leak
- match-leak-kinds: reachable
- fun:malloc
- ...
- fun:_ZN5BCLog6Logger12StartLoggingEv
-}
-{
- Suppress rest_blockhash_by_height Conditional jump or move depends on uninitialised value(s)
- Memcheck:Cond
- fun:_ZL24rest_blockhash_by_heightP11HTTPRequestRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
-}
diff --git a/share/setup.nsi.in b/share/setup.nsi.in
index 4b2903a7c9..5431909bb2 100644
--- a/share/setup.nsi.in
+++ b/share/setup.nsi.in
@@ -51,7 +51,6 @@ Var StartMenuGroup
!insertmacro MUI_LANGUAGE English
# Installer attributes
-OutFile @abs_top_srcdir@/@PACKAGE_TARNAME@-@PACKAGE_VERSION@-win64-setup-unsigned.exe
InstallDir $PROGRAMFILES64\Bitcoin
CRCCheck on
XPStyle on
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 1fe4df8059..68ba1bc68e 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -53,6 +53,7 @@ FUZZ_TARGETS = \
test/fuzz/locale \
test/fuzz/merkle_block_deserialize \
test/fuzz/merkleblock \
+ test/fuzz/message \
test/fuzz/messageheader_deserialize \
test/fuzz/multiplication_overflow \
test/fuzz/net_permissions \
@@ -595,6 +596,12 @@ test_fuzz_merkleblock_LDADD = $(FUZZ_SUITE_LD_COMMON)
test_fuzz_merkleblock_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
test_fuzz_merkleblock_SOURCES = test/fuzz/merkleblock.cpp
+test_fuzz_message_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
+test_fuzz_message_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
+test_fuzz_message_LDADD = $(FUZZ_SUITE_LD_COMMON)
+test_fuzz_message_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_message_SOURCES = test/fuzz/message.cpp
+
test_fuzz_messageheader_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGEHEADER_DESERIALIZE=1
test_fuzz_messageheader_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_messageheader_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
diff --git a/src/bench/ccoins_caching.cpp b/src/bench/ccoins_caching.cpp
index d658976c3c..86f9a0bf67 100644
--- a/src/bench/ccoins_caching.cpp
+++ b/src/bench/ccoins_caching.cpp
@@ -47,8 +47,6 @@ static void CCoinsCaching(benchmark::State& state)
while (state.KeepRunning()) {
bool success = AreInputsStandard(tx_1, coins);
assert(success);
- CAmount value = coins.GetValueIn(tx_1);
- assert(value == (50 + 21 + 22) * COIN);
}
ECC_Stop();
}
diff --git a/src/bloom.cpp b/src/bloom.cpp
index 30af507243..54fcf487e4 100644
--- a/src/bloom.cpp
+++ b/src/bloom.cpp
@@ -31,8 +31,6 @@ CBloomFilter::CBloomFilter(const unsigned int nElements, const double nFPRate, c
* Again, we ignore filter parameters which will create a bloom filter with more hash functions than the protocol limits
* See https://en.wikipedia.org/wiki/Bloom_filter for an explanation of these formulas
*/
- isFull(false),
- isEmpty(true),
nHashFuncs(std::min((unsigned int)(vData.size() * 8 / nElements * LN2), MAX_HASH_FUNCS)),
nTweak(nTweakIn),
nFlags(nFlagsIn)
@@ -47,7 +45,7 @@ inline unsigned int CBloomFilter::Hash(unsigned int nHashNum, const std::vector<
void CBloomFilter::insert(const std::vector<unsigned char>& vKey)
{
- if (isFull)
+ if (vData.empty()) // Avoid divide-by-zero (CVE-2013-5700)
return;
for (unsigned int i = 0; i < nHashFuncs; i++)
{
@@ -55,7 +53,6 @@ void CBloomFilter::insert(const std::vector<unsigned char>& vKey)
// Sets bit nIndex of vData
vData[nIndex >> 3] |= (1 << (7 & nIndex));
}
- isEmpty = false;
}
void CBloomFilter::insert(const COutPoint& outpoint)
@@ -74,10 +71,8 @@ void CBloomFilter::insert(const uint256& hash)
bool CBloomFilter::contains(const std::vector<unsigned char>& vKey) const
{
- if (isFull)
+ if (vData.empty()) // Avoid divide-by-zero (CVE-2013-5700)
return true;
- if (isEmpty)
- return false;
for (unsigned int i = 0; i < nHashFuncs; i++)
{
unsigned int nIndex = Hash(i, vKey);
@@ -112,10 +107,8 @@ bool CBloomFilter::IsRelevantAndUpdate(const CTransaction& tx)
bool fFound = false;
// Match if the filter contains the hash of tx
// for finding tx when they appear in a block
- if (isFull)
+ if (vData.empty()) // zero-size = "match-all" filter
return true;
- if (isEmpty)
- return false;
const uint256& hash = tx.GetHash();
if (contains(hash))
fFound = true;
@@ -177,19 +170,6 @@ bool CBloomFilter::IsRelevantAndUpdate(const CTransaction& tx)
return false;
}
-void CBloomFilter::UpdateEmptyFull()
-{
- bool full = true;
- bool empty = true;
- for (unsigned int i = 0; i < vData.size(); i++)
- {
- full &= vData[i] == 0xff;
- empty &= vData[i] == 0;
- }
- isFull = full;
- isEmpty = empty;
-}
-
CRollingBloomFilter::CRollingBloomFilter(const unsigned int nElements, const double fpRate)
{
double logFpRate = log(fpRate);
diff --git a/src/bloom.h b/src/bloom.h
index 8e3b7be54d..9173b80d66 100644
--- a/src/bloom.h
+++ b/src/bloom.h
@@ -45,8 +45,6 @@ class CBloomFilter
{
private:
std::vector<unsigned char> vData;
- bool isFull;
- bool isEmpty;
unsigned int nHashFuncs;
unsigned int nTweak;
unsigned char nFlags;
@@ -64,7 +62,7 @@ public:
* nFlags should be one of the BLOOM_UPDATE_* enums (not _MASK)
*/
CBloomFilter(const unsigned int nElements, const double nFPRate, const unsigned int nTweak, unsigned char nFlagsIn);
- CBloomFilter() : isFull(true), isEmpty(false), nHashFuncs(0), nTweak(0), nFlags(0) {}
+ CBloomFilter() : nHashFuncs(0), nTweak(0), nFlags(0) {}
ADD_SERIALIZE_METHODS;
@@ -90,9 +88,6 @@ public:
//! Also adds any outputs which match the filter to the filter (to match their spending txes)
bool IsRelevantAndUpdate(const CTransaction& tx);
-
- //! Checks for empty and full filters to avoid wasting cpu
- void UpdateEmptyFull();
};
/**
diff --git a/src/coins.cpp b/src/coins.cpp
index 6b4cb2aec7..7b76c13f98 100644
--- a/src/coins.cpp
+++ b/src/coins.cpp
@@ -233,18 +233,6 @@ unsigned int CCoinsViewCache::GetCacheSize() const {
return cacheCoins.size();
}
-CAmount CCoinsViewCache::GetValueIn(const CTransaction& tx) const
-{
- if (tx.IsCoinBase())
- return 0;
-
- CAmount nResult = 0;
- for (unsigned int i = 0; i < tx.vin.size(); i++)
- nResult += AccessCoin(tx.vin[i].prevout).out.nValue;
-
- return nResult;
-}
-
bool CCoinsViewCache::HaveInputs(const CTransaction& tx) const
{
if (!tx.IsCoinBase()) {
diff --git a/src/coins.h b/src/coins.h
index 2aed56c2bd..a3f34bb0ee 100644
--- a/src/coins.h
+++ b/src/coins.h
@@ -6,11 +6,11 @@
#ifndef BITCOIN_COINS_H
#define BITCOIN_COINS_H
-#include <primitives/transaction.h>
#include <compressor.h>
#include <core_memusage.h>
#include <crypto/siphash.h>
#include <memusage.h>
+#include <primitives/transaction.h>
#include <serialize.h>
#include <uint256.h>
@@ -25,7 +25,7 @@
*
* Serialized format:
* - VARINT((coinbase ? 1 : 0) | (height << 1))
- * - the non-spent CTxOut (via CTxOutCompressor)
+ * - the non-spent CTxOut (via TxOutCompression)
*/
class Coin
{
@@ -315,16 +315,6 @@ public:
//! Calculate the size of the cache (in bytes)
size_t DynamicMemoryUsage() const;
- /**
- * Amount of bitcoins coming in to a transaction
- * Note that lightweight clients may not know anything besides the hash of previous transactions,
- * so may not be able to calculate this.
- *
- * @param[in] tx transaction for which we are checking input total
- * @return Sum of value of all inputs (scriptSigs)
- */
- CAmount GetValueIn(const CTransaction& tx) const;
-
//! Check whether all prevouts of the transaction are present in the UTXO set represented by this view
bool HaveInputs(const CTransaction& tx) const;
diff --git a/src/dummywallet.cpp b/src/dummywallet.cpp
index a5582e3b2c..0f7848bae1 100644
--- a/src/dummywallet.cpp
+++ b/src/dummywallet.cpp
@@ -8,6 +8,7 @@
class CWallet;
enum class WalletCreationStatus;
+struct bilingual_str;
namespace interfaces {
class Chain;
@@ -72,12 +73,12 @@ std::vector<std::shared_ptr<CWallet>> GetWallets()
throw std::logic_error("Wallet function called in non-wallet build.");
}
-std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const std::string& name, std::string& error, std::vector<std::string>& warnings)
+std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings)
{
throw std::logic_error("Wallet function called in non-wallet build.");
}
-WalletCreationStatus CreateWallet(interfaces::Chain& chain, const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, std::string& error, std::vector<std::string>& warnings, std::shared_ptr<CWallet>& result)
+WalletCreationStatus CreateWallet(interfaces::Chain& chain, const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings, std::shared_ptr<CWallet>& result)
{
throw std::logic_error("Wallet function called in non-wallet build.");
}
diff --git a/src/init.cpp b/src/init.cpp
index a213dacbe0..3e2ee4d425 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -708,6 +708,10 @@ static void ThreadImport(std::vector<fs::path> vImportFiles)
break; // This error is logged in OpenBlockFile
LogPrintf("Reindexing block file blk%05u.dat...\n", (unsigned int)nFile);
LoadExternalBlockFile(chainparams, file, &pos);
+ if (ShutdownRequested()) {
+ LogPrintf("Shutdown requested. Exit %s\n", __func__);
+ return;
+ }
nFile++;
}
pblocktree->WriteReindexing(false);
@@ -723,6 +727,10 @@ static void ThreadImport(std::vector<fs::path> vImportFiles)
if (file) {
LogPrintf("Importing blocks file %s...\n", path.string());
LoadExternalBlockFile(chainparams, file);
+ if (ShutdownRequested()) {
+ LogPrintf("Shutdown requested. Exit %s\n", __func__);
+ return;
+ }
} else {
LogPrintf("Warning: Could not open blocks file %s\n", path.string());
}
diff --git a/src/interfaces/node.cpp b/src/interfaces/node.cpp
index 5ebbd61584..8564819e6a 100644
--- a/src/interfaces/node.cpp
+++ b/src/interfaces/node.cpp
@@ -43,8 +43,8 @@ class CWallet;
fs::path GetWalletDir();
std::vector<fs::path> ListWalletDir();
std::vector<std::shared_ptr<CWallet>> GetWallets();
-std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const std::string& name, std::string& error, std::vector<std::string>& warnings);
-WalletCreationStatus CreateWallet(interfaces::Chain& chain, const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, std::string& error, std::vector<std::string>& warnings, std::shared_ptr<CWallet>& result);
+std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings);
+WalletCreationStatus CreateWallet(interfaces::Chain& chain, const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings, std::shared_ptr<CWallet>& result);
std::unique_ptr<interfaces::Handler> HandleLoadWallet(interfaces::Node::LoadWalletFn load_wallet);
namespace interfaces {
@@ -259,11 +259,11 @@ public:
}
return wallets;
}
- std::unique_ptr<Wallet> loadWallet(const std::string& name, std::string& error, std::vector<std::string>& warnings) override
+ std::unique_ptr<Wallet> loadWallet(const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings) override
{
return MakeWallet(LoadWallet(*m_context.chain, name, error, warnings));
}
- std::unique_ptr<Wallet> createWallet(const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, std::string& error, std::vector<std::string>& warnings, WalletCreationStatus& status) override
+ std::unique_ptr<Wallet> createWallet(const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings, WalletCreationStatus& status) override
{
std::shared_ptr<CWallet> wallet;
status = CreateWallet(*m_context.chain, passphrase, wallet_creation_flags, name, error, warnings, wallet);
diff --git a/src/interfaces/node.h b/src/interfaces/node.h
index 53a20886cd..db9b42b293 100644
--- a/src/interfaces/node.h
+++ b/src/interfaces/node.h
@@ -27,9 +27,10 @@ class Coin;
class RPCTimerInterface;
class UniValue;
class proxyType;
+enum class WalletCreationStatus;
struct CNodeStateStats;
struct NodeContext;
-enum class WalletCreationStatus;
+struct bilingual_str;
namespace interfaces {
class Handler;
@@ -201,10 +202,10 @@ public:
//! Attempts to load a wallet from file or directory.
//! The loaded wallet is also notified to handlers previously registered
//! with handleLoadWallet.
- virtual std::unique_ptr<Wallet> loadWallet(const std::string& name, std::string& error, std::vector<std::string>& warnings) = 0;
+ virtual std::unique_ptr<Wallet> loadWallet(const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings) = 0;
//! Create a wallet from file
- virtual std::unique_ptr<Wallet> createWallet(const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, std::string& error, std::vector<std::string>& warnings, WalletCreationStatus& status) = 0;
+ virtual std::unique_ptr<Wallet> createWallet(const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings, WalletCreationStatus& status) = 0;
//! Register handler for init messages.
using InitMessageFn = std::function<void(const std::string& message)>;
diff --git a/src/interfaces/wallet.cpp b/src/interfaces/wallet.cpp
index 752448aac7..13b034936b 100644
--- a/src/interfaces/wallet.cpp
+++ b/src/interfaces/wallet.cpp
@@ -219,7 +219,7 @@ public:
bool sign,
int& change_pos,
CAmount& fee,
- std::string& fail_reason) override
+ bilingual_str& fail_reason) override
{
LOCK(m_wallet->cs_wallet);
CTransactionRef tx;
@@ -248,7 +248,7 @@ public:
}
bool createBumpTransaction(const uint256& txid,
const CCoinControl& coin_control,
- std::vector<std::string>& errors,
+ std::vector<bilingual_str>& errors,
CAmount& old_fee,
CAmount& new_fee,
CMutableTransaction& mtx) override
@@ -258,7 +258,7 @@ public:
bool signBumpTransaction(CMutableTransaction& mtx) override { return feebumper::SignTransaction(*m_wallet.get(), mtx); }
bool commitBumpTransaction(const uint256& txid,
CMutableTransaction&& mtx,
- std::vector<std::string>& errors,
+ std::vector<bilingual_str>& errors,
uint256& bumped_txid) override
{
return feebumper::CommitTransaction(*m_wallet.get(), txid, std::move(mtx), errors, bumped_txid) ==
diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h
index e5e3b80663..f35335c69f 100644
--- a/src/interfaces/wallet.h
+++ b/src/interfaces/wallet.h
@@ -31,6 +31,7 @@ enum class TransactionError;
enum isminetype : unsigned int;
struct CRecipient;
struct PartiallySignedTransaction;
+struct bilingual_str;
typedef uint8_t isminefilter;
namespace interfaces {
@@ -136,7 +137,7 @@ public:
bool sign,
int& change_pos,
CAmount& fee,
- std::string& fail_reason) = 0;
+ bilingual_str& fail_reason) = 0;
//! Commit transaction.
virtual void commitTransaction(CTransactionRef tx,
@@ -155,7 +156,7 @@ public:
//! Create bump transaction.
virtual bool createBumpTransaction(const uint256& txid,
const CCoinControl& coin_control,
- std::vector<std::string>& errors,
+ std::vector<bilingual_str>& errors,
CAmount& old_fee,
CAmount& new_fee,
CMutableTransaction& mtx) = 0;
@@ -166,7 +167,7 @@ public:
//! Commit bump transaction.
virtual bool commitBumpTransaction(const uint256& txid,
CMutableTransaction&& mtx,
- std::vector<std::string>& errors,
+ std::vector<bilingual_str>& errors,
uint256& bumped_txid) = 0;
//! Get a transaction.
diff --git a/src/logging/timer.h b/src/logging/timer.h
index 21bb3d121e..159920e397 100644
--- a/src/logging/timer.h
+++ b/src/logging/timer.h
@@ -93,12 +93,10 @@ private:
} // namespace BCLog
-#define LOG_TIME_MICROS(end_msg, ...) \
- BCLog::Timer<std::chrono::microseconds> PASTE2(logging_timer, __COUNTER__)(__func__, end_msg, ## __VA_ARGS__)
-#define LOG_TIME_MILLIS(end_msg, ...) \
- BCLog::Timer<std::chrono::milliseconds> PASTE2(logging_timer, __COUNTER__)(__func__, end_msg, ## __VA_ARGS__)
-#define LOG_TIME_SECONDS(end_msg, ...) \
- BCLog::Timer<std::chrono::seconds> PASTE2(logging_timer, __COUNTER__)(__func__, end_msg, ## __VA_ARGS__)
+#define LOG_TIME_MILLIS_WITH_CATEGORY(end_msg, log_category) \
+ BCLog::Timer<std::chrono::milliseconds> PASTE2(logging_timer, __COUNTER__)(__func__, end_msg, log_category)
+#define LOG_TIME_SECONDS(end_msg) \
+ BCLog::Timer<std::chrono::seconds> PASTE2(logging_timer, __COUNTER__)(__func__, end_msg)
#endif // BITCOIN_LOGGING_TIMER_H
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 50a8a8a882..a4d4953281 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -3216,7 +3216,6 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec
{
LOCK(pfrom->m_tx_relay->cs_filter);
pfrom->m_tx_relay->pfilter.reset(new CBloomFilter(filter));
- pfrom->m_tx_relay->pfilter->UpdateEmptyFull();
pfrom->m_tx_relay->fRelayTxes = true;
}
return true;
diff --git a/src/prevector.h b/src/prevector.h
index 9f2f7ba2de..aa20efaaa7 100644
--- a/src/prevector.h
+++ b/src/prevector.h
@@ -152,7 +152,7 @@ private:
struct {
char* indirect;
size_type capacity;
- };
+ } indirect_contents;
};
#pragma pack(pop)
alignas(char*) direct_or_indirect _union = {};
@@ -163,8 +163,8 @@ private:
T* direct_ptr(difference_type pos) { return reinterpret_cast<T*>(_union.direct) + pos; }
const T* direct_ptr(difference_type pos) const { return reinterpret_cast<const T*>(_union.direct) + pos; }
- T* indirect_ptr(difference_type pos) { return reinterpret_cast<T*>(_union.indirect) + pos; }
- const T* indirect_ptr(difference_type pos) const { return reinterpret_cast<const T*>(_union.indirect) + pos; }
+ T* indirect_ptr(difference_type pos) { return reinterpret_cast<T*>(_union.indirect_contents.indirect) + pos; }
+ const T* indirect_ptr(difference_type pos) const { return reinterpret_cast<const T*>(_union.indirect_contents.indirect) + pos; }
bool is_direct() const { return _size <= N; }
void change_capacity(size_type new_capacity) {
@@ -182,17 +182,17 @@ private:
/* FIXME: Because malloc/realloc here won't call new_handler if allocation fails, assert
success. These should instead use an allocator or new/delete so that handlers
are called as necessary, but performance would be slightly degraded by doing so. */
- _union.indirect = static_cast<char*>(realloc(_union.indirect, ((size_t)sizeof(T)) * new_capacity));
- assert(_union.indirect);
- _union.capacity = new_capacity;
+ _union.indirect_contents.indirect = static_cast<char*>(realloc(_union.indirect_contents.indirect, ((size_t)sizeof(T)) * new_capacity));
+ assert(_union.indirect_contents.indirect);
+ _union.indirect_contents.capacity = new_capacity;
} else {
char* new_indirect = static_cast<char*>(malloc(((size_t)sizeof(T)) * new_capacity));
assert(new_indirect);
T* src = direct_ptr(0);
T* dst = reinterpret_cast<T*>(new_indirect);
memcpy(dst, src, size() * sizeof(T));
- _union.indirect = new_indirect;
- _union.capacity = new_capacity;
+ _union.indirect_contents.indirect = new_indirect;
+ _union.indirect_contents.capacity = new_capacity;
_size += N + 1;
}
}
@@ -301,7 +301,7 @@ public:
if (is_direct()) {
return N;
} else {
- return _union.capacity;
+ return _union.indirect_contents.capacity;
}
}
@@ -468,8 +468,8 @@ public:
clear();
}
if (!is_direct()) {
- free(_union.indirect);
- _union.indirect = nullptr;
+ free(_union.indirect_contents.indirect);
+ _union.indirect_contents.indirect = nullptr;
}
}
@@ -521,7 +521,7 @@ public:
if (is_direct()) {
return 0;
} else {
- return ((size_t)(sizeof(T))) * _union.capacity;
+ return ((size_t)(sizeof(T))) * _union.indirect_contents.capacity;
}
}
diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h
index 00ccbc32f9..58b3e8aedc 100644
--- a/src/primitives/transaction.h
+++ b/src/primitives/transaction.h
@@ -324,8 +324,6 @@ public:
// Return sum of txouts.
CAmount GetValueOut() const;
- // GetValueIn() is a method on CCoinsViewCache, because
- // inputs must be known to compute value in.
/**
* Get the total transaction size in bytes, including witness data.
diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp
index 1aaf33c6a4..f48f28d03a 100644
--- a/src/qt/addressbookpage.cpp
+++ b/src/qt/addressbookpage.cpp
@@ -136,6 +136,8 @@ AddressBookPage::AddressBookPage(const PlatformStyle *platformStyle, Mode _mode,
connect(ui->tableView, &QWidget::customContextMenuRequested, this, &AddressBookPage::contextualMenu);
connect(ui->closeButton, &QPushButton::clicked, this, &QDialog::accept);
+
+ GUIUtil::handleCloseWindowShortcut(this);
}
AddressBookPage::~AddressBookPage()
diff --git a/src/qt/askpassphrasedialog.cpp b/src/qt/askpassphrasedialog.cpp
index 67e7704551..3d1963b6e6 100644
--- a/src/qt/askpassphrasedialog.cpp
+++ b/src/qt/askpassphrasedialog.cpp
@@ -10,6 +10,7 @@
#include <qt/forms/ui_askpassphrasedialog.h>
#include <qt/guiconstants.h>
+#include <qt/guiutil.h>
#include <qt/walletmodel.h>
#include <support/allocators/secure.h>
@@ -75,6 +76,8 @@ AskPassphraseDialog::AskPassphraseDialog(Mode _mode, QWidget *parent, SecureStri
connect(ui->passEdit1, &QLineEdit::textChanged, this, &AskPassphraseDialog::textChanged);
connect(ui->passEdit2, &QLineEdit::textChanged, this, &AskPassphraseDialog::textChanged);
connect(ui->passEdit3, &QLineEdit::textChanged, this, &AskPassphraseDialog::textChanged);
+
+ GUIUtil::handleCloseWindowShortcut(this);
}
AskPassphraseDialog::~AskPassphraseDialog()
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index 71e4d59ea7..cf2de1a417 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -211,6 +211,8 @@ BitcoinGUI::BitcoinGUI(interfaces::Node& node, const PlatformStyle *_platformSty
#ifdef Q_OS_MAC
m_app_nap_inhibitor = new CAppNapInhibitor;
#endif
+
+ GUIUtil::handleCloseWindowShortcut(this);
}
BitcoinGUI::~BitcoinGUI()
diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp
index 1889f5e056..b46f416b6c 100644
--- a/src/qt/coincontroldialog.cpp
+++ b/src/qt/coincontroldialog.cpp
@@ -134,6 +134,8 @@ CoinControlDialog::CoinControlDialog(const PlatformStyle *_platformStyle, QWidge
ui->radioTreeMode->click();
if (settings.contains("nCoinControlSortColumn") && settings.contains("nCoinControlSortOrder"))
sortView(settings.value("nCoinControlSortColumn").toInt(), (static_cast<Qt::SortOrder>(settings.value("nCoinControlSortOrder").toInt())));
+
+ GUIUtil::handleCloseWindowShortcut(this);
}
CoinControlDialog::~CoinControlDialog()
diff --git a/src/qt/editaddressdialog.cpp b/src/qt/editaddressdialog.cpp
index 4711412ac4..e0af9a20a8 100644
--- a/src/qt/editaddressdialog.cpp
+++ b/src/qt/editaddressdialog.cpp
@@ -43,6 +43,8 @@ EditAddressDialog::EditAddressDialog(Mode _mode, QWidget *parent) :
GUIUtil::ItemDelegate* delegate = new GUIUtil::ItemDelegate(mapper);
connect(delegate, &GUIUtil::ItemDelegate::keyEscapePressed, this, &EditAddressDialog::reject);
mapper->setItemDelegate(delegate);
+
+ GUIUtil::handleCloseWindowShortcut(this);
}
EditAddressDialog::~EditAddressDialog()
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index a54b65961c..af86fe5d27 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -54,6 +54,7 @@
#include <QSettings>
#include <QSize>
#include <QString>
+#include <QShortcut>
#include <QTextDocument> // for Qt::mightBeRichText
#include <QThread>
#include <QUrlQuery>
@@ -378,6 +379,11 @@ void bringToFront(QWidget* w)
}
}
+void handleCloseWindowShortcut(QWidget* w)
+{
+ QObject::connect(new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_W), w), &QShortcut::activated, w, &QWidget::close);
+}
+
void openDebugLogfile()
{
fs::path pathDebug = GetDataDir() / "debug.log";
diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h
index e571262443..0d9293fbad 100644
--- a/src/qt/guiutil.h
+++ b/src/qt/guiutil.h
@@ -124,6 +124,9 @@ namespace GUIUtil
// Activate, show and raise the widget
void bringToFront(QWidget* w);
+ // Set shortcut to close window
+ void handleCloseWindowShortcut(QWidget* w);
+
// Open debug.log
void openDebugLogfile();
diff --git a/src/qt/openuridialog.cpp b/src/qt/openuridialog.cpp
index b9dea2f8bf..9a3d43c2a6 100644
--- a/src/qt/openuridialog.cpp
+++ b/src/qt/openuridialog.cpp
@@ -15,6 +15,8 @@ OpenURIDialog::OpenURIDialog(QWidget *parent) :
ui(new Ui::OpenURIDialog)
{
ui->setupUi(this);
+
+ GUIUtil::handleCloseWindowShortcut(this);
}
OpenURIDialog::~OpenURIDialog()
diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp
index 8ee6c947e6..ae6aeb7709 100644
--- a/src/qt/optionsdialog.cpp
+++ b/src/qt/optionsdialog.cpp
@@ -135,6 +135,8 @@ OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) :
ui->minimizeToTray->setChecked(false);
ui->minimizeToTray->setEnabled(false);
}
+
+ GUIUtil::handleCloseWindowShortcut(this);
}
OptionsDialog::~OptionsDialog()
diff --git a/src/qt/receiverequestdialog.cpp b/src/qt/receiverequestdialog.cpp
index b4fae7d78d..30bd5c6a5a 100644
--- a/src/qt/receiverequestdialog.cpp
+++ b/src/qt/receiverequestdialog.cpp
@@ -30,6 +30,8 @@ ReceiveRequestDialog::ReceiveRequestDialog(QWidget *parent) :
#endif
connect(ui->btnSaveAs, &QPushButton::clicked, ui->lblQRCode, &QRImageWidget::saveImage);
+
+ GUIUtil::handleCloseWindowShortcut(this);
}
ReceiveRequestDialog::~ReceiveRequestDialog()
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 18a7e9b021..bfe316bdcd 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -498,6 +498,8 @@ RPCConsole::RPCConsole(interfaces::Node& node, const PlatformStyle *_platformSty
consoleFontSize = settings.value(fontSizeSettingsKey, QFontInfo(QFont()).pointSize()).toInt();
clear();
+
+ GUIUtil::handleCloseWindowShortcut(this);
}
RPCConsole::~RPCConsole()
diff --git a/src/qt/signverifymessagedialog.cpp b/src/qt/signverifymessagedialog.cpp
index 67c2c71e9c..5cfbb67449 100644
--- a/src/qt/signverifymessagedialog.cpp
+++ b/src/qt/signverifymessagedialog.cpp
@@ -47,6 +47,8 @@ SignVerifyMessageDialog::SignVerifyMessageDialog(const PlatformStyle *_platformS
ui->signatureOut_SM->setFont(GUIUtil::fixedPitchFont());
ui->signatureIn_VM->setFont(GUIUtil::fixedPitchFont());
+
+ GUIUtil::handleCloseWindowShortcut(this);
}
SignVerifyMessageDialog::~SignVerifyMessageDialog()
diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp
index d8fe4a9238..ced6a299d5 100644
--- a/src/qt/splashscreen.cpp
+++ b/src/qt/splashscreen.cpp
@@ -127,6 +127,8 @@ SplashScreen::SplashScreen(interfaces::Node& node, Qt::WindowFlags f, const Netw
subscribeToCoreSignals();
installEventFilter(this);
+
+ GUIUtil::handleCloseWindowShortcut(this);
}
SplashScreen::~SplashScreen()
diff --git a/src/qt/transactiondescdialog.cpp b/src/qt/transactiondescdialog.cpp
index ca72720e00..715e312b19 100644
--- a/src/qt/transactiondescdialog.cpp
+++ b/src/qt/transactiondescdialog.cpp
@@ -5,6 +5,7 @@
#include <qt/transactiondescdialog.h>
#include <qt/forms/ui_transactiondescdialog.h>
+#include <qt/guiutil.h>
#include <qt/transactiontablemodel.h>
#include <QModelIndex>
@@ -17,6 +18,8 @@ TransactionDescDialog::TransactionDescDialog(const QModelIndex &idx, QWidget *pa
setWindowTitle(tr("Details for %1").arg(idx.data(TransactionTableModel::TxHashRole).toString()));
QString desc = idx.data(TransactionTableModel::LongDescriptionRole).toString();
ui->detailText->setHtml(desc);
+
+ GUIUtil::handleCloseWindowShortcut(this);
}
TransactionDescDialog::~TransactionDescDialog()
diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp
index d16feba1bb..01922cf996 100644
--- a/src/qt/utilitydialog.cpp
+++ b/src/qt/utilitydialog.cpp
@@ -10,6 +10,8 @@
#include <qt/forms/ui_helpmessagedialog.h>
+#include <qt/guiutil.h>
+
#include <clientversion.h>
#include <init.h>
#include <util/system.h>
@@ -102,6 +104,8 @@ HelpMessageDialog::HelpMessageDialog(interfaces::Node& node, QWidget *parent, bo
ui->scrollArea->setVisible(false);
ui->aboutLogo->setVisible(false);
}
+
+ GUIUtil::handleCloseWindowShortcut(this);
}
HelpMessageDialog::~HelpMessageDialog()
@@ -141,6 +145,8 @@ ShutdownWindow::ShutdownWindow(QWidget *parent, Qt::WindowFlags f):
tr("%1 is shutting down...").arg(PACKAGE_NAME) + "<br /><br />" +
tr("Do not shut down the computer until this window disappears.")));
setLayout(layout);
+
+ GUIUtil::handleCloseWindowShortcut(this);
}
QWidget* ShutdownWindow::showShutdownWindow(QMainWindow* window)
diff --git a/src/qt/walletcontroller.cpp b/src/qt/walletcontroller.cpp
index 9c1488fb0e..7cde3ca30b 100644
--- a/src/qt/walletcontroller.cpp
+++ b/src/qt/walletcontroller.cpp
@@ -14,6 +14,7 @@
#include <interfaces/handler.h>
#include <interfaces/node.h>
#include <util/string.h>
+#include <util/translation.h>
#include <wallet/wallet.h>
#include <algorithm>
@@ -244,10 +245,10 @@ void CreateWalletActivity::finish()
{
destroyProgressDialog();
- if (!m_error_message.empty()) {
- QMessageBox::critical(m_parent_widget, tr("Create wallet failed"), QString::fromStdString(m_error_message));
+ if (!m_error_message.original.empty()) {
+ QMessageBox::critical(m_parent_widget, tr("Create wallet failed"), QString::fromStdString(m_error_message.translated));
} else if (!m_warning_message.empty()) {
- QMessageBox::warning(m_parent_widget, tr("Create wallet warning"), QString::fromStdString(Join(m_warning_message, "\n")));
+ QMessageBox::warning(m_parent_widget, tr("Create wallet warning"), QString::fromStdString(Join(m_warning_message, "\n", OpTranslated)));
}
if (m_wallet_model) Q_EMIT created(m_wallet_model);
@@ -285,10 +286,10 @@ void OpenWalletActivity::finish()
{
destroyProgressDialog();
- if (!m_error_message.empty()) {
- QMessageBox::critical(m_parent_widget, tr("Open wallet failed"), QString::fromStdString(m_error_message));
+ if (!m_error_message.original.empty()) {
+ QMessageBox::critical(m_parent_widget, tr("Open wallet failed"), QString::fromStdString(m_error_message.translated));
} else if (!m_warning_message.empty()) {
- QMessageBox::warning(m_parent_widget, tr("Open wallet warning"), QString::fromStdString(Join(m_warning_message, "\n")));
+ QMessageBox::warning(m_parent_widget, tr("Open wallet warning"), QString::fromStdString(Join(m_warning_message, "\n", OpTranslated)));
}
if (m_wallet_model) Q_EMIT opened(m_wallet_model);
diff --git a/src/qt/walletcontroller.h b/src/qt/walletcontroller.h
index 3808b7d8bf..24dd83adf7 100644
--- a/src/qt/walletcontroller.h
+++ b/src/qt/walletcontroller.h
@@ -8,6 +8,7 @@
#include <qt/sendcoinsrecipient.h>
#include <support/allocators/secure.h>
#include <sync.h>
+#include <util/translation.h>
#include <map>
#include <memory>
@@ -104,8 +105,8 @@ protected:
QWidget* const m_parent_widget;
QProgressDialog* m_progress_dialog{nullptr};
WalletModel* m_wallet_model{nullptr};
- std::string m_error_message;
- std::vector<std::string> m_warning_message;
+ bilingual_str m_error_message;
+ std::vector<bilingual_str> m_warning_message;
};
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index e7581cd64e..70ee7f4917 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -24,6 +24,7 @@
#include <psbt.h>
#include <ui_interface.h>
#include <util/system.h> // for GetBoolArg
+#include <util/translation.h>
#include <wallet/coincontrol.h>
#include <wallet/wallet.h> // for CRecipient
@@ -185,10 +186,10 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
{
CAmount nFeeRequired = 0;
int nChangePosRet = -1;
- std::string strFailReason;
+ bilingual_str error;
auto& newTx = transaction.getWtx();
- newTx = m_wallet->createTransaction(vecSend, coinControl, !wallet().privateKeysDisabled() /* sign */, nChangePosRet, nFeeRequired, strFailReason);
+ newTx = m_wallet->createTransaction(vecSend, coinControl, !wallet().privateKeysDisabled() /* sign */, nChangePosRet, nFeeRequired, error);
transaction.setTransactionFee(nFeeRequired);
if (fSubtractFeeFromAmount && newTx)
transaction.reassignAmounts(nChangePosRet);
@@ -199,8 +200,8 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
{
return SendCoinsReturn(AmountWithFeeExceedsBalance);
}
- Q_EMIT message(tr("Send Coins"), QString::fromStdString(strFailReason),
- CClientUIInterface::MSG_ERROR);
+ Q_EMIT message(tr("Send Coins"), QString::fromStdString(error.translated),
+ CClientUIInterface::MSG_ERROR);
return TransactionCreationFailed;
}
@@ -482,14 +483,14 @@ bool WalletModel::bumpFee(uint256 hash, uint256& new_hash)
{
CCoinControl coin_control;
coin_control.m_signal_bip125_rbf = true;
- std::vector<std::string> errors;
+ std::vector<bilingual_str> errors;
CAmount old_fee;
CAmount new_fee;
CMutableTransaction mtx;
if (!m_wallet->createBumpTransaction(hash, coin_control, errors, old_fee, new_fee, mtx)) {
QMessageBox::critical(nullptr, tr("Fee bump error"), tr("Increasing transaction fee failed") + "<br />(" +
- (errors.size() ? QString::fromStdString(errors[0]) : "") +")");
- return false;
+ (errors.size() ? QString::fromStdString(errors[0].translated) : "") +")");
+ return false;
}
const bool create_psbt = m_wallet->privateKeysDisabled();
@@ -551,8 +552,8 @@ bool WalletModel::bumpFee(uint256 hash, uint256& new_hash)
// commit the bumped transaction
if(!m_wallet->commitBumpTransaction(hash, std::move(mtx), errors, new_hash)) {
QMessageBox::critical(nullptr, tr("Fee bump error"), tr("Could not commit transaction") + "<br />(" +
- QString::fromStdString(errors[0])+")");
- return false;
+ QString::fromStdString(errors[0].translated)+")");
+ return false;
}
return true;
}
diff --git a/src/support/lockedpool.cpp b/src/support/lockedpool.cpp
index 9b14637b95..f17b539e09 100644
--- a/src/support/lockedpool.cpp
+++ b/src/support/lockedpool.cpp
@@ -253,8 +253,10 @@ void *PosixLockedPageAllocator::AllocateLocked(size_t len, bool *lockingSuccess)
}
if (addr) {
*lockingSuccess = mlock(addr, len) == 0;
-#ifdef MADV_DONTDUMP
+#if defined(MADV_DONTDUMP) // Linux
madvise(addr, len, MADV_DONTDUMP);
+#elif defined(MADV_NOCORE) // FreeBSD
+ madvise(addr, len, MADV_NOCORE);
#endif
}
return addr;
diff --git a/src/test/fuzz/bloom_filter.cpp b/src/test/fuzz/bloom_filter.cpp
index 50036ce5bd..7039bf16c1 100644
--- a/src/test/fuzz/bloom_filter.cpp
+++ b/src/test/fuzz/bloom_filter.cpp
@@ -25,7 +25,7 @@ void test_one_input(const std::vector<uint8_t>& buffer)
fuzzed_data_provider.ConsumeIntegral<unsigned int>(),
static_cast<unsigned char>(fuzzed_data_provider.PickValueInArray({BLOOM_UPDATE_NONE, BLOOM_UPDATE_ALL, BLOOM_UPDATE_P2PUBKEY_ONLY, BLOOM_UPDATE_MASK}))};
while (fuzzed_data_provider.remaining_bytes() > 0) {
- switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 4)) {
+ switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 3)) {
case 0: {
const std::vector<unsigned char> b = ConsumeRandomLengthByteVector(fuzzed_data_provider);
(void)bloom_filter.contains(b);
@@ -65,9 +65,6 @@ void test_one_input(const std::vector<uint8_t>& buffer)
(void)bloom_filter.IsRelevantAndUpdate(tx);
break;
}
- case 4:
- bloom_filter.UpdateEmptyFull();
- break;
}
(void)bloom_filter.IsWithinSizeConstraints();
}
diff --git a/src/test/fuzz/message.cpp b/src/test/fuzz/message.cpp
new file mode 100644
index 0000000000..dfa98a812b
--- /dev/null
+++ b/src/test/fuzz/message.cpp
@@ -0,0 +1,48 @@
+// 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.
+
+#include <chainparams.h>
+#include <key_io.h>
+#include <optional.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+#include <util/message.h>
+#include <util/strencodings.h>
+
+#include <cassert>
+#include <cstdint>
+#include <iostream>
+#include <string>
+#include <vector>
+
+void initialize()
+{
+ static const ECCVerifyHandle ecc_verify_handle;
+ ECC_Start();
+ SelectParams(CBaseChainParams::REGTEST);
+}
+
+void test_one_input(const std::vector<uint8_t>& buffer)
+{
+ FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
+ const std::string random_message = fuzzed_data_provider.ConsumeRandomLengthString(1024);
+ {
+ const std::vector<uint8_t> random_bytes = ConsumeRandomLengthByteVector(fuzzed_data_provider);
+ CKey private_key;
+ private_key.Set(random_bytes.begin(), random_bytes.end(), fuzzed_data_provider.ConsumeBool());
+ std::string signature;
+ const bool message_signed = MessageSign(private_key, random_message, signature);
+ if (private_key.IsValid()) {
+ assert(message_signed);
+ const MessageVerificationResult verification_result = MessageVerify(EncodeDestination(PKHash(private_key.GetPubKey().GetID())), signature, random_message);
+ assert(verification_result == MessageVerificationResult::OK);
+ }
+ }
+ {
+ (void)MessageHash(random_message);
+ (void)MessageVerify(fuzzed_data_provider.ConsumeRandomLengthString(1024), fuzzed_data_provider.ConsumeRandomLengthString(1024), random_message);
+ (void)SigningResultString(fuzzed_data_provider.PickValueInArray({SigningResult::OK, SigningResult::PRIVATE_KEY_NOT_AVAILABLE, SigningResult::SIGNING_FAILED}));
+ }
+}
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index 9d0ae56c3f..ddbc68f8e2 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -305,7 +305,6 @@ BOOST_AUTO_TEST_CASE(test_Get)
t1.vout[0].scriptPubKey << OP_1;
BOOST_CHECK(AreInputsStandard(CTransaction(t1), coins));
- BOOST_CHECK_EQUAL(coins.GetValueIn(CTransaction(t1)), (50+21+22)*CENT);
}
static void CreateCreditAndSpend(const FillableSigningProvider& keystore, const CScript& outscript, CTransactionRef& output, CMutableTransaction& input, bool success = true)
diff --git a/src/util/translation.h b/src/util/translation.h
index fc45da440a..b2d964c977 100644
--- a/src/util/translation.h
+++ b/src/util/translation.h
@@ -18,6 +18,20 @@ struct bilingual_str {
std::string translated;
};
+inline bilingual_str operator+(const bilingual_str& lhs, const bilingual_str& rhs)
+{
+ return bilingual_str{
+ lhs.original + rhs.original,
+ lhs.translated + rhs.translated};
+}
+
+/** Mark a bilingual_str as untranslated */
+inline static bilingual_str Untranslated(std::string original) { return {original, original}; }
+/** Unary operator to return the original */
+inline static std::string OpOriginal(const bilingual_str& b) { return b.original; }
+/** Unary operator to return the translation */
+inline static std::string OpTranslated(const bilingual_str& b) { return b.translated; }
+
namespace tinyformat {
template <typename... Args>
bilingual_str format(const bilingual_str& fmt, const Args&... args)
diff --git a/src/validation.cpp b/src/validation.cpp
index 259397051c..a924af90af 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -2279,11 +2279,11 @@ bool CChainState::FlushStateToDisk(
LOCK(cs_LastBlockFile);
if (fPruneMode && (fCheckForPruning || nManualPruneHeight > 0) && !fReindex) {
if (nManualPruneHeight > 0) {
- LOG_TIME_MILLIS("find files to prune (manual)", BCLog::BENCH);
+ LOG_TIME_MILLIS_WITH_CATEGORY("find files to prune (manual)", BCLog::BENCH);
FindFilesToPruneManual(setFilesToPrune, nManualPruneHeight);
} else {
- LOG_TIME_MILLIS("find files to prune", BCLog::BENCH);
+ LOG_TIME_MILLIS_WITH_CATEGORY("find files to prune", BCLog::BENCH);
FindFilesToPrune(setFilesToPrune, chainparams.PruneAfterHeight());
fCheckForPruning = false;
@@ -2321,7 +2321,7 @@ bool CChainState::FlushStateToDisk(
return AbortNode(state, "Disk space is too low!", _("Error: Disk space is too low!").translated, CClientUIInterface::MSG_NOPREFIX);
}
{
- LOG_TIME_MILLIS("write block and undo data to disk", BCLog::BENCH);
+ LOG_TIME_MILLIS_WITH_CATEGORY("write block and undo data to disk", BCLog::BENCH);
// First make sure all block and undo data is flushed to disk.
FlushBlockFile();
@@ -2329,7 +2329,7 @@ bool CChainState::FlushStateToDisk(
// Then update all block file information (which may refer to block and undo files).
{
- LOG_TIME_MILLIS("write block index to disk", BCLog::BENCH);
+ LOG_TIME_MILLIS_WITH_CATEGORY("write block index to disk", BCLog::BENCH);
std::vector<std::pair<int, const CBlockFileInfo*> > vFiles;
vFiles.reserve(setDirtyFileInfo.size());
@@ -2349,7 +2349,7 @@ bool CChainState::FlushStateToDisk(
}
// Finally remove any pruned files
if (fFlushForPrune) {
- LOG_TIME_MILLIS("unlink pruned files", BCLog::BENCH);
+ LOG_TIME_MILLIS_WITH_CATEGORY("unlink pruned files", BCLog::BENCH);
UnlinkPrunedFiles(setFilesToPrune);
}
@@ -4644,7 +4644,7 @@ bool LoadGenesisBlock(const CChainParams& chainparams)
return ::ChainstateActive().LoadGenesisBlock(chainparams);
}
-bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, FlatFilePos *dbp)
+void LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, FlatFilePos* dbp)
{
// Map of disk positions for blocks with unknown parent (only used for reindex)
static std::multimap<uint256, FlatFilePos> mapBlocksUnknownParent;
@@ -4656,7 +4656,7 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, FlatFi
CBufferedFile blkdat(fileIn, 2*MAX_BLOCK_SERIALIZED_SIZE, MAX_BLOCK_SERIALIZED_SIZE+8, SER_DISK, CLIENT_VERSION);
uint64_t nRewind = blkdat.GetPos();
while (!blkdat.eof()) {
- boost::this_thread::interruption_point();
+ if (ShutdownRequested()) return;
blkdat.SetPos(nRewind);
nRewind++; // start one byte further next time, in case of failure
@@ -4761,9 +4761,7 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, FlatFi
} catch (const std::runtime_error& e) {
AbortNode(std::string("System error: ") + e.what());
}
- if (nLoaded > 0)
- LogPrintf("Loaded %i blocks from external file in %dms\n", nLoaded, GetTimeMillis() - nStart);
- return nLoaded > 0;
+ LogPrintf("Loaded %i blocks from external file in %dms\n", nLoaded, GetTimeMillis() - nStart);
}
void CChainState::CheckBlockIndex(const Consensus::Params& consensusParams)
diff --git a/src/validation.h b/src/validation.h
index 0169362768..c4a5cc4593 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -182,7 +182,7 @@ FILE* OpenBlockFile(const FlatFilePos &pos, bool fReadOnly = false);
/** Translation to a filesystem path */
fs::path GetBlockPosFilename(const FlatFilePos &pos);
/** Import blocks from an external file */
-bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, FlatFilePos *dbp = nullptr);
+void LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, FlatFilePos* dbp = nullptr);
/** Ensures we have a genesis block in the block tree, possibly writing one to disk. */
bool LoadGenesisBlock(const CChainParams& chainparams);
/** Load the block tree and coins database from disk,
diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp
index 67be4d85d2..3f7c2d09cc 100644
--- a/src/wallet/db.cpp
+++ b/src/wallet/db.cpp
@@ -393,7 +393,7 @@ bool BerkeleyBatch::Recover(const fs::path& file_path, void *callbackDataIn, boo
return fSuccess;
}
-bool BerkeleyBatch::VerifyEnvironment(const fs::path& file_path, std::string& errorStr)
+bool BerkeleyBatch::VerifyEnvironment(const fs::path& file_path, bilingual_str& errorStr)
{
std::string walletFile;
std::shared_ptr<BerkeleyEnvironment> env = GetWalletEnv(file_path, walletFile);
@@ -403,14 +403,14 @@ bool BerkeleyBatch::VerifyEnvironment(const fs::path& file_path, std::string& er
LogPrintf("Using wallet %s\n", file_path.string());
if (!env->Open(true /* retry */)) {
- errorStr = strprintf(_("Error initializing wallet database environment %s!").translated, walletDir);
+ errorStr = strprintf(_("Error initializing wallet database environment %s!"), walletDir);
return false;
}
return true;
}
-bool BerkeleyBatch::VerifyDatabaseFile(const fs::path& file_path, std::vector<std::string>& warnings, std::string& errorStr, BerkeleyEnvironment::recoverFunc_type recoverFunc)
+bool BerkeleyBatch::VerifyDatabaseFile(const fs::path& file_path, std::vector<bilingual_str>& warnings, bilingual_str& errorStr, BerkeleyEnvironment::recoverFunc_type recoverFunc)
{
std::string walletFile;
std::shared_ptr<BerkeleyEnvironment> env = GetWalletEnv(file_path, walletFile);
@@ -425,12 +425,12 @@ bool BerkeleyBatch::VerifyDatabaseFile(const fs::path& file_path, std::vector<st
warnings.push_back(strprintf(_("Warning: Wallet file corrupt, data salvaged!"
" Original %s saved as %s in %s; if"
" your balance or transactions are incorrect you should"
- " restore from a backup.").translated,
+ " restore from a backup."),
walletFile, backup_filename, walletDir));
}
if (r == BerkeleyEnvironment::VerifyResult::RECOVER_FAIL)
{
- errorStr = strprintf(_("%s corrupt, salvage failed").translated, walletFile);
+ errorStr = strprintf(_("%s corrupt, salvage failed"), walletFile);
return false;
}
}
diff --git a/src/wallet/db.h b/src/wallet/db.h
index 1c5f42abca..1bf3375475 100644
--- a/src/wallet/db.h
+++ b/src/wallet/db.h
@@ -21,6 +21,8 @@
#include <db_cxx.h>
+struct bilingual_str;
+
static const unsigned int DEFAULT_WALLET_DBLOGSIZE = 100;
static const bool DEFAULT_WALLET_PRIVDB = true;
@@ -242,9 +244,9 @@ public:
ideal to be called periodically */
static bool PeriodicFlush(BerkeleyDatabase& database);
/* verifies the database environment */
- static bool VerifyEnvironment(const fs::path& file_path, std::string& errorStr);
+ static bool VerifyEnvironment(const fs::path& file_path, bilingual_str& errorStr);
/* verifies the database file */
- static bool VerifyDatabaseFile(const fs::path& file_path, std::vector<std::string>& warnings, std::string& errorStr, BerkeleyEnvironment::recoverFunc_type recoverFunc);
+ static bool VerifyDatabaseFile(const fs::path& file_path, std::vector<bilingual_str>& warnings, bilingual_str& errorStr, BerkeleyEnvironment::recoverFunc_type recoverFunc);
template <typename K, typename T>
bool Read(const K& key, T& value)
diff --git a/src/wallet/feebumper.cpp b/src/wallet/feebumper.cpp
index 01fcb1680e..cacf306891 100644
--- a/src/wallet/feebumper.cpp
+++ b/src/wallet/feebumper.cpp
@@ -3,44 +3,45 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <interfaces/chain.h>
-#include <wallet/coincontrol.h>
-#include <wallet/feebumper.h>
-#include <wallet/fees.h>
-#include <wallet/wallet.h>
#include <policy/fees.h>
#include <policy/policy.h>
#include <util/moneystr.h>
#include <util/rbf.h>
#include <util/system.h>
+#include <util/translation.h>
+#include <wallet/coincontrol.h>
+#include <wallet/feebumper.h>
+#include <wallet/fees.h>
+#include <wallet/wallet.h>
//! Check whether transaction has descendant in wallet or mempool, or has been
//! mined, or conflicts with a mined transaction. Return a feebumper::Result.
-static feebumper::Result PreconditionChecks(const CWallet& wallet, const CWalletTx& wtx, std::vector<std::string>& errors) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
+static feebumper::Result PreconditionChecks(const CWallet& wallet, const CWalletTx& wtx, std::vector<bilingual_str>& errors) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
{
if (wallet.HasWalletSpend(wtx.GetHash())) {
- errors.push_back("Transaction has descendants in the wallet");
+ errors.push_back(Untranslated("Transaction has descendants in the wallet"));
return feebumper::Result::INVALID_PARAMETER;
}
{
if (wallet.chain().hasDescendantsInMempool(wtx.GetHash())) {
- errors.push_back("Transaction has descendants in the mempool");
+ errors.push_back(Untranslated("Transaction has descendants in the mempool"));
return feebumper::Result::INVALID_PARAMETER;
}
}
if (wtx.GetDepthInMainChain() != 0) {
- errors.push_back("Transaction has been mined, or is conflicted with a mined transaction");
+ errors.push_back(Untranslated("Transaction has been mined, or is conflicted with a mined transaction"));
return feebumper::Result::WALLET_ERROR;
}
if (!SignalsOptInRBF(*wtx.tx)) {
- errors.push_back("Transaction is not BIP 125 replaceable");
+ errors.push_back(Untranslated("Transaction is not BIP 125 replaceable"));
return feebumper::Result::WALLET_ERROR;
}
if (wtx.mapValue.count("replaced_by_txid")) {
- errors.push_back(strprintf("Cannot bump transaction %s which was already bumped by transaction %s", wtx.GetHash().ToString(), wtx.mapValue.at("replaced_by_txid")));
+ errors.push_back(strprintf(Untranslated("Cannot bump transaction %s which was already bumped by transaction %s"), wtx.GetHash().ToString(), wtx.mapValue.at("replaced_by_txid")));
return feebumper::Result::WALLET_ERROR;
}
@@ -48,7 +49,7 @@ static feebumper::Result PreconditionChecks(const CWallet& wallet, const CWallet
// if not, we can't bump the fee, because the wallet has no way of knowing the value of the other inputs (thus the fee)
isminefilter filter = wallet.GetLegacyScriptPubKeyMan() && wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) ? ISMINE_WATCH_ONLY : ISMINE_SPENDABLE;
if (!wallet.IsAllFromMe(*wtx.tx, filter)) {
- errors.push_back("Transaction contains inputs that don't belong to this wallet");
+ errors.push_back(Untranslated("Transaction contains inputs that don't belong to this wallet"));
return feebumper::Result::WALLET_ERROR;
}
@@ -57,7 +58,8 @@ static feebumper::Result PreconditionChecks(const CWallet& wallet, const CWallet
}
//! Check if the user provided a valid feeRate
-static feebumper::Result CheckFeeRate(const CWallet& wallet, const CWalletTx& wtx, const CFeeRate& newFeerate, const int64_t maxTxSize, std::vector<std::string>& errors) {
+static feebumper::Result CheckFeeRate(const CWallet& wallet, const CWalletTx& wtx, const CFeeRate& newFeerate, const int64_t maxTxSize, std::vector<bilingual_str>& errors)
+{
// check that fee rate is higher than mempool's minimum fee
// (no point in bumping fee if we know that the new tx won't be accepted to the mempool)
// This may occur if the user set fee_rate or paytxfee too low, if fallbackfee is too low, or, perhaps,
@@ -67,7 +69,7 @@ static feebumper::Result CheckFeeRate(const CWallet& wallet, const CWalletTx& wt
if (newFeerate.GetFeePerK() < minMempoolFeeRate.GetFeePerK()) {
errors.push_back(strprintf(
- "New fee rate (%s) is lower than the minimum fee rate (%s) to get into the mempool -- ",
+ Untranslated("New fee rate (%s) is lower than the minimum fee rate (%s) to get into the mempool -- "),
FormatMoney(newFeerate.GetFeePerK()),
FormatMoney(minMempoolFeeRate.GetFeePerK())));
return feebumper::Result::WALLET_ERROR;
@@ -86,14 +88,14 @@ static feebumper::Result CheckFeeRate(const CWallet& wallet, const CWalletTx& wt
CAmount minTotalFee = nOldFeeRate.GetFee(maxTxSize) + incrementalRelayFee.GetFee(maxTxSize);
if (new_total_fee < minTotalFee) {
- errors.push_back(strprintf("Insufficient total fee %s, must be at least %s (oldFee %s + incrementalFee %s)",
+ errors.push_back(strprintf(Untranslated("Insufficient total fee %s, must be at least %s (oldFee %s + incrementalFee %s)"),
FormatMoney(new_total_fee), FormatMoney(minTotalFee), FormatMoney(nOldFeeRate.GetFee(maxTxSize)), FormatMoney(incrementalRelayFee.GetFee(maxTxSize))));
return feebumper::Result::INVALID_PARAMETER;
}
CAmount requiredFee = GetRequiredFee(wallet, maxTxSize);
if (new_total_fee < requiredFee) {
- errors.push_back(strprintf("Insufficient total fee (cannot be less than required fee %s)",
+ errors.push_back(strprintf(Untranslated("Insufficient total fee (cannot be less than required fee %s)"),
FormatMoney(requiredFee)));
return feebumper::Result::INVALID_PARAMETER;
}
@@ -101,8 +103,8 @@ static feebumper::Result CheckFeeRate(const CWallet& wallet, const CWalletTx& wt
// Check that in all cases the new fee doesn't violate maxTxFee
const CAmount max_tx_fee = wallet.m_default_max_tx_fee;
if (new_total_fee > max_tx_fee) {
- errors.push_back(strprintf("Specified or calculated fee %s is too high (cannot be higher than -maxtxfee %s)",
- FormatMoney(new_total_fee), FormatMoney(max_tx_fee)));
+ errors.push_back(strprintf(Untranslated("Specified or calculated fee %s is too high (cannot be higher than -maxtxfee %s)"),
+ FormatMoney(new_total_fee), FormatMoney(max_tx_fee)));
return feebumper::Result::WALLET_ERROR;
}
@@ -144,12 +146,12 @@ bool TransactionCanBeBumped(const CWallet& wallet, const uint256& txid)
const CWalletTx* wtx = wallet.GetWalletTx(txid);
if (wtx == nullptr) return false;
- std::vector<std::string> errors_dummy;
+ std::vector<bilingual_str> errors_dummy;
feebumper::Result res = PreconditionChecks(wallet, *wtx, errors_dummy);
return res == feebumper::Result::OK;
}
-Result CreateRateBumpTransaction(CWallet& wallet, const uint256& txid, const CCoinControl& coin_control, std::vector<std::string>& errors,
+Result CreateRateBumpTransaction(CWallet& wallet, const uint256& txid, const CCoinControl& coin_control, std::vector<bilingual_str>& errors,
CAmount& old_fee, CAmount& new_fee, CMutableTransaction& mtx)
{
// We are going to modify coin control later, copy to re-use
@@ -159,7 +161,7 @@ Result CreateRateBumpTransaction(CWallet& wallet, const uint256& txid, const CCo
errors.clear();
auto it = wallet.mapWallet.find(txid);
if (it == wallet.mapWallet.end()) {
- errors.push_back("Invalid or non-wallet transaction id");
+ errors.push_back(Untranslated("Invalid or non-wallet transaction id"));
return Result::INVALID_ADDRESS_OR_KEY;
}
const CWalletTx& wtx = it->second;
@@ -216,9 +218,9 @@ Result CreateRateBumpTransaction(CWallet& wallet, const uint256& txid, const CCo
CTransactionRef tx_new = MakeTransactionRef();
CAmount fee_ret;
int change_pos_in_out = -1; // No requested location for change
- std::string fail_reason;
+ bilingual_str fail_reason;
if (!wallet.CreateTransaction(recipients, tx_new, fee_ret, change_pos_in_out, fail_reason, new_coin_control, false)) {
- errors.push_back("Unable to create transaction: " + fail_reason);
+ errors.push_back(Untranslated("Unable to create transaction.") + Untranslated(" ") + fail_reason);
return Result::WALLET_ERROR;
}
@@ -242,7 +244,7 @@ bool SignTransaction(CWallet& wallet, CMutableTransaction& mtx) {
return wallet.SignTransaction(mtx);
}
-Result CommitTransaction(CWallet& wallet, const uint256& txid, CMutableTransaction&& mtx, std::vector<std::string>& errors, uint256& bumped_txid)
+Result CommitTransaction(CWallet& wallet, const uint256& txid, CMutableTransaction&& mtx, std::vector<bilingual_str>& errors, uint256& bumped_txid)
{
LOCK(wallet.cs_wallet);
if (!errors.empty()) {
@@ -250,7 +252,7 @@ Result CommitTransaction(CWallet& wallet, const uint256& txid, CMutableTransacti
}
auto it = txid.IsNull() ? wallet.mapWallet.end() : wallet.mapWallet.find(txid);
if (it == wallet.mapWallet.end()) {
- errors.push_back("Invalid or non-wallet transaction id");
+ errors.push_back(Untranslated("Invalid or non-wallet transaction id"));
return Result::MISC_ERROR;
}
CWalletTx& oldWtx = it->second;
@@ -275,7 +277,7 @@ Result CommitTransaction(CWallet& wallet, const uint256& txid, CMutableTransacti
// along with an exception. It would be good to return information about
// wtxBumped to the caller even if marking the original transaction
// replaced does not succeed for some reason.
- errors.push_back("Created new bumpfee transaction but could not mark the original transaction as replaced");
+ errors.push_back(Untranslated("Created new bumpfee transaction but could not mark the original transaction as replaced"));
}
return Result::OK;
}
diff --git a/src/wallet/feebumper.h b/src/wallet/feebumper.h
index fc038ae731..50577c9d3e 100644
--- a/src/wallet/feebumper.h
+++ b/src/wallet/feebumper.h
@@ -12,6 +12,7 @@ class CWalletTx;
class uint256;
class CCoinControl;
enum class FeeEstimateMode;
+struct bilingual_str;
namespace feebumper {
@@ -30,12 +31,12 @@ bool TransactionCanBeBumped(const CWallet& wallet, const uint256& txid);
//! Create bumpfee transaction based on feerate estimates.
Result CreateRateBumpTransaction(CWallet& wallet,
- const uint256& txid,
- const CCoinControl& coin_control,
- std::vector<std::string>& errors,
- CAmount& old_fee,
- CAmount& new_fee,
- CMutableTransaction& mtx);
+ const uint256& txid,
+ const CCoinControl& coin_control,
+ std::vector<bilingual_str>& errors,
+ CAmount& old_fee,
+ CAmount& new_fee,
+ CMutableTransaction& mtx);
//! Sign the new transaction,
//! @return false if the tx couldn't be found or if it was
@@ -47,10 +48,10 @@ bool SignTransaction(CWallet& wallet, CMutableTransaction& mtx);
//! but sets errors if the tx could not be added to the mempool (will try later)
//! or if the old transaction could not be marked as replaced.
Result CommitTransaction(CWallet& wallet,
- const uint256& txid,
- CMutableTransaction&& mtx,
- std::vector<std::string>& errors,
- uint256& bumped_txid);
+ const uint256& txid,
+ CMutableTransaction&& mtx,
+ std::vector<bilingual_str>& errors,
+ uint256& bumped_txid);
} // namespace feebumper
diff --git a/src/wallet/load.cpp b/src/wallet/load.cpp
index 0afd2dfcf0..217a950457 100644
--- a/src/wallet/load.cpp
+++ b/src/wallet/load.cpp
@@ -53,12 +53,14 @@ bool VerifyWallets(interfaces::Chain& chain, const std::vector<std::string>& wal
return false;
}
- std::string error_string;
- std::vector<std::string> warnings;
+ bilingual_str error_string;
+ std::vector<bilingual_str> warnings;
bool verify_success = CWallet::Verify(chain, location, salvage_wallet, error_string, warnings);
- if (!error_string.empty()) chain.initError(error_string);
- if (!warnings.empty()) chain.initWarning(Join(warnings, "\n"));
- if (!verify_success) return false;
+ if (!warnings.empty()) chain.initWarning(Join(warnings, "\n", OpTranslated));
+ if (!verify_success) {
+ chain.initError(error_string.translated);
+ return false;
+ }
}
return true;
@@ -68,12 +70,12 @@ bool LoadWallets(interfaces::Chain& chain, const std::vector<std::string>& walle
{
try {
for (const std::string& walletFile : wallet_files) {
- std::string error;
- std::vector<std::string> warnings;
+ bilingual_str error;
+ std::vector<bilingual_str> warnings;
std::shared_ptr<CWallet> pwallet = CWallet::CreateWalletFromFile(chain, WalletLocation(walletFile), error, warnings);
- if (!warnings.empty()) chain.initWarning(Join(warnings, "\n"));
+ if (!warnings.empty()) chain.initWarning(Join(warnings, "\n", OpTranslated));
if (!pwallet) {
- chain.initError(error);
+ chain.initError(error.translated);
return false;
}
AddWallet(pwallet);
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index c863d22530..7bf3d169c3 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -345,7 +345,6 @@ UniValue importprunedfunds(const JSONRPCRequest& request)
if (!DecodeHexTx(tx, request.params[0].get_str()))
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
uint256 hashTx = tx.GetHash();
- CWalletTx wtx(pwallet, MakeTransactionRef(std::move(tx)));
CDataStream ssMB(ParseHexV(request.params[1], "proof"), SER_NETWORK, PROTOCOL_VERSION);
CMerkleBlock merkleBlock;
@@ -372,10 +371,10 @@ UniValue importprunedfunds(const JSONRPCRequest& request)
unsigned int txnIndex = vIndex[it - vMatch.begin()];
CWalletTx::Confirmation confirm(CWalletTx::Status::CONFIRMED, height, merkleBlock.header.GetHash(), txnIndex);
- wtx.m_confirm = confirm;
- if (pwallet->IsMine(*wtx.tx)) {
- pwallet->AddToWallet(wtx, false);
+ CTransactionRef tx_ref = MakeTransactionRef(tx);
+ if (pwallet->IsMine(*tx_ref)) {
+ pwallet->AddToWallet(std::move(tx_ref), confirm);
return NullUniValue;
}
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 91162d575d..dda00f1fe7 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -23,6 +23,7 @@
#include <util/moneystr.h>
#include <util/string.h>
#include <util/system.h>
+#include <util/translation.h>
#include <util/url.h>
#include <util/vector.h>
#include <wallet/coincontrol.h>
@@ -338,16 +339,16 @@ static CTransactionRef SendMoney(CWallet* const pwallet, const CTxDestination& a
// Create and send the transaction
CAmount nFeeRequired = 0;
- std::string strError;
+ bilingual_str error;
std::vector<CRecipient> vecSend;
int nChangePosRet = -1;
CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount};
vecSend.push_back(recipient);
CTransactionRef tx;
- if (!pwallet->CreateTransaction(vecSend, tx, nFeeRequired, nChangePosRet, strError, coin_control)) {
+ if (!pwallet->CreateTransaction(vecSend, tx, nFeeRequired, nChangePosRet, error, coin_control)) {
if (!fSubtractFeeFromAmount && nValue + nFeeRequired > curBalance)
- strError = strprintf("Error: This transaction requires a transaction fee of at least %s", FormatMoney(nFeeRequired));
- throw JSONRPCError(RPC_WALLET_ERROR, strError);
+ error = strprintf(Untranslated("Error: This transaction requires a transaction fee of at least %s"), FormatMoney(nFeeRequired));
+ throw JSONRPCError(RPC_WALLET_ERROR, error.original);
}
pwallet->CommitTransaction(tx, std::move(mapValue), {} /* orderForm */);
return tx;
@@ -903,11 +904,11 @@ static UniValue sendmany(const JSONRPCRequest& request)
// Send
CAmount nFeeRequired = 0;
int nChangePosRet = -1;
- std::string strFailReason;
+ bilingual_str error;
CTransactionRef tx;
- bool fCreated = pwallet->CreateTransaction(vecSend, tx, nFeeRequired, nChangePosRet, strFailReason, coin_control);
+ bool fCreated = pwallet->CreateTransaction(vecSend, tx, nFeeRequired, nChangePosRet, error, coin_control);
if (!fCreated)
- throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason);
+ throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, error.original);
pwallet->CommitTransaction(tx, std::move(mapValue), {} /* orderForm */);
return tx->GetHash().GetHex();
}
@@ -1582,7 +1583,7 @@ static UniValue listsinceblock(const JSONRPCRequest& request)
UniValue transactions(UniValue::VARR);
for (const std::pair<const uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
- CWalletTx tx = pairWtx.second;
+ const CWalletTx& tx = pairWtx.second;
if (depth == -1 || abs(tx.GetDepthInMainChain()) < depth) {
ListTransactions(pwallet, tx, 0, true, transactions, filter, nullptr /* filter_label */);
@@ -2589,14 +2590,14 @@ static UniValue loadwallet(const JSONRPCRequest& request)
}
}
- std::string error;
- std::vector<std::string> warning;
- std::shared_ptr<CWallet> const wallet = LoadWallet(*g_rpc_chain, location, error, warning);
- if (!wallet) throw JSONRPCError(RPC_WALLET_ERROR, error);
+ bilingual_str error;
+ std::vector<bilingual_str> warnings;
+ std::shared_ptr<CWallet> const wallet = LoadWallet(*g_rpc_chain, location, error, warnings);
+ if (!wallet) throw JSONRPCError(RPC_WALLET_ERROR, error.original);
UniValue obj(UniValue::VOBJ);
obj.pushKV("name", wallet->GetName());
- obj.pushKV("warning", Join(warning, "\n"));
+ obj.pushKV("warning", Join(warnings, "\n", OpOriginal));
return obj;
}
@@ -2705,12 +2706,12 @@ static UniValue createwallet(const JSONRPCRequest& request)
}
SecureString passphrase;
passphrase.reserve(100);
- std::vector<std::string> warnings;
+ std::vector<bilingual_str> warnings;
if (!request.params[3].isNull()) {
passphrase = request.params[3].get_str().c_str();
if (passphrase.empty()) {
// Empty string means unencrypted
- warnings.emplace_back("Empty string given as passphrase, wallet will not be encrypted.");
+ warnings.emplace_back(Untranslated("Empty string given as passphrase, wallet will not be encrypted."));
}
}
@@ -2721,14 +2722,14 @@ static UniValue createwallet(const JSONRPCRequest& request)
flags |= WALLET_FLAG_DESCRIPTORS;
}
- std::string error;
+ bilingual_str error;
std::shared_ptr<CWallet> wallet;
WalletCreationStatus status = CreateWallet(*g_rpc_chain, passphrase, flags, request.params[0].get_str(), error, warnings, wallet);
switch (status) {
case WalletCreationStatus::CREATION_FAILED:
- throw JSONRPCError(RPC_WALLET_ERROR, error);
+ throw JSONRPCError(RPC_WALLET_ERROR, error.original);
case WalletCreationStatus::ENCRYPTION_FAILED:
- throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, error);
+ throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, error.original);
case WalletCreationStatus::SUCCESS:
break;
// no default case, so the compiler can warn about missing cases
@@ -2736,7 +2737,7 @@ static UniValue createwallet(const JSONRPCRequest& request)
UniValue obj(UniValue::VOBJ);
obj.pushKV("name", wallet->GetName());
- obj.pushKV("warning", Join(warnings, "\n"));
+ obj.pushKV("warning", Join(warnings, "\n", OpOriginal));
return obj;
}
@@ -3108,10 +3109,10 @@ void FundTransaction(CWallet* const pwallet, CMutableTransaction& tx, CAmount& f
setSubtractFeeFromOutputs.insert(pos);
}
- std::string strFailReason;
+ bilingual_str error;
- if (!pwallet->FundTransaction(tx, fee_out, change_position, strFailReason, lockUnspents, setSubtractFeeFromOutputs, coinControl)) {
- throw JSONRPCError(RPC_WALLET_ERROR, strFailReason);
+ if (!pwallet->FundTransaction(tx, fee_out, change_position, error, lockUnspents, setSubtractFeeFromOutputs, coinControl)) {
+ throw JSONRPCError(RPC_WALLET_ERROR, error.original);
}
}
@@ -3417,7 +3418,7 @@ static UniValue bumpfee(const JSONRPCRequest& request)
EnsureWalletIsUnlocked(pwallet);
- std::vector<std::string> errors;
+ std::vector<bilingual_str> errors;
CAmount old_fee;
CAmount new_fee;
CMutableTransaction mtx;
@@ -3427,19 +3428,19 @@ static UniValue bumpfee(const JSONRPCRequest& request)
if (res != feebumper::Result::OK) {
switch(res) {
case feebumper::Result::INVALID_ADDRESS_OR_KEY:
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, errors[0]);
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, errors[0].original);
break;
case feebumper::Result::INVALID_REQUEST:
- throw JSONRPCError(RPC_INVALID_REQUEST, errors[0]);
+ throw JSONRPCError(RPC_INVALID_REQUEST, errors[0].original);
break;
case feebumper::Result::INVALID_PARAMETER:
- throw JSONRPCError(RPC_INVALID_PARAMETER, errors[0]);
+ throw JSONRPCError(RPC_INVALID_PARAMETER, errors[0].original);
break;
case feebumper::Result::WALLET_ERROR:
- throw JSONRPCError(RPC_WALLET_ERROR, errors[0]);
+ throw JSONRPCError(RPC_WALLET_ERROR, errors[0].original);
break;
default:
- throw JSONRPCError(RPC_MISC_ERROR, errors[0]);
+ throw JSONRPCError(RPC_MISC_ERROR, errors[0].original);
break;
}
}
@@ -3455,7 +3456,7 @@ static UniValue bumpfee(const JSONRPCRequest& request)
uint256 txid;
if (feebumper::CommitTransaction(*pwallet, hash, std::move(mtx), errors, txid) != feebumper::Result::OK) {
- throw JSONRPCError(RPC_WALLET_ERROR, errors[0]);
+ throw JSONRPCError(RPC_WALLET_ERROR, errors[0].original);
}
result.pushKV("txid", txid.GetHex());
@@ -3473,8 +3474,8 @@ static UniValue bumpfee(const JSONRPCRequest& request)
result.pushKV("origfee", ValueFromAmount(old_fee));
result.pushKV("fee", ValueFromAmount(new_fee));
UniValue result_errors(UniValue::VARR);
- for (const std::string& error : errors) {
- result_errors.push_back(error);
+ for (const bilingual_str& error : errors) {
+ result_errors.push_back(error.original);
}
result.pushKV("errors", result_errors);
@@ -4239,12 +4240,12 @@ static UniValue upgradewallet(const JSONRPCRequest& request)
version = request.params[0].get_int();
}
- std::string error;
- std::vector<std::string> warnings;
+ bilingual_str error;
+ std::vector<bilingual_str> warnings;
if (!pwallet->UpgradeWallet(version, error, warnings)) {
- throw JSONRPCError(RPC_WALLET_ERROR, error);
+ throw JSONRPCError(RPC_WALLET_ERROR, error.original);
}
- return error;
+ return error.original;
}
UniValue abortrescan(const JSONRPCRequest& request); // in rpcdump.cpp
diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp
index ecb95d599d..e4be5045e1 100644
--- a/src/wallet/scriptpubkeyman.cpp
+++ b/src/wallet/scriptpubkeyman.cpp
@@ -377,10 +377,9 @@ bool LegacyScriptPubKeyMan::CanGetAddresses(bool internal) const
return keypool_has_keys;
}
-bool LegacyScriptPubKeyMan::Upgrade(int prev_version, std::string& error)
+bool LegacyScriptPubKeyMan::Upgrade(int prev_version, bilingual_str& error)
{
LOCK(cs_KeyStore);
- error = "";
bool hd_upgrade = false;
bool split_upgrade = false;
if (m_storage.CanSupportFeature(FEATURE_HD) && !IsHDEnabled()) {
@@ -405,7 +404,7 @@ bool LegacyScriptPubKeyMan::Upgrade(int prev_version, std::string& error)
// Regenerate the keypool if upgraded to HD
if (hd_upgrade) {
if (!TopUp()) {
- error = _("Unable to generate keys").translated;
+ error = _("Unable to generate keys");
return false;
}
}
diff --git a/src/wallet/scriptpubkeyman.h b/src/wallet/scriptpubkeyman.h
index 3117b13d35..4c002edf2d 100644
--- a/src/wallet/scriptpubkeyman.h
+++ b/src/wallet/scriptpubkeyman.h
@@ -19,6 +19,7 @@
#include <boost/signals2/signal.hpp>
enum class OutputType;
+struct bilingual_str;
// Wallet storage things that ScriptPubKeyMans need in order to be able to store things to the wallet database.
// It provides access to things that are part of the entire wallet and not specific to a ScriptPubKeyMan such as
@@ -191,7 +192,7 @@ public:
virtual bool CanGetAddresses(bool internal = false) const { return false; }
/** Upgrades the wallet to the specified version */
- virtual bool Upgrade(int prev_version, std::string& error) { return false; }
+ virtual bool Upgrade(int prev_version, bilingual_str& error) { return false; }
virtual bool HavePrivateKeys() const { return false; }
@@ -343,7 +344,7 @@ public:
bool SetupGeneration(bool force = false) override;
- bool Upgrade(int prev_version, std::string& error) override;
+ bool Upgrade(int prev_version, bilingual_str& error) override;
bool HavePrivateKeys() const override;
@@ -497,7 +498,7 @@ private:
int32_t m_max_cached_index = -1;
OutputType m_address_type;
- bool m_internal;
+ bool m_internal = false;
KeyMap m_map_keys GUARDED_BY(cs_desc_man);
CryptedKeyMap m_map_crypted_keys GUARDED_BY(cs_desc_man);
diff --git a/src/wallet/test/coinselector_tests.cpp b/src/wallet/test/coinselector_tests.cpp
index 66f4542cf9..657d0828f2 100644
--- a/src/wallet/test/coinselector_tests.cpp
+++ b/src/wallet/test/coinselector_tests.cpp
@@ -24,8 +24,6 @@ BOOST_FIXTURE_TEST_SUITE(coinselector_tests, WalletTestingSetup)
// we repeat those tests this many times and only complain if all iterations of the test fail
#define RANDOM_REPEATS 5
-std::vector<std::unique_ptr<CWalletTx>> wtxn;
-
typedef std::set<CInputCoin> CoinSet;
static std::vector<COutput> vCoins;
@@ -74,16 +72,14 @@ static void add_coin(CWallet& wallet, const CAmount& nValue, int nAge = 6*24, bo
// so stop vin being empty, and cache a non-zero Debit to fake out IsFromMe()
tx.vin.resize(1);
}
- std::unique_ptr<CWalletTx> wtx = MakeUnique<CWalletTx>(&wallet, MakeTransactionRef(std::move(tx)));
+ CWalletTx* wtx = wallet.AddToWallet(MakeTransactionRef(std::move(tx)), /* confirm= */ {});
if (fIsFromMe)
{
wtx->m_amounts[CWalletTx::DEBIT].Set(ISMINE_SPENDABLE, 1);
wtx->m_is_cache_empty = false;
}
- COutput output(wtx.get(), nInput, nAge, true /* spendable */, true /* solvable */, true /* safe */);
+ COutput output(wtx, nInput, nAge, true /* spendable */, true /* solvable */, true /* safe */);
vCoins.push_back(output);
- wallet.AddToWallet(*wtx.get());
- wtxn.emplace_back(std::move(wtx));
}
static void add_coin(const CAmount& nValue, int nAge = 6*24, bool fIsFromMe = false, int nInput=0, bool spendable = false)
{
@@ -93,7 +89,6 @@ static void add_coin(const CAmount& nValue, int nAge = 6*24, bool fIsFromMe = fa
static void empty_wallet(void)
{
vCoins.clear();
- wtxn.clear();
balance = 0;
}
diff --git a/src/wallet/test/psbt_wallet_tests.cpp b/src/wallet/test/psbt_wallet_tests.cpp
index 35860577cd..b4c65a8665 100644
--- a/src/wallet/test/psbt_wallet_tests.cpp
+++ b/src/wallet/test/psbt_wallet_tests.cpp
@@ -22,14 +22,12 @@ BOOST_AUTO_TEST_CASE(psbt_updater_test)
CDataStream s_prev_tx1(ParseHex("0200000000010158e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7501000000171600145f275f436b09a8cc9a2eb2a2f528485c68a56323feffffff02d8231f1b0100000017a914aed962d6654f9a2b36608eb9d64d2b260db4f1118700c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e88702483045022100a22edcc6e5bc511af4cc4ae0de0fcd75c7e04d8c1c3a8aa9d820ed4b967384ec02200642963597b9b1bc22c75e9f3e117284a962188bf5e8a74c895089046a20ad770121035509a48eb623e10aace8bfd0212fdb8a8e5af3c94b0b133b95e114cab89e4f7965000000"), SER_NETWORK, PROTOCOL_VERSION);
CTransactionRef prev_tx1;
s_prev_tx1 >> prev_tx1;
- CWalletTx prev_wtx1(&m_wallet, prev_tx1);
- m_wallet.mapWallet.emplace(prev_wtx1.GetHash(), std::move(prev_wtx1));
+ m_wallet.mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(prev_tx1->GetHash()), std::forward_as_tuple(&m_wallet, prev_tx1));
CDataStream s_prev_tx2(ParseHex("0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f618765000000"), SER_NETWORK, PROTOCOL_VERSION);
CTransactionRef prev_tx2;
s_prev_tx2 >> prev_tx2;
- CWalletTx prev_wtx2(&m_wallet, prev_tx2);
- m_wallet.mapWallet.emplace(prev_wtx2.GetHash(), std::move(prev_wtx2));
+ m_wallet.mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(prev_tx2->GetHash()), std::forward_as_tuple(&m_wallet, prev_tx2));
// Add scripts
CScript rs1;
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index c049f2f15f..3dba106c41 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -15,6 +15,7 @@
#include <rpc/server.h>
#include <test/util/logging.h>
#include <test/util/setup_common.h>
+#include <util/translation.h>
#include <validation.h>
#include <wallet/coincontrol.h>
#include <wallet/test/wallet_test_fixture.h>
@@ -30,8 +31,8 @@ BOOST_FIXTURE_TEST_SUITE(wallet_tests, WalletTestingSetup)
static std::shared_ptr<CWallet> TestLoadWallet(interfaces::Chain& chain)
{
- std::string error;
- std::vector<std::string> warnings;
+ bilingual_str error;
+ std::vector<bilingual_str> warnings;
auto wallet = CWallet::CreateWalletFromFile(chain, WalletLocation(""), error, warnings);
wallet->postInitProcess();
return wallet;
@@ -331,6 +332,7 @@ BOOST_FIXTURE_TEST_CASE(coin_mark_dirty_immature_credit, TestChain100Setup)
static int64_t AddTx(CWallet& wallet, uint32_t lockTime, int64_t mockTime, int64_t blockTime)
{
CMutableTransaction tx;
+ CWalletTx::Confirmation confirm;
tx.nLockTime = lockTime;
SetMockTime(mockTime);
CBlockIndex* block = nullptr;
@@ -341,23 +343,15 @@ static int64_t AddTx(CWallet& wallet, uint32_t lockTime, int64_t mockTime, int64
block = inserted.first->second;
block->nTime = blockTime;
block->phashBlock = &hash;
+ confirm = {CWalletTx::Status::CONFIRMED, block->nHeight, hash, 0};
}
- CWalletTx wtx(&wallet, MakeTransactionRef(tx));
- LOCK(wallet.cs_wallet);
// If transaction is already in map, to avoid inconsistencies, unconfirmation
// is needed before confirm again with different block.
- std::map<uint256, CWalletTx>::iterator it = wallet.mapWallet.find(wtx.GetHash());
- if (it != wallet.mapWallet.end()) {
+ return wallet.AddToWallet(MakeTransactionRef(tx), confirm, [&](CWalletTx& wtx, bool /* new_tx */) {
wtx.setUnconfirmed();
- wallet.AddToWallet(wtx);
- }
- if (block) {
- CWalletTx::Confirmation confirm(CWalletTx::Status::CONFIRMED, block->nHeight, block->GetBlockHash(), 0);
- wtx.m_confirm = confirm;
- }
- wallet.AddToWallet(wtx);
- return wallet.mapWallet.at(wtx.GetHash()).nTimeSmart;
+ return true;
+ })->nTimeSmart;
}
// Simple test to verify assignment of CWalletTx::nSmartTime value. Could be
@@ -515,7 +509,7 @@ public:
CTransactionRef tx;
CAmount fee;
int changePos = -1;
- std::string error;
+ bilingual_str error;
CCoinControl dummy;
{
BOOST_CHECK(wallet->CreateTransaction({recipient}, tx, fee, changePos, error, dummy));
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index a20ede59fd..004ec57eb6 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -27,6 +27,7 @@
#include <util/fees.h>
#include <util/moneystr.h>
#include <util/rbf.h>
+#include <util/string.h>
#include <util/translation.h>
#include <wallet/coincontrol.h>
#include <wallet/fees.h>
@@ -149,34 +150,34 @@ void UnloadWallet(std::shared_ptr<CWallet>&& wallet)
}
}
-std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const WalletLocation& location, std::string& error, std::vector<std::string>& warnings)
+std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const WalletLocation& location, bilingual_str& error, std::vector<bilingual_str>& warnings)
{
try {
if (!CWallet::Verify(chain, location, false, error, warnings)) {
- error = "Wallet file verification failed: " + error;
+ error = Untranslated("Wallet file verification failed.") + Untranslated(" ") + error;
return nullptr;
}
std::shared_ptr<CWallet> wallet = CWallet::CreateWalletFromFile(chain, location, error, warnings);
if (!wallet) {
- error = "Wallet loading failed: " + error;
+ error = Untranslated("Wallet loading failed.") + Untranslated(" ") + error;
return nullptr;
}
AddWallet(wallet);
wallet->postInitProcess();
return wallet;
} catch (const std::runtime_error& e) {
- error = e.what();
+ error = Untranslated(e.what());
return nullptr;
}
}
-std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const std::string& name, std::string& error, std::vector<std::string>& warnings)
+std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings)
{
return LoadWallet(chain, WalletLocation(name), error, warnings);
}
-WalletCreationStatus CreateWallet(interfaces::Chain& chain, const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, std::string& error, std::vector<std::string>& warnings, std::shared_ptr<CWallet>& result)
+WalletCreationStatus CreateWallet(interfaces::Chain& chain, const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings, std::shared_ptr<CWallet>& result)
{
// Indicate that the wallet is actually supposed to be blank and not just blank to make it encrypted
bool create_blank = (wallet_creation_flags & WALLET_FLAG_BLANK_WALLET);
@@ -189,39 +190,39 @@ WalletCreationStatus CreateWallet(interfaces::Chain& chain, const SecureString&
// Check the wallet file location
WalletLocation location(name);
if (location.Exists()) {
- error = "Wallet " + location.GetName() + " already exists.";
+ error = strprintf(Untranslated("Wallet %s already exists."), location.GetName());
return WalletCreationStatus::CREATION_FAILED;
}
// Wallet::Verify will check if we're trying to create a wallet with a duplicate name.
if (!CWallet::Verify(chain, location, false, error, warnings)) {
- error = "Wallet file verification failed: " + error;
+ error = Untranslated("Wallet file verification failed.") + Untranslated(" ") + error;
return WalletCreationStatus::CREATION_FAILED;
}
// Do not allow a passphrase when private keys are disabled
if (!passphrase.empty() && (wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
- error = "Passphrase provided but private keys are disabled. A passphrase is only used to encrypt private keys, so cannot be used for wallets with private keys disabled.";
+ error = Untranslated("Passphrase provided but private keys are disabled. A passphrase is only used to encrypt private keys, so cannot be used for wallets with private keys disabled.");
return WalletCreationStatus::CREATION_FAILED;
}
// Make the wallet
std::shared_ptr<CWallet> wallet = CWallet::CreateWalletFromFile(chain, location, error, warnings, wallet_creation_flags);
if (!wallet) {
- error = "Wallet creation failed: " + error;
+ error = Untranslated("Wallet creation failed.") + Untranslated(" ") + error;
return WalletCreationStatus::CREATION_FAILED;
}
// Encrypt the wallet
if (!passphrase.empty() && !(wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
if (!wallet->EncryptWallet(passphrase)) {
- error = "Error: Wallet created but failed to encrypt.";
+ error = Untranslated("Error: Wallet created but failed to encrypt.");
return WalletCreationStatus::ENCRYPTION_FAILED;
}
if (!create_blank) {
// Unlock the wallet
if (!wallet->Unlock(passphrase)) {
- error = "Error: Wallet was encrypted but could not be unlocked";
+ error = Untranslated("Error: Wallet was encrypted but could not be unlocked");
return WalletCreationStatus::ENCRYPTION_FAILED;
}
@@ -233,7 +234,7 @@ WalletCreationStatus CreateWallet(interfaces::Chain& chain, const SecureString&
} else {
for (auto spk_man : wallet->GetActiveScriptPubKeyMans()) {
if (!spk_man->SetupGeneration()) {
- error = "Unable to generate initial keys";
+ error = Untranslated("Unable to generate initial keys");
return WalletCreationStatus::CREATION_FAILED;
}
}
@@ -783,19 +784,19 @@ bool CWallet::IsSpentKey(const uint256& hash, unsigned int n) const
return false;
}
-bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
+CWalletTx* CWallet::AddToWallet(CTransactionRef tx, const CWalletTx::Confirmation& confirm, const UpdateWalletTxFn& update_wtx, bool fFlushOnClose)
{
LOCK(cs_wallet);
WalletBatch batch(*database, "r+", fFlushOnClose);
- uint256 hash = wtxIn.GetHash();
+ uint256 hash = tx->GetHash();
if (IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE)) {
// Mark used destinations
std::set<CTxDestination> tx_destinations;
- for (const CTxIn& txin : wtxIn.tx->vin) {
+ for (const CTxIn& txin : tx->vin) {
const COutPoint& op = txin.prevout;
SetSpentKeyState(batch, op.hash, op.n, true, tx_destinations);
}
@@ -804,11 +805,12 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
}
// Inserts only if not already there, returns tx inserted or tx found
- std::pair<std::map<uint256, CWalletTx>::iterator, bool> ret = mapWallet.insert(std::make_pair(hash, wtxIn));
+ auto ret = mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(hash), std::forward_as_tuple(this, tx));
CWalletTx& wtx = (*ret.first).second;
- wtx.BindWallet(this);
bool fInsertedNew = ret.second;
+ bool fUpdated = update_wtx && update_wtx(wtx, fInsertedNew);
if (fInsertedNew) {
+ wtx.m_confirm = confirm;
wtx.nTimeReceived = chain().getAdjustedTime();
wtx.nOrderPos = IncOrderPosNext(&batch);
wtx.m_it_wtxOrdered = wtxOrdered.insert(std::make_pair(wtx.nOrderPos, &wtx));
@@ -816,43 +818,37 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
AddToSpends(hash);
}
- bool fUpdated = false;
if (!fInsertedNew)
{
- if (wtxIn.m_confirm.status != wtx.m_confirm.status) {
- wtx.m_confirm.status = wtxIn.m_confirm.status;
- wtx.m_confirm.nIndex = wtxIn.m_confirm.nIndex;
- wtx.m_confirm.hashBlock = wtxIn.m_confirm.hashBlock;
- wtx.m_confirm.block_height = wtxIn.m_confirm.block_height;
+ if (confirm.status != wtx.m_confirm.status) {
+ wtx.m_confirm.status = confirm.status;
+ wtx.m_confirm.nIndex = confirm.nIndex;
+ wtx.m_confirm.hashBlock = confirm.hashBlock;
+ wtx.m_confirm.block_height = confirm.block_height;
fUpdated = true;
} else {
- assert(wtx.m_confirm.nIndex == wtxIn.m_confirm.nIndex);
- assert(wtx.m_confirm.hashBlock == wtxIn.m_confirm.hashBlock);
- assert(wtx.m_confirm.block_height == wtxIn.m_confirm.block_height);
- }
- if (wtxIn.fFromMe && wtxIn.fFromMe != wtx.fFromMe)
- {
- wtx.fFromMe = wtxIn.fFromMe;
- fUpdated = true;
+ assert(wtx.m_confirm.nIndex == confirm.nIndex);
+ assert(wtx.m_confirm.hashBlock == confirm.hashBlock);
+ assert(wtx.m_confirm.block_height == confirm.block_height);
}
// If we have a witness-stripped version of this transaction, and we
// see a new version with a witness, then we must be upgrading a pre-segwit
// wallet. Store the new version of the transaction with the witness,
// as the stripped-version must be invalid.
// TODO: Store all versions of the transaction, instead of just one.
- if (wtxIn.tx->HasWitness() && !wtx.tx->HasWitness()) {
- wtx.SetTx(wtxIn.tx);
+ if (tx->HasWitness() && !wtx.tx->HasWitness()) {
+ wtx.SetTx(tx);
fUpdated = true;
}
}
//// debug print
- WalletLogPrintf("AddToWallet %s %s%s\n", wtxIn.GetHash().ToString(), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : ""));
+ WalletLogPrintf("AddToWallet %s %s%s\n", hash.ToString(), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : ""));
// Write to disk
if (fInsertedNew || fUpdated)
if (!batch.WriteTx(wtx))
- return false;
+ return nullptr;
// Break debit/credit balance caches:
wtx.MarkDirty();
@@ -866,7 +862,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
if (!strCmd.empty())
{
- boost::replace_all(strCmd, "%s", wtxIn.GetHash().GetHex());
+ boost::replace_all(strCmd, "%s", hash.GetHex());
#ifndef WIN32
// Substituting the wallet name isn't currently supported on windows
// because windows shell escaping has not been implemented yet:
@@ -880,35 +876,36 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
}
#endif
- return true;
+ return &wtx;
}
-void CWallet::LoadToWallet(CWalletTx& wtxIn)
+bool CWallet::LoadToWallet(const uint256& hash, const UpdateWalletTxFn& fill_wtx)
{
+ const auto& ins = mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(hash), std::forward_as_tuple(this, nullptr));
+ CWalletTx& wtx = ins.first->second;
+ if (!fill_wtx(wtx, ins.second)) {
+ return false;
+ }
// If wallet doesn't have a chain (e.g wallet-tool), don't bother to update txn.
if (HaveChain()) {
- Optional<int> block_height = chain().getBlockHeight(wtxIn.m_confirm.hashBlock);
+ Optional<int> block_height = chain().getBlockHeight(wtx.m_confirm.hashBlock);
if (block_height) {
// Update cached block height variable since it not stored in the
// serialized transaction.
- wtxIn.m_confirm.block_height = *block_height;
- } else if (wtxIn.isConflicted() || wtxIn.isConfirmed()) {
+ wtx.m_confirm.block_height = *block_height;
+ } else if (wtx.isConflicted() || wtx.isConfirmed()) {
// If tx block (or conflicting block) was reorged out of chain
// while the wallet was shutdown, change tx status to UNCONFIRMED
// and reset block height, hash, and index. ABANDONED tx don't have
// associated blocks and don't need to be updated. The case where a
// transaction was reorged out while online and then reconfirmed
// while offline is covered by the rescan logic.
- wtxIn.setUnconfirmed();
- wtxIn.m_confirm.hashBlock = uint256();
- wtxIn.m_confirm.block_height = 0;
- wtxIn.m_confirm.nIndex = 0;
+ wtx.setUnconfirmed();
+ wtx.m_confirm.hashBlock = uint256();
+ wtx.m_confirm.block_height = 0;
+ wtx.m_confirm.nIndex = 0;
}
}
- uint256 hash = wtxIn.GetHash();
- const auto& ins = mapWallet.emplace(hash, wtxIn);
- CWalletTx& wtx = ins.first->second;
- wtx.BindWallet(this);
if (/* insertion took place */ ins.second) {
wtx.m_it_wtxOrdered = wtxOrdered.insert(std::make_pair(wtx.nOrderPos, &wtx));
}
@@ -922,6 +919,7 @@ void CWallet::LoadToWallet(CWalletTx& wtxIn)
}
}
}
+ return true;
}
bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, CWalletTx::Confirmation confirm, bool fUpdate)
@@ -960,13 +958,9 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, CWalletTx::Co
}
}
- CWalletTx wtx(this, ptx);
-
// Block disconnection override an abandoned tx as unconfirmed
// which means user may have to call abandontransaction again
- wtx.m_confirm = confirm;
-
- return AddToWallet(wtx, false);
+ return AddToWallet(MakeTransactionRef(tx), confirm, /* update_wtx= */ nullptr, /* fFlushOnClose= */ false);
}
}
return false;
@@ -2520,7 +2514,7 @@ SigningResult CWallet::SignMessage(const std::string& message, const PKHash& pkh
return SigningResult::PRIVATE_KEY_NOT_AVAILABLE;
}
-bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nChangePosInOut, std::string& strFailReason, bool lockUnspents, const std::set<int>& setSubtractFeeFromOutputs, CCoinControl coinControl)
+bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nChangePosInOut, bilingual_str& error, bool lockUnspents, const std::set<int>& setSubtractFeeFromOutputs, CCoinControl coinControl)
{
std::vector<CRecipient> vecSend;
@@ -2542,7 +2536,7 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nC
LOCK(cs_wallet);
CTransactionRef tx_new;
- if (!CreateTransaction(vecSend, tx_new, nFeeRet, nChangePosInOut, strFailReason, coinControl, false)) {
+ if (!CreateTransaction(vecSend, tx_new, nFeeRet, nChangePosInOut, error, coinControl, false)) {
return false;
}
@@ -2658,7 +2652,7 @@ OutputType CWallet::TransactionChangeType(OutputType change_type, const std::vec
return m_default_address_type;
}
-bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransactionRef& tx, CAmount& nFeeRet, int& nChangePosInOut, std::string& strFailReason, const CCoinControl& coin_control, bool sign)
+bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransactionRef& tx, CAmount& nFeeRet, int& nChangePosInOut, bilingual_str& error, const CCoinControl& coin_control, bool sign)
{
CAmount nValue = 0;
const OutputType change_type = TransactionChangeType(coin_control.m_change_type ? *coin_control.m_change_type : m_default_change_type, vecSend);
@@ -2669,7 +2663,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac
{
if (nValue < 0 || recipient.nAmount < 0)
{
- strFailReason = _("Transaction amounts must not be negative").translated;
+ error = _("Transaction amounts must not be negative");
return false;
}
nValue += recipient.nAmount;
@@ -2679,7 +2673,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac
}
if (vecSend.empty())
{
- strFailReason = _("Transaction must have at least one recipient").translated;
+ error = _("Transaction must have at least one recipient");
return false;
}
@@ -2716,7 +2710,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac
// destination in case we don't need change.
CTxDestination dest;
if (!reservedest.GetReservedDestination(dest, true)) {
- strFailReason = _("Transaction needs a change address, but we can't generate it. Please call keypoolrefill first.").translated;
+ error = _("Transaction needs a change address, but we can't generate it. Please call keypoolrefill first.");
}
scriptChange = GetScriptForDestination(dest);
assert(!dest.empty() || scriptChange.empty());
@@ -2778,12 +2772,12 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac
if (recipient.fSubtractFeeFromAmount && nFeeRet > 0)
{
if (txout.nValue < 0)
- strFailReason = _("The transaction amount is too small to pay the fee").translated;
+ error = _("The transaction amount is too small to pay the fee");
else
- strFailReason = _("The transaction amount is too small to send after the fee has been deducted").translated;
+ error = _("The transaction amount is too small to send after the fee has been deducted");
}
else
- strFailReason = _("Transaction amount too small").translated;
+ error = _("Transaction amount too small");
return false;
}
txNew.vout.push_back(txout);
@@ -2811,7 +2805,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac
continue;
}
else {
- strFailReason = _("Insufficient funds").translated;
+ error = _("Insufficient funds");
return false;
}
}
@@ -2842,7 +2836,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac
}
else if ((unsigned int)nChangePosInOut > txNew.vout.size())
{
- strFailReason = _("Change index out of range").translated;
+ error = _("Change index out of range");
return false;
}
@@ -2861,14 +2855,14 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac
nBytes = CalculateMaximumSignedTxSize(CTransaction(txNew), this, coin_control.fAllowWatchOnly);
if (nBytes < 0) {
- strFailReason = _("Signing transaction failed").translated;
+ error = _("Signing transaction failed");
return false;
}
nFeeNeeded = GetMinimumFee(*this, nBytes, coin_control, &feeCalc);
if (feeCalc.reason == FeeReason::FALLBACK && !m_allow_fallback_fee) {
// eventually allow a fallback fee
- strFailReason = _("Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.").translated;
+ error = _("Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.");
return false;
}
@@ -2908,7 +2902,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac
// fee to pay for the new output and still meet nFeeNeeded
// Or we should have just subtracted fee from recipients and
// nFeeNeeded should not have changed
- strFailReason = _("Transaction fee and change calculation failed").translated;
+ error = _("Transaction fee and change calculation failed");
return false;
}
@@ -2961,7 +2955,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac
}
if (sign && !SignTransaction(txNew)) {
- strFailReason = _("Signing transaction failed").translated;
+ error = _("Signing transaction failed");
return false;
}
@@ -2971,20 +2965,20 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac
// Limit size
if (GetTransactionWeight(*tx) > MAX_STANDARD_TX_WEIGHT)
{
- strFailReason = _("Transaction too large").translated;
+ error = _("Transaction too large");
return false;
}
}
if (nFeeRet > m_default_max_tx_fee) {
- strFailReason = TransactionErrorString(TransactionError::MAX_FEE_EXCEEDED);
+ error = Untranslated(TransactionErrorString(TransactionError::MAX_FEE_EXCEEDED));
return false;
}
if (gArgs.GetBoolArg("-walletrejectlongchains", DEFAULT_WALLET_REJECT_LONG_CHAINS)) {
// Lastly, ensure this tx will pass the mempool's chain limits
if (!chain().checkChainLimits(tx)) {
- strFailReason = _("Transaction has too long of a mempool chain").translated;
+ error = _("Transaction has too long of a mempool chain");
return false;
}
}
@@ -3007,29 +3001,30 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac
void CWallet::CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::vector<std::pair<std::string, std::string>> orderForm)
{
LOCK(cs_wallet);
-
- CWalletTx wtxNew(this, std::move(tx));
- wtxNew.mapValue = std::move(mapValue);
- wtxNew.vOrderForm = std::move(orderForm);
- wtxNew.fTimeReceivedIsTxTime = true;
- wtxNew.fFromMe = true;
-
- WalletLogPrintf("CommitTransaction:\n%s", wtxNew.tx->ToString()); /* Continued */
+ WalletLogPrintf("CommitTransaction:\n%s", tx->ToString()); /* Continued */
// Add tx to wallet, because if it has change it's also ours,
// otherwise just for transaction history.
- AddToWallet(wtxNew);
+ AddToWallet(tx, {}, [&](CWalletTx& wtx, bool new_tx) {
+ CHECK_NONFATAL(wtx.mapValue.empty());
+ CHECK_NONFATAL(wtx.vOrderForm.empty());
+ wtx.mapValue = std::move(mapValue);
+ wtx.vOrderForm = std::move(orderForm);
+ wtx.fTimeReceivedIsTxTime = true;
+ wtx.fFromMe = true;
+ return true;
+ });
// Notify that old coins are spent
- for (const CTxIn& txin : wtxNew.tx->vin) {
+ for (const CTxIn& txin : tx->vin) {
CWalletTx &coin = mapWallet.at(txin.prevout.hash);
- coin.BindWallet(this);
+ coin.MarkDirty();
NotifyTransactionChanged(this, coin.GetHash(), CT_UPDATED);
}
// Get the inserted-CWalletTx from mapWallet so that the
// fInMempool flag is cached properly
- CWalletTx& wtx = mapWallet.at(wtxNew.GetHash());
+ CWalletTx& wtx = mapWallet.at(tx->GetHash());
if (!fBroadcastTransactions) {
// Don't submit tx to the mempool
@@ -3101,7 +3096,7 @@ DBErrors CWallet::ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256
return DBErrors::LOAD_OK;
}
-DBErrors CWallet::ZapWalletTx(std::vector<CWalletTx>& vWtx)
+DBErrors CWallet::ZapWalletTx(std::list<CWalletTx>& vWtx)
{
DBErrors nZapWalletTxRet = WalletBatch(*database,"cr+").ZapWalletTx(vWtx);
if (nZapWalletTxRet == DBErrors::NEED_REWRITE)
@@ -3656,7 +3651,7 @@ std::vector<std::string> CWallet::GetDestValues(const std::string& prefix) const
return values;
}
-bool CWallet::Verify(interfaces::Chain& chain, const WalletLocation& location, bool salvage_wallet, std::string& error_string, std::vector<std::string>& warnings)
+bool CWallet::Verify(interfaces::Chain& chain, const WalletLocation& location, bool salvage_wallet, bilingual_str& error_string, std::vector<bilingual_str>& warnings)
{
// Do some checking on wallet path. It should be either a:
//
@@ -3670,17 +3665,17 @@ bool CWallet::Verify(interfaces::Chain& chain, const WalletLocation& location, b
if (!(path_type == fs::file_not_found || path_type == fs::directory_file ||
(path_type == fs::symlink_file && fs::is_directory(wallet_path)) ||
(path_type == fs::regular_file && fs::path(location.GetName()).filename() == location.GetName()))) {
- error_string = strprintf(
+ error_string = Untranslated(strprintf(
"Invalid -wallet path '%s'. -wallet path should point to a directory where wallet.dat and "
"database/log.?????????? files can be stored, a location where such a directory could be created, "
"or (for backwards compatibility) the name of an existing data file in -walletdir (%s)",
- location.GetName(), GetWalletDir());
+ location.GetName(), GetWalletDir()));
return false;
}
// Make sure that the wallet path doesn't clash with an existing wallet path
if (IsWalletLoaded(wallet_path)) {
- error_string = strprintf("Error loading wallet %s. Duplicate -wallet filename specified.", location.GetName());
+ error_string = Untranslated(strprintf("Error loading wallet %s. Duplicate -wallet filename specified.", location.GetName()));
return false;
}
@@ -3692,7 +3687,7 @@ bool CWallet::Verify(interfaces::Chain& chain, const WalletLocation& location, b
return false;
}
} catch (const fs::filesystem_error& e) {
- error_string = strprintf("Error loading wallet %s. %s", location.GetName(), fsbridge::get_filesystem_error_message(e));
+ error_string = Untranslated(strprintf("Error loading wallet %s. %s", location.GetName(), fsbridge::get_filesystem_error_message(e)));
return false;
}
@@ -3708,12 +3703,12 @@ bool CWallet::Verify(interfaces::Chain& chain, const WalletLocation& location, b
return WalletBatch::VerifyDatabaseFile(wallet_path, warnings, error_string);
}
-std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain, const WalletLocation& location, std::string& error, std::vector<std::string>& warnings, uint64_t wallet_creation_flags)
+std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain, const WalletLocation& location, bilingual_str& error, std::vector<bilingual_str>& warnings, uint64_t wallet_creation_flags)
{
const std::string walletFile = WalletDataFilePath(location.GetPath()).string();
// needed to restore wallet transaction meta data after -zapwallettxes
- std::vector<CWalletTx> vWtx;
+ std::list<CWalletTx> vWtx;
if (gArgs.GetBoolArg("-zapwallettxes", false)) {
chain.initMessage(_("Zapping all transactions from wallet...").translated);
@@ -3721,7 +3716,7 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
std::unique_ptr<CWallet> tempWallet = MakeUnique<CWallet>(&chain, location, WalletDatabase::Create(location.GetPath()));
DBErrors nZapWalletRet = tempWallet->ZapWalletTx(vWtx);
if (nZapWalletRet != DBErrors::LOAD_OK) {
- error = strprintf(_("Error loading %s: Wallet corrupted").translated, walletFile);
+ error = strprintf(_("Error loading %s: Wallet corrupted"), walletFile);
return nullptr;
}
}
@@ -3736,26 +3731,26 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
DBErrors nLoadWalletRet = walletInstance->LoadWallet(fFirstRun);
if (nLoadWalletRet != DBErrors::LOAD_OK) {
if (nLoadWalletRet == DBErrors::CORRUPT) {
- error = strprintf(_("Error loading %s: Wallet corrupted").translated, walletFile);
+ error = strprintf(_("Error loading %s: Wallet corrupted"), walletFile);
return nullptr;
}
else if (nLoadWalletRet == DBErrors::NONCRITICAL_ERROR)
{
warnings.push_back(strprintf(_("Error reading %s! All keys read correctly, but transaction data"
- " or address book entries might be missing or incorrect.").translated,
+ " or address book entries might be missing or incorrect."),
walletFile));
}
else if (nLoadWalletRet == DBErrors::TOO_NEW) {
- error = strprintf(_("Error loading %s: Wallet requires newer version of %s").translated, walletFile, PACKAGE_NAME);
+ error = strprintf(_("Error loading %s: Wallet requires newer version of %s"), walletFile, PACKAGE_NAME);
return nullptr;
}
else if (nLoadWalletRet == DBErrors::NEED_REWRITE)
{
- error = strprintf(_("Wallet needed to be rewritten: restart %s to complete").translated, PACKAGE_NAME);
+ error = strprintf(_("Wallet needed to be rewritten: restart %s to complete"), PACKAGE_NAME);
return nullptr;
}
else {
- error = strprintf(_("Error loading %s").translated, walletFile);
+ error = strprintf(_("Error loading %s"), walletFile);
return nullptr;
}
}
@@ -3781,7 +3776,7 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
// Legacy wallets need SetupGeneration here.
for (auto spk_man : walletInstance->GetActiveScriptPubKeyMans()) {
if (!spk_man->SetupGeneration()) {
- error = _("Unable to generate initial keys").translated;
+ error = _("Unable to generate initial keys");
return nullptr;
}
}
@@ -3791,36 +3786,36 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
walletInstance->chainStateFlushed(chain.getTipLocator());
} else if (wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS) {
// Make it impossible to disable private keys after creation
- error = strprintf(_("Error loading %s: Private keys can only be disabled during creation").translated, walletFile);
+ error = strprintf(_("Error loading %s: Private keys can only be disabled during creation"), walletFile);
return NULL;
} else if (walletInstance->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
for (auto spk_man : walletInstance->GetActiveScriptPubKeyMans()) {
if (spk_man->HavePrivateKeys()) {
- warnings.push_back(strprintf(_("Warning: Private keys detected in wallet {%s} with disabled private keys").translated, walletFile));
+ warnings.push_back(strprintf(_("Warning: Private keys detected in wallet {%s} with disabled private keys"), walletFile));
break;
}
}
}
if (!gArgs.GetArg("-addresstype", "").empty() && !ParseOutputType(gArgs.GetArg("-addresstype", ""), walletInstance->m_default_address_type)) {
- error = strprintf(_("Unknown address type '%s'").translated, gArgs.GetArg("-addresstype", ""));
+ error = strprintf(_("Unknown address type '%s'"), gArgs.GetArg("-addresstype", ""));
return nullptr;
}
if (!gArgs.GetArg("-changetype", "").empty() && !ParseOutputType(gArgs.GetArg("-changetype", ""), walletInstance->m_default_change_type)) {
- error = strprintf(_("Unknown change type '%s'").translated, gArgs.GetArg("-changetype", ""));
+ error = strprintf(_("Unknown change type '%s'"), gArgs.GetArg("-changetype", ""));
return nullptr;
}
if (gArgs.IsArgSet("-mintxfee")) {
CAmount n = 0;
if (!ParseMoney(gArgs.GetArg("-mintxfee", ""), n) || 0 == n) {
- error = AmountErrMsg("mintxfee", gArgs.GetArg("-mintxfee", "")).translated;
+ error = AmountErrMsg("mintxfee", gArgs.GetArg("-mintxfee", ""));
return nullptr;
}
if (n > HIGH_TX_FEE_PER_KB) {
- warnings.push_back(AmountHighWarn("-mintxfee").translated + " " +
- _("This is the minimum transaction fee you pay on every transaction.").translated);
+ warnings.push_back(AmountHighWarn("-mintxfee") + Untranslated(" ") +
+ _("This is the minimum transaction fee you pay on every transaction."));
}
walletInstance->m_min_fee = CFeeRate(n);
}
@@ -3828,12 +3823,12 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
if (gArgs.IsArgSet("-fallbackfee")) {
CAmount nFeePerK = 0;
if (!ParseMoney(gArgs.GetArg("-fallbackfee", ""), nFeePerK)) {
- error = strprintf(_("Invalid amount for -fallbackfee=<amount>: '%s'").translated, gArgs.GetArg("-fallbackfee", ""));
+ error = strprintf(_("Invalid amount for -fallbackfee=<amount>: '%s'"), gArgs.GetArg("-fallbackfee", ""));
return nullptr;
}
if (nFeePerK > HIGH_TX_FEE_PER_KB) {
- warnings.push_back(AmountHighWarn("-fallbackfee").translated + " " +
- _("This is the transaction fee you may pay when fee estimates are not available.").translated);
+ warnings.push_back(AmountHighWarn("-fallbackfee") + Untranslated(" ") +
+ _("This is the transaction fee you may pay when fee estimates are not available."));
}
walletInstance->m_fallback_fee = CFeeRate(nFeePerK);
}
@@ -3843,28 +3838,28 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
if (gArgs.IsArgSet("-discardfee")) {
CAmount nFeePerK = 0;
if (!ParseMoney(gArgs.GetArg("-discardfee", ""), nFeePerK)) {
- error = strprintf(_("Invalid amount for -discardfee=<amount>: '%s'").translated, gArgs.GetArg("-discardfee", ""));
+ error = strprintf(_("Invalid amount for -discardfee=<amount>: '%s'"), gArgs.GetArg("-discardfee", ""));
return nullptr;
}
if (nFeePerK > HIGH_TX_FEE_PER_KB) {
- warnings.push_back(AmountHighWarn("-discardfee").translated + " " +
- _("This is the transaction fee you may discard if change is smaller than dust at this level").translated);
+ warnings.push_back(AmountHighWarn("-discardfee") + Untranslated(" ") +
+ _("This is the transaction fee you may discard if change is smaller than dust at this level"));
}
walletInstance->m_discard_rate = CFeeRate(nFeePerK);
}
if (gArgs.IsArgSet("-paytxfee")) {
CAmount nFeePerK = 0;
if (!ParseMoney(gArgs.GetArg("-paytxfee", ""), nFeePerK)) {
- error = AmountErrMsg("paytxfee", gArgs.GetArg("-paytxfee", "")).translated;
+ error = AmountErrMsg("paytxfee", gArgs.GetArg("-paytxfee", ""));
return nullptr;
}
if (nFeePerK > HIGH_TX_FEE_PER_KB) {
- warnings.push_back(AmountHighWarn("-paytxfee").translated + " " +
- _("This is the transaction fee you will pay if you send a transaction.").translated);
+ warnings.push_back(AmountHighWarn("-paytxfee") + Untranslated(" ") +
+ _("This is the transaction fee you will pay if you send a transaction."));
}
walletInstance->m_pay_tx_fee = CFeeRate(nFeePerK, 1000);
if (walletInstance->m_pay_tx_fee < chain.relayMinFee()) {
- error = strprintf(_("Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)").translated,
+ error = strprintf(_("Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)"),
gArgs.GetArg("-paytxfee", ""), chain.relayMinFee().ToString());
return nullptr;
}
@@ -3873,23 +3868,23 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
if (gArgs.IsArgSet("-maxtxfee")) {
CAmount nMaxFee = 0;
if (!ParseMoney(gArgs.GetArg("-maxtxfee", ""), nMaxFee)) {
- error = AmountErrMsg("maxtxfee", gArgs.GetArg("-maxtxfee", "")).translated;
+ error = AmountErrMsg("maxtxfee", gArgs.GetArg("-maxtxfee", ""));
return nullptr;
}
if (nMaxFee > HIGH_MAX_TX_FEE) {
- warnings.push_back(_("-maxtxfee is set very high! Fees this large could be paid on a single transaction.").translated);
+ warnings.push_back(_("-maxtxfee is set very high! Fees this large could be paid on a single transaction."));
}
if (CFeeRate(nMaxFee, 1000) < chain.relayMinFee()) {
- error = strprintf(_("Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)").translated,
- gArgs.GetArg("-maxtxfee", ""), chain.relayMinFee().ToString());
+ error = strprintf(_("Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"),
+ gArgs.GetArg("-maxtxfee", ""), chain.relayMinFee().ToString());
return nullptr;
}
walletInstance->m_default_max_tx_fee = nMaxFee;
}
if (chain.relayMinFee().GetFeePerK() > HIGH_TX_FEE_PER_KB) {
- warnings.push_back(AmountHighWarn("-minrelaytxfee").translated + " " +
- _("The wallet will avoid paying less than the minimum relay fee.").translated);
+ warnings.push_back(AmountHighWarn("-minrelaytxfee") + Untranslated(" ") +
+ _("The wallet will avoid paying less than the minimum relay fee."));
}
walletInstance->m_confirm_target = gArgs.GetArg("-txconfirmtarget", DEFAULT_TX_CONFIRM_TARGET);
@@ -3949,7 +3944,7 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
}
if (rescan_height != block_height) {
- error = _("Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)").translated;
+ error = _("Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)");
return nullptr;
}
}
@@ -3974,7 +3969,7 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
{
WalletRescanReserver reserver(*walletInstance);
if (!reserver.reserve() || (ScanResult::SUCCESS != walletInstance->ScanForWalletTransactions(chain.getBlockHash(rescan_height), rescan_height, {} /* max height */, reserver, true /* update */).status)) {
- error = _("Failed to rescan the wallet during initialization").translated;
+ error = _("Failed to rescan the wallet during initialization");
return nullptr;
}
}
@@ -4034,7 +4029,7 @@ const CAddressBookData* CWallet::FindAddressBookEntry(const CTxDestination& dest
return &address_book_it->second;
}
-bool CWallet::UpgradeWallet(int version, std::string& error, std::vector<std::string>& warnings)
+bool CWallet::UpgradeWallet(int version, bilingual_str& error, std::vector<bilingual_str>& warnings)
{
int prev_version = GetVersion();
int nMaxVersion = version;
@@ -4043,12 +4038,12 @@ bool CWallet::UpgradeWallet(int version, std::string& error, std::vector<std::st
WalletLogPrintf("Performing wallet upgrade to %i\n", FEATURE_LATEST);
nMaxVersion = FEATURE_LATEST;
SetMinVersion(FEATURE_LATEST); // permanently upgrade the wallet immediately
- }
- else
+ } else {
WalletLogPrintf("Allowing wallet upgrade up to %i\n", nMaxVersion);
+ }
if (nMaxVersion < GetVersion())
{
- error = _("Cannot downgrade wallet").translated;
+ error = _("Cannot downgrade wallet");
return false;
}
SetMaxVersion(nMaxVersion);
@@ -4058,7 +4053,7 @@ bool CWallet::UpgradeWallet(int version, std::string& error, std::vector<std::st
// Do not upgrade versions to any version between HD_SPLIT and FEATURE_PRE_SPLIT_KEYPOOL unless already supporting HD_SPLIT
int max_version = GetVersion();
if (!CanSupportFeature(FEATURE_HD_SPLIT) && max_version >= FEATURE_HD_SPLIT && max_version < FEATURE_PRE_SPLIT_KEYPOOL) {
- error = _("Cannot upgrade a non HD split wallet without upgrading to support pre split keypool. Please use version 169900 or no version specified.").translated;
+ error = _("Cannot upgrade a non HD split wallet without upgrading to support pre split keypool. Please use version 169900 or no version specified.");
return false;
}
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 72b3cf1fb8..8f624c25d7 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -40,6 +40,8 @@
using LoadWalletFn = std::function<void(std::unique_ptr<interfaces::Wallet> wallet)>;
+struct bilingual_str;
+
//! Explicitly unload and delete the wallet.
//! Blocks the current thread after signaling the unload intent so that all
//! wallet clients release the wallet.
@@ -52,7 +54,7 @@ bool RemoveWallet(const std::shared_ptr<CWallet>& wallet);
bool HasWallets();
std::vector<std::shared_ptr<CWallet>> GetWallets();
std::shared_ptr<CWallet> GetWallet(const std::string& name);
-std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const WalletLocation& location, std::string& error, std::vector<std::string>& warnings);
+std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const WalletLocation& location, bilingual_str& error, std::vector<bilingual_str>& warnings);
std::unique_ptr<interfaces::Handler> HandleLoadWallet(LoadWalletFn load_wallet);
enum class WalletCreationStatus {
@@ -61,7 +63,7 @@ enum class WalletCreationStatus {
ENCRYPTION_FAILED
};
-WalletCreationStatus CreateWallet(interfaces::Chain& chain, const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, std::string& error, std::vector<std::string>& warnings, std::shared_ptr<CWallet>& result);
+WalletCreationStatus CreateWallet(interfaces::Chain& chain, const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings, std::shared_ptr<CWallet>& result);
//! -paytxfee default
constexpr CAmount DEFAULT_PAY_TX_FEE = 0;
@@ -338,15 +340,15 @@ public:
mutable bool fInMempool;
mutable CAmount nChangeCached;
- CWalletTx(const CWallet* pwalletIn, CTransactionRef arg)
- : tx(std::move(arg))
+ CWalletTx(const CWallet* wallet, CTransactionRef arg)
+ : pwallet(wallet),
+ tx(std::move(arg))
{
- Init(pwalletIn);
+ Init();
}
- void Init(const CWallet* pwalletIn)
+ void Init()
{
- pwallet = pwalletIn;
mapValue.clear();
vOrderForm.clear();
fTimeReceivedIsTxTime = false;
@@ -414,7 +416,7 @@ public:
template<typename Stream>
void Unserialize(Stream& s)
{
- Init(nullptr);
+ Init();
std::vector<uint256> dummy_vector1; //!< Used to be vMerkleBranch
std::vector<CMerkleTx> dummy_vector2; //!< Used to be vtxPrev
@@ -463,12 +465,6 @@ public:
m_is_cache_empty = true;
}
- void BindWallet(CWallet *pwalletIn)
- {
- pwallet = pwalletIn;
- MarkDirty();
- }
-
//! filter decides which addresses will count towards the debit
CAmount GetDebit(const isminefilter& filter) const;
CAmount GetCredit(const isminefilter& filter) const;
@@ -553,6 +549,12 @@ public:
const uint256& GetHash() const { return tx->GetHash(); }
bool IsCoinBase() const { return tx->IsCoinBase(); }
bool IsImmatureCoinBase() const;
+
+ // Disable copying of CWalletTx objects to prevent bugs where instances get
+ // copied in and out of the mapWallet map, and fields are updated in the
+ // wrong copy.
+ CWalletTx(CWalletTx const &) = delete;
+ void operator=(CWalletTx const &x) = delete;
};
class COutput
@@ -886,8 +888,17 @@ public:
DBErrors ReorderTransactions();
void MarkDirty();
- bool AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose=true);
- void LoadToWallet(CWalletTx& wtxIn) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+
+ //! Callback for updating transaction metadata in mapWallet.
+ //!
+ //! @param wtx - reference to mapWallet transaction to update
+ //! @param new_tx - true if wtx is newly inserted, false if it previously existed
+ //!
+ //! @return true if wtx is changed and needs to be saved to disk, otherwise false
+ using UpdateWalletTxFn = std::function<bool(CWalletTx& wtx, bool new_tx)>;
+
+ CWalletTx* AddToWallet(CTransactionRef tx, const CWalletTx::Confirmation& confirm, const UpdateWalletTxFn& update_wtx=nullptr, bool fFlushOnClose=true);
+ bool LoadToWallet(const uint256& hash, const UpdateWalletTxFn& fill_wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
void transactionAddedToMempool(const CTransactionRef& tx) override;
void blockConnected(const CBlock& block, int height) override;
void blockDisconnected(const CBlock& block, int height) override;
@@ -930,7 +941,7 @@ public:
* Insert additional inputs into the transaction by
* calling CreateTransaction();
*/
- bool FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nChangePosInOut, std::string& strFailReason, bool lockUnspents, const std::set<int>& setSubtractFeeFromOutputs, CCoinControl);
+ bool FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nChangePosInOut, bilingual_str& error, bool lockUnspents, const std::set<int>& setSubtractFeeFromOutputs, CCoinControl);
// Fetch the inputs and sign with SIGHASH_ALL.
bool SignTransaction(CMutableTransaction& tx) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
// Sign the tx given the input coins and sighash.
@@ -961,7 +972,7 @@ public:
* selected by SelectCoins(); Also create the change output, when needed
* @note passing nChangePosInOut as -1 will result in setting a random position
*/
- bool CreateTransaction(const std::vector<CRecipient>& vecSend, CTransactionRef& tx, CAmount& nFeeRet, int& nChangePosInOut, std::string& strFailReason, const CCoinControl& coin_control, bool sign = true);
+ bool CreateTransaction(const std::vector<CRecipient>& vecSend, CTransactionRef& tx, CAmount& nFeeRet, int& nChangePosInOut, bilingual_str& error, const CCoinControl& coin_control, bool sign = true);
/**
* Submit the transaction to the node's mempool and then relay to peers.
* Should be called after CreateTransaction unless you want to abort
@@ -1048,7 +1059,7 @@ public:
void chainStateFlushed(const CBlockLocator& loc) override;
DBErrors LoadWallet(bool& fFirstRunRet);
- DBErrors ZapWalletTx(std::vector<CWalletTx>& vWtx);
+ DBErrors ZapWalletTx(std::list<CWalletTx>& vWtx);
DBErrors ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256>& vHashOut) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
bool SetAddressBook(const CTxDestination& address, const std::string& strName, const std::string& purpose);
@@ -1124,10 +1135,10 @@ public:
bool MarkReplaced(const uint256& originalHash, const uint256& newHash);
//! Verify wallet naming and perform salvage on the wallet if required
- static bool Verify(interfaces::Chain& chain, const WalletLocation& location, bool salvage_wallet, std::string& error_string, std::vector<std::string>& warnings);
+ static bool Verify(interfaces::Chain& chain, const WalletLocation& location, bool salvage_wallet, bilingual_str& error_string, std::vector<bilingual_str>& warnings);
/* Initializes the wallet, returns a new CWallet instance or a null pointer in case of an error */
- static std::shared_ptr<CWallet> CreateWalletFromFile(interfaces::Chain& chain, const WalletLocation& location, std::string& error, std::vector<std::string>& warnings, uint64_t wallet_creation_flags = 0);
+ static std::shared_ptr<CWallet> CreateWalletFromFile(interfaces::Chain& chain, const WalletLocation& location, bilingual_str& error, std::vector<bilingual_str>& warnings, uint64_t wallet_creation_flags = 0);
/**
* Wallet post-init setup
@@ -1180,7 +1191,7 @@ public:
};
/** Upgrade the wallet */
- bool UpgradeWallet(int version, std::string& error, std::vector<std::string>& warnings);
+ bool UpgradeWallet(int version, bilingual_str& error, std::vector<bilingual_str>& warnings);
//! Returns all unique ScriptPubKeyMans in m_internal_spk_managers and m_external_spk_managers
std::set<ScriptPubKeyMan*> GetActiveScriptPubKeyMans() const;
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index 79316ca3e7..98597bdb0f 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -272,36 +272,43 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
} else if (strType == DBKeys::TX) {
uint256 hash;
ssKey >> hash;
- CWalletTx wtx(nullptr /* pwallet */, MakeTransactionRef());
- ssValue >> wtx;
- if (wtx.GetHash() != hash)
- return false;
+ // LoadToWallet call below creates a new CWalletTx that fill_wtx
+ // callback fills with transaction metadata.
+ auto fill_wtx = [&](CWalletTx& wtx, bool new_tx) {
+ assert(new_tx);
+ ssValue >> wtx;
+ if (wtx.GetHash() != hash)
+ return false;
- // Undo serialize changes in 31600
- if (31404 <= wtx.fTimeReceivedIsTxTime && wtx.fTimeReceivedIsTxTime <= 31703)
- {
- if (!ssValue.empty())
- {
- char fTmp;
- char fUnused;
- std::string unused_string;
- ssValue >> fTmp >> fUnused >> unused_string;
- strErr = strprintf("LoadWallet() upgrading tx ver=%d %d %s",
- wtx.fTimeReceivedIsTxTime, fTmp, hash.ToString());
- wtx.fTimeReceivedIsTxTime = fTmp;
- }
- else
+ // Undo serialize changes in 31600
+ if (31404 <= wtx.fTimeReceivedIsTxTime && wtx.fTimeReceivedIsTxTime <= 31703)
{
- strErr = strprintf("LoadWallet() repairing tx ver=%d %s", wtx.fTimeReceivedIsTxTime, hash.ToString());
- wtx.fTimeReceivedIsTxTime = 0;
+ if (!ssValue.empty())
+ {
+ char fTmp;
+ char fUnused;
+ std::string unused_string;
+ ssValue >> fTmp >> fUnused >> unused_string;
+ strErr = strprintf("LoadWallet() upgrading tx ver=%d %d %s",
+ wtx.fTimeReceivedIsTxTime, fTmp, hash.ToString());
+ wtx.fTimeReceivedIsTxTime = fTmp;
+ }
+ else
+ {
+ strErr = strprintf("LoadWallet() repairing tx ver=%d %s", wtx.fTimeReceivedIsTxTime, hash.ToString());
+ wtx.fTimeReceivedIsTxTime = 0;
+ }
+ wss.vWalletUpgrade.push_back(hash);
}
- wss.vWalletUpgrade.push_back(hash);
- }
- if (wtx.nOrderPos == -1)
- wss.fAnyUnordered = true;
+ if (wtx.nOrderPos == -1)
+ wss.fAnyUnordered = true;
- pwallet->LoadToWallet(wtx);
+ return true;
+ };
+ if (!pwallet->LoadToWallet(hash, fill_wtx)) {
+ return false;
+ }
} else if (strType == DBKeys::WATCHS) {
wss.nWatchKeys++;
CScript script;
@@ -731,7 +738,7 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
return result;
}
-DBErrors WalletBatch::FindWalletTx(std::vector<uint256>& vTxHash, std::vector<CWalletTx>& vWtx)
+DBErrors WalletBatch::FindWalletTx(std::vector<uint256>& vTxHash, std::list<CWalletTx>& vWtx)
{
DBErrors result = DBErrors::LOAD_OK;
@@ -769,12 +776,9 @@ DBErrors WalletBatch::FindWalletTx(std::vector<uint256>& vTxHash, std::vector<CW
if (strType == DBKeys::TX) {
uint256 hash;
ssKey >> hash;
-
- CWalletTx wtx(nullptr /* pwallet */, MakeTransactionRef());
- ssValue >> wtx;
-
vTxHash.push_back(hash);
- vWtx.push_back(wtx);
+ vWtx.emplace_back(nullptr /* wallet */, nullptr /* tx */);
+ ssValue >> vWtx.back();
}
}
pcursor->close();
@@ -793,7 +797,7 @@ DBErrors WalletBatch::ZapSelectTx(std::vector<uint256>& vTxHashIn, std::vector<u
{
// build list of wallet TXs and hashes
std::vector<uint256> vTxHash;
- std::vector<CWalletTx> vWtx;
+ std::list<CWalletTx> vWtx;
DBErrors err = FindWalletTx(vTxHash, vWtx);
if (err != DBErrors::LOAD_OK) {
return err;
@@ -827,7 +831,7 @@ DBErrors WalletBatch::ZapSelectTx(std::vector<uint256>& vTxHashIn, std::vector<u
return DBErrors::LOAD_OK;
}
-DBErrors WalletBatch::ZapWalletTx(std::vector<CWalletTx>& vWtx)
+DBErrors WalletBatch::ZapWalletTx(std::list<CWalletTx>& vWtx)
{
// build list of wallet TXs
std::vector<uint256> vTxHash;
@@ -913,12 +917,12 @@ bool WalletBatch::RecoverKeysOnlyFilter(void *callbackData, CDataStream ssKey, C
return true;
}
-bool WalletBatch::VerifyEnvironment(const fs::path& wallet_path, std::string& errorStr)
+bool WalletBatch::VerifyEnvironment(const fs::path& wallet_path, bilingual_str& errorStr)
{
return BerkeleyBatch::VerifyEnvironment(wallet_path, errorStr);
}
-bool WalletBatch::VerifyDatabaseFile(const fs::path& wallet_path, std::vector<std::string>& warnings, std::string& errorStr)
+bool WalletBatch::VerifyDatabaseFile(const fs::path& wallet_path, std::vector<bilingual_str>& warnings, bilingual_str& errorStr)
{
return BerkeleyBatch::VerifyDatabaseFile(wallet_path, warnings, errorStr, WalletBatch::Recover);
}
diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h
index 2701481c58..e2bf229c68 100644
--- a/src/wallet/walletdb.h
+++ b/src/wallet/walletdb.h
@@ -260,8 +260,8 @@ public:
bool WriteActiveScriptPubKeyMan(uint8_t type, const uint256& id, bool internal);
DBErrors LoadWallet(CWallet* pwallet);
- DBErrors FindWalletTx(std::vector<uint256>& vTxHash, std::vector<CWalletTx>& vWtx);
- DBErrors ZapWalletTx(std::vector<CWalletTx>& vWtx);
+ DBErrors FindWalletTx(std::vector<uint256>& vTxHash, std::list<CWalletTx>& vWtx);
+ DBErrors ZapWalletTx(std::list<CWalletTx>& vWtx);
DBErrors ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256>& vHashOut);
/* Try to (very carefully!) recover wallet database (with a possible key type filter) */
static bool Recover(const fs::path& wallet_path, void *callbackDataIn, bool (*recoverKVcallback)(void* callbackData, CDataStream ssKey, CDataStream ssValue), std::string& out_backup_filename);
@@ -272,9 +272,9 @@ public:
/* Function to determine if a certain KV/key-type is a key (cryptographical key) type */
static bool IsKeyType(const std::string& strType);
/* verifies the database environment */
- static bool VerifyEnvironment(const fs::path& wallet_path, std::string& errorStr);
+ static bool VerifyEnvironment(const fs::path& wallet_path, bilingual_str& errorStr);
/* verifies the database file */
- static bool VerifyDatabaseFile(const fs::path& wallet_path, std::vector<std::string>& warnings, std::string& errorStr);
+ static bool VerifyDatabaseFile(const fs::path& wallet_path, std::vector<bilingual_str>& warnings, bilingual_str& errorStr);
//! write the hdchain model (external chain child index counter)
bool WriteHDChain(const CHDChain& chain);
diff --git a/src/wallet/wallettool.cpp b/src/wallet/wallettool.cpp
index 65643669c2..522efaa884 100644
--- a/src/wallet/wallettool.cpp
+++ b/src/wallet/wallettool.cpp
@@ -4,6 +4,7 @@
#include <fs.h>
#include <util/system.h>
+#include <util/translation.h>
#include <wallet/wallet.h>
#include <wallet/walletutil.h>
@@ -117,9 +118,9 @@ bool ExecuteWalletToolFunc(const std::string& command, const std::string& name)
tfm::format(std::cerr, "Error: no wallet file at %s\n", name);
return false;
}
- std::string error;
+ bilingual_str error;
if (!WalletBatch::VerifyEnvironment(path, error)) {
- tfm::format(std::cerr, "Error loading %s. Is wallet being used by other process?\n", name);
+ tfm::format(std::cerr, "%s\nError loading %s. Is wallet being used by other process?\n", error.original, name);
return false;
}
std::shared_ptr<CWallet> wallet_instance = LoadWallet(name, path);
diff --git a/src/wallet/walletutil.h b/src/wallet/walletutil.h
index d7e07ed04c..599b1a9f5a 100644
--- a/src/wallet/walletutil.h
+++ b/src/wallet/walletutil.h
@@ -92,10 +92,10 @@ class WalletDescriptor
{
public:
std::shared_ptr<Descriptor> descriptor;
- uint64_t creation_time;
- int32_t range_start; // First item in range; start of range, inclusive, i.e. [range_start, range_end). This never changes.
- int32_t range_end; // Item after the last; end of range, exclusive, i.e. [range_start, range_end). This will increment with each TopUp()
- int32_t next_index; // Position of the next item to generate
+ uint64_t creation_time = 0;
+ int32_t range_start = 0; // First item in range; start of range, inclusive, i.e. [range_start, range_end). This never changes.
+ int32_t range_end = 0; // Item after the last; end of range, exclusive, i.e. [range_start, range_end). This will increment with each TopUp()
+ int32_t next_index = 0; // Position of the next item to generate
DescriptorCache cache;
ADD_SERIALIZE_METHODS;
diff --git a/test/functional/feature_backwards_compatibility.py b/test/functional/feature_backwards_compatibility.py
index e69a217fad..9cff79a42c 100755
--- a/test/functional/feature_backwards_compatibility.py
+++ b/test/functional/feature_backwards_compatibility.py
@@ -302,9 +302,9 @@ class BackwardsCompatibilityTest(BitcoinTestFramework):
node_v17.rpc.createwallet(wallet_name="u1_v17")
wallet = node_v17.get_wallet_rpc("u1_v17")
address = wallet.getnewaddress("bech32")
- info = wallet.getaddressinfo(address)
- hdkeypath = info["hdkeypath"]
- pubkey = info["pubkey"]
+ v17_info = wallet.getaddressinfo(address)
+ hdkeypath = v17_info["hdkeypath"]
+ pubkey = v17_info["pubkey"]
# Copy the 0.17 wallet to the last Bitcoin Core version and open it:
node_v17.unloadwallet("u1_v17")
@@ -318,6 +318,18 @@ class BackwardsCompatibilityTest(BitcoinTestFramework):
descriptor = "wpkh([" + info["hdmasterfingerprint"] + hdkeypath[1:] + "]" + pubkey + ")"
assert_equal(info["desc"], descsum_create(descriptor))
+ # Now copy that same wallet back to 0.17 to make sure no automatic upgrade breaks it
+ node_master.unloadwallet("u1_v17")
+ shutil.rmtree(os.path.join(node_v17_wallets_dir, "u1_v17"))
+ shutil.copytree(
+ os.path.join(node_master_wallets_dir, "u1_v17"),
+ os.path.join(node_v17_wallets_dir, "u1_v17")
+ )
+ node_v17.loadwallet("u1_v17")
+ wallet = node_v17.get_wallet_rpc("u1_v17")
+ info = wallet.getaddressinfo(address)
+ assert_equal(info, v17_info)
+
# Copy the 0.19 wallet to the last Bitcoin Core version and open it:
shutil.copytree(
os.path.join(node_v19_wallets_dir, "w1_v19"),
@@ -327,5 +339,16 @@ class BackwardsCompatibilityTest(BitcoinTestFramework):
wallet = node_master.get_wallet_rpc("w1_v19")
assert wallet.getaddressinfo(address_18075)["solvable"]
+ # Now copy that same wallet back to 0.19 to make sure no automatic upgrade breaks it
+ node_master.unloadwallet("w1_v19")
+ shutil.rmtree(os.path.join(node_v19_wallets_dir, "w1_v19"))
+ shutil.copytree(
+ os.path.join(node_master_wallets_dir, "w1_v19"),
+ os.path.join(node_v19_wallets_dir, "w1_v19")
+ )
+ node_v19.loadwallet("w1_v19")
+ wallet = node_v19.get_wallet_rpc("w1_v19")
+ assert wallet.getaddressinfo(address_18075)["solvable"]
+
if __name__ == '__main__':
BackwardsCompatibilityTest().main()
diff --git a/test/functional/p2p_leak.py b/test/functional/p2p_leak.py
index 7f7430d04e..157af68203 100755
--- a/test/functional/p2p_leak.py
+++ b/test/functional/p2p_leak.py
@@ -141,12 +141,11 @@ class P2PLeakTest(BitcoinTestFramework):
assert no_verack_idlenode.unexpected_msg == False
self.log.info('Check that the version message does not leak the local address of the node')
- time_begin = int(time.time())
p2p_version_store = self.nodes[0].add_p2p_connection(P2PVersionStore())
- time_end = time.time()
ver = p2p_version_store.version_received
- assert_greater_than_or_equal(ver.nTime, time_begin)
- assert_greater_than_or_equal(time_end, ver.nTime)
+ # Check that received time is within one hour of now
+ assert_greater_than_or_equal(ver.nTime, time.time() - 3600)
+ assert_greater_than_or_equal(time.time() + 3600, ver.nTime)
assert_equal(ver.addrFrom.port, 0)
assert_equal(ver.addrFrom.ip, '0.0.0.0')
assert_equal(ver.nStartingHeight, 201)
diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py
index dbdce6552a..6fb0fec32b 100755
--- a/test/functional/p2p_segwit.py
+++ b/test/functional/p2p_segwit.py
@@ -1896,12 +1896,12 @@ class SegWitTest(BitcoinTestFramework):
def test_upgrade_after_activation(self):
"""Test the behavior of starting up a segwit-aware node after the softfork has activated."""
- # Restart with the new binary
self.stop_node(2)
self.start_node(2, extra_args=["-segwitheight={}".format(SEGWIT_HEIGHT)])
connect_nodes(self.nodes[0], 2)
- self.sync_blocks()
+ # We reconnect more than 100 blocks, give it plenty of time
+ self.sync_blocks(timeout=240)
# Make sure that this peer thinks segwit has activated.
assert softfork_active(self.nodes[2], 'segwit')
diff --git a/test/functional/tool_wallet.py b/test/functional/tool_wallet.py
index b3d496dd51..039ce7daee 100755
--- a/test/functional/tool_wallet.py
+++ b/test/functional/tool_wallet.py
@@ -15,6 +15,7 @@ from test_framework.util import assert_equal
BUFFER_SIZE = 16 * 1024
+
class ToolWalletTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
@@ -48,7 +49,7 @@ class ToolWalletTest(BitcoinTestFramework):
h = hashlib.sha1()
mv = memoryview(bytearray(BUFFER_SIZE))
with open(self.wallet_path, 'rb', buffering=0) as f:
- for n in iter(lambda : f.readinto(mv), 0):
+ for n in iter(lambda: f.readinto(mv), 0):
h.update(mv[:n])
return h.hexdigest()
@@ -69,7 +70,12 @@ class ToolWalletTest(BitcoinTestFramework):
self.assert_raises_tool_error('Invalid command: help', 'help')
self.assert_raises_tool_error('Error: two methods provided (info and create). Only one method should be provided.', 'info', 'create')
self.assert_raises_tool_error('Error parsing command line arguments: Invalid parameter -foo', '-foo')
- self.assert_raises_tool_error('Error loading wallet.dat. Is wallet being used by other process?', '-wallet=wallet.dat', 'info')
+ self.assert_raises_tool_error(
+ 'Error initializing wallet database environment "{}"!\nError loading wallet.dat. Is wallet being used by other process?'
+ .format(os.path.join(self.nodes[0].datadir, self.chain, 'wallets')),
+ '-wallet=wallet.dat',
+ 'info',
+ )
self.assert_raises_tool_error('Error: no wallet file at nonexistent.dat', '-wallet=nonexistent.dat', 'info')
def test_tool_wallet_info(self):
@@ -84,7 +90,7 @@ class ToolWalletTest(BitcoinTestFramework):
#
# self.log.debug('Setting wallet file permissions to 400 (read-only)')
# os.chmod(self.wallet_path, stat.S_IRUSR)
- # assert(self.wallet_permissions() in ['400', '666']) # Sanity check. 666 because Appveyor.
+ # assert self.wallet_permissions() in ['400', '666'] # Sanity check. 666 because Appveyor.
# shasum_before = self.wallet_shasum()
timestamp_before = self.wallet_timestamp()
self.log.debug('Wallet file timestamp before calling info: {}'.format(timestamp_before))
@@ -103,7 +109,7 @@ class ToolWalletTest(BitcoinTestFramework):
self.log_wallet_timestamp_comparison(timestamp_before, timestamp_after)
self.log.debug('Setting wallet file permissions back to 600 (read/write)')
os.chmod(self.wallet_path, stat.S_IRUSR | stat.S_IWUSR)
- assert(self.wallet_permissions() in ['600', '666']) # Sanity check. 666 because Appveyor.
+ assert self.wallet_permissions() in ['600', '666'] # Sanity check. 666 because Appveyor.
#
# TODO: Wallet tool info should not write to the wallet file.
# The following lines should be uncommented and the tests still succeed:
diff --git a/test/functional/wallet_bumpfee.py b/test/functional/wallet_bumpfee.py
index 9ba23db42d..27197e3b6d 100755
--- a/test/functional/wallet_bumpfee.py
+++ b/test/functional/wallet_bumpfee.py
@@ -300,7 +300,7 @@ def test_maxtxfee_fails(self, rbf_node, dest_address):
self.restart_node(1, ['-maxtxfee=0.000025'] + self.extra_args[1])
rbf_node.walletpassphrase(WALLET_PASSPHRASE, WALLET_PASSPHRASE_TIMEOUT)
rbfid = spend_one_input(rbf_node, dest_address)
- assert_raises_rpc_error(-4, "Unable to create transaction: Fee exceeds maximum configured by -maxtxfee", rbf_node.bumpfee, rbfid)
+ assert_raises_rpc_error(-4, "Unable to create transaction. Fee exceeds maximum configured by -maxtxfee", rbf_node.bumpfee, rbfid)
self.restart_node(1, self.extra_args[1])
rbf_node.walletpassphrase(WALLET_PASSPHRASE, WALLET_PASSPHRASE_TIMEOUT)
@@ -517,7 +517,7 @@ def test_no_more_inputs_fails(self, rbf_node, dest_address):
rbf_node.generatetoaddress(1, dest_address)
# spend all funds, no change output
rbfid = rbf_node.sendtoaddress(rbf_node.getnewaddress(), rbf_node.getbalance(), "", "", True)
- assert_raises_rpc_error(-4, "Unable to create transaction: Insufficient funds", rbf_node.bumpfee, rbfid)
+ assert_raises_rpc_error(-4, "Unable to create transaction. Insufficient funds", rbf_node.bumpfee, rbfid)
if __name__ == "__main__":
diff --git a/test/functional/wallet_multiwallet.py b/test/functional/wallet_multiwallet.py
index c569416292..580a61f9f3 100755
--- a/test/functional/wallet_multiwallet.py
+++ b/test/functional/wallet_multiwallet.py
@@ -227,10 +227,10 @@ class MultiWalletTest(BitcoinTestFramework):
assert_raises_rpc_error(-18, 'Wallet wallets not found.', self.nodes[0].loadwallet, 'wallets')
# Fail to load duplicate wallets
- assert_raises_rpc_error(-4, 'Wallet file verification failed: Error loading wallet w1. Duplicate -wallet filename specified.', self.nodes[0].loadwallet, wallet_names[0])
+ assert_raises_rpc_error(-4, 'Wallet file verification failed. Error loading wallet w1. Duplicate -wallet filename specified.', self.nodes[0].loadwallet, wallet_names[0])
# Fail to load duplicate wallets by different ways (directory and filepath)
- assert_raises_rpc_error(-4, "Wallet file verification failed: Error loading wallet wallet.dat. Duplicate -wallet filename specified.", self.nodes[0].loadwallet, 'wallet.dat')
+ assert_raises_rpc_error(-4, "Wallet file verification failed. Error loading wallet wallet.dat. Duplicate -wallet filename specified.", self.nodes[0].loadwallet, 'wallet.dat')
# Fail to load if one wallet is a copy of another
assert_raises_rpc_error(-4, "BerkeleyBatch: Can't open database w8_copy (duplicates fileid", self.nodes[0].loadwallet, 'w8_copy')
@@ -240,7 +240,7 @@ class MultiWalletTest(BitcoinTestFramework):
# Fail to load if wallet file is a symlink
- assert_raises_rpc_error(-4, "Wallet file verification failed: Invalid -wallet path 'w8_symlink'", self.nodes[0].loadwallet, 'w8_symlink')
+ assert_raises_rpc_error(-4, "Wallet file verification failed. Invalid -wallet path 'w8_symlink'", self.nodes[0].loadwallet, 'w8_symlink')
# Fail to load if a directory is specified that doesn't contain a wallet
os.mkdir(wallet_dir('empty_wallet_dir'))
diff --git a/test/lint/lint-shell.sh b/test/lint/lint-shell.sh
index 2bb76ec286..563e076b35 100755
--- a/test/lint/lint-shell.sh
+++ b/test/lint/lint-shell.sh
@@ -35,8 +35,9 @@ if ! command -v shellcheck > /dev/null; then
exit $EXIT_CODE
fi
+SHELLCHECK_CMD=(shellcheck --external-sources --check-sourced)
EXCLUDE="--exclude=$(IFS=','; echo "${disabled[*]}")"
-if ! shellcheck "$EXCLUDE" $(git ls-files -- '*.sh' | grep -vE 'src/(leveldb|secp256k1|univalue)/'); then
+if ! "${SHELLCHECK_CMD[@]}" "$EXCLUDE" $(git ls-files -- '*.sh' | grep -vE 'src/(leveldb|secp256k1|univalue)/'); then
EXIT_CODE=1
fi
@@ -46,14 +47,13 @@ if ! command -v yq > /dev/null; then
fi
EXCLUDE_GITIAN=${EXCLUDE}",$(IFS=','; echo "${disabled_gitian[*]}")"
-SHELLCHECK_CMD="shellcheck --external-sources --check-sourced $EXCLUDE_GITIAN"
for descriptor in $(git ls-files -- 'contrib/gitian-descriptors/*.yml')
do
script=$(basename "$descriptor")
# Use #!/bin/bash as gitian-builder/bin/gbuild does to complete a script.
echo "#!/bin/bash" > $script
yq -r .script "$descriptor" >> $script
- if ! $SHELLCHECK_CMD $script; then
+ if ! "${SHELLCHECK_CMD[@]}" "$EXCLUDE_GITIAN" $script; then
EXIT_CODE=1
fi
rm $script