aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml2
-rw-r--r--.tx/config2
-rw-r--r--build_msvc/bench_bitcoin/bench_bitcoin.vcxproj.in (renamed from build_msvc/bench_bitcoin/bench_bitcoin.vcxproj)22
-rw-r--r--build_msvc/common.init.vcxproj3
-rw-r--r--build_msvc/msvc-autogen.py1
-rwxr-xr-xci/test/00_setup_env.sh7
-rwxr-xr-xci/test/04_install.sh1
-rwxr-xr-xci/test/06_script_b.sh2
-rw-r--r--configure.ac2
-rw-r--r--contrib/init/bitcoind.service12
-rw-r--r--doc/bitcoin-conf.md10
-rw-r--r--doc/developer-notes.md18
-rw-r--r--doc/init.md10
-rw-r--r--doc/release-notes-16185.md3
-rw-r--r--doc/release-notes-16695.md5
-rw-r--r--share/setup.nsi.in2
-rw-r--r--src/chain.h6
-rw-r--r--src/qt/bitcoinamountfield.cpp3
-rw-r--r--src/qt/bitcoingui.cpp6
-rw-r--r--src/qt/bitcoinstrings.cpp3
-rw-r--r--src/qt/forms/debugwindow.ui19
-rw-r--r--src/qt/guiutil.cpp22
-rw-r--r--src/qt/guiutil.h8
-rw-r--r--src/qt/locale/bitcoin_en.ts134
-rw-r--r--src/qt/macdockiconhandler.mm21
-rw-r--r--src/qt/overviewpage.cpp5
-rw-r--r--src/qt/paymentserver.cpp6
-rw-r--r--src/qt/receivecoinsdialog.cpp2
-rw-r--r--src/qt/recentrequeststablemodel.h2
-rw-r--r--src/qt/rpcconsole.cpp39
-rw-r--r--src/qt/rpcconsole.h3
-rw-r--r--src/qt/sendcoinsdialog.cpp2
-rw-r--r--src/qt/splashscreen.cpp16
-rw-r--r--src/qt/transactionview.cpp12
-rw-r--r--src/qt/transactionview.h2
-rw-r--r--src/rpc/blockchain.cpp2
-rw-r--r--src/rpc/client.cpp1
-rw-r--r--src/test/README.md4
-rw-r--r--src/test/txvalidationcache_tests.cpp20
-rw-r--r--src/validation.cpp172
-rw-r--r--src/wallet/rpcwallet.cpp13
-rw-r--r--src/wallet/wallet.cpp28
-rwxr-xr-xtest/functional/rpc_blockchain.py2
-rwxr-xr-xtest/functional/test_framework/messages.py4
-rwxr-xr-xtest/functional/wallet_basic.py5
-rwxr-xr-xtest/functional/wallet_importmulti.py4
-rwxr-xr-xtest/lint/lint-python-mutable-default-parameters.sh52
-rwxr-xr-xtest/lint/lint-spelling.sh5
48 files changed, 414 insertions, 311 deletions
diff --git a/.travis.yml b/.travis.yml
index f515ab2b87..04308a5fa6 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -33,7 +33,7 @@ cache:
directories:
- $TRAVIS_BUILD_DIR/depends/built
- $TRAVIS_BUILD_DIR/depends/sdk-sources
- - $HOME/.ccache
+ - $TRAVIS_BUILD_DIR/ci/scratch/.ccache
stages:
- lint
- test
diff --git a/.tx/config b/.tx/config
index 743510a7f2..0e18a0df98 100644
--- a/.tx/config
+++ b/.tx/config
@@ -1,7 +1,7 @@
[main]
host = https://www.transifex.com
-[bitcoin.qt-translation-018x]
+[bitcoin.qt-translation-019x]
file_filter = src/qt/locale/bitcoin_<lang>.ts
source_file = src/qt/locale/bitcoin_en.ts
source_lang = en
diff --git a/build_msvc/bench_bitcoin/bench_bitcoin.vcxproj b/build_msvc/bench_bitcoin/bench_bitcoin.vcxproj.in
index e64614c09d..56401d7618 100644
--- a/build_msvc/bench_bitcoin/bench_bitcoin.vcxproj
+++ b/build_msvc/bench_bitcoin/bench_bitcoin.vcxproj.in
@@ -9,27 +9,7 @@
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
</PropertyGroup>
<ItemGroup>
- <ClCompile Include="..\..\src\test\util.cpp" />
- <ClCompile Include="..\..\src\test\setup_common.cpp" />
- <ClCompile Include="..\..\src\bench\base58.cpp" />
- <ClCompile Include="..\..\src\bench\bech32.cpp" />
- <ClCompile Include="..\..\src\bench\bench.cpp" />
- <ClCompile Include="..\..\src\bench\bench_bitcoin.cpp" />
- <ClCompile Include="..\..\src\bench\ccoins_caching.cpp" />
- <ClCompile Include="..\..\src\bench\checkblock.cpp" />
- <ClCompile Include="..\..\src\bench\checkqueue.cpp" />
- <ClCompile Include="..\..\src\bench\coin_selection.cpp" />
- <ClCompile Include="..\..\src\bench\crypto_hash.cpp" />
- <ClCompile Include="..\..\src\bench\data.cpp" />
- <ClCompile Include="..\..\src\bench\examples.cpp" />
- <ClCompile Include="..\..\src\bench\lockedpool.cpp" />
- <ClCompile Include="..\..\src\bench\mempool_eviction.cpp" />
- <ClCompile Include="..\..\src\bench\rpc_blockchain.cpp" />
- <ClCompile Include="..\..\src\bench\rpc_mempool.cpp" />
- <ClCompile Include="..\..\src\bench\merkle_root.cpp" />
- <ClCompile Include="..\..\src\bench\rollingbloom.cpp" />
- <ClCompile Include="..\..\src\bench\wallet_balance.cpp" />
- <ClCompile Include="..\..\src\bench\verify_script.cpp" />
+@SOURCE_FILES@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\libbitcoinconsensus\libbitcoinconsensus.vcxproj">
diff --git a/build_msvc/common.init.vcxproj b/build_msvc/common.init.vcxproj
index 0d186b5af2..e9f4e23862 100644
--- a/build_msvc/common.init.vcxproj
+++ b/build_msvc/common.init.vcxproj
@@ -113,6 +113,9 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>crypt32.lib;Iphlpapi.lib;ws2_32.lib;Shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
+ <Lib>
+ <AdditionalOptions>/ignore:4221</AdditionalOptions>
+ </Lib>
</ItemDefinitionGroup>
<Import Project="common.init.vcxproj.user" Condition="Exists('common.init.vcxproj.user')" />
</Project>
diff --git a/build_msvc/msvc-autogen.py b/build_msvc/msvc-autogen.py
index b612467bf3..5ddda3c03e 100644
--- a/build_msvc/msvc-autogen.py
+++ b/build_msvc/msvc-autogen.py
@@ -17,6 +17,7 @@ libs = [
'libbitcoin_wallet_tool',
'libbitcoin_wallet',
'libbitcoin_zmq',
+ 'bench_bitcoin',
]
ignore_list = [
diff --git a/ci/test/00_setup_env.sh b/ci/test/00_setup_env.sh
index 09b37f8240..51b5cfdd3f 100755
--- a/ci/test/00_setup_env.sh
+++ b/ci/test/00_setup_env.sh
@@ -11,7 +11,10 @@ echo "Setting default values in env"
BASE_ROOT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )"/../../ >/dev/null 2>&1 && pwd )
export BASE_ROOT_DIR
-export MAKEJOBS=${MAKEJOBS:--j3}
+# The number of parallel jobs to pass down to make and test_runner.py
+export MAKEJOBS=${MAKEJOBS:--j4}
+# A folder for the ci system to put temporary files (ccache, datadirs for tests, ...)
+export BASE_SCRATCH_DIR=${BASE_SCRATCH_DIR:-$BASE_ROOT_DIR/ci/scratch/}
export HOST=${HOST:-x86_64-unknown-linux-gnu}
export RUN_UNIT_TESTS=${RUN_UNIT_TESTS:-true}
export RUN_FUNCTIONAL_TESTS=${RUN_FUNCTIONAL_TESTS:-true}
@@ -21,7 +24,7 @@ export BOOST_TEST_RANDOM=${BOOST_TEST_RANDOM:-1$TRAVIS_BUILD_ID}
export CCACHE_SIZE=${CCACHE_SIZE:-100M}
export CCACHE_TEMPDIR=${CCACHE_TEMPDIR:-/tmp/.ccache-temp}
export CCACHE_COMPRESS=${CCACHE_COMPRESS:-1}
-export CCACHE_DIR=${CCACHE_DIR:-$HOME/.ccache}
+export CCACHE_DIR=${CCACHE_DIR:-$BASE_SCRATCH_DIR/.ccache}
export BASE_BUILD_DIR=${BASE_BUILD_DIR:-${TRAVIS_BUILD_DIR:-$BASE_ROOT_DIR}}
export BASE_OUTDIR=${BASE_OUTDIR:-$BASE_BUILD_DIR/out/$HOST}
export SDK_URL=${SDK_URL:-https://bitcoincore.org/depends-sources/sdks}
diff --git a/ci/test/04_install.sh b/ci/test/04_install.sh
index 3535746e83..54d7a9b814 100755
--- a/ci/test/04_install.sh
+++ b/ci/test/04_install.sh
@@ -6,6 +6,7 @@
export LC_ALL=C.UTF-8
+mkdir -p "${BASE_SCRATCH_DIR}"
ccache echo "Creating ccache dir if it didn't already exist"
if [ ! -d ${DIR_QA_ASSETS} ]; then
diff --git a/ci/test/06_script_b.sh b/ci/test/06_script_b.sh
index d179ce81c0..ea7beae85f 100755
--- a/ci/test/06_script_b.sh
+++ b/ci/test/06_script_b.sh
@@ -16,7 +16,7 @@ fi
if [ "$RUN_FUNCTIONAL_TESTS" = "true" ]; then
BEGIN_FOLD functional-tests
- DOCKER_EXEC test/functional/test_runner.py --ci --ansi --combinedlogslen=4000 ${TEST_RUNNER_EXTRA} --quiet --failfast
+ DOCKER_EXEC test/functional/test_runner.py --ci $MAKEJOBS --tmpdirprefix "${BASE_SCRATCH_DIR}/test_runner/" --ansi --combinedlogslen=4000 ${TEST_RUNNER_EXTRA} --quiet --failfast
END_FOLD
fi
diff --git a/configure.ac b/configure.ac
index 35bb0c0231..97974d0f14 100644
--- a/configure.ac
+++ b/configure.ac
@@ -585,7 +585,7 @@ case $host in
fi
AX_CHECK_LINK_FLAG([[-Wl,-headerpad_max_install_names]], [LDFLAGS="$LDFLAGS -Wl,-headerpad_max_install_names"])
- CPPFLAGS="$CPPFLAGS -DMAC_OSX"
+ CPPFLAGS="$CPPFLAGS -DMAC_OSX -DOBJC_OLD_DISPATCH_PROTOTYPES=0"
OBJCXXFLAGS="$CXXFLAGS"
;;
*android*)
diff --git a/contrib/init/bitcoind.service b/contrib/init/bitcoind.service
index cfc5f77580..34c3e7b3ab 100644
--- a/contrib/init/bitcoind.service
+++ b/contrib/init/bitcoind.service
@@ -5,8 +5,9 @@
# See "man systemd.service" for details.
# Note that almost all daemon options could be specified in
-# /etc/bitcoin/bitcoin.conf, except for those explicitly specified as arguments
-# in ExecStart=
+# /etc/bitcoin/bitcoin.conf, but keep in mind those explicitly
+# specified as arguments in ExecStart= will override those in the
+# config file.
[Unit]
Description=Bitcoin daemon
@@ -18,6 +19,10 @@ ExecStart=/usr/bin/bitcoind -daemon \
-conf=/etc/bitcoin/bitcoin.conf \
-datadir=/var/lib/bitcoind
+# Make sure the config directory is readable by the service user
+PermissionsStartOnly=true
+ExecStartPre=/bin/chgrp bitcoin /etc/bitcoin
+
# Process management
####################
@@ -53,6 +58,9 @@ PrivateTmp=true
# Mount /usr, /boot/ and /etc read-only for the process.
ProtectSystem=full
+# Deny access to /home, /root and /run/user
+ProtectHome=true
+
# Disallow the process and all of its children to gain
# new privileges through execve().
NoNewPrivileges=true
diff --git a/doc/bitcoin-conf.md b/doc/bitcoin-conf.md
index f8146b5d75..f4a8edec75 100644
--- a/doc/bitcoin-conf.md
+++ b/doc/bitcoin-conf.md
@@ -50,3 +50,13 @@ rpcport=4000
The configuration file is not automatically created; you can create it using your favorite text editor. By default, the configuration file name is `bitcoin.conf` and it is located in the Bitcoin data directory, but both the Bitcoin data directory and the configuration file path may be changed using the `-datadir` and `-conf` command-line options.
The `includeconf=<file>` option in the `bitcoin.conf` file can be used to include additional configuration files.
+
+### Default configuration file locations
+
+Operating System | Data Directory | Example Path
+-- | -- | --
+Windows | `%APPDATA%\Bitcoin\` | `C:\Users\username\AppData\Roaming\Bitcoin\bitcoin.conf`
+Linux | `$HOME/.bitcoin/` | `/home/username/.bitcoin/bitcoin.conf`
+macOS | `$HOME/Library/Application Support/Bitcoin/` | `/Users/username/Library/Application Support/Bitcoin/bitcoin.conf`
+
+You can find an example bitcoin.conf file in [share/examples/bitcoin.conf](../share/examples/bitcoin.conf).
diff --git a/doc/developer-notes.md b/doc/developer-notes.md
index d1114b0c73..561f623cd5 100644
--- a/doc/developer-notes.md
+++ b/doc/developer-notes.md
@@ -27,7 +27,7 @@ Developer Notes
- [General C++](#general-c)
- [C++ data structures](#c-data-structures)
- [Strings and formatting](#strings-and-formatting)
- - [Variable names](#variable-names)
+ - [Shadowing](#shadowing)
- [Threads and synchronization](#threads-and-synchronization)
- [Scripts](#scripts)
- [Shebang](#shebang)
@@ -613,27 +613,13 @@ Strings and formatting
- *Rationale*: Bitcoin Core uses tinyformat, which is type safe. Leave them out to avoid confusion.
-Variable names
+Shadowing
--------------
Although the shadowing warning (`-Wshadow`) is not enabled by default (it prevents issues arising
from using a different variable with the same name),
please name variables so that their names do not shadow variables defined in the source code.
-E.g. in member initializers, prepend `_` to the argument name shadowing the
-member name:
-
-```c++
-class AddressBookPage
-{
- Mode m_mode;
-}
-
-AddressBookPage::AddressBookPage(Mode _mode)
- : m_mode(_mode)
-...
-```
-
When using nested cycles, do not name the inner cycle variable the same as in
the upper cycle, etc.
diff --git a/doc/init.md b/doc/init.md
index a6c9bb94d8..87e939c636 100644
--- a/doc/init.md
+++ b/doc/init.md
@@ -59,11 +59,11 @@ Data directory: `/var/lib/bitcoind`
PID file: `/var/run/bitcoind/bitcoind.pid` (OpenRC and Upstart) or `/run/bitcoind/bitcoind.pid` (systemd)
Lock file: `/var/lock/subsys/bitcoind` (CentOS)
-The configuration file, PID directory (if applicable) and data directory
-should all be owned by the bitcoin user and group. It is advised for security
-reasons to make the configuration file and data directory only readable by the
-bitcoin user and group. Access to bitcoin-cli and other bitcoind rpc clients
-can then be controlled by group membership.
+The PID directory (if applicable) and data directory should both be owned by the
+bitcoin user and group. It is advised for security reasons to make the
+configuration file and data directory only readable by the bitcoin user and
+group. Access to bitcoin-cli and other bitcoind rpc clients can then be
+controlled by group membership.
NOTE: When using the systemd .service file, the creation of the aforementioned
directories and the setting of their permissions is automatically handled by
diff --git a/doc/release-notes-16185.md b/doc/release-notes-16185.md
new file mode 100644
index 0000000000..eeeb951e5b
--- /dev/null
+++ b/doc/release-notes-16185.md
@@ -0,0 +1,3 @@
+RPC changes
+-----------
+The `gettransaction` RPC now accepts a third (boolean) argument `decode`. If set to `true`, a new `decoded` field will be added to the response containing the decoded transaction.
diff --git a/doc/release-notes-16695.md b/doc/release-notes-16695.md
new file mode 100644
index 0000000000..7acf1dcf97
--- /dev/null
+++ b/doc/release-notes-16695.md
@@ -0,0 +1,5 @@
+Updated RPCs
+------------
+
+- The `getchaintxstats` RPC now returns the additional key of
+ `window_final_block_height`.
diff --git a/share/setup.nsi.in b/share/setup.nsi.in
index acf9e86667..e9aa1f2b73 100644
--- a/share/setup.nsi.in
+++ b/share/setup.nsi.in
@@ -101,7 +101,7 @@ Section -post SEC0001
WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" DisplayVersion "@PACKAGE_VERSION@"
WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" Publisher "${COMPANY}"
WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" URLInfoAbout "${URL}"
- WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" DisplayIcon $INSTDIR\uninstall.exe
+ WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" DisplayIcon $INSTDIR\bitcoin-qt.exe
WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" UninstallString $INSTDIR\uninstall.exe
WriteRegDWORD HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" NoModify 1
WriteRegDWORD HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" NoRepair 1
diff --git a/src/chain.h b/src/chain.h
index dd9cc2a598..1b67ebbe41 100644
--- a/src/chain.h
+++ b/src/chain.h
@@ -95,8 +95,8 @@ enum BlockStatus: uint32_t {
//! Unused.
BLOCK_VALID_UNKNOWN = 0,
- //! Parsed, version ok, hash satisfies claimed PoW, 1 <= vtx count <= max, timestamp not in future
- BLOCK_VALID_HEADER = 1,
+ //! Reserved (was BLOCK_VALID_HEADER).
+ BLOCK_VALID_RESERVED = 1,
//! All parent headers found, difficulty matches, timestamp >= median previous, checkpoint. Implies all parents
//! are also at least TREE.
@@ -117,7 +117,7 @@ enum BlockStatus: uint32_t {
BLOCK_VALID_SCRIPTS = 5,
//! All validity bits.
- BLOCK_VALID_MASK = BLOCK_VALID_HEADER | BLOCK_VALID_TREE | BLOCK_VALID_TRANSACTIONS |
+ BLOCK_VALID_MASK = BLOCK_VALID_RESERVED | BLOCK_VALID_TREE | BLOCK_VALID_TRANSACTIONS |
BLOCK_VALID_CHAIN | BLOCK_VALID_SCRIPTS,
BLOCK_HAVE_DATA = 8, //!< full block available in blk*.dat
diff --git a/src/qt/bitcoinamountfield.cpp b/src/qt/bitcoinamountfield.cpp
index 5854ade655..9fa49b87fa 100644
--- a/src/qt/bitcoinamountfield.cpp
+++ b/src/qt/bitcoinamountfield.cpp
@@ -6,6 +6,7 @@
#include <qt/bitcoinunits.h>
#include <qt/guiconstants.h>
+#include <qt/guiutil.h>
#include <qt/qvaluecombobox.h>
#include <QApplication>
@@ -121,7 +122,7 @@ public:
const QFontMetrics fm(fontMetrics());
int h = lineEdit()->minimumSizeHint().height();
- int w = fm.width(BitcoinUnits::format(BitcoinUnits::BTC, BitcoinUnits::maxMoney(), false, BitcoinUnits::separatorAlways));
+ int w = GUIUtil::TextWidth(fm, BitcoinUnits::format(BitcoinUnits::BTC, BitcoinUnits::maxMoney(), false, BitcoinUnits::separatorAlways));
w += 2; // cursor blinking space
QStyleOptionSpinBox opt;
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index bc9af9793e..323797a4b6 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -40,7 +40,6 @@
#include <QApplication>
#include <QComboBox>
#include <QDateTime>
-#include <QDesktopWidget>
#include <QDragEnterEvent>
#include <QListWidget>
#include <QMenu>
@@ -48,6 +47,7 @@
#include <QMessageBox>
#include <QMimeData>
#include <QProgressDialog>
+#include <QScreen>
#include <QSettings>
#include <QShortcut>
#include <QStackedWidget>
@@ -81,7 +81,7 @@ BitcoinGUI::BitcoinGUI(interfaces::Node& node, const PlatformStyle *_platformSty
QSettings settings;
if (!restoreGeometry(settings.value("MainWindowGeometry").toByteArray())) {
// Restore failed (perhaps missing setting), center the window
- move(QApplication::desktop()->availableGeometry().center() - frameGeometry().center());
+ move(QGuiApplication::primaryScreen()->availableGeometry().center() - frameGeometry().center());
}
#ifdef ENABLE_WALLET
@@ -1407,7 +1407,7 @@ UnitDisplayStatusBarControl::UnitDisplayStatusBarControl(const PlatformStyle *pl
const QFontMetrics fm(font());
for (const BitcoinUnits::Unit unit : units)
{
- max_width = qMax(max_width, fm.width(BitcoinUnits::longName(unit)));
+ max_width = qMax(max_width, GUIUtil::TextWidth(fm, BitcoinUnits::longName(unit)));
}
setMinimumSize(max_width, 0);
setAlignment(Qt::AlignRight | Qt::AlignVCenter);
diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp
index 87736cd185..5cde21eec6 100644
--- a/src/qt/bitcoinstrings.cpp
+++ b/src/qt/bitcoinstrings.cpp
@@ -131,12 +131,12 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Initialization sanity check failed. %s is shu
QT_TRANSLATE_NOOP("bitcoin-core", "Insufficient funds"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid -onion address or hostname: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid -proxy address or hostname: '%s'"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Invalid P2P permission: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -%s=<amount>: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -discardfee=<amount>: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -fallbackfee=<amount>: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid netmask specified in -whitelist: '%s'"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Keypool ran out, please call keypoolrefill first"),
QT_TRANSLATE_NOOP("bitcoin-core", "Loading P2P addresses..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Loading banlist..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Loading block index..."),
@@ -170,7 +170,6 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Transaction amounts must not be negative"),
QT_TRANSLATE_NOOP("bitcoin-core", "Transaction fee and change calculation failed"),
QT_TRANSLATE_NOOP("bitcoin-core", "Transaction has too long of a mempool chain"),
QT_TRANSLATE_NOOP("bitcoin-core", "Transaction must have at least one recipient"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Transaction too large for fee policy"),
QT_TRANSLATE_NOOP("bitcoin-core", "Transaction too large"),
QT_TRANSLATE_NOOP("bitcoin-core", "Unable to bind to %s on this computer (bind returned error %s)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Unable to bind to %s on this computer. %s is probably already running."),
diff --git a/src/qt/forms/debugwindow.ui b/src/qt/forms/debugwindow.ui
index 6e52c5e477..be807b20c0 100644
--- a/src/qt/forms/debugwindow.ui
+++ b/src/qt/forms/debugwindow.ui
@@ -15,6 +15,25 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
+ <widget class="QLabel" name="label_alerts">
+ <property name="visible">
+ <bool>false</bool>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">QLabel { background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0, stop:0 #F0D0A0, stop:1 #F8D488); color:#000000; }</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ <property name="margin">
+ <number>3</number>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index dc1da7f8a9..070df31aa6 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -39,7 +39,6 @@
#include <QClipboard>
#include <QDateTime>
#include <QDesktopServices>
-#include <QDesktopWidget>
#include <QDoubleValidator>
#include <QFileDialog>
#include <QFont>
@@ -58,9 +57,10 @@
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-#include <objc/objc-runtime.h>
#include <CoreServices/CoreServices.h>
#include <QProcess>
+
+void ForceActivation();
#endif
namespace GUIUtil {
@@ -360,10 +360,7 @@ bool isObscured(QWidget *w)
void bringToFront(QWidget* w)
{
#ifdef Q_OS_MAC
- // Force application activation on macOS. With Qt 5.4 this is required when
- // an action in the dock menu is triggered.
- id app = objc_msgSend((id) objc_getClass("NSApplication"), sel_registerName("sharedApplication"));
- objc_msgSend(app, sel_registerName("activateIgnoringOtherApps:"), YES);
+ ForceActivation();
#endif
if (w) {
@@ -916,7 +913,7 @@ qreal calculateIdealFontSize(int width, const QString& text, QFont font, qreal m
while(font_size >= minPointSize) {
font.setPointSizeF(font_size);
QFontMetrics fm(font);
- if (fm.width(text) < width) {
+ if (TextWidth(fm, text) < width) {
break;
}
font_size -= 0.5;
@@ -948,7 +945,7 @@ void PolishProgressDialog(QProgressDialog* dialog)
{
#ifdef Q_OS_MAC
// Workaround for macOS-only Qt bug; see: QTBUG-65750, QTBUG-70357.
- const int margin = dialog->fontMetrics().width("X");
+ const int margin = TextWidth(dialog->fontMetrics(), ("X"));
dialog->resize(dialog->width() + 2 * margin, dialog->height());
dialog->show();
#else
@@ -956,4 +953,13 @@ void PolishProgressDialog(QProgressDialog* dialog)
#endif
}
+int TextWidth(const QFontMetrics& fm, const QString& text)
+{
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 11, 0))
+ return fm.horizontalAdvance(text);
+#else
+ return fm.width(text);
+#endif
+}
+
} // namespace GUIUtil
diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h
index bea4a83494..9db92f94d7 100644
--- a/src/qt/guiutil.h
+++ b/src/qt/guiutil.h
@@ -257,6 +257,14 @@ namespace GUIUtil
// Fix known bugs in QProgressDialog class.
void PolishProgressDialog(QProgressDialog* dialog);
+
+ /**
+ * Returns the distance in pixels appropriate for drawing a subsequent character after text.
+ *
+ * In Qt 5.12 and before the QFontMetrics::width() is used and it is deprecated since Qt 13.0.
+ * In Qt 5.11 the QFontMetrics::horizontalAdvance() was introduced.
+ */
+ int TextWidth(const QFontMetrics& fm, const QString& text);
} // namespace GUIUtil
#endif // BITCOIN_QT_GUIUTIL_H
diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts
index bff7469071..7864f97f31 100644
--- a/src/qt/locale/bitcoin_en.ts
+++ b/src/qt/locale/bitcoin_en.ts
@@ -132,7 +132,7 @@
<context>
<name>AddressTableModel</name>
<message>
- <location filename="../addresstablemodel.cpp" line="+163"/>
+ <location filename="../addresstablemodel.cpp" line="+165"/>
<source>Label</source>
<translation type="unfinished"></translation>
</message>
@@ -297,7 +297,7 @@
<context>
<name>BanTableModel</name>
<message>
- <location filename="../bantablemodel.cpp" line="+86"/>
+ <location filename="../bantablemodel.cpp" line="+88"/>
<source>IP/Netmask</source>
<translation type="unfinished"></translation>
</message>
@@ -310,17 +310,17 @@
<context>
<name>BitcoinGUI</name>
<message>
- <location filename="../bitcoingui.cpp" line="+318"/>
+ <location filename="../bitcoingui.cpp" line="+315"/>
<source>Sign &amp;message...</source>
<translation>Sign &amp;message...</translation>
</message>
<message>
- <location line="+638"/>
+ <location line="+637"/>
<source>Synchronizing with network...</source>
<translation>Synchronizing with network...</translation>
</message>
<message>
- <location line="-716"/>
+ <location line="-715"/>
<source>&amp;Overview</source>
<translation>&amp;Overview</translation>
</message>
@@ -400,7 +400,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+217"/>
+ <location line="+216"/>
<source>Wallet:</source>
<translation type="unfinished"></translation>
</message>
@@ -435,7 +435,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-1036"/>
+ <location line="-1035"/>
<source>Send coins to a Bitcoin address</source>
<translation>Send coins to a Bitcoin address</translation>
</message>
@@ -500,7 +500,7 @@
<translation>Verify messages to ensure they were signed with specified Bitcoin addresses</translation>
</message>
<message>
- <location line="+118"/>
+ <location line="+117"/>
<source>&amp;File</source>
<translation>&amp;File</translation>
</message>
@@ -520,7 +520,7 @@
<translation>Tabs toolbar</translation>
</message>
<message>
- <location line="-271"/>
+ <location line="-270"/>
<source>Request payments (generates QR codes and bitcoin: URIs)</source>
<translation type="unfinished"></translation>
</message>
@@ -545,7 +545,7 @@
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
- <location line="+540"/>
+ <location line="+539"/>
<source>%n active connection(s) to Bitcoin network</source>
<translation>
<numerusform>%n active connection to Bitcoin network</numerusform>
@@ -606,7 +606,7 @@
<translation>Up to date</translation>
</message>
<message>
- <location line="-657"/>
+ <location line="-656"/>
<source>&amp;Sending addresses</source>
<translation type="unfinished"></translation>
</message>
@@ -641,7 +641,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+30"/>
+ <location line="+29"/>
<source>default wallet</source>
<translation type="unfinished"></translation>
</message>
@@ -782,7 +782,7 @@
<translation>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</translation>
</message>
<message>
- <location filename="../bitcoin.cpp" line="+390"/>
+ <location filename="../bitcoin.cpp" line="+382"/>
<source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source>
<translation type="unfinished"></translation>
</message>
@@ -941,7 +941,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+155"/>
+ <location line="+157"/>
<source>yes</source>
<translation type="unfinished"></translation>
</message>
@@ -1736,14 +1736,14 @@
<location filename="../paymentserver.cpp" line="+226"/>
<location line="+346"/>
<location line="+42"/>
- <location line="+110"/>
+ <location line="+108"/>
<location line="+14"/>
<location line="+18"/>
<source>Payment request error</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-529"/>
+ <location line="-527"/>
<source>Cannot start bitcoin: click-to-pay handler</source>
<translation type="unfinished"></translation>
</message>
@@ -1805,12 +1805,12 @@
<location line="+31"/>
<location line="+10"/>
<location line="+17"/>
- <location line="+85"/>
+ <location line="+83"/>
<source>Payment request rejected</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-152"/>
+ <location line="-150"/>
<source>Payment request network doesn&apos;t match client network.</source>
<translation type="unfinished"></translation>
</message>
@@ -1841,7 +1841,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+65"/>
+ <location line="+63"/>
<source>Refund from %1</source>
<translation type="unfinished"></translation>
</message>
@@ -1879,7 +1879,7 @@
<context>
<name>PeerTableModel</name>
<message>
- <location filename="../peertablemodel.cpp" line="+108"/>
+ <location filename="../peertablemodel.cpp" line="+110"/>
<source>User Agent</source>
<translation type="unfinished"></translation>
</message>
@@ -1922,7 +1922,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+702"/>
+ <location line="+699"/>
<source>%1 d</source>
<translation type="unfinished"></translation>
</message>
@@ -1938,7 +1938,7 @@
</message>
<message>
<location line="+2"/>
- <location line="+50"/>
+ <location line="+47"/>
<source>%1 s</source>
<translation type="unfinished"></translation>
</message>
@@ -2032,27 +2032,22 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoin.cpp" line="+74"/>
- <source>Error parsing command line arguments: %1.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+37"/>
+ <location filename="../bitcoin.cpp" line="+116"/>
<source>Error: Specified data directory &quot;%1&quot; does not exist.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+5"/>
+ <location line="+6"/>
<source>Error: Cannot parse configuration file: %1.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+14"/>
+ <location line="+15"/>
<source>Error: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+57"/>
+ <location line="+59"/>
<source>%1 didn&apos;t yet exit safely...</source>
<translation type="unfinished"></translation>
</message>
@@ -2103,7 +2098,7 @@
<context>
<name>RPCConsole</name>
<message>
- <location filename="../forms/debugwindow.ui" line="+56"/>
+ <location filename="../forms/debugwindow.ui" line="+75"/>
<location line="+26"/>
<location line="+26"/>
<location line="+26"/>
@@ -2147,12 +2142,12 @@
<translation>&amp;Information</translation>
</message>
<message>
- <location line="-10"/>
+ <location line="-29"/>
<source>Debug window</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+25"/>
+ <location line="+44"/>
<source>General</source>
<translation type="unfinished"></translation>
</message>
@@ -2265,8 +2260,8 @@
</message>
<message>
<location line="+65"/>
- <location filename="../rpcconsole.cpp" line="+498"/>
- <location line="+757"/>
+ <location filename="../rpcconsole.cpp" line="+497"/>
+ <location line="+759"/>
<source>Select a peer to view detailed information.</source>
<translation type="unfinished"></translation>
</message>
@@ -2417,7 +2412,7 @@
<translation>Clear console</translation>
</message>
<message>
- <location filename="../rpcconsole.cpp" line="-252"/>
+ <location filename="../rpcconsole.cpp" line="-243"/>
<source>1 &amp;hour</source>
<translation type="unfinished"></translation>
</message>
@@ -2450,7 +2445,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+47"/>
+ <location line="+38"/>
<source>&amp;Unban</source>
<translation type="unfinished"></translation>
</message>
@@ -2628,7 +2623,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../receivecoinsdialog.cpp" line="+45"/>
+ <location filename="../receivecoinsdialog.cpp" line="+46"/>
<source>Copy URI</source>
<translation type="unfinished"></translation>
</message>
@@ -2714,7 +2709,7 @@
<context>
<name>RecentRequestsTableModel</name>
<message>
- <location filename="../recentrequeststablemodel.cpp" line="+25"/>
+ <location filename="../recentrequeststablemodel.cpp" line="+27"/>
<source>Date</source>
<translation type="unfinished">Date</translation>
</message>
@@ -2753,7 +2748,7 @@
<name>SendCoinsDialog</name>
<message>
<location filename="../forms/sendcoinsdialog.ui" line="+14"/>
- <location filename="../sendcoinsdialog.cpp" line="+600"/>
+ <location filename="../sendcoinsdialog.cpp" line="+601"/>
<source>Send Coins</source>
<translation>Send Coins</translation>
</message>
@@ -2940,7 +2935,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation>S&amp;end</translation>
</message>
<message>
- <location filename="../sendcoinsdialog.cpp" line="-512"/>
+ <location filename="../sendcoinsdialog.cpp" line="-513"/>
<source>Copy quantity</source>
<translation type="unfinished"></translation>
</message>
@@ -2980,7 +2975,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+117"/>
+ <location line="+118"/>
<source> from wallet &apos;%1&apos;</source>
<translation type="unfinished"></translation>
</message>
@@ -3698,7 +3693,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<context>
<name>TransactionTableModel</name>
<message>
- <location filename="../transactiontablemodel.cpp" line="+223"/>
+ <location filename="../transactiontablemodel.cpp" line="+225"/>
<source>Date</source>
<translation type="unfinished">Date</translation>
</message>
@@ -3834,7 +3829,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<context>
<name>TransactionView</name>
<message>
- <location filename="../transactionview.cpp" line="+70"/>
+ <location filename="../transactionview.cpp" line="+69"/>
<location line="+16"/>
<source>All</source>
<translation type="unfinished"></translation>
@@ -3955,7 +3950,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+199"/>
+ <location line="+194"/>
<source>Export Transaction History</source>
<translation type="unfinished"></translation>
</message>
@@ -4033,7 +4028,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<context>
<name>UnitDisplayStatusBarControl</name>
<message>
- <location filename="../bitcoingui.cpp" line="+155"/>
+ <location filename="../bitcoingui.cpp" line="+156"/>
<source>Unit to show amounts in. Click to select another unit.</source>
<translation type="unfinished"></translation>
</message>
@@ -4041,7 +4036,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<context>
<name>WalletController</name>
<message>
- <location filename="../walletcontroller.cpp" line="+70"/>
+ <location filename="../walletcontroller.cpp" line="+73"/>
<source>Close wallet</source>
<translation type="unfinished"></translation>
</message>
@@ -4072,7 +4067,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished">Send Coins</translation>
</message>
<message>
- <location line="+301"/>
+ <location line="+309"/>
<location line="+39"/>
<location line="+5"/>
<source>Fee bump error</source>
@@ -4205,12 +4200,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+31"/>
+ <location line="+30"/>
<source>Unable to start HTTP server. See debug log for details.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-168"/>
+ <location line="-167"/>
<source>The %s developers</source>
<translation type="unfinished"></translation>
</message>
@@ -4391,6 +4386,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
</message>
<message>
<location line="+4"/>
+ <source>Invalid P2P permission: &apos;%s&apos;</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
<source>Invalid amount for -%s=&lt;amount&gt;: &apos;%s&apos;</source>
<translation type="unfinished"></translation>
</message>
@@ -4405,17 +4405,17 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+23"/>
+ <location line="+22"/>
<source>Specified blocks directory &quot;%s&quot; does not exist.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+26"/>
+ <location line="+25"/>
<source>Upgrading txindex database</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-45"/>
+ <location line="-44"/>
<source>Loading P2P addresses...</source>
<translation type="unfinished"></translation>
</message>
@@ -4465,7 +4465,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+6"/>
+ <location line="+5"/>
<source>Unable to bind to %s on this computer. %s is probably already running.</source>
<translation type="unfinished"></translation>
</message>
@@ -4500,7 +4500,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-155"/>
+ <location line="-154"/>
<source>Error: Listening for incoming connections failed (listen returned error %s)</source>
<translation type="unfinished"></translation>
</message>
@@ -4545,7 +4545,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+4"/>
+ <location line="+5"/>
<source>Invalid amount for -paytxfee=&lt;amount&gt;: &apos;%s&apos; (must be at least %s)</source>
<translation type="unfinished"></translation>
</message>
@@ -4555,7 +4555,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+6"/>
+ <location line="+5"/>
<source>Need to specify a port with -whitebind: &apos;%s&apos;</source>
<translation type="unfinished"></translation>
</message>
@@ -4617,11 +4617,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
</message>
<message>
<location line="+5"/>
- <source>Transaction too large for fee policy</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+1"/>
<source>Transaction too large</source>
<translation>Transaction too large</translation>
</message>
@@ -4661,7 +4656,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-178"/>
+ <location line="-177"/>
<source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source>
<translation type="unfinished"></translation>
</message>
@@ -4696,12 +4691,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+20"/>
- <source>Keypool ran out, please call keypoolrefill first</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+21"/>
+ <location line="+41"/>
<source>Starting network threads...</source>
<translation type="unfinished"></translation>
</message>
@@ -4736,12 +4726,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+10"/>
+ <location line="+9"/>
<source>Unknown network specified in -onlynet: &apos;%s&apos;</source>
<translation>Unknown network specified in -onlynet: &apos;%s&apos;</translation>
</message>
<message>
- <location line="-51"/>
+ <location line="-50"/>
<source>Insufficient funds</source>
<translation>Insufficient funds</translation>
</message>
diff --git a/src/qt/macdockiconhandler.mm b/src/qt/macdockiconhandler.mm
index 102adce6c5..5eb23c76e6 100644
--- a/src/qt/macdockiconhandler.mm
+++ b/src/qt/macdockiconhandler.mm
@@ -1,12 +1,11 @@
-// Copyright (c) 2011-2018 The Bitcoin Core developers
+// Copyright (c) 2011-2019 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 "macdockiconhandler.h"
-#undef slots
-#include <objc/objc.h>
-#include <objc/message.h>
+#include <AppKit/AppKit.h>
+#include <objc/runtime.h>
static MacDockIconHandler *s_instance = nullptr;
@@ -21,9 +20,7 @@ bool dockClickHandler(id self, SEL _cmd, ...) {
}
void setupDockClickHandler() {
- id app = objc_msgSend((id)objc_getClass("NSApplication"), sel_registerName("sharedApplication"));
- id delegate = objc_msgSend(app, sel_registerName("delegate"));
- Class delClass = (Class)objc_msgSend(delegate, sel_registerName("class"));
+ Class delClass = (Class)[[[NSApplication sharedApplication] delegate] class];
SEL shouldHandle = sel_registerName("applicationShouldHandleReopen:hasVisibleWindows:");
class_replaceMethod(delClass, shouldHandle, (IMP)dockClickHandler, "B@:");
}
@@ -44,3 +41,13 @@ void MacDockIconHandler::cleanup()
{
delete s_instance;
}
+
+/**
+ * Force application activation on macOS. With Qt 5.5.1 this is required when
+ * an action in the Dock menu is triggered.
+ * TODO: Define a Qt version where it's no-longer necessary.
+ */
+void ForceActivation()
+{
+ [[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
+}
diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp
index d8e48f350a..07ffff0126 100644
--- a/src/qt/overviewpage.cpp
+++ b/src/qt/overviewpage.cpp
@@ -204,9 +204,8 @@ void OverviewPage::updateWatchOnlyLabels(bool showWatchOnly)
void OverviewPage::setClientModel(ClientModel *model)
{
this->clientModel = model;
- if(model)
- {
- // Show warning if this is a prerelease version
+ if (model) {
+ // Show warning, for example if this is a prerelease version
connect(model, &ClientModel::alertsChanged, this, &OverviewPage::updateAlerts);
updateAlerts(model->getStatusBarWarnings());
}
diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp
index f3f5d28af9..0bb87742e9 100644
--- a/src/qt/paymentserver.cpp
+++ b/src/qt/paymentserver.cpp
@@ -41,8 +41,8 @@
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QSslCertificate>
+#include <QSslConfiguration>
#include <QSslError>
-#include <QSslSocket>
#include <QStringList>
#include <QTextDocument>
#include <QUrlQuery>
@@ -448,9 +448,9 @@ void PaymentServer::LoadRootCAs(X509_STORE* _store)
certList = QSslCertificate::fromPath(certFile);
// Use those certificates when fetching payment requests, too:
- QSslSocket::setDefaultCaCertificates(certList);
+ QSslConfiguration::defaultConfiguration().setCaCertificates(certList);
} else
- certList = QSslSocket::systemCaCertificates();
+ certList = QSslConfiguration::systemCaCertificates();
int nRootCerts = 0;
const QDateTime currentTime = QDateTime::currentDateTime();
diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp
index 05157c2a4a..e8cf432131 100644
--- a/src/qt/receivecoinsdialog.cpp
+++ b/src/qt/receivecoinsdialog.cpp
@@ -261,7 +261,7 @@ void ReceiveCoinsDialog::copyColumnToClipboard(int column)
if (!firstIndex.isValid()) {
return;
}
- GUIUtil::setClipboard(model->getRecentRequestsTableModel()->data(firstIndex.child(firstIndex.row(), column), Qt::EditRole).toString());
+ GUIUtil::setClipboard(model->getRecentRequestsTableModel()->index(firstIndex.row(), column).data(Qt::EditRole).toString());
}
// context menu
diff --git a/src/qt/recentrequeststablemodel.h b/src/qt/recentrequeststablemodel.h
index 8a1140e952..130b709d46 100644
--- a/src/qt/recentrequeststablemodel.h
+++ b/src/qt/recentrequeststablemodel.h
@@ -76,7 +76,7 @@ public:
QVariant data(const QModelIndex &index, int role) const;
bool setData(const QModelIndex &index, const QVariant &value, int role);
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
- QModelIndex index(int row, int column, const QModelIndex &parent) const;
+ QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex());
Qt::ItemFlags flags(const QModelIndex &index) const;
/*@}*/
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 19b11ba1cd..eccc34e12f 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -28,13 +28,12 @@
#include <wallet/wallet.h>
#endif
-#include <QDesktopWidget>
#include <QKeyEvent>
#include <QMenu>
#include <QMessageBox>
#include <QScrollBar>
+#include <QScreen>
#include <QSettings>
-#include <QSignalMapper>
#include <QTime>
#include <QTimer>
#include <QStringList>
@@ -451,7 +450,7 @@ RPCConsole::RPCConsole(interfaces::Node& node, const PlatformStyle *_platformSty
QSettings settings;
if (!restoreGeometry(settings.value("RPCConsoleWindowGeometry").toByteArray())) {
// Restore failed (perhaps missing setting), center the window
- move(QApplication::desktop()->availableGeometry().center() - frameGeometry().center());
+ move(QGuiApplication::primaryScreen()->availableGeometry().center() - frameGeometry().center());
}
QChar nonbreaking_hyphen(8209);
@@ -558,6 +557,17 @@ bool RPCConsole::eventFilter(QObject* obj, QEvent *event)
void RPCConsole::setClientModel(ClientModel *model)
{
clientModel = model;
+
+ bool wallet_enabled{false};
+#ifdef ENABLE_WALLET
+ wallet_enabled = WalletModel::isWalletEnabled();
+#endif // ENABLE_WALLET
+ if (model && !wallet_enabled) {
+ // Show warning, for example if this is a prerelease version
+ connect(model, &ClientModel::alertsChanged, this, &RPCConsole::updateAlerts);
+ updateAlerts(model->getStatusBarWarnings());
+ }
+
ui->trafficGraph->setClientModel(model);
if (model && clientModel->getPeerTableModel() && clientModel->getBanTableModel()) {
// Keep up to date with client
@@ -603,19 +613,10 @@ void RPCConsole::setClientModel(ClientModel *model)
peersTableContextMenu->addAction(banAction7d);
peersTableContextMenu->addAction(banAction365d);
- // Add a signal mapping to allow dynamic context menu arguments.
- // We need to use int (instead of int64_t), because signal mapper only supports
- // int or objects, which is okay because max bantime (1 year) is < int_max.
- QSignalMapper* signalMapper = new QSignalMapper(this);
- signalMapper->setMapping(banAction1h, 60*60);
- signalMapper->setMapping(banAction24h, 60*60*24);
- signalMapper->setMapping(banAction7d, 60*60*24*7);
- signalMapper->setMapping(banAction365d, 60*60*24*365);
- connect(banAction1h, &QAction::triggered, signalMapper, static_cast<void (QSignalMapper::*)()>(&QSignalMapper::map));
- connect(banAction24h, &QAction::triggered, signalMapper, static_cast<void (QSignalMapper::*)()>(&QSignalMapper::map));
- connect(banAction7d, &QAction::triggered, signalMapper, static_cast<void (QSignalMapper::*)()>(&QSignalMapper::map));
- connect(banAction365d, &QAction::triggered, signalMapper, static_cast<void (QSignalMapper::*)()>(&QSignalMapper::map));
- connect(signalMapper, static_cast<void (QSignalMapper::*)(int)>(&QSignalMapper::mapped), this, &RPCConsole::banSelectedNode);
+ connect(banAction1h, &QAction::triggered, [this] { banSelectedNode(60 * 60); });
+ connect(banAction24h, &QAction::triggered, [this] { banSelectedNode(60 * 60 * 24); });
+ connect(banAction7d, &QAction::triggered, [this] { banSelectedNode(60 * 60 * 24 * 7); });
+ connect(banAction365d, &QAction::triggered, [this] { banSelectedNode(60 * 60 * 24 * 365); });
// peer table context menu signals
connect(ui->peerWidget, &QTableView::customContextMenuRequested, this, &RPCConsole::showPeersTableContextMenu);
@@ -1274,3 +1275,9 @@ QString RPCConsole::tabTitle(TabTypes tab_type) const
{
return ui->tabWidget->tabText(tab_type);
}
+
+void RPCConsole::updateAlerts(const QString& warnings)
+{
+ this->ui->label_alerts->setVisible(!warnings.isEmpty());
+ this->ui->label_alerts->setText(warnings);
+}
diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h
index 38015e38fd..3f7a74ba03 100644
--- a/src/qt/rpcconsole.h
+++ b/src/qt/rpcconsole.h
@@ -167,6 +167,9 @@ private:
/** Update UI with latest network info from model. */
void updateNetworkState();
+
+private Q_SLOTS:
+ void updateAlerts(const QString& warnings);
};
#endif // BITCOIN_QT_RPCCONSOLE_H
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index 0ed057bc8b..f23c47736f 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -704,7 +704,7 @@ void SendCoinsDialog::updateSmartFeeLabel()
int lightness = ui->fallbackFeeWarningLabel->palette().color(QPalette::WindowText).lightness();
QColor warning_colour(255 - (lightness / 5), 176 - (lightness / 3), 48 - (lightness / 14));
ui->fallbackFeeWarningLabel->setStyleSheet("QLabel { color: " + warning_colour.name() + "; }");
- ui->fallbackFeeWarningLabel->setIndent(QFontMetrics(ui->fallbackFeeWarningLabel->font()).width("x"));
+ ui->fallbackFeeWarningLabel->setIndent(GUIUtil::TextWidth(QFontMetrics(ui->fallbackFeeWarningLabel->font()), "x"));
}
else
{
diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp
index 5bceb1f945..0e5abb89f3 100644
--- a/src/qt/splashscreen.cpp
+++ b/src/qt/splashscreen.cpp
@@ -8,12 +8,12 @@
#include <qt/splashscreen.h>
-#include <qt/networkstyle.h>
-
#include <clientversion.h>
#include <interfaces/handler.h>
#include <interfaces/node.h>
#include <interfaces/wallet.h>
+#include <qt/guiutil.h>
+#include <qt/networkstyle.h>
#include <ui_interface.h>
#include <util/system.h>
#include <util/translation.h>
@@ -21,9 +21,9 @@
#include <QApplication>
#include <QCloseEvent>
-#include <QDesktopWidget>
#include <QPainter>
#include <QRadialGradient>
+#include <QScreen>
SplashScreen::SplashScreen(interfaces::Node& node, Qt::WindowFlags f, const NetworkStyle *networkStyle) :
@@ -75,21 +75,21 @@ SplashScreen::SplashScreen(interfaces::Node& node, Qt::WindowFlags f, const Netw
// check font size and drawing with
pixPaint.setFont(QFont(font, 33*fontFactor));
QFontMetrics fm = pixPaint.fontMetrics();
- int titleTextWidth = fm.width(titleText);
+ int titleTextWidth = GUIUtil::TextWidth(fm, titleText);
if (titleTextWidth > 176) {
fontFactor = fontFactor * 176 / titleTextWidth;
}
pixPaint.setFont(QFont(font, 33*fontFactor));
fm = pixPaint.fontMetrics();
- titleTextWidth = fm.width(titleText);
+ titleTextWidth = GUIUtil::TextWidth(fm, titleText);
pixPaint.drawText(pixmap.width()/devicePixelRatio-titleTextWidth-paddingRight,paddingTop,titleText);
pixPaint.setFont(QFont(font, 15*fontFactor));
// if the version string is too long, reduce size
fm = pixPaint.fontMetrics();
- int versionTextWidth = fm.width(versionText);
+ int versionTextWidth = GUIUtil::TextWidth(fm, versionText);
if(versionTextWidth > titleTextWidth+paddingRight-10) {
pixPaint.setFont(QFont(font, 10*fontFactor));
titleVersionVSpace -= 5;
@@ -111,7 +111,7 @@ SplashScreen::SplashScreen(interfaces::Node& node, Qt::WindowFlags f, const Netw
boldFont.setWeight(QFont::Bold);
pixPaint.setFont(boldFont);
fm = pixPaint.fontMetrics();
- int titleAddTextWidth = fm.width(titleAddText);
+ int titleAddTextWidth = GUIUtil::TextWidth(fm, titleAddText);
pixPaint.drawText(pixmap.width()/devicePixelRatio-titleAddTextWidth-10,15,titleAddText);
}
@@ -124,7 +124,7 @@ SplashScreen::SplashScreen(interfaces::Node& node, Qt::WindowFlags f, const Netw
QRect r(QPoint(), QSize(pixmap.size().width()/devicePixelRatio,pixmap.size().height()/devicePixelRatio));
resize(r.size());
setFixedSize(r.size());
- move(QApplication::desktop()->screenGeometry().center() - r.center());
+ move(QGuiApplication::primaryScreen()->geometry().center() - r.center());
subscribeToCoreSignals();
installEventFilter(this);
diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp
index 17e174e57a..cbc4ab49f5 100644
--- a/src/qt/transactionview.cpp
+++ b/src/qt/transactionview.cpp
@@ -30,7 +30,6 @@
#include <QMenu>
#include <QPoint>
#include <QScrollBar>
-#include <QSignalMapper>
#include <QTableView>
#include <QTimer>
#include <QUrl>
@@ -176,11 +175,6 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa
contextMenu->addAction(abandonAction);
contextMenu->addAction(editLabelAction);
- mapperThirdPartyTxUrls = new QSignalMapper(this);
-
- // Connect actions
- connect(mapperThirdPartyTxUrls, static_cast<void (QSignalMapper::*)(const QString&)>(&QSignalMapper::mapped), this, &TransactionView::openThirdPartyTxUrl);
-
connect(dateWidget, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this, &TransactionView::chooseDate);
connect(typeWidget, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this, &TransactionView::chooseType);
connect(watchOnlyWidget, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this, &TransactionView::chooseWatchonly);
@@ -246,15 +240,15 @@ void TransactionView::setModel(WalletModel *_model)
QStringList listUrls = _model->getOptionsModel()->getThirdPartyTxUrls().split("|", QString::SkipEmptyParts);
for (int i = 0; i < listUrls.size(); ++i)
{
- QString host = QUrl(listUrls[i].trimmed(), QUrl::StrictMode).host();
+ QString url = listUrls[i].trimmed();
+ QString host = QUrl(url, QUrl::StrictMode).host();
if (!host.isEmpty())
{
QAction *thirdPartyTxUrlAction = new QAction(host, this); // use host as menu item label
if (i == 0)
contextMenu->addSeparator();
contextMenu->addAction(thirdPartyTxUrlAction);
- connect(thirdPartyTxUrlAction, &QAction::triggered, mapperThirdPartyTxUrls, static_cast<void (QSignalMapper::*)()>(&QSignalMapper::map));
- mapperThirdPartyTxUrls->setMapping(thirdPartyTxUrlAction, listUrls[i].trimmed());
+ connect(thirdPartyTxUrlAction, &QAction::triggered, [this, url] { openThirdPartyTxUrl(url); });
}
}
}
diff --git a/src/qt/transactionview.h b/src/qt/transactionview.h
index e07181d1c8..79347c371f 100644
--- a/src/qt/transactionview.h
+++ b/src/qt/transactionview.h
@@ -23,7 +23,6 @@ class QFrame;
class QLineEdit;
class QMenu;
class QModelIndex;
-class QSignalMapper;
class QTableView;
QT_END_NAMESPACE
@@ -72,7 +71,6 @@ private:
QLineEdit *amountWidget;
QMenu *contextMenu;
- QSignalMapper *mapperThirdPartyTxUrls;
QFrame *dateRangeWidget;
QDateTimeEdit *dateFrom;
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 7161c39ffd..5419e33396 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -1569,6 +1569,7 @@ static UniValue getchaintxstats(const JSONRPCRequest& request)
" \"time\": xxxxx, (numeric) The timestamp for the final block in the window in UNIX format.\n"
" \"txcount\": xxxxx, (numeric) The total number of transactions in the chain up to that point.\n"
" \"window_final_block_hash\": \"...\", (string) The hash of the final block in the window.\n"
+ " \"window_final_block_height\": xxxxx, (numeric) The height of the final block in the window.\n"
" \"window_block_count\": xxxxx, (numeric) Size of the window in number of blocks.\n"
" \"window_tx_count\": xxxxx, (numeric) The number of transactions in the window. Only returned if \"window_block_count\" is > 0.\n"
" \"window_interval\": xxxxx, (numeric) The elapsed time in the window in seconds. Only returned if \"window_block_count\" is > 0.\n"
@@ -1619,6 +1620,7 @@ static UniValue getchaintxstats(const JSONRPCRequest& request)
ret.pushKV("time", (int64_t)pindex->nTime);
ret.pushKV("txcount", (int64_t)pindex->nChainTx);
ret.pushKV("window_final_block_hash", pindex->GetBlockHash().GetHex());
+ ret.pushKV("window_final_block_height", pindex->nHeight);
ret.pushKV("window_block_count", blockcount);
if (blockcount > 0) {
ret.pushKV("window_tx_count", nTxDiff);
diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp
index 3cd661e067..93fca5a6de 100644
--- a/src/rpc/client.cpp
+++ b/src/rpc/client.cpp
@@ -85,6 +85,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "getblockheader", 1, "verbose" },
{ "getchaintxstats", 0, "nblocks" },
{ "gettransaction", 1, "include_watchonly" },
+ { "gettransaction", 2, "decode" },
{ "getrawtransaction", 1, "verbose" },
{ "createrawtransaction", 0, "inputs" },
{ "createrawtransaction", 1, "outputs" },
diff --git a/src/test/README.md b/src/test/README.md
index 0017e3de26..8901fae7bd 100644
--- a/src/test/README.md
+++ b/src/test/README.md
@@ -49,7 +49,3 @@ unit tests. The file naming convention is `<source_filename>_tests.cpp`
and such files should wrap their tests in a test suite
called `<source_filename>_tests`. For an example of this pattern,
examine `uint256_tests.cpp`.
-
-For further reading, I found the following website to be helpful in
-explaining how the boost unit test framework works:
-[http://www.alittlemadness.com/2009/03/31/c-unit-testing-with-boosttest/](http://archive.is/dRBGf).
diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp
index e69ebcc2c3..193858cca9 100644
--- a/src/test/txvalidationcache_tests.cpp
+++ b/src/test/txvalidationcache_tests.cpp
@@ -13,7 +13,7 @@
#include <boost/test/unit_test.hpp>
-bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks);
+bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks);
BOOST_AUTO_TEST_SUITE(tx_validationcache_tests)
@@ -125,7 +125,7 @@ static void ValidateCheckInputsForAllFlags(const CTransaction &tx, uint32_t fail
// WITNESS requires P2SH
test_flags |= SCRIPT_VERIFY_P2SH;
}
- bool ret = CheckInputs(tx, state, &::ChainstateActive().CoinsTip(), true, test_flags, true, add_to_cache, txdata, nullptr);
+ bool ret = CheckInputs(tx, state, &::ChainstateActive().CoinsTip(), test_flags, true, add_to_cache, txdata, nullptr);
// CheckInputs should succeed iff test_flags doesn't intersect with
// failing_flags
bool expected_return_value = !(test_flags & failing_flags);
@@ -135,13 +135,13 @@ static void ValidateCheckInputsForAllFlags(const CTransaction &tx, uint32_t fail
if (ret && add_to_cache) {
// Check that we get a cache hit if the tx was valid
std::vector<CScriptCheck> scriptchecks;
- BOOST_CHECK(CheckInputs(tx, state, &::ChainstateActive().CoinsTip(), true, test_flags, true, add_to_cache, txdata, &scriptchecks));
+ BOOST_CHECK(CheckInputs(tx, state, &::ChainstateActive().CoinsTip(), test_flags, true, add_to_cache, txdata, &scriptchecks));
BOOST_CHECK(scriptchecks.empty());
} else {
// Check that we get script executions to check, if the transaction
// was invalid, or we didn't add to cache.
std::vector<CScriptCheck> scriptchecks;
- BOOST_CHECK(CheckInputs(tx, state, &::ChainstateActive().CoinsTip(), true, test_flags, true, add_to_cache, txdata, &scriptchecks));
+ BOOST_CHECK(CheckInputs(tx, state, &::ChainstateActive().CoinsTip(), test_flags, true, add_to_cache, txdata, &scriptchecks));
BOOST_CHECK_EQUAL(scriptchecks.size(), tx.vin.size());
}
}
@@ -204,13 +204,13 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
CValidationState state;
PrecomputedTransactionData ptd_spend_tx(spend_tx);
- BOOST_CHECK(!CheckInputs(CTransaction(spend_tx), state, &::ChainstateActive().CoinsTip(), true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, nullptr));
+ BOOST_CHECK(!CheckInputs(CTransaction(spend_tx), state, &::ChainstateActive().CoinsTip(), SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, nullptr));
// If we call again asking for scriptchecks (as happens in
// ConnectBlock), we should add a script check object for this -- we're
// not caching invalidity (if that changes, delete this test case).
std::vector<CScriptCheck> scriptchecks;
- BOOST_CHECK(CheckInputs(CTransaction(spend_tx), state, &::ChainstateActive().CoinsTip(), true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, &scriptchecks));
+ BOOST_CHECK(CheckInputs(CTransaction(spend_tx), state, &::ChainstateActive().CoinsTip(), SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, &scriptchecks));
BOOST_CHECK_EQUAL(scriptchecks.size(), 1U);
// Test that CheckInputs returns true iff DERSIG-enforcing flags are
@@ -272,7 +272,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
invalid_with_cltv_tx.vin[0].scriptSig = CScript() << vchSig << 100;
CValidationState state;
PrecomputedTransactionData txdata(invalid_with_cltv_tx);
- BOOST_CHECK(CheckInputs(CTransaction(invalid_with_cltv_tx), state, ::ChainstateActive().CoinsTip(), true, SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, true, true, txdata, nullptr));
+ BOOST_CHECK(CheckInputs(CTransaction(invalid_with_cltv_tx), state, ::ChainstateActive().CoinsTip(), SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, true, true, txdata, nullptr));
}
// TEST CHECKSEQUENCEVERIFY
@@ -300,7 +300,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
invalid_with_csv_tx.vin[0].scriptSig = CScript() << vchSig << 100;
CValidationState state;
PrecomputedTransactionData txdata(invalid_with_csv_tx);
- BOOST_CHECK(CheckInputs(CTransaction(invalid_with_csv_tx), state, &::ChainstateActive().CoinsTip(), true, SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, true, true, txdata, nullptr));
+ BOOST_CHECK(CheckInputs(CTransaction(invalid_with_csv_tx), state, &::ChainstateActive().CoinsTip(), SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, true, true, txdata, nullptr));
}
// TODO: add tests for remaining script flags
@@ -362,12 +362,12 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
CValidationState state;
PrecomputedTransactionData txdata(tx);
// This transaction is now invalid under segwit, because of the second input.
- BOOST_CHECK(!CheckInputs(CTransaction(tx), state, &::ChainstateActive().CoinsTip(), true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, true, true, txdata, nullptr));
+ BOOST_CHECK(!CheckInputs(CTransaction(tx), state, &::ChainstateActive().CoinsTip(), SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, true, true, txdata, nullptr));
std::vector<CScriptCheck> scriptchecks;
// Make sure this transaction was not cached (ie because the first
// input was valid)
- BOOST_CHECK(CheckInputs(CTransaction(tx), state, &::ChainstateActive().CoinsTip(), true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, true, true, txdata, &scriptchecks));
+ BOOST_CHECK(CheckInputs(CTransaction(tx), state, &::ChainstateActive().CoinsTip(), SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, true, true, txdata, &scriptchecks));
// Should get 2 script checks back -- caching is on a whole-transaction basis.
BOOST_CHECK_EQUAL(scriptchecks.size(), 2U);
}
diff --git a/src/validation.cpp b/src/validation.cpp
index 74f68a3047..a8ebbc1b96 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -184,7 +184,7 @@ std::unique_ptr<CBlockTreeDB> pblocktree;
// See definition for documentation
static void FindFilesToPruneManual(std::set<int>& setFilesToPrune, int nManualPruneHeight);
static void FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfterHeight);
-bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks = nullptr);
+bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks = nullptr);
static FILE* OpenUndoFile(const FlatFilePos &pos, bool fReadOnly = false);
static FlatFileSeq BlockFileSeq();
static FlatFileSeq UndoFileSeq();
@@ -425,7 +425,7 @@ static bool CheckInputsFromMempoolAndCache(const CTransaction& tx, CValidationSt
}
}
- return CheckInputs(tx, state, view, true, flags, cacheSigStore, true, txdata);
+ return CheckInputs(tx, state, view, flags, cacheSigStore, true, txdata);
}
/**
@@ -773,15 +773,17 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
constexpr unsigned int scriptVerifyFlags = STANDARD_SCRIPT_VERIFY_FLAGS;
// Check against previous transactions
- // This is done last to help prevent CPU exhaustion denial-of-service attacks.
+ // The first loop above does all the inexpensive checks.
+ // Only if ALL inputs pass do we perform expensive ECDSA signature checks.
+ // Helps prevent CPU exhaustion denial-of-service attacks.
PrecomputedTransactionData txdata(tx);
- if (!CheckInputs(tx, state, view, true, scriptVerifyFlags, true, false, txdata)) {
+ if (!CheckInputs(tx, state, view, scriptVerifyFlags, true, false, txdata)) {
// SCRIPT_VERIFY_CLEANSTACK requires SCRIPT_VERIFY_WITNESS, so we
// need to turn both off, and compare against just turning off CLEANSTACK
// to see if the failure is specifically due to witness validation.
CValidationState stateDummy; // Want reported failures to be from first CheckInputs
- if (!tx.HasWitness() && CheckInputs(tx, stateDummy, view, true, scriptVerifyFlags & ~(SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK), true, false, txdata) &&
- !CheckInputs(tx, stateDummy, view, true, scriptVerifyFlags & ~SCRIPT_VERIFY_CLEANSTACK, true, false, txdata)) {
+ if (!tx.HasWitness() && CheckInputs(tx, stateDummy, view, scriptVerifyFlags & ~(SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK), true, false, txdata) &&
+ !CheckInputs(tx, stateDummy, view, scriptVerifyFlags & ~SCRIPT_VERIFY_CLEANSTACK, true, false, txdata)) {
// Only the witness is missing, so the transaction itself may be fine.
state.Invalid(ValidationInvalidReason::TX_WITNESS_MUTATED, false,
state.GetRejectCode(), state.GetRejectReason(), state.GetDebugMessage());
@@ -1298,90 +1300,79 @@ void InitScriptExecutionCache() {
*
* Non-static (and re-declared) in src/test/txvalidationcache_tests.cpp
*/
-bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
- if (!tx.IsCoinBase())
- {
- if (pvChecks)
- pvChecks->reserve(tx.vin.size());
-
- // The first loop above does all the inexpensive checks.
- // Only if ALL inputs pass do we perform expensive ECDSA signature checks.
- // Helps prevent CPU exhaustion attacks.
-
- // Skip script verification when connecting blocks under the
- // assumevalid block. Assuming the assumevalid block is valid this
- // is safe because block merkle hashes are still computed and checked,
- // Of course, if an assumed valid block is invalid due to false scriptSigs
- // this optimization would allow an invalid chain to be accepted.
- if (fScriptChecks) {
- // First check if script executions have been cached with the same
- // flags. Note that this assumes that the inputs provided are
- // correct (ie that the transaction hash which is in tx's prevouts
- // properly commits to the scriptPubKey in the inputs view of that
- // transaction).
- uint256 hashCacheEntry;
- // We only use the first 19 bytes of nonce to avoid a second SHA
- // round - giving us 19 + 32 + 4 = 55 bytes (+ 8 + 1 = 64)
- static_assert(55 - sizeof(flags) - 32 >= 128/8, "Want at least 128 bits of nonce for script execution cache");
- CSHA256().Write(scriptExecutionCacheNonce.begin(), 55 - sizeof(flags) - 32).Write(tx.GetWitnessHash().begin(), 32).Write((unsigned char*)&flags, sizeof(flags)).Finalize(hashCacheEntry.begin());
- AssertLockHeld(cs_main); //TODO: Remove this requirement by making CuckooCache not require external locks
- if (scriptExecutionCache.contains(hashCacheEntry, !cacheFullScriptStore)) {
- return true;
- }
-
- for (unsigned int i = 0; i < tx.vin.size(); i++) {
- const COutPoint &prevout = tx.vin[i].prevout;
- const Coin& coin = inputs.AccessCoin(prevout);
- assert(!coin.IsSpent());
-
- // We very carefully only pass in things to CScriptCheck which
- // are clearly committed to by tx' witness hash. This provides
- // a sanity check that our caching is not introducing consensus
- // failures through additional data in, eg, the coins being
- // spent being checked as a part of CScriptCheck.
-
- // Verify signature
- CScriptCheck check(coin.out, tx, i, flags, cacheSigStore, &txdata);
- if (pvChecks) {
- pvChecks->push_back(CScriptCheck());
- check.swap(pvChecks->back());
- } else if (!check()) {
- if (flags & STANDARD_NOT_MANDATORY_VERIFY_FLAGS) {
- // Check whether the failure was caused by a
- // non-mandatory script verification check, such as
- // non-standard DER encodings or non-null dummy
- // arguments; if so, ensure we return NOT_STANDARD
- // instead of CONSENSUS to avoid downstream users
- // splitting the network between upgraded and
- // non-upgraded nodes by banning CONSENSUS-failing
- // data providers.
- CScriptCheck check2(coin.out, tx, i,
- flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheSigStore, &txdata);
- if (check2())
- return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, REJECT_NONSTANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError())));
- }
- // MANDATORY flag failures correspond to
- // ValidationInvalidReason::CONSENSUS. Because CONSENSUS
- // failures are the most serious case of validation
- // failures, we may need to consider using
- // RECENT_CONSENSUS_CHANGE for any script failure that
- // could be due to non-upgraded nodes which we may want to
- // support, to avoid splitting the network (but this
- // depends on the details of how net_processing handles
- // such errors).
- return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, strprintf("mandatory-script-verify-flag-failed (%s)", ScriptErrorString(check.GetScriptError())));
- }
- }
+ if (tx.IsCoinBase()) return true;
+
+ if (pvChecks) {
+ pvChecks->reserve(tx.vin.size());
+ }
+
+ // First check if script executions have been cached with the same
+ // flags. Note that this assumes that the inputs provided are
+ // correct (ie that the transaction hash which is in tx's prevouts
+ // properly commits to the scriptPubKey in the inputs view of that
+ // transaction).
+ uint256 hashCacheEntry;
+ // We only use the first 19 bytes of nonce to avoid a second SHA
+ // round - giving us 19 + 32 + 4 = 55 bytes (+ 8 + 1 = 64)
+ static_assert(55 - sizeof(flags) - 32 >= 128/8, "Want at least 128 bits of nonce for script execution cache");
+ CSHA256().Write(scriptExecutionCacheNonce.begin(), 55 - sizeof(flags) - 32).Write(tx.GetWitnessHash().begin(), 32).Write((unsigned char*)&flags, sizeof(flags)).Finalize(hashCacheEntry.begin());
+ AssertLockHeld(cs_main); //TODO: Remove this requirement by making CuckooCache not require external locks
+ if (scriptExecutionCache.contains(hashCacheEntry, !cacheFullScriptStore)) {
+ return true;
+ }
- if (cacheFullScriptStore && !pvChecks) {
- // We executed all of the provided scripts, and were told to
- // cache the result. Do so now.
- scriptExecutionCache.insert(hashCacheEntry);
+ for (unsigned int i = 0; i < tx.vin.size(); i++) {
+ const COutPoint &prevout = tx.vin[i].prevout;
+ const Coin& coin = inputs.AccessCoin(prevout);
+ assert(!coin.IsSpent());
+
+ // We very carefully only pass in things to CScriptCheck which
+ // are clearly committed to by tx' witness hash. This provides
+ // a sanity check that our caching is not introducing consensus
+ // failures through additional data in, eg, the coins being
+ // spent being checked as a part of CScriptCheck.
+
+ // Verify signature
+ CScriptCheck check(coin.out, tx, i, flags, cacheSigStore, &txdata);
+ if (pvChecks) {
+ pvChecks->push_back(CScriptCheck());
+ check.swap(pvChecks->back());
+ } else if (!check()) {
+ if (flags & STANDARD_NOT_MANDATORY_VERIFY_FLAGS) {
+ // Check whether the failure was caused by a
+ // non-mandatory script verification check, such as
+ // non-standard DER encodings or non-null dummy
+ // arguments; if so, ensure we return NOT_STANDARD
+ // instead of CONSENSUS to avoid downstream users
+ // splitting the network between upgraded and
+ // non-upgraded nodes by banning CONSENSUS-failing
+ // data providers.
+ CScriptCheck check2(coin.out, tx, i,
+ flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheSigStore, &txdata);
+ if (check2())
+ return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, REJECT_NONSTANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError())));
}
+ // MANDATORY flag failures correspond to
+ // ValidationInvalidReason::CONSENSUS. Because CONSENSUS
+ // failures are the most serious case of validation
+ // failures, we may need to consider using
+ // RECENT_CONSENSUS_CHANGE for any script failure that
+ // could be due to non-upgraded nodes which we may want to
+ // support, to avoid splitting the network (but this
+ // depends on the details of how net_processing handles
+ // such errors).
+ return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, strprintf("mandatory-script-verify-flag-failed (%s)", ScriptErrorString(check.GetScriptError())));
}
}
+ if (cacheFullScriptStore && !pvChecks) {
+ // We executed all of the provided scripts, and were told to
+ // cache the result. Do so now.
+ scriptExecutionCache.insert(hashCacheEntry);
+ }
+
return true;
}
@@ -1769,6 +1760,11 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
pindexBestHeader->GetAncestor(pindex->nHeight) == pindex &&
pindexBestHeader->nChainWork >= nMinimumChainWork) {
// This block is a member of the assumed verified chain and an ancestor of the best header.
+ // Script verification is skipped when connecting blocks under the
+ // assumevalid block. Assuming the assumevalid block is valid this
+ // is safe because block merkle hashes are still computed and checked,
+ // Of course, if an assumed valid block is invalid due to false scriptSigs
+ // this optimization would allow an invalid chain to be accepted.
// The equivalent time check discourages hash power from extorting the network via DOS attack
// into accepting an invalid block through telling users they must manually set assumevalid.
// Requiring a software change or burying the invalid block, regardless of the setting, makes
@@ -1952,7 +1948,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
{
std::vector<CScriptCheck> vChecks;
bool fCacheResults = fJustCheck; /* Don't cache results if we're actually connecting blocks (still consult the cache, though) */
- if (!CheckInputs(tx, state, view, fScriptChecks, flags, fCacheResults, fCacheResults, txdata[i], nScriptCheckThreads ? &vChecks : nullptr)) {
+ if (fScriptChecks && !CheckInputs(tx, state, view, flags, fCacheResults, fCacheResults, txdata[i], nScriptCheckThreads ? &vChecks : nullptr)) {
if (state.GetReason() == ValidationInvalidReason::TX_NOT_STANDARD) {
// CheckInputs may return NOT_STANDARD for extra flags we passed,
// but we can't return that, as it's not defined for a block, so
@@ -3401,6 +3397,12 @@ bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& headers, CValidatio
}
}
NotifyHeaderTip();
+ {
+ LOCK(cs_main);
+ if (::ChainstateActive().IsInitialBlockDownload() && ppindex && *ppindex) {
+ LogPrintf("Synchronizing blockheaders, height: %d (~%.2f%%)\n", (*ppindex)->nHeight, 100.0/((*ppindex)->nHeight+(GetAdjustedTime() - (*ppindex)->GetBlockTime()) / Params().GetConsensus().nPowTargetSpacing) * (*ppindex)->nHeight);
+ }
+ }
return true;
}
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 30e767e489..18be3a6ea5 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -1649,6 +1649,7 @@ static UniValue gettransaction(const JSONRPCRequest& request)
{
{"txid", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction id"},
{"include_watchonly", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false", "Whether to include watch-only addresses in balance calculation and details[]"},
+ {"decode", RPCArg::Type::BOOL, /* default */ "false", "Whether to add a field with the decoded transaction"},
},
RPCResult{
"{\n"
@@ -1684,11 +1685,13 @@ static UniValue gettransaction(const JSONRPCRequest& request)
" ,...\n"
" ],\n"
" \"hex\" : \"data\" (string) Raw data for transaction\n"
+ " \"decoded\" : transaction (json object) Optional, the decoded transaction\n"
"}\n"
},
RPCExamples{
HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
+ HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\" true")
+ + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\" false true")
+ HelpExampleRpc("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
},
}.Check(request);
@@ -1708,6 +1711,8 @@ static UniValue gettransaction(const JSONRPCRequest& request)
filter |= ISMINE_WATCH_ONLY;
}
+ bool decode_tx = request.params[2].isNull() ? false : request.params[2].get_bool();
+
UniValue entry(UniValue::VOBJ);
auto it = pwallet->mapWallet.find(hash);
if (it == pwallet->mapWallet.end()) {
@@ -1733,6 +1738,12 @@ static UniValue gettransaction(const JSONRPCRequest& request)
std::string strHex = EncodeHexTx(*wtx.tx, pwallet->chain().rpcSerializationFlags());
entry.pushKV("hex", strHex);
+ if (decode_tx) {
+ UniValue decoded(UniValue::VOBJ);
+ TxToUniv(*wtx.tx, uint256(), decoded, false);
+ entry.pushKV("decoded", decoded);
+ }
+
return entry;
}
@@ -4175,7 +4186,7 @@ static const CRPCCommand commands[] =
{ "wallet", "getrawchangeaddress", &getrawchangeaddress, {"address_type"} },
{ "wallet", "getreceivedbyaddress", &getreceivedbyaddress, {"address","minconf"} },
{ "wallet", "getreceivedbylabel", &getreceivedbylabel, {"label","minconf"} },
- { "wallet", "gettransaction", &gettransaction, {"txid","include_watchonly"} },
+ { "wallet", "gettransaction", &gettransaction, {"txid","include_watchonly","decode"} },
{ "wallet", "getunconfirmedbalance", &getunconfirmedbalance, {} },
{ "wallet", "getbalances", &getbalances, {} },
{ "wallet", "getwalletinfo", &getwalletinfo, {} },
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 2bf08b16d8..84fd01730d 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -93,13 +93,14 @@ std::shared_ptr<CWallet> GetWallet(const std::string& name)
static Mutex g_wallet_release_mutex;
static std::condition_variable g_wallet_release_cv;
-static std::set<CWallet*> g_unloading_wallet_set;
+static std::set<std::string> g_unloading_wallet_set;
// Custom deleter for shared_ptr<CWallet>.
static void ReleaseWallet(CWallet* wallet)
{
// Unregister and delete the wallet right after BlockUntilSyncedToCurrentChain
// so that it's in sync with the current chainstate.
+ const std::string name = wallet->GetName();
wallet->WalletLogPrintf("Releasing wallet\n");
wallet->BlockUntilSyncedToCurrentChain();
wallet->Flush();
@@ -108,7 +109,7 @@ static void ReleaseWallet(CWallet* wallet)
// Wallet is now released, notify UnloadWallet, if any.
{
LOCK(g_wallet_release_mutex);
- if (g_unloading_wallet_set.erase(wallet) == 0) {
+ if (g_unloading_wallet_set.erase(name) == 0) {
// UnloadWallet was not called for this wallet, all done.
return;
}
@@ -119,21 +120,21 @@ static void ReleaseWallet(CWallet* wallet)
void UnloadWallet(std::shared_ptr<CWallet>&& wallet)
{
// Mark wallet for unloading.
- CWallet* pwallet = wallet.get();
+ const std::string name = wallet->GetName();
{
LOCK(g_wallet_release_mutex);
- auto it = g_unloading_wallet_set.insert(pwallet);
+ auto it = g_unloading_wallet_set.insert(name);
assert(it.second);
}
// The wallet can be in use so it's not possible to explicitly unload here.
// Notify the unload intent so that all remaining shared pointers are
// released.
- pwallet->NotifyUnload();
+ wallet->NotifyUnload();
// Time to ditch our shared_ptr and wait for ReleaseWallet call.
wallet.reset();
{
WAIT_LOCK(g_wallet_release_mutex, lock);
- while (g_unloading_wallet_set.count(pwallet) == 1) {
+ while (g_unloading_wallet_set.count(name) == 1) {
g_wallet_release_cv.wait(lock);
}
}
@@ -523,18 +524,9 @@ bool CWallet::LoadCScript(const CScript& redeemScript)
static bool ExtractPubKey(const CScript &dest, CPubKey& pubKeyOut)
{
- //TODO: Use Solver to extract this?
- CScript::const_iterator pc = dest.begin();
- opcodetype opcode;
- std::vector<unsigned char> vch;
- if (!dest.GetOp(pc, opcode, vch) || !CPubKey::ValidSize(vch))
- return false;
- pubKeyOut = CPubKey(vch);
- if (!pubKeyOut.IsFullyValid())
- return false;
- if (!dest.GetOp(pc, opcode, vch) || opcode != OP_CHECKSIG || dest.GetOp(pc, opcode, vch))
- return false;
- return true;
+ std::vector<std::vector<unsigned char>> solutions;
+ return Solver(dest, solutions) == TX_PUBKEY &&
+ (pubKeyOut = CPubKey(solutions[0])).IsFullyValid();
}
bool CWallet::AddWatchOnlyInMem(const CScript &dest)
diff --git a/test/functional/rpc_blockchain.py b/test/functional/rpc_blockchain.py
index 6c30e05084..266a0d6cd2 100755
--- a/test/functional/rpc_blockchain.py
+++ b/test/functional/rpc_blockchain.py
@@ -186,6 +186,7 @@ class BlockchainTest(BitcoinTestFramework):
assert_equal(chaintxstats['time'], b200['time'])
assert_equal(chaintxstats['txcount'], 201)
assert_equal(chaintxstats['window_final_block_hash'], b200_hash)
+ assert_equal(chaintxstats['window_final_block_height'], 200)
assert_equal(chaintxstats['window_block_count'], 199)
assert_equal(chaintxstats['window_tx_count'], 199)
assert_equal(chaintxstats['window_interval'], time_diff)
@@ -195,6 +196,7 @@ class BlockchainTest(BitcoinTestFramework):
assert_equal(chaintxstats['time'], b1['time'])
assert_equal(chaintxstats['txcount'], 2)
assert_equal(chaintxstats['window_final_block_hash'], b1_hash)
+ assert_equal(chaintxstats['window_final_block_height'], 1)
assert_equal(chaintxstats['window_block_count'], 0)
assert 'window_tx_count' not in chaintxstats
assert 'window_interval' not in chaintxstats
diff --git a/test/functional/test_framework/messages.py b/test/functional/test_framework/messages.py
index 89a5a65e64..917efaa833 100755
--- a/test/functional/test_framework/messages.py
+++ b/test/functional/test_framework/messages.py
@@ -803,7 +803,9 @@ class HeaderAndShortIDs:
return [ key0, key1 ]
# Version 2 compact blocks use wtxid in shortids (rather than txid)
- def initialize_from_block(self, block, nonce=0, prefill_list = [0], use_witness = False):
+ def initialize_from_block(self, block, nonce=0, prefill_list=None, use_witness=False):
+ if prefill_list is None:
+ prefill_list = [0]
self.header = CBlockHeader(block)
self.nonce = nonce
self.prefilled_txn = [ PrefilledTransaction(i, block.vtx[i]) for i in prefill_list ]
diff --git a/test/functional/wallet_basic.py b/test/functional/wallet_basic.py
index 34e84fcf55..74350649c7 100755
--- a/test/functional/wallet_basic.py
+++ b/test/functional/wallet_basic.py
@@ -499,6 +499,11 @@ class WalletTest(BitcoinTestFramework):
self.nodes[0].setlabel(change, 'foobar')
assert_equal(self.nodes[0].getaddressinfo(change)['ischange'], False)
+ # Test "decoded" field value in gettransaction response
+ self.log.info("Testing gettransaction decoding...")
+ tx = self.nodes[0].gettransaction(txid=txid, decode=True)
+ assert_equal(tx["decoded"], self.nodes[0].decoderawtransaction(tx["hex"]))
+
if __name__ == '__main__':
WalletTest().main()
diff --git a/test/functional/wallet_importmulti.py b/test/functional/wallet_importmulti.py
index e4a4ab1f35..23748e5dd7 100755
--- a/test/functional/wallet_importmulti.py
+++ b/test/functional/wallet_importmulti.py
@@ -44,8 +44,10 @@ class ImportMultiTest(BitcoinTestFramework):
def setup_network(self):
self.setup_nodes()
- def test_importmulti(self, req, success, error_code=None, error_message=None, warnings=[]):
+ def test_importmulti(self, req, success, error_code=None, error_message=None, warnings=None):
"""Run importmulti and assert success"""
+ if warnings is None:
+ warnings = []
result = self.nodes[1].importmulti([req])
observed_warnings = []
if 'warnings' in result[0]:
diff --git a/test/lint/lint-python-mutable-default-parameters.sh b/test/lint/lint-python-mutable-default-parameters.sh
new file mode 100755
index 0000000000..1f9f035d30
--- /dev/null
+++ b/test/lint/lint-python-mutable-default-parameters.sh
@@ -0,0 +1,52 @@
+#!/usr/bin/env bash
+#
+# Copyright (c) 2019 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#
+# Detect when a mutable list or dict is used as a default parameter value in a Python function.
+
+export LC_ALL=C
+EXIT_CODE=0
+OUTPUT=$(git grep -E '^\s*def [a-zA-Z0-9_]+\(.*=\s*(\[|\{)' -- "*.py")
+if [[ ${OUTPUT} != "" ]]; then
+ echo "A mutable list or dict seems to be used as default parameter value:"
+ echo
+ echo "${OUTPUT}"
+ echo
+ cat << EXAMPLE
+This is how mutable list and dict default parameter values behave:
+
+>>> def f(i, j=[], k={}):
+... j.append(i)
+... k[i] = True
+... return j, k
+...
+>>> f(1)
+([1], {1: True})
+>>> f(1)
+([1, 1], {1: True})
+>>> f(2)
+([1, 1, 2], {1: True, 2: True})
+
+The intended behaviour was likely:
+
+>>> def f(i, j=None, k=None):
+... if j is None:
+... j = []
+... if k is None:
+... k = {}
+... j.append(i)
+... k[i] = True
+... return j, k
+...
+>>> f(1)
+([1], {1: True})
+>>> f(1)
+([1], {1: True})
+>>> f(2)
+([2], {2: True})
+EXAMPLE
+ EXIT_CODE=1
+fi
+exit ${EXIT_CODE}
diff --git a/test/lint/lint-spelling.sh b/test/lint/lint-spelling.sh
index 5d672698a7..e70b73e1cc 100755
--- a/test/lint/lint-spelling.sh
+++ b/test/lint/lint-spelling.sh
@@ -9,6 +9,11 @@
export LC_ALL=C
+if ! command -v codespell > /dev/null; then
+ echo "Skipping spell check linting since codespell is not installed."
+ exit 0
+fi
+
IGNORE_WORDS_FILE=test/lint/lint-spelling.ignore-words.txt
if ! codespell --check-filenames --disable-colors --quiet-level=7 --ignore-words=${IGNORE_WORDS_FILE} $(git ls-files -- ":(exclude)build-aux/m4/" ":(exclude)contrib/seeds/*.txt" ":(exclude)depends/" ":(exclude)doc/release-notes/" ":(exclude)src/leveldb/" ":(exclude)src/qt/locale/" ":(exclude)src/secp256k1/" ":(exclude)src/univalue/"); then
echo "^ Warning: codespell identified likely spelling errors. Any false positives? Add them to the list of ignored words in ${IGNORE_WORDS_FILE}"