Merge pull request #2553

9d5eb00 TransactionHistory: guard tx info list against concurrent access (xiphon)
This commit is contained in:
luigi1111 2019-12-05 08:49:14 -06:00
commit fd9e7d00ed
No known key found for this signature in database
GPG key ID: F4ACA0183641E010
2 changed files with 45 additions and 31 deletions

View file

@ -32,10 +32,13 @@
#include <QFile>
#include <QDebug>
#include <QReadLocker>
#include <QWriteLocker>
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<TransactionInfo *> 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<TransactionHistory*>(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<TransactionHistory*>(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();
}

View file

@ -31,6 +31,7 @@
#include <QObject>
#include <QList>
#include <QReadWriteLock>
#include <QDateTime>
namespace Monero {
@ -76,6 +77,7 @@ private:
friend class Wallet;
Monero::TransactionHistory * m_pimpl;
mutable QList<TransactionInfo*> m_tinfo;
mutable QReadWriteLock m_tinfoLock;
mutable QDateTime m_firstDateTime;
mutable QDateTime m_lastDateTime;
mutable int m_minutesToUnlock;