aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-x.travis/lint_04_install.sh4
-rw-r--r--configure.ac11
-rwxr-xr-xcontrib/macdeploy/macdeployqtplus6
-rw-r--r--depends/packages/zeromq.mk4
-rw-r--r--doc/REST-interface.md2
-rw-r--r--doc/dependencies.md2
-rw-r--r--doc/fuzzing.md2
-rw-r--r--src/Makefile.qt.include3
-rw-r--r--src/net.h2
-rw-r--r--src/qt/bitcoin.cpp70
-rw-r--r--src/qt/bitcoin.h9
-rw-r--r--src/qt/bitcoingui.cpp55
-rw-r--r--src/qt/bitcoingui.h5
-rw-r--r--src/qt/forms/debugwindow.ui3
-rw-r--r--src/qt/guiutil.cpp16
-rw-r--r--src/qt/guiutil.h4
-rw-r--r--src/qt/intro.cpp5
-rw-r--r--src/qt/intro.h1
-rw-r--r--src/qt/rpcconsole.cpp23
-rw-r--r--src/qt/rpcconsole.h1
-rw-r--r--src/qt/walletcontroller.cpp95
-rw-r--r--src/qt/walletcontroller.h59
-rw-r--r--src/qt/walletmodel.cpp2
-rw-r--r--src/qt/walletview.cpp17
-rw-r--r--src/util/system.cpp2
-rw-r--r--src/wallet/rpcwallet.cpp7
-rw-r--r--src/zmq/zmqpublishnotifier.cpp1
-rwxr-xr-xtest/functional/interface_rest.py10
-rwxr-xr-xtest/lint/lint-format-strings.sh28
-rwxr-xr-xtest/lint/lint-shell.sh7
-rwxr-xr-xtest/lint/lint-whitespace.sh2
31 files changed, 299 insertions, 159 deletions
diff --git a/.travis/lint_04_install.sh b/.travis/lint_04_install.sh
index 723e7c56f1..9a22773e57 100755
--- a/.travis/lint_04_install.sh
+++ b/.travis/lint_04_install.sh
@@ -9,3 +9,7 @@ export LC_ALL=C
travis_retry pip install codespell==1.13.0
travis_retry pip install flake8==3.5.0
travis_retry pip install vulture==0.29
+
+SHELLCHECK_VERSION=v0.6.0
+curl -s "https://storage.googleapis.com/shellcheck/shellcheck-${SHELLCHECK_VERSION}.linux.x86_64.tar.xz" | tar --xz -xf - --directory /tmp/
+export PATH="/tmp/shellcheck-${SHELLCHECK_VERSION}:${PATH}"
diff --git a/configure.ac b/configure.ac
index e1c265f10f..c4b1d63bfe 100644
--- a/configure.ac
+++ b/configure.ac
@@ -511,17 +511,6 @@ case $host in
LEVELDB_TARGET_FLAGS="-DOS_MACOSX"
if test x$cross_compiling != xyes; then
BUILD_OS=darwin
- AC_CHECK_PROG([PORT],port, port)
- if test x$PORT = xport; then
- dnl add default macports paths
- CPPFLAGS="$CPPFLAGS -isystem /opt/local/include"
- LIBS="$LIBS -L/opt/local/lib"
- if test -d /opt/local/include/db48; then
- CPPFLAGS="$CPPFLAGS -I/opt/local/include/db48"
- LIBS="$LIBS -L/opt/local/lib/db48"
- fi
- fi
-
AC_PATH_PROGS([RSVG_CONVERT], [rsvg-convert rsvg],rsvg-convert)
AC_CHECK_PROG([BREW],brew, brew)
if test x$BREW = xbrew; then
diff --git a/contrib/macdeploy/macdeployqtplus b/contrib/macdeploy/macdeployqtplus
index 17ce6c44f9..9da03e5b02 100755
--- a/contrib/macdeploy/macdeployqtplus
+++ b/contrib/macdeploy/macdeployqtplus
@@ -172,12 +172,6 @@ class DeploymentInfo(object):
if os.path.exists(os.path.join(parentDir, "translations")):
# Classic layout, e.g. "/usr/local/Trolltech/Qt-4.x.x"
self.qtPath = parentDir
- elif os.path.exists(os.path.join(parentDir, "share", "qt4", "translations")):
- # MacPorts layout, e.g. "/opt/local/share/qt4"
- self.qtPath = os.path.join(parentDir, "share", "qt4")
- elif os.path.exists(os.path.join(os.path.dirname(parentDir), "share", "qt4", "translations")):
- # Newer Macports layout
- self.qtPath = os.path.join(os.path.dirname(parentDir), "share", "qt4")
else:
self.qtPath = os.getenv("QTDIR", None)
diff --git a/depends/packages/zeromq.mk b/depends/packages/zeromq.mk
index c9068e83a5..dfbc50580c 100644
--- a/depends/packages/zeromq.mk
+++ b/depends/packages/zeromq.mk
@@ -1,8 +1,8 @@
package=zeromq
-$(package)_version=4.2.5
+$(package)_version=4.3.1
$(package)_download_path=https://github.com/zeromq/libzmq/releases/download/v$($(package)_version)/
$(package)_file_name=$(package)-$($(package)_version).tar.gz
-$(package)_sha256_hash=cc9090ba35713d59bb2f7d7965f877036c49c5558ea0c290b0dcc6f2a17e489f
+$(package)_sha256_hash=bcbabe1e2c7d0eec4ed612e10b94b112dd5f06fcefa994a0c79a45d835cd21eb
$(package)_patches=0001-fix-build-with-older-mingw64.patch 0002-disable-pthread_set_name_np.patch
define $(package)_set_vars
diff --git a/doc/REST-interface.md b/doc/REST-interface.md
index 44df698382..ff7ef6ce1c 100644
--- a/doc/REST-interface.md
+++ b/doc/REST-interface.md
@@ -27,6 +27,7 @@ For full TX query capability, one must enable the transaction index via "txindex
`GET /rest/block/notxdetails/<BLOCK-HASH>.<bin|hex|json>`
Given a block hash: returns a block, in binary, hex-encoded binary or JSON formats.
+Responds with 404 if the block doesn't exist.
The HTTP request and response are both handled entirely in-memory, thus making maximum memory usage at least 2.66MB (1 MB max block, plus hex encoding) per request.
@@ -36,6 +37,7 @@ With the /notxdetails/ option JSON response will only contain the transaction ha
`GET /rest/headers/<COUNT>/<BLOCK-HASH>.<bin|hex|json>`
Given a block hash: returns <COUNT> amount of blockheaders in upward direction.
+Returns empty if the block doesn't exist or it isn't in the active chain.
#### Chaininfos
`GET /rest/chaininfo.json`
diff --git a/doc/dependencies.md b/doc/dependencies.md
index 50dde02fad..b833e9151f 100644
--- a/doc/dependencies.md
+++ b/doc/dependencies.md
@@ -26,5 +26,5 @@ These are the dependencies currently used by Bitcoin Core. You can find instruct
| Qt | [5.9.7](https://download.qt.io/official_releases/qt/) | [5.2](https://github.com/bitcoin/bitcoin/pull/14725) | No | | |
| XCB | | | | | [Yes](https://github.com/bitcoin/bitcoin/blob/master/depends/packages/qt.mk#L87) (Linux only) |
| xkbcommon | | | | | [Yes](https://github.com/bitcoin/bitcoin/blob/master/depends/packages/qt.mk#L86) (Linux only) |
-| ZeroMQ | [4.2.5](https://github.com/zeromq/libzmq/releases) | 4.0.0 | No | | |
+| ZeroMQ | [4.3.1](https://github.com/zeromq/libzmq/releases) | 4.0.0 | No | | |
| zlib | [1.2.11](https://zlib.net/) | | | | No |
diff --git a/doc/fuzzing.md b/doc/fuzzing.md
index dff9e71bba..23317e938e 100644
--- a/doc/fuzzing.md
+++ b/doc/fuzzing.md
@@ -82,7 +82,7 @@ make
```
The fuzzer needs some inputs to work on, but the inputs or seeds can be used
-interchangably between libFuzzer and AFL.
+interchangeably between libFuzzer and AFL.
See https://llvm.org/docs/LibFuzzer.html#running on how to run the libFuzzer
instrumented executable.
diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include
index f4f84e2a99..ba6523d7c2 100644
--- a/src/Makefile.qt.include
+++ b/src/Makefile.qt.include
@@ -157,6 +157,7 @@ QT_MOC_CPP = \
qt/moc_transactiontablemodel.cpp \
qt/moc_transactionview.cpp \
qt/moc_utilitydialog.cpp \
+ qt/moc_walletcontroller.cpp \
qt/moc_walletframe.cpp \
qt/moc_walletmodel.cpp \
qt/moc_walletview.cpp
@@ -237,6 +238,7 @@ BITCOIN_QT_H = \
qt/transactiontablemodel.h \
qt/transactionview.h \
qt/utilitydialog.h \
+ qt/walletcontroller.h \
qt/walletframe.h \
qt/walletmodel.h \
qt/walletmodeltransaction.h \
@@ -350,6 +352,7 @@ BITCOIN_QT_WALLET_CPP = \
qt/transactionrecord.cpp \
qt/transactiontablemodel.cpp \
qt/transactionview.cpp \
+ qt/walletcontroller.cpp \
qt/walletframe.cpp \
qt/walletmodel.cpp \
qt/walletmodeltransaction.cpp \
diff --git a/src/net.h b/src/net.h
index 3606b4d7ba..9c477f6db6 100644
--- a/src/net.h
+++ b/src/net.h
@@ -659,6 +659,8 @@ public:
bool m_limited_node{false}; //after BIP159, set by version message
const bool fInbound;
std::atomic_bool fSuccessfullyConnected{false};
+ // Setting fDisconnect to true will cause the node to be disconnected the
+ // next time DisconnectNodes() runs
std::atomic_bool fDisconnect{false};
// We use fRelayTxes for two purposes -
// a) it allows us to not relay tx invs before receiving the peer's version message
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 893dda1601..ca26131b95 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -24,7 +24,7 @@
#ifdef ENABLE_WALLET
#include <qt/paymentserver.h>
-#include <qt/walletmodel.h>
+#include <qt/walletcontroller.h>
#endif
#include <interfaces/handler.h>
@@ -184,10 +184,6 @@ BitcoinApplication::BitcoinApplication(interfaces::Node& node, int &argc, char *
clientModel(nullptr),
window(nullptr),
pollShutdownTimer(nullptr),
-#ifdef ENABLE_WALLET
- paymentServer(nullptr),
- m_wallet_models(),
-#endif
returnValue(0),
platformStyle(nullptr)
{
@@ -212,7 +208,7 @@ BitcoinApplication::~BitcoinApplication()
if(coreThread)
{
qDebug() << __func__ << ": Stopping thread";
- Q_EMIT stopThread();
+ coreThread->quit();
coreThread->wait();
qDebug() << __func__ << ": Stopped thread";
}
@@ -279,8 +275,7 @@ void BitcoinApplication::startThread()
connect(this, &BitcoinApplication::requestedInitialize, executor, &BitcoinCore::initialize);
connect(this, &BitcoinApplication::requestedShutdown, executor, &BitcoinCore::shutdown);
/* make sure executor object is deleted in its own thread */
- connect(this, &BitcoinApplication::stopThread, executor, &QObject::deleteLater);
- connect(this, &BitcoinApplication::stopThread, coreThread, &QThread::quit);
+ connect(coreThread, &QThread::finished, executor, &QObject::deleteLater);
coreThread->start();
}
@@ -316,11 +311,8 @@ void BitcoinApplication::requestShutdown()
pollShutdownTimer->stop();
#ifdef ENABLE_WALLET
- window->removeAllWallets();
- for (const WalletModel* walletModel : m_wallet_models) {
- delete walletModel;
- }
- m_wallet_models.clear();
+ delete m_wallet_controller;
+ m_wallet_controller = nullptr;
#endif
delete clientModel;
clientModel = nullptr;
@@ -331,35 +323,6 @@ void BitcoinApplication::requestShutdown()
Q_EMIT requestedShutdown();
}
-void BitcoinApplication::addWallet(WalletModel* walletModel)
-{
-#ifdef ENABLE_WALLET
- window->addWallet(walletModel);
-
- if (m_wallet_models.empty()) {
- window->setCurrentWallet(walletModel);
- }
-
-#ifdef ENABLE_BIP70
- connect(walletModel, &WalletModel::coinsSent,
- paymentServer, &PaymentServer::fetchPaymentACK);
-#endif
- connect(walletModel, &WalletModel::unload, this, &BitcoinApplication::removeWallet);
-
- m_wallet_models.push_back(walletModel);
-#endif
-}
-
-void BitcoinApplication::removeWallet()
-{
-#ifdef ENABLE_WALLET
- WalletModel* walletModel = static_cast<WalletModel*>(sender());
- m_wallet_models.erase(std::find(m_wallet_models.begin(), m_wallet_models.end(), walletModel));
- window->removeWallet(walletModel);
- walletModel->deleteLater();
-#endif
-}
-
void BitcoinApplication::initializeResult(bool success)
{
qDebug() << __func__ << ": Initialization result: " << success;
@@ -370,26 +333,22 @@ void BitcoinApplication::initializeResult(bool success)
// Log this only after AppInitMain finishes, as then logging setup is guaranteed complete
qWarning() << "Platform customization:" << platformStyle->getName();
#ifdef ENABLE_WALLET
+ m_wallet_controller = new WalletController(m_node, platformStyle, optionsModel, this);
#ifdef ENABLE_BIP70
PaymentServer::LoadRootCAs();
#endif
- if (paymentServer) paymentServer->setOptionsModel(optionsModel);
+ if (paymentServer) {
+ paymentServer->setOptionsModel(optionsModel);
+#ifdef ENABLE_BIP70
+ connect(m_wallet_controller, &WalletController::coinsSent, paymentServer, &PaymentServer::fetchPaymentACK);
+#endif
+ }
#endif
clientModel = new ClientModel(m_node, optionsModel);
window->setClientModel(clientModel);
-
#ifdef ENABLE_WALLET
- m_handler_load_wallet = m_node.handleLoadWallet([this](std::unique_ptr<interfaces::Wallet> wallet) {
- WalletModel* wallet_model = new WalletModel(std::move(wallet), m_node, platformStyle, optionsModel, nullptr);
- // Fix wallet model thread affinity.
- wallet_model->moveToThread(thread());
- QMetaObject::invokeMethod(this, "addWallet", Qt::QueuedConnection, Q_ARG(WalletModel*, wallet_model));
- });
-
- for (auto& wallet : m_node.getWallets()) {
- addWallet(new WalletModel(std::move(wallet), m_node, platformStyle, optionsModel));
- }
+ window->setWalletController(m_wallet_controller);
#endif
// If -min option passed, start window minimized (iconified) or minimized to tray
@@ -493,9 +452,6 @@ int GuiMain(int argc, char* argv[])
// IMPORTANT if it is no longer a typedef use the normal variant above
qRegisterMetaType< CAmount >("CAmount");
qRegisterMetaType< std::function<void()> >("std::function<void()>");
-#ifdef ENABLE_WALLET
- qRegisterMetaType<WalletModel*>("WalletModel*");
-#endif
/// 2. Parse command-line options. We do this after qt in order to show an error if there are problems parsing these
// Command-line options take precedence:
diff --git a/src/qt/bitcoin.h b/src/qt/bitcoin.h
index 48b5907570..370712d953 100644
--- a/src/qt/bitcoin.h
+++ b/src/qt/bitcoin.h
@@ -19,6 +19,7 @@ class NetworkStyle;
class OptionsModel;
class PaymentServer;
class PlatformStyle;
+class WalletController;
class WalletModel;
namespace interfaces {
@@ -93,13 +94,10 @@ public Q_SLOTS:
void shutdownResult();
/// Handle runaway exceptions. Shows a message box with the problem and quits the program.
void handleRunawayException(const QString &message);
- void addWallet(WalletModel* walletModel);
- void removeWallet();
Q_SIGNALS:
void requestedInitialize();
void requestedShutdown();
- void stopThread();
void splashFinished();
void windowShown(BitcoinGUI* window);
@@ -111,9 +109,8 @@ private:
BitcoinGUI *window;
QTimer *pollShutdownTimer;
#ifdef ENABLE_WALLET
- PaymentServer* paymentServer;
- std::vector<WalletModel*> m_wallet_models;
- std::unique_ptr<interfaces::Handler> m_handler_load_wallet;
+ PaymentServer* paymentServer{nullptr};
+ WalletController* m_wallet_controller{nullptr};
#endif
int returnValue;
const PlatformStyle *platformStyle;
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index ddaf771fa1..ba7e8c7daf 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -19,6 +19,7 @@
#include <qt/utilitydialog.h>
#ifdef ENABLE_WALLET
+#include <qt/walletcontroller.h>
#include <qt/walletframe.h>
#include <qt/walletmodel.h>
#include <qt/walletview.h>
@@ -483,6 +484,7 @@ void BitcoinGUI::createToolBars()
toolbar->addWidget(spacer);
m_wallet_selector = new QComboBox();
+ m_wallet_selector->setSizeAdjustPolicy(QComboBox::AdjustToContents);
connect(m_wallet_selector, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &BitcoinGUI::setCurrentWalletBySelectorIndex);
m_wallet_selector_label = new QLabel();
@@ -565,18 +567,33 @@ void BitcoinGUI::setClientModel(ClientModel *_clientModel)
}
#ifdef ENABLE_WALLET
+void BitcoinGUI::setWalletController(WalletController* wallet_controller)
+{
+ assert(!m_wallet_controller);
+ assert(wallet_controller);
+
+ m_wallet_controller = wallet_controller;
+
+ connect(wallet_controller, &WalletController::walletAdded, this, &BitcoinGUI::addWallet);
+ connect(wallet_controller, &WalletController::walletRemoved, this, &BitcoinGUI::removeWallet);
+
+ for (WalletModel* wallet_model : m_wallet_controller->getWallets()) {
+ addWallet(wallet_model);
+ }
+}
+
void BitcoinGUI::addWallet(WalletModel* walletModel)
{
if (!walletFrame) return;
const QString display_name = walletModel->getDisplayName();
setWalletActionsEnabled(true);
+ rpcConsole->addWallet(walletModel);
+ walletFrame->addWallet(walletModel);
m_wallet_selector->addItem(display_name, QVariant::fromValue(walletModel));
if (m_wallet_selector->count() == 2) {
m_wallet_selector_label_action->setVisible(true);
m_wallet_selector_action->setVisible(true);
}
- rpcConsole->addWallet(walletModel);
- walletFrame->addWallet(walletModel);
}
void BitcoinGUI::removeWallet(WalletModel* walletModel)
@@ -599,13 +616,19 @@ void BitcoinGUI::setCurrentWallet(WalletModel* wallet_model)
{
if (!walletFrame) return;
walletFrame->setCurrentWallet(wallet_model);
+ for (int index = 0; index < m_wallet_selector->count(); ++index) {
+ if (m_wallet_selector->itemData(index).value<WalletModel*>() == wallet_model) {
+ m_wallet_selector->setCurrentIndex(index);
+ break;
+ }
+ }
updateWindowTitle();
}
void BitcoinGUI::setCurrentWalletBySelectorIndex(int index)
{
WalletModel* wallet_model = m_wallet_selector->itemData(index).value<WalletModel*>();
- setCurrentWallet(wallet_model);
+ if (wallet_model) setCurrentWallet(wallet_model);
}
void BitcoinGUI::removeAllWallets()
@@ -1203,16 +1226,18 @@ void BitcoinGUI::updateProxyIcon()
void BitcoinGUI::updateWindowTitle()
{
- QString window_title = tr(PACKAGE_NAME) + " - ";
+ QString window_title = tr(PACKAGE_NAME);
#ifdef ENABLE_WALLET
if (walletFrame) {
WalletModel* const wallet_model = walletFrame->currentWalletModel();
if (wallet_model && !wallet_model->getWalletName().isEmpty()) {
- window_title += wallet_model->getDisplayName() + " - ";
+ window_title += " - " + wallet_model->getDisplayName();
}
}
#endif
- window_title += m_network_style->getTitleAddText();
+ if (!m_network_style->getTitleAddText().isEmpty()) {
+ window_title += " - " + m_network_style->getTitleAddText();
+ }
setWindowTitle(window_title);
}
@@ -1245,25 +1270,21 @@ void BitcoinGUI::detectShutdown()
void BitcoinGUI::showProgress(const QString &title, int nProgress)
{
- if (nProgress == 0)
- {
- progressDialog = new QProgressDialog(title, "", 0, 100);
+ if (nProgress == 0) {
+ progressDialog = new QProgressDialog(title, QString(), 0, 100);
+ GUIUtil::PolishProgressDialog(progressDialog);
progressDialog->setWindowModality(Qt::ApplicationModal);
progressDialog->setMinimumDuration(0);
- progressDialog->setCancelButton(nullptr);
progressDialog->setAutoClose(false);
progressDialog->setValue(0);
- }
- else if (nProgress == 100)
- {
- if (progressDialog)
- {
+ } else if (nProgress == 100) {
+ if (progressDialog) {
progressDialog->close();
progressDialog->deleteLater();
}
- }
- else if (progressDialog)
+ } else if (progressDialog) {
progressDialog->setValue(nProgress);
+ }
}
void BitcoinGUI::setTrayIconVisible(bool fHideTrayIcon)
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index 4eb5e43f5e..f1b76a6b64 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -33,6 +33,7 @@ class PlatformStyle;
class RPCConsole;
class SendCoinsRecipient;
class UnitDisplayStatusBarControl;
+class WalletController;
class WalletFrame;
class WalletModel;
class HelpMessageDialog;
@@ -74,6 +75,9 @@ public:
The client model represents the part of the core that communicates with the P2P network, and is wallet-agnostic.
*/
void setClientModel(ClientModel *clientModel);
+#ifdef ENABLE_WALLET
+ void setWalletController(WalletController* wallet_controller);
+#endif
#ifdef ENABLE_WALLET
/** Set the wallet model.
@@ -101,6 +105,7 @@ protected:
private:
interfaces::Node& m_node;
+ WalletController* m_wallet_controller{nullptr};
std::unique_ptr<interfaces::Handler> m_handler_message_box;
std::unique_ptr<interfaces::Handler> m_handler_question;
ClientModel* clientModel = nullptr;
diff --git a/src/qt/forms/debugwindow.ui b/src/qt/forms/debugwindow.ui
index 8e8d436ce2..f0b976001e 100644
--- a/src/qt/forms/debugwindow.ui
+++ b/src/qt/forms/debugwindow.ui
@@ -453,6 +453,9 @@
</item>
<item>
<widget class="QComboBox" name="WalletSelector">
+ <property name="sizeAdjustPolicy">
+ <enum>QComboBox::AdjustToContents</enum>
+ </property>
<item>
<property name="text">
<string>(none)</string>
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index 2fc166b0c5..b84c07d51a 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -48,13 +48,15 @@
#include <QFileDialog>
#include <QFont>
#include <QFontDatabase>
+#include <QFontMetrics>
#include <QKeyEvent>
#include <QLineEdit>
+#include <QMouseEvent>
+#include <QProgressDialog>
#include <QSettings>
#include <QTextDocument> // for Qt::mightBeRichText
#include <QThread>
#include <QUrlQuery>
-#include <QMouseEvent>
#if defined(Q_OS_MAC)
#pragma GCC diagnostic push
@@ -933,4 +935,16 @@ bool ItemDelegate::eventFilter(QObject *object, QEvent *event)
return QItemDelegate::eventFilter(object, event);
}
+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");
+ dialog->resize(dialog->width() + 2 * margin, dialog->height());
+ dialog->show();
+#else
+ Q_UNUSED(dialog);
+#endif
+}
+
} // namespace GUIUtil
diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h
index ecb770d147..cbec73a882 100644
--- a/src/qt/guiutil.h
+++ b/src/qt/guiutil.h
@@ -31,6 +31,7 @@ class QAbstractItemView;
class QDateTime;
class QFont;
class QLineEdit;
+class QProgressDialog;
class QUrl;
class QWidget;
QT_END_NAMESPACE
@@ -248,6 +249,9 @@ namespace GUIUtil
private:
bool eventFilter(QObject *object, QEvent *event);
};
+
+ // Fix known bugs in QProgressDialog class.
+ void PolishProgressDialog(QProgressDialog* dialog);
} // namespace GUIUtil
#endif // BITCOIN_QT_GUIUTIL_H
diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp
index fa9a50b1ed..69972fce3b 100644
--- a/src/qt/intro.cpp
+++ b/src/qt/intro.cpp
@@ -156,7 +156,7 @@ Intro::~Intro()
{
delete ui;
/* Ensure thread is finished before it is deleted */
- Q_EMIT stopThread();
+ thread->quit();
thread->wait();
}
@@ -311,8 +311,7 @@ void Intro::startThread()
connect(executor, &FreespaceChecker::reply, this, &Intro::setStatus);
connect(this, &Intro::requestCheck, executor, &FreespaceChecker::check);
/* make sure executor object is deleted in its own thread */
- connect(this, &Intro::stopThread, executor, &QObject::deleteLater);
- connect(this, &Intro::stopThread, thread, &QThread::quit);
+ connect(thread, &QThread::finished, executor, &QObject::deleteLater);
thread->start();
}
diff --git a/src/qt/intro.h b/src/qt/intro.h
index 3da8a16114..b537c94f7d 100644
--- a/src/qt/intro.h
+++ b/src/qt/intro.h
@@ -55,7 +55,6 @@ public:
Q_SIGNALS:
void requestCheck();
- void stopThread();
public Q_SLOTS:
void setStatus(int status, const QString &message, quint64 bytesAvailable);
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 2989e1e9e5..fc1e14b031 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -396,13 +396,12 @@ void RPCExecutor::request(const QString &command, const WalletModel* wallet_mode
std::string executableCommand = command.toStdString() + "\n";
// Catch the console-only-help command before RPC call is executed and reply with help text as-if a RPC reply.
- if(executableCommand == "help-console\n")
- {
+ if(executableCommand == "help-console\n") {
Q_EMIT reply(RPCConsole::CMD_REPLY, QString(("\n"
"This console accepts RPC commands using the standard syntax.\n"
" example: getblockhash 0\n\n"
- "This console can also accept RPC commands using parenthesized syntax.\n"
+ "This console can also accept RPC commands using the parenthesized syntax.\n"
" example: getblockhash(0)\n\n"
"Commands may be nested when specified with the parenthesized syntax.\n"
@@ -412,11 +411,11 @@ void RPCExecutor::request(const QString &command, const WalletModel* wallet_mode
" example: getblockhash 0\n"
" getblockhash,0\n\n"
- "Named results can be queried with a non-quoted key string in brackets.\n"
- " example: getblock(getblockhash(0) true)[tx]\n\n"
+ "Named results can be queried with a non-quoted key string in brackets using the parenthesized syntax.\n"
+ " example: getblock(getblockhash(0) 1)[tx]\n\n"
- "Results without keys can be queried using an integer in brackets.\n"
- " example: getblock(getblockhash(0),true)[tx][0]\n\n")));
+ "Results without keys can be queried with an integer in brackets using the parenthesized syntax.\n"
+ " example: getblock(getblockhash(0),1)[tx][0]\n\n")));
return;
}
if (!RPCConsole::RPCExecuteCommandLine(m_node, result, executableCommand, nullptr, wallet_model)) {
@@ -688,8 +687,7 @@ void RPCConsole::setClientModel(ClientModel *model)
}
if (!model) {
// Client model is being set to 0, this means shutdown() is about to be called.
- // Make sure we clean up the executor thread
- Q_EMIT stopExecutor();
+ thread.quit();
thread.wait();
}
}
@@ -975,11 +973,8 @@ void RPCConsole::startExecutor()
// Requests from this object must go to executor
connect(this, &RPCConsole::cmdRequest, executor, &RPCExecutor::request);
- // On stopExecutor signal
- // - quit the Qt event loop in the execution thread
- connect(this, &RPCConsole::stopExecutor, &thread, &QThread::quit);
- // - queue executor for deletion (in execution thread)
- connect(&thread, &QThread::finished, executor, &RPCExecutor::deleteLater, Qt::DirectConnection);
+ // Make sure executor object is deleted in its own thread
+ connect(&thread, &QThread::finished, executor, &RPCExecutor::deleteLater);
// Default implementation of QThread::run() simply spins up an event loop in the thread,
// which is what we want.
diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h
index 6c000ba096..79b0f3b19c 100644
--- a/src/qt/rpcconsole.h
+++ b/src/qt/rpcconsole.h
@@ -132,7 +132,6 @@ public Q_SLOTS:
Q_SIGNALS:
// For RPC command executor
- void stopExecutor();
void cmdRequest(const QString &command, const WalletModel* wallet_model);
private:
diff --git a/src/qt/walletcontroller.cpp b/src/qt/walletcontroller.cpp
new file mode 100644
index 0000000000..df2b7a3f9b
--- /dev/null
+++ b/src/qt/walletcontroller.cpp
@@ -0,0 +1,95 @@
+// 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.
+
+#include <qt/walletcontroller.h>
+
+#include <interfaces/handler.h>
+#include <interfaces/node.h>
+
+#include <algorithm>
+
+#include <QMutexLocker>
+#include <QThread>
+
+WalletController::WalletController(interfaces::Node& node, const PlatformStyle* platform_style, OptionsModel* options_model, QObject* parent)
+ : QObject(parent)
+ , m_node(node)
+ , m_platform_style(platform_style)
+ , m_options_model(options_model)
+{
+ m_handler_load_wallet = m_node.handleLoadWallet([this](std::unique_ptr<interfaces::Wallet> wallet) {
+ getOrCreateWallet(std::move(wallet));
+ });
+
+ for (std::unique_ptr<interfaces::Wallet>& wallet : m_node.getWallets()) {
+ getOrCreateWallet(std::move(wallet));
+ }
+}
+
+// Not using the default destructor because not all member types definitions are
+// available in the header, just forward declared.
+WalletController::~WalletController() {}
+
+std::vector<WalletModel*> WalletController::getWallets() const
+{
+ QMutexLocker locker(&m_mutex);
+ return m_wallets;
+}
+
+WalletModel* WalletController::getOrCreateWallet(std::unique_ptr<interfaces::Wallet> wallet)
+{
+ QMutexLocker locker(&m_mutex);
+
+ // Return model instance if exists.
+ if (!m_wallets.empty()) {
+ std::string name = wallet->getWalletName();
+ for (WalletModel* wallet_model : m_wallets) {
+ if (wallet_model->wallet().getWalletName() == name) {
+ return wallet_model;
+ }
+ }
+ }
+
+ // Instantiate model and register it.
+ WalletModel* wallet_model = new WalletModel(std::move(wallet), m_node, m_platform_style, m_options_model, nullptr);
+ m_wallets.push_back(wallet_model);
+
+ connect(wallet_model, &WalletModel::unload, [this, wallet_model] {
+ removeAndDeleteWallet(wallet_model);
+ });
+
+ // Re-emit coinsSent signal from wallet model.
+ connect(wallet_model, &WalletModel::coinsSent, this, &WalletController::coinsSent);
+
+ // Notify walletAdded signal on the GUI thread.
+ if (QThread::currentThread() == thread()) {
+ addWallet(wallet_model);
+ } else {
+ // Handler callback runs in a different thread so fix wallet model thread affinity.
+ wallet_model->moveToThread(thread());
+ QMetaObject::invokeMethod(this, "addWallet", Qt::QueuedConnection, Q_ARG(WalletModel*, wallet_model));
+ }
+
+ return wallet_model;
+}
+
+void WalletController::addWallet(WalletModel* wallet_model)
+{
+ // Take ownership of the wallet model and register it.
+ wallet_model->setParent(this);
+ Q_EMIT walletAdded(wallet_model);
+}
+
+void WalletController::removeAndDeleteWallet(WalletModel* wallet_model)
+{
+ // Unregister wallet model.
+ {
+ QMutexLocker locker(&m_mutex);
+ m_wallets.erase(std::remove(m_wallets.begin(), m_wallets.end(), wallet_model));
+ }
+ Q_EMIT walletRemoved(wallet_model);
+ // Currently this can trigger the unload since the model can hold the last
+ // CWallet shared pointer.
+ delete wallet_model;
+}
diff --git a/src/qt/walletcontroller.h b/src/qt/walletcontroller.h
new file mode 100644
index 0000000000..22b71b07ff
--- /dev/null
+++ b/src/qt/walletcontroller.h
@@ -0,0 +1,59 @@
+// 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.
+
+#ifndef BITCOIN_QT_WALLETCONTROLLER_H
+#define BITCOIN_QT_WALLETCONTROLLER_H
+
+#include <qt/walletmodel.h>
+#include <sync.h>
+
+#include <list>
+#include <memory>
+#include <vector>
+
+#include <QMutex>
+
+class OptionsModel;
+class PlatformStyle;
+
+namespace interfaces {
+class Handler;
+class Node;
+} // namespace interfaces
+
+/**
+ * Controller between interfaces::Node, WalletModel instances and the GUI.
+ */
+class WalletController : public QObject
+{
+ Q_OBJECT
+
+ WalletModel* getOrCreateWallet(std::unique_ptr<interfaces::Wallet> wallet);
+ void removeAndDeleteWallet(WalletModel* wallet_model);
+
+public:
+ WalletController(interfaces::Node& node, const PlatformStyle* platform_style, OptionsModel* options_model, QObject* parent);
+ ~WalletController();
+
+ std::vector<WalletModel*> getWallets() const;
+
+private Q_SLOTS:
+ void addWallet(WalletModel* wallet_model);
+
+Q_SIGNALS:
+ void walletAdded(WalletModel* wallet_model);
+ void walletRemoved(WalletModel* wallet_model);
+
+ void coinsSent(WalletModel* wallet_model, SendCoinsRecipient recipient, QByteArray transaction);
+
+private:
+ interfaces::Node& m_node;
+ const PlatformStyle* const m_platform_style;
+ OptionsModel* const m_options_model;
+ mutable QMutex m_mutex;
+ std::vector<WalletModel*> m_wallets;
+ std::unique_ptr<interfaces::Handler> m_handler_load_wallet;
+};
+
+#endif // BITCOIN_QT_WALLETCONTROLLER_H
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index e1fb4819f1..f139152042 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -376,7 +376,7 @@ bool WalletModel::changePassphrase(const SecureString &oldPass, const SecureStri
static void NotifyUnload(WalletModel* walletModel)
{
qDebug() << "NotifyUnload";
- QMetaObject::invokeMethod(walletModel, "unload", Qt::QueuedConnection);
+ QMetaObject::invokeMethod(walletModel, "unload");
}
static void NotifyKeyStoreStatusChanged(WalletModel *walletmodel)
diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp
index dd089d8310..5f6f93d948 100644
--- a/src/qt/walletview.cpp
+++ b/src/qt/walletview.cpp
@@ -305,24 +305,19 @@ void WalletView::usedReceivingAddresses()
void WalletView::showProgress(const QString &title, int nProgress)
{
- if (nProgress == 0)
- {
- progressDialog = new QProgressDialog(title, "", 0, 100);
+ if (nProgress == 0) {
+ progressDialog = new QProgressDialog(title, tr("Cancel"), 0, 100);
+ GUIUtil::PolishProgressDialog(progressDialog);
progressDialog->setWindowModality(Qt::ApplicationModal);
progressDialog->setMinimumDuration(0);
progressDialog->setAutoClose(false);
progressDialog->setValue(0);
- progressDialog->setCancelButtonText(tr("Cancel"));
- }
- else if (nProgress == 100)
- {
- if (progressDialog)
- {
+ } else if (nProgress == 100) {
+ if (progressDialog) {
progressDialog->close();
progressDialog->deleteLater();
}
- }
- else if (progressDialog) {
+ } else if (progressDialog) {
if (progressDialog->wasCanceled()) {
getWalletModel()->wallet().abortRescan();
} else {
diff --git a/src/util/system.cpp b/src/util/system.cpp
index 7f2e9a3114..3ef8111b32 100644
--- a/src/util/system.cpp
+++ b/src/util/system.cpp
@@ -1290,7 +1290,7 @@ fs::path AbsPathForConfigVal(const fs::path& path, bool net_specific)
int ScheduleBatchPriority()
{
#ifdef SCHED_BATCH
- const static sched_param param{0};
+ const static sched_param param{};
if (int ret = pthread_setschedparam(pthread_self(), SCHED_BATCH, &param)) {
LogPrintf("Failed to pthread_setschedparam: %s\n", strerror(errno));
return ret;
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 39c17743ec..cb08112761 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -3586,7 +3586,6 @@ UniValue getaddressinfo(const JSONRPCRequest& request)
" \"address\" : \"address\", (string) The bitcoin address validated\n"
" \"scriptPubKey\" : \"hex\", (string) The hex-encoded scriptPubKey generated by the address\n"
" \"ismine\" : true|false, (boolean) If the address is yours or not\n"
- " \"solvable\" : true|false, (boolean) If the address is solvable by the wallet\n"
" \"iswatchonly\" : true|false, (boolean) If the address is watchonly\n"
" \"solvable\" : true|false, (boolean) Whether we know how to spend coins sent to this address, ignoring the possible lack of private keys\n"
" \"desc\" : \"desc\", (string, optional) A descriptor for spending coins sent to this address (only when solvable)\n"
@@ -3605,7 +3604,7 @@ UniValue getaddressinfo(const JSONRPCRequest& request)
" \"sigsrequired\" : xxxxx (numeric, optional) Number of signatures required to spend multisig output (only if \"script\" is \"multisig\")\n"
" \"pubkey\" : \"publickeyhex\", (string, optional) The hex value of the raw public key, for single-key addresses (possibly embedded in P2SH or P2WSH)\n"
" \"embedded\" : {...}, (object, optional) Information about the address embedded in P2SH or P2WSH, if relevant and known. It includes all getaddressinfo output fields for the embedded address, excluding metadata (\"timestamp\", \"hdkeypath\", \"hdseedid\") and relation to the wallet (\"ismine\", \"iswatchonly\").\n"
- " \"iscompressed\" : true|false, (boolean) If the address is compressed\n"
+ " \"iscompressed\" : true|false, (boolean, optional) If the pubkey is compressed\n"
" \"label\" : \"label\" (string) The label associated with the address, \"\" is the default label\n"
" \"timestamp\" : timestamp, (number, optional) The creation time of the key if available in seconds since epoch (Jan 1 1970 GMT)\n"
" \"hdkeypath\" : \"keypath\" (string, optional) The HD keypath if the key is HD and available\n"
@@ -3649,7 +3648,6 @@ UniValue getaddressinfo(const JSONRPCRequest& request)
ret.pushKV("desc", InferDescriptor(scriptPubKey, *pwallet)->ToString());
}
ret.pushKV("iswatchonly", bool(mine & ISMINE_WATCH_ONLY));
- ret.pushKV("solvable", IsSolvable(*pwallet, scriptPubKey));
UniValue detail = DescribeWalletAddress(pwallet, dest);
ret.pushKVs(detail);
if (pwallet->mapAddressBook.count(dest)) {
@@ -4044,8 +4042,7 @@ UniValue walletcreatefundedpsbt(const JSONRPCRequest& request)
},
},
},
- {"locktime", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "0", "Raw locktime. Non-0 value also locktime-activates inputs\n"
- " Allows this transaction to be replaced by a transaction with higher fees. If provided, it is an error if explicit sequence numbers are incompatible."},
+ {"locktime", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "0", "Raw locktime. Non-0 value also locktime-activates inputs"},
{"options", RPCArg::Type::OBJ, /* opt */ true, /* default_val */ "null", "",
{
{"changeAddress", RPCArg::Type::STR_HEX, /* opt */ true, /* default_val */ "pool address", "The bitcoin address to receive the change"},
diff --git a/src/zmq/zmqpublishnotifier.cpp b/src/zmq/zmqpublishnotifier.cpp
index 15d4ac1b89..ba89d1401d 100644
--- a/src/zmq/zmqpublishnotifier.cpp
+++ b/src/zmq/zmqpublishnotifier.cpp
@@ -101,6 +101,7 @@ bool CZMQAbstractPublishNotifier::Initialize(void *pcontext)
else
{
LogPrint(BCLog::ZMQ, "zmq: Reusing socket for address %s\n", address);
+ LogPrint(BCLog::ZMQ, "zmq: Outbound message high water mark for %s at %s is %d\n", type, address, outbound_message_high_water_mark);
psocket = i->second->psocket;
mapPublishNotifiers.insert(std::make_pair(address, this));
diff --git a/test/functional/interface_rest.py b/test/functional/interface_rest.py
index afa9de580f..23b13fc4f1 100755
--- a/test/functional/interface_rest.py
+++ b/test/functional/interface_rest.py
@@ -201,6 +201,16 @@ class RESTTest (BitcoinTestFramework):
self.log.info("Test the /block and /headers URIs")
bb_hash = self.nodes[0].getbestblockhash()
+ # Check result if block does not exists
+ assert_equal(self.test_rest_request('/headers/1/0000000000000000000000000000000000000000000000000000000000000000'), [])
+ self.test_rest_request('/block/0000000000000000000000000000000000000000000000000000000000000000', status=404, ret_type=RetType.OBJ)
+
+ # Check result if block is not in the active chain
+ self.nodes[0].invalidateblock(bb_hash)
+ assert_equal(self.test_rest_request('/headers/1/{}'.format(bb_hash)), [])
+ self.test_rest_request('/block/{}'.format(bb_hash))
+ self.nodes[0].reconsiderblock(bb_hash)
+
# Check binary format
response = self.test_rest_request("/block/{}".format(bb_hash), req_type=ReqType.BIN, ret_type=RetType.OBJ)
assert_greater_than(int(response.getheader('content-length')), 80)
diff --git a/test/lint/lint-format-strings.sh b/test/lint/lint-format-strings.sh
index 2c443abf6b..c994ae3f4d 100755
--- a/test/lint/lint-format-strings.sh
+++ b/test/lint/lint-format-strings.sh
@@ -11,20 +11,20 @@
export LC_ALL=C
FUNCTION_NAMES_AND_NUMBER_OF_LEADING_ARGUMENTS=(
- FatalError,0
- fprintf,1
- LogConnectFailure,1
- LogPrint,1
- LogPrintf,0
- printf,0
- snprintf,2
- sprintf,1
- strprintf,0
- vfprintf,1
- vprintf,1
- vsnprintf,1
- vsprintf,1
- WalletLogPrintf,0
+ "FatalError,0"
+ "fprintf,1"
+ "LogConnectFailure,1"
+ "LogPrint,1"
+ "LogPrintf,0"
+ "printf,0"
+ "snprintf,2"
+ "sprintf,1"
+ "strprintf,0"
+ "vfprintf,1"
+ "vprintf,1"
+ "vsnprintf,1"
+ "vsprintf,1"
+ "WalletLogPrintf,0"
)
EXIT_CODE=0
diff --git a/test/lint/lint-shell.sh b/test/lint/lint-shell.sh
index cf8a37c3a1..6f5e6546c5 100755
--- a/test/lint/lint-shell.sh
+++ b/test/lint/lint-shell.sh
@@ -13,7 +13,7 @@ export LC_ALL=C
# respectively. So export LC_ALL=C is set as required by lint-shell-locale.sh
# but unset here in case of running in Travis.
if [ "$TRAVIS" = "true" ]; then
- unset LC_ALL
+ unset LC_ALL
fi
if ! command -v shellcheck > /dev/null; then
@@ -24,7 +24,6 @@ fi
# Disabled warnings:
disabled=(
SC1087 # Use braces when expanding arrays, e.g. ${array[idx]} (or ${var}[.. to quiet).
- SC1117 # Backslash is literal in "\.". Prefer explicit escaping: "\\.".
SC2001 # See if you can use ${variable//search/replace} instead.
SC2004 # $/${} is unnecessary on arithmetic variables.
SC2005 # Useless echo? Instead of 'echo $(cmd)', just use 'cmd'.
@@ -36,10 +35,8 @@ disabled=(
SC2066 # Since you double quoted this, it will not word split, and the loop will only run once.
SC2086 # Double quote to prevent globbing and word splitting.
SC2116 # Useless echo? Instead of 'cmd $(echo foo)', just use 'cmd foo'.
- SC2148 # Tips depend on target shell and yours is unknown. Add a shebang.
SC2162 # read without -r will mangle backslashes.
- SC2166 # Prefer [ p ] && [ q ] as [ p -a q ] is not well defined.
- SC2166 # Prefer [ p ] || [ q ] as [ p -o q ] is not well defined.
+ SC2166 # Prefer [ p ] {&&,||} [ q ] as [ p -{a,o} q ] is not well defined.
SC2181 # Check exit code directly with e.g. 'if mycmd;', not indirectly with $?.
SC2206 # Quote to prevent word splitting, or split robustly with mapfile or read -a.
SC2207 # Prefer mapfile or read -a to split command output (or quote to avoid splitting).
diff --git a/test/lint/lint-whitespace.sh b/test/lint/lint-whitespace.sh
index beb7ec42f4..f318e19071 100755
--- a/test/lint/lint-whitespace.sh
+++ b/test/lint/lint-whitespace.sh
@@ -23,7 +23,7 @@ while getopts "?" opt; do
done
if [ -z "${TRAVIS_COMMIT_RANGE}" ]; then
- if [ "$1" ]; then
+ if [ -n "$1" ]; then
TRAVIS_COMMIT_RANGE="HEAD~$1...HEAD"
else
TRAVIS_COMMIT_RANGE="HEAD"