Browse Source

support incremental wallet updates

0.8
Wladimir J. van der Laan 14 years ago
parent
commit
9d9a4e874d
  1. 3
      gui/include/clientmodel.h
  2. 2
      gui/include/transactiontablemodel.h
  3. 11
      gui/src/clientmodel.cpp
  4. 110
      gui/src/transactiontablemodel.cpp

3
gui/include/clientmodel.h

@ -29,6 +29,9 @@ public:
int getNumBlocks(); int getNumBlocks();
int getNumTransactions(); int getNumTransactions();
/* Set default address */
void setAddress(const QString &defaultAddress);
/* Send coins */
StatusCode sendCoins(const QString &payTo, qint64 payAmount); StatusCode sendCoins(const QString &payTo, qint64 payAmount);
private: private:
OptionsModel *options_model; OptionsModel *options_model;

2
gui/include/transactiontablemodel.h

@ -49,6 +49,8 @@ private:
private slots: private slots:
void update(); void update();
friend class TransactionTablePriv;
}; };
#endif #endif

11
gui/src/clientmodel.cpp

@ -63,6 +63,17 @@ void ClientModel::update()
emit numTransactionsChanged(getNumTransactions()); emit numTransactionsChanged(getNumTransactions());
} }
void ClientModel::setAddress(const QString &defaultAddress)
{
uint160 hash160;
std::string strAddress = defaultAddress.toStdString();
if (!AddressToHash160(strAddress, hash160))
return;
if (!mapPubKeys.count(hash160))
return;
CWalletDB().WriteDefaultKey(mapPubKeys[hash160]);
}
ClientModel::StatusCode ClientModel::sendCoins(const QString &payTo, qint64 payAmount) ClientModel::StatusCode ClientModel::sendCoins(const QString &payTo, qint64 payAmount)
{ {
uint160 hash160 = 0; uint160 hash160 = 0;

110
gui/src/transactiontablemodel.cpp

@ -9,14 +9,39 @@
#include <QList> #include <QList>
#include <QColor> #include <QColor>
#include <QTimer> #include <QTimer>
#include <QtAlgorithms>
const QString TransactionTableModel::Sent = "s"; const QString TransactionTableModel::Sent = "s";
const QString TransactionTableModel::Received = "r"; const QString TransactionTableModel::Received = "r";
const QString TransactionTableModel::Other = "o"; const QString TransactionTableModel::Other = "o";
/* Comparison operator for sort/binary search of model tx list */
struct TxLessThan
{
bool operator()(const TransactionRecord &a, const TransactionRecord &b) const
{
return a.hash < b.hash;
}
bool operator()(const TransactionRecord &a, const uint256 &b) const
{
return a.hash < b;
}
bool operator()(const uint256 &a, const TransactionRecord &b) const
{
return a < b.hash;
}
};
/* Private implementation */ /* Private implementation */
struct TransactionTablePriv struct TransactionTablePriv
{ {
TransactionTablePriv(TransactionTableModel *parent):
parent(parent)
{
}
TransactionTableModel *parent;
/* Local cache of wallet. /* Local cache of wallet.
* As it is in the same order as the CWallet, by definition * As it is in the same order as the CWallet, by definition
* this is sorted by sha256. * this is sorted by sha256.
@ -39,28 +64,79 @@ struct TransactionTablePriv
} }
} }
/* Update our model of the wallet. /* Update our model of the wallet incrementally.
Call with list of hashes of transactions that were added, removed or changed. Call with list of hashes of transactions that were added, removed or changed.
*/ */
void updateWallet(const QList<uint256> &updated) void updateWallet(const QList<uint256> &updated)
{ {
/* TODO: update only transactions in updated, and only if /* Walk through updated transactions, update model as needed.
the transactions are really part of the visible wallet.
Update status of the other transactions in the cache just in case,
because this call means that a new block came in.
*/ */
qDebug() << "updateWallet"; qDebug() << "updateWallet";
foreach(uint256 hash, updated)
/* Sort update list, and iterate through it in reverse, so that model updates
can be emitted from end to beginning (so that earlier updates will not influence
the indices of latter ones).
*/
QList<uint256> updated_sorted = updated;
qSort(updated_sorted);
CRITICAL_BLOCK(cs_mapWallet)
{ {
qDebug() << " " << QString::fromStdString(hash.ToString()); for(int update_idx = updated_sorted.size()-1; update_idx >= 0; --update_idx)
{
const uint256 &hash = updated_sorted.at(update_idx);
/* Find transaction in wallet */
std::map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);
bool inWallet = mi != mapWallet.end();
/* Find bounds of this transaction in model */
QList<TransactionRecord>::iterator lower = qLowerBound(
cachedWallet.begin(), cachedWallet.end(), hash, TxLessThan());
QList<TransactionRecord>::iterator upper = qUpperBound(
cachedWallet.begin(), cachedWallet.end(), hash, TxLessThan());
int lowerIndex = (lower - cachedWallet.begin());
int upperIndex = (upper - cachedWallet.begin());
bool inModel = false;
if(lower != upper)
{
inModel = true;
} }
/* beginInsertRows(QModelIndex(), first, last) */
/* endInsertRows */
/* beginRemoveRows(QModelIndex(), first, last) */
/* beginEndRows */
refreshWallet(); qDebug() << " " << QString::fromStdString(hash.ToString()) << inWallet << " " << inModel
<< lowerIndex << "-" << upperIndex;
if(inWallet && !inModel)
{
/* Added */
QList<TransactionRecord> toInsert =
TransactionRecord::decomposeTransaction(mi->second);
if(!toInsert.isEmpty()) /* only if something to insert */
{
parent->beginInsertRows(QModelIndex(), lowerIndex, lowerIndex+toInsert.size()-1);
int insert_idx = lowerIndex;
foreach(const TransactionRecord &rec, toInsert)
{
cachedWallet.insert(insert_idx, rec);
insert_idx += 1;
}
parent->endInsertRows();
}
} else if(!inWallet && inModel)
{
/* Removed */
parent->beginRemoveRows(QModelIndex(), lowerIndex, upperIndex-1);
cachedWallet.erase(lower, upper);
parent->endRemoveRows();
} else if(inWallet && inModel)
{
/* Updated */
}
}
}
/* TODO: invalidate status for all transactions
Use counter. Emit dataChanged for column.
*/
} }
int size() int size()
@ -92,7 +168,7 @@ static int column_alignments[] = {
TransactionTableModel::TransactionTableModel(QObject *parent): TransactionTableModel::TransactionTableModel(QObject *parent):
QAbstractTableModel(parent), QAbstractTableModel(parent),
priv(new TransactionTablePriv()) priv(new TransactionTablePriv(this))
{ {
columns << tr("Status") << tr("Date") << tr("Description") << tr("Debit") << tr("Credit"); columns << tr("Status") << tr("Date") << tr("Description") << tr("Debit") << tr("Credit");
@ -127,13 +203,7 @@ void TransactionTableModel::update()
if(!updated.empty()) if(!updated.empty())
{ {
/* TODO: improve this, way too brute-force at the moment,
only update transactions that actually changed, and add/remove
transactions that were added/removed.
*/
beginResetModel();
priv->updateWallet(updated); priv->updateWallet(updated);
endResetModel();
} }
} }

Loading…
Cancel
Save