gui: Avoid redundant tx status updates

In TransactionTablePriv::index, avoid calling
interfaces::Wallet::tryGetTxStatus if the status is up to date as of the most
recent NotifyBlockTip notification.  Store height from the most recent
notification in a new ClientModel::cachedNumBlocks variable in order to check
this.

This avoids floods of IPC traffic from tryGetTxStatus with #10102 when there
are a lot of transactions. It might also make the GUI a little more efficient
even when there is no IPC.
This commit is contained in:
Russell Yanofsky
2018-08-01 13:38:45 -04:00
parent e7f8450357
commit 96cb597325
10 changed files with 46 additions and 16 deletions

View File

@@ -336,7 +336,7 @@ void BitcoinApplication::initializeResult(bool success)
window->setClientModel(clientModel); window->setClientModel(clientModel);
#ifdef ENABLE_WALLET #ifdef ENABLE_WALLET
if (WalletModel::isWalletEnabled()) { if (WalletModel::isWalletEnabled()) {
m_wallet_controller = new WalletController(m_node, platformStyle, optionsModel, this); m_wallet_controller = new WalletController(*clientModel, platformStyle, this);
window->setWalletController(m_wallet_controller); window->setWalletController(m_wallet_controller);
if (paymentServer) { if (paymentServer) {
paymentServer->setOptionsModel(optionsModel); paymentServer->setOptionsModel(optionsModel);

View File

@@ -105,6 +105,14 @@ int64_t ClientModel::getHeaderTipTime() const
return cachedBestHeaderTime; return cachedBestHeaderTime;
} }
int ClientModel::getNumBlocks() const
{
if (m_cached_num_blocks == -1) {
m_cached_num_blocks = m_node.getNumBlocks();
}
return m_cached_num_blocks;
}
void ClientModel::updateNumConnections(int numConnections) void ClientModel::updateNumConnections(int numConnections)
{ {
Q_EMIT numConnectionsChanged(numConnections); Q_EMIT numConnectionsChanged(numConnections);
@@ -241,6 +249,8 @@ static void BlockTipChanged(ClientModel *clientmodel, bool initialSync, int heig
// cache best headers time and height to reduce future cs_main locks // cache best headers time and height to reduce future cs_main locks
clientmodel->cachedBestHeaderHeight = height; clientmodel->cachedBestHeaderHeight = height;
clientmodel->cachedBestHeaderTime = blockTime; clientmodel->cachedBestHeaderTime = blockTime;
} else {
clientmodel->m_cached_num_blocks = height;
} }
// if we are in-sync or if we notify a header update, update the UI regardless of last update time // if we are in-sync or if we notify a header update, update the UI regardless of last update time
if (fHeader || !initialSync || now - nLastUpdateNotification > MODEL_UPDATE_DELAY) { if (fHeader || !initialSync || now - nLastUpdateNotification > MODEL_UPDATE_DELAY) {

View File

@@ -56,6 +56,7 @@ public:
//! Return number of connections, default is in- and outbound (total) //! Return number of connections, default is in- and outbound (total)
int getNumConnections(unsigned int flags = CONNECTIONS_ALL) const; int getNumConnections(unsigned int flags = CONNECTIONS_ALL) const;
int getNumBlocks() const;
int getHeaderTipHeight() const; int getHeaderTipHeight() const;
int64_t getHeaderTipTime() const; int64_t getHeaderTipTime() const;
@@ -73,9 +74,10 @@ public:
bool getProxyInfo(std::string& ip_port) const; bool getProxyInfo(std::string& ip_port) const;
// caches for the best header // caches for the best header, number of blocks
mutable std::atomic<int> cachedBestHeaderHeight; mutable std::atomic<int> cachedBestHeaderHeight;
mutable std::atomic<int64_t> cachedBestHeaderTime; mutable std::atomic<int64_t> cachedBestHeaderTime;
mutable std::atomic<int> m_cached_num_blocks{-1};
private: private:
interfaces::Node& m_node; interfaces::Node& m_node;

View File

@@ -4,6 +4,7 @@
#include <interfaces/chain.h> #include <interfaces/chain.h>
#include <interfaces/node.h> #include <interfaces/node.h>
#include <qt/clientmodel.h>
#include <qt/editaddressdialog.h> #include <qt/editaddressdialog.h>
#include <qt/optionsmodel.h> #include <qt/optionsmodel.h>
#include <qt/platformstyle.h> #include <qt/platformstyle.h>
@@ -101,8 +102,9 @@ void TestAddAddressesToSendBook(interfaces::Node& node)
// Initialize relevant QT models. // Initialize relevant QT models.
std::unique_ptr<const PlatformStyle> platformStyle(PlatformStyle::instantiate("other")); std::unique_ptr<const PlatformStyle> platformStyle(PlatformStyle::instantiate("other"));
OptionsModel optionsModel(node); OptionsModel optionsModel(node);
ClientModel clientModel(node, &optionsModel);
AddWallet(wallet); AddWallet(wallet);
WalletModel walletModel(interfaces::MakeWallet(wallet), node, platformStyle.get(), &optionsModel); WalletModel walletModel(interfaces::MakeWallet(wallet), clientModel, platformStyle.get());
RemoveWallet(wallet); RemoveWallet(wallet);
EditAddressDialog editAddressDialog(EditAddressDialog::NewSendingAddress); EditAddressDialog editAddressDialog(EditAddressDialog::NewSendingAddress);
editAddressDialog.setModel(walletModel.getAddressTableModel()); editAddressDialog.setModel(walletModel.getAddressTableModel());

View File

@@ -4,6 +4,7 @@
#include <interfaces/chain.h> #include <interfaces/chain.h>
#include <interfaces/node.h> #include <interfaces/node.h>
#include <qt/bitcoinamountfield.h> #include <qt/bitcoinamountfield.h>
#include <qt/clientmodel.h>
#include <qt/optionsmodel.h> #include <qt/optionsmodel.h>
#include <qt/platformstyle.h> #include <qt/platformstyle.h>
#include <qt/qvalidatedlineedit.h> #include <qt/qvalidatedlineedit.h>
@@ -165,8 +166,9 @@ void TestGUI(interfaces::Node& node)
SendCoinsDialog sendCoinsDialog(platformStyle.get()); SendCoinsDialog sendCoinsDialog(platformStyle.get());
TransactionView transactionView(platformStyle.get()); TransactionView transactionView(platformStyle.get());
OptionsModel optionsModel(node); OptionsModel optionsModel(node);
ClientModel clientModel(node, &optionsModel);
AddWallet(wallet); AddWallet(wallet);
WalletModel walletModel(interfaces::MakeWallet(wallet), node, platformStyle.get(), &optionsModel); WalletModel walletModel(interfaces::MakeWallet(wallet), clientModel, platformStyle.get());
RemoveWallet(wallet); RemoveWallet(wallet);
sendCoinsDialog.setModel(&walletModel); sendCoinsDialog.setModel(&walletModel);
transactionView.setModel(&walletModel); transactionView.setModel(&walletModel);

View File

@@ -5,6 +5,7 @@
#include <qt/transactiontablemodel.h> #include <qt/transactiontablemodel.h>
#include <qt/addresstablemodel.h> #include <qt/addresstablemodel.h>
#include <qt/clientmodel.h>
#include <qt/guiconstants.h> #include <qt/guiconstants.h>
#include <qt/guiutil.h> #include <qt/guiutil.h>
#include <qt/optionsmodel.h> #include <qt/optionsmodel.h>
@@ -175,7 +176,7 @@ public:
return cachedWallet.size(); return cachedWallet.size();
} }
TransactionRecord *index(interfaces::Wallet& wallet, int idx) TransactionRecord *index(interfaces::Wallet& wallet, const int cur_num_blocks, const int idx)
{ {
if(idx >= 0 && idx < cachedWallet.size()) if(idx >= 0 && idx < cachedWallet.size())
{ {
@@ -191,7 +192,7 @@ public:
interfaces::WalletTxStatus wtx; interfaces::WalletTxStatus wtx;
int numBlocks; int numBlocks;
int64_t block_time; int64_t block_time;
if (wallet.tryGetTxStatus(rec->hash, wtx, numBlocks, block_time) && rec->statusUpdateNeeded(numBlocks)) { if (rec->statusUpdateNeeded(cur_num_blocks) && wallet.tryGetTxStatus(rec->hash, wtx, numBlocks, block_time)) {
rec->updateStatus(wtx, numBlocks, block_time); rec->updateStatus(wtx, numBlocks, block_time);
} }
return rec; return rec;
@@ -663,10 +664,10 @@ QVariant TransactionTableModel::headerData(int section, Qt::Orientation orientat
QModelIndex TransactionTableModel::index(int row, int column, const QModelIndex &parent) const QModelIndex TransactionTableModel::index(int row, int column, const QModelIndex &parent) const
{ {
Q_UNUSED(parent); Q_UNUSED(parent);
TransactionRecord *data = priv->index(walletModel->wallet(), row); TransactionRecord *data = priv->index(walletModel->wallet(), walletModel->clientModel().getNumBlocks(), row);
if(data) if(data)
{ {
return createIndex(row, column, priv->index(walletModel->wallet(), row)); return createIndex(row, column, data);
} }
return QModelIndex(); return QModelIndex();
} }

View File

@@ -5,6 +5,7 @@
#include <qt/walletcontroller.h> #include <qt/walletcontroller.h>
#include <qt/askpassphrasedialog.h> #include <qt/askpassphrasedialog.h>
#include <qt/clientmodel.h>
#include <qt/createwalletdialog.h> #include <qt/createwalletdialog.h>
#include <qt/guiconstants.h> #include <qt/guiconstants.h>
#include <qt/guiutil.h> #include <qt/guiutil.h>
@@ -24,13 +25,14 @@
#include <QTimer> #include <QTimer>
#include <QWindow> #include <QWindow>
WalletController::WalletController(interfaces::Node& node, const PlatformStyle* platform_style, OptionsModel* options_model, QObject* parent) WalletController::WalletController(ClientModel& client_model, const PlatformStyle* platform_style, QObject* parent)
: QObject(parent) : QObject(parent)
, m_activity_thread(new QThread(this)) , m_activity_thread(new QThread(this))
, m_activity_worker(new QObject) , m_activity_worker(new QObject)
, m_node(node) , m_client_model(client_model)
, m_node(client_model.node())
, m_platform_style(platform_style) , m_platform_style(platform_style)
, m_options_model(options_model) , m_options_model(client_model.getOptionsModel())
{ {
m_handler_load_wallet = m_node.handleLoadWallet([this](std::unique_ptr<interfaces::Wallet> wallet) { m_handler_load_wallet = m_node.handleLoadWallet([this](std::unique_ptr<interfaces::Wallet> wallet) {
getOrCreateWallet(std::move(wallet)); getOrCreateWallet(std::move(wallet));
@@ -104,7 +106,7 @@ WalletModel* WalletController::getOrCreateWallet(std::unique_ptr<interfaces::Wal
} }
// Instantiate model and register it. // Instantiate model and register it.
WalletModel* wallet_model = new WalletModel(std::move(wallet), m_node, m_platform_style, m_options_model, nullptr); WalletModel* wallet_model = new WalletModel(std::move(wallet), m_client_model, m_platform_style, nullptr);
// Handler callback runs in a different thread so fix wallet model thread affinity. // Handler callback runs in a different thread so fix wallet model thread affinity.
wallet_model->moveToThread(thread()); wallet_model->moveToThread(thread());
wallet_model->setParent(this); wallet_model->setParent(this);

View File

@@ -21,6 +21,7 @@
#include <QTimer> #include <QTimer>
#include <QString> #include <QString>
class ClientModel;
class OptionsModel; class OptionsModel;
class PlatformStyle; class PlatformStyle;
class WalletModel; class WalletModel;
@@ -47,7 +48,7 @@ class WalletController : public QObject
void removeAndDeleteWallet(WalletModel* wallet_model); void removeAndDeleteWallet(WalletModel* wallet_model);
public: public:
WalletController(interfaces::Node& node, const PlatformStyle* platform_style, OptionsModel* options_model, QObject* parent); WalletController(ClientModel& client_model, const PlatformStyle* platform_style, QObject* parent);
~WalletController(); ~WalletController();
//! Returns wallet models currently open. //! Returns wallet models currently open.
@@ -70,6 +71,7 @@ Q_SIGNALS:
private: private:
QThread* const m_activity_thread; QThread* const m_activity_thread;
QObject* const m_activity_worker; QObject* const m_activity_worker;
ClientModel& m_client_model;
interfaces::Node& m_node; interfaces::Node& m_node;
const PlatformStyle* const m_platform_style; const PlatformStyle* const m_platform_style;
OptionsModel* const m_options_model; OptionsModel* const m_options_model;

View File

@@ -9,6 +9,7 @@
#include <qt/walletmodel.h> #include <qt/walletmodel.h>
#include <qt/addresstablemodel.h> #include <qt/addresstablemodel.h>
#include <qt/clientmodel.h>
#include <qt/guiconstants.h> #include <qt/guiconstants.h>
#include <qt/optionsmodel.h> #include <qt/optionsmodel.h>
#include <qt/paymentserver.h> #include <qt/paymentserver.h>
@@ -32,8 +33,13 @@
#include <QTimer> #include <QTimer>
WalletModel::WalletModel(std::unique_ptr<interfaces::Wallet> wallet, interfaces::Node& node, const PlatformStyle *platformStyle, OptionsModel *_optionsModel, QObject *parent) : WalletModel::WalletModel(std::unique_ptr<interfaces::Wallet> wallet, ClientModel& client_model, const PlatformStyle *platformStyle, QObject *parent) :
QObject(parent), m_wallet(std::move(wallet)), m_node(node), optionsModel(_optionsModel), addressTableModel(nullptr), QObject(parent),
m_wallet(std::move(wallet)),
m_client_model(client_model),
m_node(client_model.node()),
optionsModel(client_model.getOptionsModel()),
addressTableModel(nullptr),
transactionTableModel(nullptr), transactionTableModel(nullptr),
recentRequestsTableModel(nullptr), recentRequestsTableModel(nullptr),
cachedEncryptionStatus(Unencrypted), cachedEncryptionStatus(Unencrypted),

View File

@@ -24,6 +24,7 @@
enum class OutputType; enum class OutputType;
class AddressTableModel; class AddressTableModel;
class ClientModel;
class OptionsModel; class OptionsModel;
class PlatformStyle; class PlatformStyle;
class RecentRequestsTableModel; class RecentRequestsTableModel;
@@ -52,7 +53,7 @@ class WalletModel : public QObject
Q_OBJECT Q_OBJECT
public: public:
explicit WalletModel(std::unique_ptr<interfaces::Wallet> wallet, interfaces::Node& node, const PlatformStyle *platformStyle, OptionsModel *optionsModel, QObject *parent = nullptr); explicit WalletModel(std::unique_ptr<interfaces::Wallet> wallet, ClientModel& client_model, const PlatformStyle *platformStyle, QObject *parent = nullptr);
~WalletModel(); ~WalletModel();
enum StatusCode // Returned by sendCoins enum StatusCode // Returned by sendCoins
@@ -145,6 +146,7 @@ public:
interfaces::Node& node() const { return m_node; } interfaces::Node& node() const { return m_node; }
interfaces::Wallet& wallet() const { return *m_wallet; } interfaces::Wallet& wallet() const { return *m_wallet; }
ClientModel& clientModel() const { return m_client_model; }
QString getWalletName() const; QString getWalletName() const;
QString getDisplayName() const; QString getDisplayName() const;
@@ -161,6 +163,7 @@ private:
std::unique_ptr<interfaces::Handler> m_handler_show_progress; std::unique_ptr<interfaces::Handler> m_handler_show_progress;
std::unique_ptr<interfaces::Handler> m_handler_watch_only_changed; std::unique_ptr<interfaces::Handler> m_handler_watch_only_changed;
std::unique_ptr<interfaces::Handler> m_handler_can_get_addrs_changed; std::unique_ptr<interfaces::Handler> m_handler_can_get_addrs_changed;
ClientModel& m_client_model;
interfaces::Node& m_node; interfaces::Node& m_node;
bool fHaveWatchOnly; bool fHaveWatchOnly;