1 #include "mintingtablemodel.h"
2 #include "transactiontablemodel.h"
4 #include "kernelrecord.h"
5 #include "guiconstants.h"
6 #include "transactiondesc.h"
7 #include "walletmodel.h"
8 #include "optionsmodel.h"
9 #include "addresstablemodel.h"
10 #include "bitcoinunits.h"
22 #include <QtAlgorithms>
24 extern double GetDifficulty(const CBlockIndex* blockindex);
26 static int column_alignments[] = {
27 Qt::AlignLeft|Qt::AlignVCenter,
28 Qt::AlignLeft|Qt::AlignVCenter,
29 Qt::AlignRight|Qt::AlignVCenter,
30 Qt::AlignRight|Qt::AlignVCenter,
31 Qt::AlignRight|Qt::AlignVCenter,
32 Qt::AlignRight|Qt::AlignVCenter
37 bool operator()(const KernelRecord &a, const KernelRecord &b) const
39 return a.hash < b.hash;
41 bool operator()(const KernelRecord &a, const uint256 &b) const
45 bool operator()(const uint256 &a, const KernelRecord &b) const
51 class MintingTablePriv
54 MintingTablePriv(CWallet *wallet, MintingTableModel *parent):
60 MintingTableModel *parent;
62 QList<KernelRecord> cachedWallet;
66 #ifdef WALLET_UPDATE_DEBUG
67 qDebug() << "refreshWallet";
71 LOCK(wallet->cs_wallet);
72 for(std::map<uint256, CWalletTx>::iterator it = wallet->mapWallet.begin(); it != wallet->mapWallet.end(); ++it)
74 std::vector<KernelRecord> txList = KernelRecord::decomposeOutput(wallet, it->second);
75 BOOST_FOREACH(KernelRecord& kr, txList) {
77 cachedWallet.append(kr);
85 /* Update our model of the wallet incrementally, to synchronize our model of the wallet
86 with that of the core.
88 Call with list of hashes of transactions that were added, removed or changed.
90 void updateWallet(const QList<uint256> &updated)
92 // Walk through updated transactions, update model as needed.
93 #ifdef WALLET_UPDATE_DEBUG
94 qDebug() << "updateWallet";
96 // Sort update list, and iterate through it in reverse, so that model updates
97 // can be emitted from end to beginning (so that earlier updates will not influence
98 // the indices of latter ones).
99 QList<uint256> updated_sorted = updated;
100 qSort(updated_sorted);
103 LOCK(wallet->cs_wallet);
104 for(int update_idx = updated_sorted.size()-1; update_idx >= 0; --update_idx)
106 const uint256 &hash = updated_sorted.at(update_idx);
107 // Find transaction in wallet
108 std::map<uint256, CWalletTx>::iterator mi = wallet->mapWallet.find(hash);
109 bool inWallet = mi != wallet->mapWallet.end();
110 // Find bounds of this transaction in model
111 QList<KernelRecord>::iterator lower = qLowerBound(
112 cachedWallet.begin(), cachedWallet.end(), hash, TxLessThan());
113 QList<KernelRecord>::iterator upper = qUpperBound(
114 cachedWallet.begin(), cachedWallet.end(), hash, TxLessThan());
115 int lowerIndex = (lower - cachedWallet.begin());
116 int upperIndex = (upper - cachedWallet.begin());
118 // Determine if transaction is in model already
119 bool inModel = false;
125 #ifdef WALLET_UPDATE_DEBUG
126 qDebug() << " " << QString::fromStdString(hash.ToString()) << inWallet << " " << inModel
127 << lowerIndex << "-" << upperIndex;
130 if(inWallet && !inModel)
132 // Added -- insert at the right position
133 std::vector<KernelRecord> toInsert =
134 KernelRecord::decomposeOutput(wallet, mi->second);
135 if(!toInsert.empty()) /* only if something to insert */
137 parent->beginInsertRows(QModelIndex(), lowerIndex, lowerIndex+toInsert.size()-1);
138 int insert_idx = lowerIndex;
139 BOOST_FOREACH(const KernelRecord &rec, toInsert)
142 cachedWallet.insert(insert_idx, rec);
146 parent->endInsertRows();
149 else if(!inWallet && inModel)
151 // Removed -- remove entire transaction from table
152 parent->beginRemoveRows(QModelIndex(), lowerIndex, upperIndex-1);
153 cachedWallet.erase(lower, upper);
154 parent->endRemoveRows();
156 else if(inWallet && inModel)
158 // Updated -- nothing to do, status update will take care of this
166 return cachedWallet.size();
169 KernelRecord *index(int idx)
171 if(idx >= 0 && idx < cachedWallet.size())
173 KernelRecord *rec = &cachedWallet[idx];
182 QString describe(KernelRecord *rec)
185 LOCK(wallet->cs_wallet);
186 std::map<uint256, CWalletTx>::iterator mi = wallet->mapWallet.find(rec->hash);
187 if(mi != wallet->mapWallet.end())
189 return TransactionDesc::toHTML(wallet, mi->second);
198 MintingTableModel::MintingTableModel(CWallet *wallet, WalletModel *parent):
199 QAbstractTableModel(parent),
203 priv(new MintingTablePriv(wallet, this))
205 columns << tr("Transaction") << tr("Address") << tr("Age") << tr("Balance") << tr("CoinDay") << tr("MintProbability");
206 priv->refreshWallet();
208 QTimer *timer = new QTimer(this);
209 connect(timer, SIGNAL(timeout()), this, SLOT(update()));
210 timer->start(MODEL_UPDATE_DELAY);
213 MintingTableModel::~MintingTableModel()
218 void MintingTableModel::update()
220 QList<uint256> updated;
222 // Check if there are changes to wallet map
224 TRY_LOCK(wallet->cs_wallet, lockWallet);
225 if (lockWallet && !wallet->vMintingWalletUpdated.empty())
227 BOOST_FOREACH(uint256 hash, wallet->vMintingWalletUpdated)
229 updated.append(hash);
231 wallet->vMintingWalletUpdated.clear();
237 priv->updateWallet(updated);
241 int MintingTableModel::rowCount(const QModelIndex &parent) const
247 int MintingTableModel::columnCount(const QModelIndex &parent) const
250 return columns.length();
253 QVariant MintingTableModel::data(const QModelIndex &index, int role) const
257 KernelRecord *rec = static_cast<KernelRecord*>(index.internalPointer());
261 case Qt::DisplayRole:
262 switch(index.column())
265 return formatTxAddress(rec, false);
267 return formatTxHash(rec);
269 return formatTxAge(rec);
271 return formatTxBalance(rec);
273 return formatTxCoinDay(rec);
274 case MintProbability:
275 return formatDayToMint(rec);
278 case Qt::TextAlignmentRole:
279 return column_alignments[index.column()];
281 case Qt::ToolTipRole:
282 switch(index.column())
284 case MintProbability:
285 int interval = this->mintingInterval;
286 QString unit = tr("minutes");
288 int hours = interval / 60;
289 int days = hours / 24;
300 QString str = QString(tr("You have %1 chance to find a POS block if you mint %2 %3 at current difficulty."));
301 return str.arg(index.data().toString().toUtf8().constData()).arg(interval).arg(unit);
305 switch(index.column())
308 return formatTxAddress(rec, false);
310 return formatTxHash(rec);
312 return rec->getAge();
317 case MintProbability:
318 return getDayToMint(rec);
321 case Qt::BackgroundColorRole:
322 int minAge = nStakeMinAge / 60 / 60 / 24;
323 int maxAge = nStakeMaxAge / 60 / 60 / 24;
324 if(rec->getAge() < minAge)
326 return COLOR_MINT_YOUNG;
328 else if (rec->getAge() >= minAge && rec->getAge() < (maxAge + minAge))
330 return COLOR_MINT_MATURE;
334 return COLOR_MINT_OLD;
342 void MintingTableModel::setMintingInterval(int interval)
344 mintingInterval = interval;
347 QString MintingTableModel::lookupAddress(const std::string &address, bool tooltip) const
349 QString label = walletModel->getAddressTableModel()->labelForAddress(QString::fromStdString(address));
353 description += label + QString(" ");
355 if(label.isEmpty() || walletModel->getOptionsModel()->getDisplayAddresses() || tooltip)
357 description += QString("(") + QString::fromStdString(address) + QString(")");
362 double MintingTableModel::getDayToMint(KernelRecord *wtx) const
364 const CBlockIndex *p = GetLastBlockIndex(pindexBest, true);
365 double difficulty = GetDifficulty(p);
367 double prob = wtx->getProbToMintWithinNMinutes(difficulty, mintingInterval);
372 QString MintingTableModel::formatDayToMint(KernelRecord *wtx) const
374 double prob = getDayToMint(wtx);
375 return QString::number(prob, 'f', 3) + "%";
378 QString MintingTableModel::formatTxAddress(const KernelRecord *wtx, bool tooltip) const
380 return QString::fromStdString(wtx->address);
383 QString MintingTableModel::formatTxHash(const KernelRecord *wtx) const
385 return QString::fromStdString(wtx->hash.ToString());
388 QString MintingTableModel::formatTxCoinDay(const KernelRecord *wtx) const
390 return QString::number(wtx->coinAge);
393 QString MintingTableModel::formatTxAge(const KernelRecord *wtx) const
395 int64 nAge = wtx->getAge();
396 return QString::number(nAge);
399 QString MintingTableModel::formatTxBalance(const KernelRecord *wtx) const
401 return BitcoinUnits::format(walletModel->getOptionsModel()->getDisplayUnit(), wtx->nValue);
404 QVariant MintingTableModel::headerData(int section, Qt::Orientation orientation, int role) const
406 if(orientation == Qt::Horizontal)
408 if(role == Qt::DisplayRole)
410 return columns[section];
412 else if (role == Qt::TextAlignmentRole)
414 return column_alignments[section];
415 } else if (role == Qt::ToolTipRole)
420 return tr("Destination address of the output.");
422 return tr("Original transaction id.");
424 return tr("Age of the transaction in days.");
426 return tr("Balance of the output.");
428 return tr("Coin age in the output.");
429 case MintProbability:
430 return tr("Chance to mint a block within given time interval.");
437 QModelIndex MintingTableModel::index(int row, int column, const QModelIndex &parent) const
440 KernelRecord *data = priv->index(row);
443 return createIndex(row, column, priv->index(row));
447 return QModelIndex();