From 9d5eb002ae5a2308acc1f5a6f2c37bec12fce06f Mon Sep 17 00:00:00 2001 From: xiphon Date: Wed, 4 Dec 2019 10:29:27 +0000 Subject: [PATCH] TransactionHistory: guard tx info list against concurrent access --- src/libwalletqt/TransactionHistory.cpp | 74 +++++++++++++++----------- src/libwalletqt/TransactionHistory.h | 2 + 2 files changed, 45 insertions(+), 31 deletions(-) diff --git a/src/libwalletqt/TransactionHistory.cpp b/src/libwalletqt/TransactionHistory.cpp index e6cfa44e..889bd7c4 100644 --- a/src/libwalletqt/TransactionHistory.cpp +++ b/src/libwalletqt/TransactionHistory.cpp @@ -32,10 +32,13 @@ #include #include +#include +#include TransactionInfo *TransactionHistory::transaction(int index) { + QReadLocker locker(&m_tinfoLock); if (index < 0 || index >= m_tinfo.size()) { qCritical("%s: no transaction info for index %d", __FUNCTION__, index); @@ -53,41 +56,48 @@ TransactionInfo *TransactionHistory::transaction(int index) QList TransactionHistory::getAll(quint32 accountIndex) const { - // XXX this invalidates previously saved history that might be used by model - emit refreshStarted(); - qDeleteAll(m_tinfo); - m_tinfo.clear(); - QDateTime firstDateTime = QDateTime(QDate(2014, 4, 18)); // the genesis block QDateTime lastDateTime = QDateTime::currentDateTime().addDays(1); // tomorrow (guard against jitter and timezones) - quint64 lastTxHeight = 0; - m_locked = false; - m_minutesToUnlock = 0; - TransactionHistory * parent = const_cast(this); - for (const auto i : m_pimpl->getAll()) { - TransactionInfo * ti = new TransactionInfo(i, parent); - if (ti->subaddrAccount() != accountIndex) { - delete ti; - continue; - } - m_tinfo.append(ti); - // looking for transactions timestamp scope - if (ti->timestamp() >= lastDateTime) { - lastDateTime = ti->timestamp(); - } - if (ti->timestamp() <= firstDateTime) { - firstDateTime = ti->timestamp(); - } - quint64 requiredConfirmations = (ti->blockHeight() < ti->unlockTime()) ? ti->unlockTime() - ti->blockHeight() : 10; - // store last tx height - if (ti->confirmations() < requiredConfirmations && ti->blockHeight() >= lastTxHeight) { - lastTxHeight = ti->blockHeight(); - // TODO: Fetch block time and confirmations needed from wallet2? - m_minutesToUnlock = (requiredConfirmations - ti->confirmations()) * 2; - m_locked = true; - } + emit refreshStarted(); + + { + QWriteLocker locker(&m_tinfoLock); + + // XXX this invalidates previously saved history that might be used by model + qDeleteAll(m_tinfo); + m_tinfo.clear(); + + quint64 lastTxHeight = 0; + m_locked = false; + m_minutesToUnlock = 0; + TransactionHistory * parent = const_cast(this); + for (const auto i : m_pimpl->getAll()) { + TransactionInfo * ti = new TransactionInfo(i, parent); + if (ti->subaddrAccount() != accountIndex) { + delete ti; + continue; + } + m_tinfo.append(ti); + // looking for transactions timestamp scope + if (ti->timestamp() >= lastDateTime) { + lastDateTime = ti->timestamp(); + } + if (ti->timestamp() <= firstDateTime) { + firstDateTime = ti->timestamp(); + } + quint64 requiredConfirmations = (ti->blockHeight() < ti->unlockTime()) ? ti->unlockTime() - ti->blockHeight() : 10; + // store last tx height + if (ti->confirmations() < requiredConfirmations && ti->blockHeight() >= lastTxHeight) { + lastTxHeight = ti->blockHeight(); + // TODO: Fetch block time and confirmations needed from wallet2? + m_minutesToUnlock = (requiredConfirmations - ti->confirmations()) * 2; + m_locked = true; + } + + } } + emit refreshFinished(); if (m_firstDateTime != firstDateTime) { @@ -112,6 +122,8 @@ void TransactionHistory::refresh(quint32 accountIndex) quint64 TransactionHistory::count() const { + QReadLocker locker(&m_tinfoLock); + return m_tinfo.count(); } diff --git a/src/libwalletqt/TransactionHistory.h b/src/libwalletqt/TransactionHistory.h index ab494e1d..d28a0f6c 100644 --- a/src/libwalletqt/TransactionHistory.h +++ b/src/libwalletqt/TransactionHistory.h @@ -31,6 +31,7 @@ #include #include +#include #include namespace Monero { @@ -76,6 +77,7 @@ private: friend class Wallet; Monero::TransactionHistory * m_pimpl; mutable QList m_tinfo; + mutable QReadWriteLock m_tinfoLock; mutable QDateTime m_firstDateTime; mutable QDateTime m_lastDateTime; mutable int m_minutesToUnlock;