From 35887fce5961f04ac417caf695ea68b4aa43e7bb Mon Sep 17 00:00:00 2001 From: serisia Date: Mon, 11 Feb 2019 01:23:02 +0900 Subject: [PATCH 01/10] implove refresh process --- src/interfaces/wallet.cpp | 5 + src/interfaces/wallet.h | 3 + src/kernelrecord.cpp | 21 +++ src/kernelrecord.h | 2 +- src/qt/mintingtablemodel.cpp | 279 ++++++++++++++++++++++++++++++++++- src/qt/mintingtablemodel.h | 4 + 6 files changed, 306 insertions(+), 8 deletions(-) diff --git a/src/interfaces/wallet.cpp b/src/interfaces/wallet.cpp index 0e8852301ca8..6eb060e04c53 100644 --- a/src/interfaces/wallet.cpp +++ b/src/interfaces/wallet.cpp @@ -211,6 +211,11 @@ class WalletImpl : public Wallet LOCK2(cs_main, m_wallet.cs_wallet); return m_wallet.IsLockedCoin(output.hash, output.n); } + bool isSpent(const uint256& hash, unsigned int n) override + { + LOCK2(cs_main, m_wallet.cs_wallet); + return m_wallet.IsSpent(hash, n); + } void listLockedCoins(std::vector& outputs) override { LOCK2(cs_main, m_wallet.cs_wallet); diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h index d6899f2aa565..70a945f7439e 100644 --- a/src/interfaces/wallet.h +++ b/src/interfaces/wallet.h @@ -128,6 +128,9 @@ class Wallet //! Return whether coin is locked. virtual bool isLockedCoin(const COutPoint& output) = 0; + //! Return whether coin is Spent. + virtual bool isSpent(const uint256& hash, unsigned int n) = 0; + //! List locked coins. virtual void listLockedCoins(std::vector& outputs) = 0; diff --git a/src/kernelrecord.cpp b/src/kernelrecord.cpp index 5a1223474db5..10e5d0440ac9 100644 --- a/src/kernelrecord.cpp +++ b/src/kernelrecord.cpp @@ -39,6 +39,27 @@ vector KernelRecord::decomposeOutput(const COutPoint& output, cons return parts; } +vector KernelRecord::decomposeOutput(const interfaces::WalletTx& wtx) +{ + uint256 hash = wtx.tx->GetHash(); + const std::vector outs = wtx.tx->vout; + std::vector isMine = wtx.txout_is_mine; + vector parts; + int64_t nTime = wtx.time; + + for(uint32_t n = 0; n <= outs.size(); n++){ + if(isMine[n] == isminetype::ISMINE_SPENDABLE){ + int64_t nValue = outs[n].nValue; + CTxDestination address; + std::string addrStr; + ExtractDestination(outs[n].scriptPubKey, address); + addrStr = EncodeDestination(address); + parts.push_back(KernelRecord(hash, n, nTime, addrStr, nValue)); + } + } + return parts; +} + std::string KernelRecord::getTxID() { return hash.ToString(); diff --git a/src/kernelrecord.h b/src/kernelrecord.h index bc8bce6afb22..c17e9a8f8a79 100644 --- a/src/kernelrecord.h +++ b/src/kernelrecord.h @@ -32,7 +32,7 @@ class KernelRecord static bool showTransaction(); static std::vector decomposeOutput(const COutPoint& output, const interfaces::WalletTxOut& out); - + static std::vector decomposeOutput(const interfaces::WalletTx& wtx); uint256 hash; uint32_t n; diff --git a/src/qt/mintingtablemodel.cpp b/src/qt/mintingtablemodel.cpp index d5f1194620a5..c188fcdd52fa 100644 --- a/src/qt/mintingtablemodel.cpp +++ b/src/qt/mintingtablemodel.cpp @@ -61,6 +61,22 @@ struct TxLessThan { return a.hash < b.hash || (a.hash == b.hash && a.n < b.n); } + bool operator()(const KernelRecord &a, const std::pair &b) const + { + return a.hash < b.first || (a.hash == b.first && a.n < b.second); + } + bool operator()(const std::pair &a, const KernelRecord &b) const + { + return a.first < b.hash || (a.first == b.hash && a.second < b.n); + } + bool operator()(const KernelRecord &a, const uint256 &b) const + { + return a.hash < b; + } + bool operator()(const uint256 &a, const KernelRecord &b) const + { + return a < b.hash; + } }; // Private implementation @@ -79,20 +95,73 @@ class MintingTablePriv * this is sorted by sha256. */ QList cachedWallet; - + QList> procQueue; + /* Query entire wallet anew from core. */ - void refreshWallet(interfaces::Wallet& wallet) + void refreshWallet() { qDebug() << "MintingTablePriv::refreshWallet"; + if(procQueue.size() > 0) + { + // dequeue one event + std::pair pair = procQueue[0]; + procEvent(pair.first, pair.second); + procQueue.removeAt(0); + } + +// // delete changed hash +// while(delQueue.size() > 0) +// { +// std::pair pair = delQueue[0]; +// uint256 hash = pair.first; +// uint32_t n = pair.second; +//std::cout << hash.ToString() << "-" << n << "\n"; +// +// for(int i = 0; i < cachedWallet.size(); i++){ +// if(cachedWallet[i].hash == hash && cachedWallet[i].n == n){ +//std::cout << "found at " << i << "\n"; +// parent->beginRemoveRows(QModelIndex(), i, i); +// cachedWallet.removeAt(i); +// parent->endRemoveRows(); +// break; +// } +// else{ +//std::cout << "no match (" << cachedWallet[i].getTxID() << "-" << cachedWallet[i].n << ")\n"; +// } +// } +// +// delQueue.removeAt(0); +// } + + + // +// while(addQueue.size() > 0) +// { +// const KernelRecord& kr = addQueue[0]; // FIFO +// +// QList::iterator lower = qLowerBound( +// cachedWallet.begin(), cachedWallet.end(), kr, TxLessThan()); +// int lowerIndex = (lower - cachedWallet.begin()); +// +// parent->beginInsertRows(QModelIndex(), lowerIndex, lowerIndex); +// cachedWallet.insert(lowerIndex, kr); +// parent->endInsertRows(); +// +// addQueue.removeAt(0); +// } + +return; + +/* // Make mask QList mask; for(int i = 0; i < cachedWallet.size(); i++) { mask.append(false); } - + // Update and add records for (const auto& coins : wallet.listCoins()) { @@ -139,6 +208,123 @@ class MintingTablePriv parent->endRemoveRows(); } } +*/ + } + + void procEvent(uint256 hash, int status) + { +printf("(procEvent) proc %s : %d\n", hash.ToString().c_str(), status); + + // Find bounds of this transaction in model + QList::iterator lower = qLowerBound( + cachedWallet.begin(), cachedWallet.end(), hash, TxLessThan()); + QList::iterator upper = qUpperBound( + cachedWallet.begin(), cachedWallet.end(), hash, TxLessThan()); + int lowerIndex = (lower - cachedWallet.begin()); + int upperIndex = (upper - cachedWallet.begin()); + + interfaces::WalletTx wtx = parent->walletModel->wallet().getWalletTx(hash); + interfaces::WalletTxStatus tx_status; + int num_blocks; + int64_t block_time; + bool success = parent->walletModel->wallet().tryGetTxStatus(hash, tx_status, num_blocks, block_time); + + if(!success){ + // not found status + return; + } + + if(status == CT_NEW) + { + // requeue if the transaction is coinbase and immature + if(tx_status.is_coinbase && tx_status.blocks_to_maturity > 0) + { +printf("(procEvent) requeue : %s (depth = %d)\n", hash.ToString().c_str(), tx_status.depth_in_main_chain); + procQueue.append(std::make_pair(hash, status)); + return; + } + + int offsetLower = 0; + for(const KernelRecord& kr : KernelRecord::decomposeOutput(wtx)) + { +printf("(procEvent) addRow %d : %ld\n", kr.n, kr.nValue); + if(parent->walletModel->wallet().isSpent(kr.hash, kr.n)) // spent + { + continue; + } + + parent->beginInsertRows(QModelIndex(), lowerIndex + offsetLower, lowerIndex + offsetLower); + cachedWallet.insert(lowerIndex + offsetLower, kr); + parent->endInsertRows(); + offsetLower++; + } + + // spent + const std::vector ins = wtx.tx->vin; + const std::vector isMine = wtx.txin_is_mine; + for(uint32_t i = 0; i < ins.size(); i++) + { + if(isMine[i] == isminetype::ISMINE_SPENDABLE) + { + uint256 phash = ins[i].prevout.hash; + uint32_t n = ins[i].prevout.n; +printf("(procEvent) delRow %s : %d\n", phash.ToString().c_str(), n); + + for(int i = 0; i < cachedWallet.size(); i++){ + if(cachedWallet[i].hash == phash && cachedWallet[i].n == n){ +printf("(procEvent) delRow found at %d\n", i); + parent->beginRemoveRows(QModelIndex(), i, i); + cachedWallet.removeAt(i); + parent->endRemoveRows(); + break; + } + } + } + } + } + else if(status == CT_UPDATED) + { + // nothing to do + } + else if(status == CT_DELETED) + { + // this status is not thrown +printf("(procEvent) delete tx %s\n", hash.ToString().c_str()); + parent->beginRemoveRows(QModelIndex(), lowerIndex, upperIndex - 1); + for(int i = lowerIndex; i < upperIndex; i++) + { + cachedWallet.removeAt(i); + } + parent->endRemoveRows(); + + for(uint32_t n = 0; n <= wtx.tx->vin.size(); n++) + { + if(wtx.txin_is_mine[n] == isminetype::ISMINE_SPENDABLE) + { + interfaces::WalletTx prev_wtx = parent->walletModel->wallet().getWalletTx(wtx.tx->vin[n].prevout.hash); + + std::vector krs = KernelRecord::decomposeOutput(prev_wtx); + const KernelRecord& kr = krs[wtx.tx->vin[n].prevout.n]; + + QList::iterator prev_lower = qLowerBound( + cachedWallet.begin(), cachedWallet.end(), kr, TxLessThan()); + QList::iterator prev_upper = qUpperBound( + cachedWallet.begin(), cachedWallet.end(), kr, TxLessThan()); + int prev_lowerIndex = (prev_lower - cachedWallet.begin()); + + if(prev_lower == prev_upper) // not in model + { +printf("(procEvent) reviveRow %s : %d\n", kr.hash.ToString().c_str(), kr.n); + parent->beginInsertRows(QModelIndex(), prev_lowerIndex, prev_lowerIndex); + cachedWallet.insert(prev_lowerIndex, kr); + parent->endInsertRows(); + } + } + } + } + else{ + qDebug() << "MintingTablePriv::procEvent : Unexpected status"; + } } int size() @@ -184,7 +370,25 @@ MintingTableModel::MintingTableModel(const PlatformStyle *_platformStyle, Wallet { columns << tr("Transaction") << tr("Address") << tr("Balance") << tr("Age") << tr("CoinDay") << tr("MintProbability") << tr("MintReward"); - priv->refreshWallet(walletModel->wallet()); + // Initialize records + for (const auto& wtx : walletModel->wallet().getWalletTxs()) + { + priv->procEvent(wtx.tx->GetHash(), CT_NEW); +// for(const KernelRecord& kr : KernelRecord::decomposeOutput(wtx)){ +// priv->addQueue.append(kr); + +// QList::iterator lower = qLowerBound( +// priv->cachedWallet.begin(), priv->cachedWallet.end(), kr, TxLessThan()); +// int lowerIndex = (lower - priv->cachedWallet.begin()); +// +// beginInsertRows(QModelIndex(), lowerIndex, lowerIndex); +// priv->cachedWallet.insert(lowerIndex, kr); +// endInsertRows(); +// } + } + + subscribeToCoreSignals(); + priv->refreshWallet(); QTimer *timer = new QTimer(this); connect(timer, SIGNAL(timeout()), this, SLOT(updateAge())); @@ -195,6 +399,7 @@ MintingTableModel::MintingTableModel(const PlatformStyle *_platformStyle, Wallet MintingTableModel::~MintingTableModel() { + unsubscribeFromCoreSignals(); delete priv; } @@ -203,8 +408,13 @@ void MintingTableModel::updateTransaction(const QString &hash, int status, bool uint256 updated; updated.SetHex(hash.toStdString()); - priv->refreshWallet(walletModel->wallet()); - mintingProxyModel->invalidate(); // Force deletion of empty rows + // CT_NEW -> add + // !showTransaction -> delete + // CT_UPDATED && inModel -> nothing to do + // CT_UPDATED && !inModel -> add + priv->procQueue.append(std::make_pair(updated, showTransaction ? status : CT_DELETED)); +// priv->refreshWallet(walletModel->wallet()); +// mintingProxyModel->invalidate(); // Force deletion of empty rows } void MintingTableModel::updateAge() @@ -213,7 +423,7 @@ void MintingTableModel::updateAge() Q_EMIT dataChanged(index(0, CoinDay), index(priv->size()-1, CoinDay)); Q_EMIT dataChanged(index(0, MintProbability), index(priv->size()-1, MintProbability)); Q_EMIT dataChanged(index(0, MintReward), index(priv->size()-1, MintReward)); - priv->refreshWallet(walletModel->wallet()); + priv->refreshWallet(); } void MintingTableModel::setMintingProxyModel(MintingFilterProxy *mintingProxy) @@ -448,3 +658,58 @@ void MintingTableModel::updateDisplayUnit() // emit dataChanged to update Balance column with the current unit Q_EMIT dataChanged(index(0, Balance), index(priv->size()-1, Balance)); } + +// queue notifications to show a non freezing progress dialog e.g. for rescan +struct TransactionNotification +{ +public: + TransactionNotification() {} + TransactionNotification(uint256 _hash, ChangeType _status, bool _showTransaction): + hash(_hash), status(_status), showTransaction(_showTransaction) {} + + void invoke(QObject *mtm) + { + QString strHash = QString::fromStdString(hash.GetHex()); + qDebug() << "NotifyTransactionChanged: " + strHash + " status= " + QString::number(status); + QMetaObject::invokeMethod(mtm, "updateTransaction", Qt::QueuedConnection, + Q_ARG(QString, strHash), + Q_ARG(int, status), + Q_ARG(bool, showTransaction)); + } +private: + uint256 hash; + ChangeType status; + bool showTransaction; +}; + +static bool fQueueNotifications = false; +static std::vector< TransactionNotification > vQueueNotifications; + +static void NotifyTransactionChanged(MintingTableModel *mtm, const uint256 &hash, ChangeType status) +{ + // Find transaction in wallet + // Determine whether to show transaction or not (determine this here so that no relocking is needed in GUI thread) + bool showTransaction = KernelRecord::showTransaction(); + + TransactionNotification notification(hash, status, showTransaction); + + if (fQueueNotifications) + { + vQueueNotifications.push_back(notification); + return; + } + notification.invoke(mtm); +} + +void MintingTableModel::subscribeToCoreSignals() +{ + // Connect signals to wallet + m_handler_transaction_changed = walletModel->wallet().handleTransactionChanged(boost::bind(NotifyTransactionChanged, this, _1, _2)); +} + +void MintingTableModel::unsubscribeFromCoreSignals() +{ + // Disconnect signals from wallet + m_handler_transaction_changed->disconnect(); +} + diff --git a/src/qt/mintingtablemodel.h b/src/qt/mintingtablemodel.h index aab33968a8b2..ddb8e4bce232 100644 --- a/src/qt/mintingtablemodel.h +++ b/src/qt/mintingtablemodel.h @@ -47,6 +47,7 @@ class MintingTableModel : public QAbstractTableModel private: WalletModel *walletModel; + std::unique_ptr m_handler_transaction_changed; QStringList columns; int mintingInterval; MintingTablePriv *priv; @@ -64,6 +65,9 @@ class MintingTableModel : public QAbstractTableModel QString formatTxCoinDay(const KernelRecord *wtx) const; QString formatTxPoSReward(KernelRecord *wtx) const; + void subscribeToCoreSignals(); + void unsubscribeFromCoreSignals(); + public Q_SLOTS: void updateTransaction(const QString &hash, int status, bool showTransaction); void updateAge(); From 7f4f734dc4e192a2d048dd55d7b4d8dce7c21a96 Mon Sep 17 00:00:00 2001 From: serisia Date: Mon, 11 Feb 2019 01:35:56 +0900 Subject: [PATCH 02/10] remove MODEL_MINTING_UPDATE_DELAY --- src/qt/guiconstants.h | 3 --- src/qt/mintingtablemodel.cpp | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/qt/guiconstants.h b/src/qt/guiconstants.h index 323f50158282..7f0fdcb92ff6 100644 --- a/src/qt/guiconstants.h +++ b/src/qt/guiconstants.h @@ -8,9 +8,6 @@ /* Milliseconds between model updates */ static const int MODEL_UPDATE_DELAY = 250; -/* Milliseconds between mintingtablemodel updates */ -static const int MODEL_MINTING_UPDATE_DELAY = 1000; - /* AskPassphraseDialog -- Maximum passphrase length */ static const int MAX_PASSPHRASE_SIZE = 1024; diff --git a/src/qt/mintingtablemodel.cpp b/src/qt/mintingtablemodel.cpp index c188fcdd52fa..90636a5eef67 100644 --- a/src/qt/mintingtablemodel.cpp +++ b/src/qt/mintingtablemodel.cpp @@ -392,7 +392,7 @@ MintingTableModel::MintingTableModel(const PlatformStyle *_platformStyle, Wallet QTimer *timer = new QTimer(this); connect(timer, SIGNAL(timeout()), this, SLOT(updateAge())); - timer->start(MODEL_MINTING_UPDATE_DELAY); + timer->start(MODEL_UPDATE_DELAY); connect(walletModel->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit())); } From 5b13389c6b845881e4e707add770b0f33bf51ad3 Mon Sep 17 00:00:00 2001 From: serisia Date: Mon, 11 Feb 2019 15:58:38 +0900 Subject: [PATCH 03/10] use destination in WalletTx --- src/kernelrecord.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/kernelrecord.cpp b/src/kernelrecord.cpp index 10e5d0440ac9..66201bd9070a 100644 --- a/src/kernelrecord.cpp +++ b/src/kernelrecord.cpp @@ -50,10 +50,7 @@ vector KernelRecord::decomposeOutput(const interfaces::WalletTx& w for(uint32_t n = 0; n <= outs.size(); n++){ if(isMine[n] == isminetype::ISMINE_SPENDABLE){ int64_t nValue = outs[n].nValue; - CTxDestination address; - std::string addrStr; - ExtractDestination(outs[n].scriptPubKey, address); - addrStr = EncodeDestination(address); + std::string addrStr = EncodeDestination(wtx.txout_address[n]); parts.push_back(KernelRecord(hash, n, nTime, addrStr, nValue)); } } From 5cdc9a80f8ad8387ce4b956479bab6fd0fec8dbf Mon Sep 17 00:00:00 2001 From: serisia Date: Mon, 11 Feb 2019 15:59:08 +0900 Subject: [PATCH 04/10] sort initialize queue --- src/qt/mintingtablemodel.cpp | 57 +++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/src/qt/mintingtablemodel.cpp b/src/qt/mintingtablemodel.cpp index 90636a5eef67..44a50eec0863 100644 --- a/src/qt/mintingtablemodel.cpp +++ b/src/qt/mintingtablemodel.cpp @@ -79,6 +79,10 @@ struct TxLessThan } }; +bool compareWtx(const interfaces::WalletTx &a, const interfaces::WalletTx &b) +{ + return a.time < b.time; +} // Private implementation class MintingTablePriv { @@ -103,13 +107,16 @@ class MintingTablePriv { qDebug() << "MintingTablePriv::refreshWallet"; - if(procQueue.size() > 0) + int dequeue = std::min(procQueue.size(), 100); // limit 100 + while(dequeue-- > 0) { // dequeue one event std::pair pair = procQueue[0]; procEvent(pair.first, pair.second); procQueue.removeAt(0); } + +printf("(refreshWallet) size %d\n", cachedWallet.size()); // // delete changed hash // while(delQueue.size() > 0) @@ -213,7 +220,7 @@ return; void procEvent(uint256 hash, int status) { -printf("(procEvent) proc %s : %d\n", hash.ToString().c_str(), status); +//printf("(procEvent) proc %s : %d\n", hash.ToString().c_str(), status); // Find bounds of this transaction in model QList::iterator lower = qLowerBound( @@ -239,26 +246,11 @@ printf("(procEvent) proc %s : %d\n", hash.ToString().c_str(), status); // requeue if the transaction is coinbase and immature if(tx_status.is_coinbase && tx_status.blocks_to_maturity > 0) { -printf("(procEvent) requeue : %s (depth = %d)\n", hash.ToString().c_str(), tx_status.depth_in_main_chain); +//printf("(procEvent) requeue : %s (depth = %d)\n", hash.ToString().c_str(), tx_status.depth_in_main_chain); procQueue.append(std::make_pair(hash, status)); return; } - int offsetLower = 0; - for(const KernelRecord& kr : KernelRecord::decomposeOutput(wtx)) - { -printf("(procEvent) addRow %d : %ld\n", kr.n, kr.nValue); - if(parent->walletModel->wallet().isSpent(kr.hash, kr.n)) // spent - { - continue; - } - - parent->beginInsertRows(QModelIndex(), lowerIndex + offsetLower, lowerIndex + offsetLower); - cachedWallet.insert(lowerIndex + offsetLower, kr); - parent->endInsertRows(); - offsetLower++; - } - // spent const std::vector ins = wtx.tx->vin; const std::vector isMine = wtx.txin_is_mine; @@ -268,11 +260,11 @@ printf("(procEvent) addRow %d : %ld\n", kr.n, kr.nValue); { uint256 phash = ins[i].prevout.hash; uint32_t n = ins[i].prevout.n; -printf("(procEvent) delRow %s : %d\n", phash.ToString().c_str(), n); +//printf("(procEvent) delRow %s : %d\n", phash.ToString().c_str(), n); for(int i = 0; i < cachedWallet.size(); i++){ if(cachedWallet[i].hash == phash && cachedWallet[i].n == n){ -printf("(procEvent) delRow found at %d\n", i); +//printf("(procEvent) delRow found at %d\n", i); parent->beginRemoveRows(QModelIndex(), i, i); cachedWallet.removeAt(i); parent->endRemoveRows(); @@ -281,6 +273,23 @@ printf("(procEvent) delRow found at %d\n", i); } } } + + // append + int offsetLower = 0; + for(const KernelRecord& kr : KernelRecord::decomposeOutput(wtx)) + { +//printf("%s\t%d\n", kr.hash.ToString().c_str(), kr.n); +//printf("(procEvent) addRow %d : %ld\n", kr.n, kr.nValue); + if(parent->walletModel->wallet().isSpent(kr.hash, kr.n)) // spent + { + continue; + } + + parent->beginInsertRows(QModelIndex(), lowerIndex + offsetLower, lowerIndex + offsetLower); + cachedWallet.insert(lowerIndex + offsetLower, kr); + parent->endInsertRows(); + offsetLower++; + } } else if(status == CT_UPDATED) { @@ -289,7 +298,7 @@ printf("(procEvent) delRow found at %d\n", i); else if(status == CT_DELETED) { // this status is not thrown -printf("(procEvent) delete tx %s\n", hash.ToString().c_str()); +//printf("(procEvent) delete tx %s\n", hash.ToString().c_str()); parent->beginRemoveRows(QModelIndex(), lowerIndex, upperIndex - 1); for(int i = lowerIndex; i < upperIndex; i++) { @@ -314,7 +323,7 @@ printf("(procEvent) delete tx %s\n", hash.ToString().c_str()); if(prev_lower == prev_upper) // not in model { -printf("(procEvent) reviveRow %s : %d\n", kr.hash.ToString().c_str(), kr.n); +//printf("(procEvent) reviveRow %s : %d\n", kr.hash.ToString().c_str(), kr.n); parent->beginInsertRows(QModelIndex(), prev_lowerIndex, prev_lowerIndex); cachedWallet.insert(prev_lowerIndex, kr); parent->endInsertRows(); @@ -371,7 +380,9 @@ MintingTableModel::MintingTableModel(const PlatformStyle *_platformStyle, Wallet columns << tr("Transaction") << tr("Address") << tr("Balance") << tr("Age") << tr("CoinDay") << tr("MintProbability") << tr("MintReward"); // Initialize records - for (const auto& wtx : walletModel->wallet().getWalletTxs()) + std::vector wtxs = walletModel->wallet().getWalletTxs(); + std::sort(wtxs.begin(), wtxs.end(), compareWtx); + for (const auto& wtx : wtxs) { priv->procEvent(wtx.tx->GetHash(), CT_NEW); // for(const KernelRecord& kr : KernelRecord::decomposeOutput(wtx)){ From 3201aea5d2ba7bc428ea8b6b28b69a23d3430e22 Mon Sep 17 00:00:00 2001 From: serisia Date: Mon, 11 Feb 2019 16:04:59 +0900 Subject: [PATCH 05/10] remove unnecessary code --- src/qt/mintingtablemodel.cpp | 115 +---------------------------------- 1 file changed, 1 insertion(+), 114 deletions(-) diff --git a/src/qt/mintingtablemodel.cpp b/src/qt/mintingtablemodel.cpp index 44a50eec0863..2464054cb54a 100644 --- a/src/qt/mintingtablemodel.cpp +++ b/src/qt/mintingtablemodel.cpp @@ -117,105 +117,6 @@ class MintingTablePriv } printf("(refreshWallet) size %d\n", cachedWallet.size()); - -// // delete changed hash -// while(delQueue.size() > 0) -// { -// std::pair pair = delQueue[0]; -// uint256 hash = pair.first; -// uint32_t n = pair.second; -//std::cout << hash.ToString() << "-" << n << "\n"; -// -// for(int i = 0; i < cachedWallet.size(); i++){ -// if(cachedWallet[i].hash == hash && cachedWallet[i].n == n){ -//std::cout << "found at " << i << "\n"; -// parent->beginRemoveRows(QModelIndex(), i, i); -// cachedWallet.removeAt(i); -// parent->endRemoveRows(); -// break; -// } -// else{ -//std::cout << "no match (" << cachedWallet[i].getTxID() << "-" << cachedWallet[i].n << ")\n"; -// } -// } -// -// delQueue.removeAt(0); -// } - - - // -// while(addQueue.size() > 0) -// { -// const KernelRecord& kr = addQueue[0]; // FIFO -// -// QList::iterator lower = qLowerBound( -// cachedWallet.begin(), cachedWallet.end(), kr, TxLessThan()); -// int lowerIndex = (lower - cachedWallet.begin()); -// -// parent->beginInsertRows(QModelIndex(), lowerIndex, lowerIndex); -// cachedWallet.insert(lowerIndex, kr); -// parent->endInsertRows(); -// -// addQueue.removeAt(0); -// } - -return; - -/* - // Make mask - QList mask; - for(int i = 0; i < cachedWallet.size(); i++) - { - mask.append(false); - } - - // Update and add records - for (const auto& coins : wallet.listCoins()) - { - for (const auto& outpair : coins.second) - { - const COutPoint& output = std::get<0>(outpair); - const interfaces::WalletTxOut& out = std::get<1>(outpair); - std::vector txList = KernelRecord::decomposeOutput(output, out); - if(KernelRecord::showTransaction()) - { - - for(const KernelRecord& kr : txList) - { - QList::iterator lower = qLowerBound( - cachedWallet.begin(), cachedWallet.end(), kr, TxLessThan()); - QList::iterator upper = qUpperBound( - cachedWallet.begin(), cachedWallet.end(), kr, TxLessThan()); - int lowerIndex = (lower - cachedWallet.begin()); - bool inModel = (lower != upper); - - if(inModel) - { - cachedWallet.replace(lowerIndex, kr); - mask.replace(lowerIndex, true); - } - else - { - parent->beginInsertRows(QModelIndex(), lowerIndex, lowerIndex); - cachedWallet.insert(lowerIndex, kr); - mask.insert(lowerIndex, true); - parent->endInsertRows(); - } - } - } - } - } - // Delete old records - for(int i = 0; i < mask.size(); i++) - { - if(mask.at(i) == false) - { - parent->beginRemoveRows(QModelIndex(), i, i); - cachedWallet.removeAt(i); - parent->endRemoveRows(); - } - } -*/ } void procEvent(uint256 hash, int status) @@ -385,17 +286,6 @@ MintingTableModel::MintingTableModel(const PlatformStyle *_platformStyle, Wallet for (const auto& wtx : wtxs) { priv->procEvent(wtx.tx->GetHash(), CT_NEW); -// for(const KernelRecord& kr : KernelRecord::decomposeOutput(wtx)){ -// priv->addQueue.append(kr); - -// QList::iterator lower = qLowerBound( -// priv->cachedWallet.begin(), priv->cachedWallet.end(), kr, TxLessThan()); -// int lowerIndex = (lower - priv->cachedWallet.begin()); -// -// beginInsertRows(QModelIndex(), lowerIndex, lowerIndex); -// priv->cachedWallet.insert(lowerIndex, kr); -// endInsertRows(); -// } } subscribeToCoreSignals(); @@ -421,11 +311,8 @@ void MintingTableModel::updateTransaction(const QString &hash, int status, bool // CT_NEW -> add // !showTransaction -> delete - // CT_UPDATED && inModel -> nothing to do - // CT_UPDATED && !inModel -> add + // CT_UPDATED -> nothing to do priv->procQueue.append(std::make_pair(updated, showTransaction ? status : CT_DELETED)); -// priv->refreshWallet(walletModel->wallet()); -// mintingProxyModel->invalidate(); // Force deletion of empty rows } void MintingTableModel::updateAge() From 7774859cb8408fa1ea27a2a87f0920c0b8744679 Mon Sep 17 00:00:00 2001 From: serisia Date: Mon, 11 Feb 2019 18:34:19 +0900 Subject: [PATCH 06/10] fix out of range issue --- src/kernelrecord.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernelrecord.cpp b/src/kernelrecord.cpp index 66201bd9070a..856b76984843 100644 --- a/src/kernelrecord.cpp +++ b/src/kernelrecord.cpp @@ -47,7 +47,7 @@ vector KernelRecord::decomposeOutput(const interfaces::WalletTx& w vector parts; int64_t nTime = wtx.time; - for(uint32_t n = 0; n <= outs.size(); n++){ + for(uint32_t n = 0; n < outs.size(); n++){ if(isMine[n] == isminetype::ISMINE_SPENDABLE){ int64_t nValue = outs[n].nValue; std::string addrStr = EncodeDestination(wtx.txout_address[n]); From 407146d46fe285a65cabc63dfc80ed035d8b74c7 Mon Sep 17 00:00:00 2001 From: serisia Date: Mon, 11 Feb 2019 18:35:35 +0900 Subject: [PATCH 07/10] remove debug print --- src/qt/mintingtablemodel.cpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/qt/mintingtablemodel.cpp b/src/qt/mintingtablemodel.cpp index 2464054cb54a..1a441aca39d9 100644 --- a/src/qt/mintingtablemodel.cpp +++ b/src/qt/mintingtablemodel.cpp @@ -115,14 +115,10 @@ class MintingTablePriv procEvent(pair.first, pair.second); procQueue.removeAt(0); } - -printf("(refreshWallet) size %d\n", cachedWallet.size()); } void procEvent(uint256 hash, int status) { -//printf("(procEvent) proc %s : %d\n", hash.ToString().c_str(), status); - // Find bounds of this transaction in model QList::iterator lower = qLowerBound( cachedWallet.begin(), cachedWallet.end(), hash, TxLessThan()); @@ -147,7 +143,6 @@ printf("(refreshWallet) size %d\n", cachedWallet.size()); // requeue if the transaction is coinbase and immature if(tx_status.is_coinbase && tx_status.blocks_to_maturity > 0) { -//printf("(procEvent) requeue : %s (depth = %d)\n", hash.ToString().c_str(), tx_status.depth_in_main_chain); procQueue.append(std::make_pair(hash, status)); return; } @@ -161,11 +156,9 @@ printf("(refreshWallet) size %d\n", cachedWallet.size()); { uint256 phash = ins[i].prevout.hash; uint32_t n = ins[i].prevout.n; -//printf("(procEvent) delRow %s : %d\n", phash.ToString().c_str(), n); for(int i = 0; i < cachedWallet.size(); i++){ if(cachedWallet[i].hash == phash && cachedWallet[i].n == n){ -//printf("(procEvent) delRow found at %d\n", i); parent->beginRemoveRows(QModelIndex(), i, i); cachedWallet.removeAt(i); parent->endRemoveRows(); @@ -179,8 +172,6 @@ printf("(refreshWallet) size %d\n", cachedWallet.size()); int offsetLower = 0; for(const KernelRecord& kr : KernelRecord::decomposeOutput(wtx)) { -//printf("%s\t%d\n", kr.hash.ToString().c_str(), kr.n); -//printf("(procEvent) addRow %d : %ld\n", kr.n, kr.nValue); if(parent->walletModel->wallet().isSpent(kr.hash, kr.n)) // spent { continue; @@ -199,7 +190,6 @@ printf("(refreshWallet) size %d\n", cachedWallet.size()); else if(status == CT_DELETED) { // this status is not thrown -//printf("(procEvent) delete tx %s\n", hash.ToString().c_str()); parent->beginRemoveRows(QModelIndex(), lowerIndex, upperIndex - 1); for(int i = lowerIndex; i < upperIndex; i++) { @@ -224,7 +214,6 @@ printf("(refreshWallet) size %d\n", cachedWallet.size()); if(prev_lower == prev_upper) // not in model { -//printf("(procEvent) reviveRow %s : %d\n", kr.hash.ToString().c_str(), kr.n); parent->beginInsertRows(QModelIndex(), prev_lowerIndex, prev_lowerIndex); cachedWallet.insert(prev_lowerIndex, kr); parent->endInsertRows(); From 3cbe36c73f8e3faeb63bd271147fd23a54e5f161 Mon Sep 17 00:00:00 2001 From: serisia Date: Mon, 11 Feb 2019 20:51:14 +0900 Subject: [PATCH 08/10] remove whitespace --- src/kernelrecord.cpp | 2 +- src/qt/mintingtablemodel.cpp | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/kernelrecord.cpp b/src/kernelrecord.cpp index 856b76984843..bdad10f1b2b5 100644 --- a/src/kernelrecord.cpp +++ b/src/kernelrecord.cpp @@ -46,7 +46,7 @@ vector KernelRecord::decomposeOutput(const interfaces::WalletTx& w std::vector isMine = wtx.txout_is_mine; vector parts; int64_t nTime = wtx.time; - + for(uint32_t n = 0; n < outs.size(); n++){ if(isMine[n] == isminetype::ISMINE_SPENDABLE){ int64_t nValue = outs[n].nValue; diff --git a/src/qt/mintingtablemodel.cpp b/src/qt/mintingtablemodel.cpp index 1a441aca39d9..6079f6d7d004 100644 --- a/src/qt/mintingtablemodel.cpp +++ b/src/qt/mintingtablemodel.cpp @@ -100,7 +100,7 @@ class MintingTablePriv */ QList cachedWallet; QList> procQueue; - + /* Query entire wallet anew from core. */ void refreshWallet() @@ -116,7 +116,7 @@ class MintingTablePriv procQueue.removeAt(0); } } - + void procEvent(uint256 hash, int status) { // Find bounds of this transaction in model @@ -126,13 +126,13 @@ class MintingTablePriv cachedWallet.begin(), cachedWallet.end(), hash, TxLessThan()); int lowerIndex = (lower - cachedWallet.begin()); int upperIndex = (upper - cachedWallet.begin()); - + interfaces::WalletTx wtx = parent->walletModel->wallet().getWalletTx(hash); interfaces::WalletTxStatus tx_status; int num_blocks; int64_t block_time; bool success = parent->walletModel->wallet().tryGetTxStatus(hash, tx_status, num_blocks, block_time); - + if(!success){ // not found status return; @@ -146,7 +146,7 @@ class MintingTablePriv procQueue.append(std::make_pair(hash, status)); return; } - + // spent const std::vector ins = wtx.tx->vin; const std::vector isMine = wtx.txin_is_mine; @@ -156,7 +156,7 @@ class MintingTablePriv { uint256 phash = ins[i].prevout.hash; uint32_t n = ins[i].prevout.n; - + for(int i = 0; i < cachedWallet.size(); i++){ if(cachedWallet[i].hash == phash && cachedWallet[i].n == n){ parent->beginRemoveRows(QModelIndex(), i, i); @@ -167,7 +167,7 @@ class MintingTablePriv } } } - + // append int offsetLower = 0; for(const KernelRecord& kr : KernelRecord::decomposeOutput(wtx)) @@ -176,7 +176,7 @@ class MintingTablePriv { continue; } - + parent->beginInsertRows(QModelIndex(), lowerIndex + offsetLower, lowerIndex + offsetLower); cachedWallet.insert(lowerIndex + offsetLower, kr); parent->endInsertRows(); @@ -202,16 +202,16 @@ class MintingTablePriv if(wtx.txin_is_mine[n] == isminetype::ISMINE_SPENDABLE) { interfaces::WalletTx prev_wtx = parent->walletModel->wallet().getWalletTx(wtx.tx->vin[n].prevout.hash); - + std::vector krs = KernelRecord::decomposeOutput(prev_wtx); const KernelRecord& kr = krs[wtx.tx->vin[n].prevout.n]; - + QList::iterator prev_lower = qLowerBound( cachedWallet.begin(), cachedWallet.end(), kr, TxLessThan()); QList::iterator prev_upper = qUpperBound( cachedWallet.begin(), cachedWallet.end(), kr, TxLessThan()); int prev_lowerIndex = (prev_lower - cachedWallet.begin()); - + if(prev_lower == prev_upper) // not in model { parent->beginInsertRows(QModelIndex(), prev_lowerIndex, prev_lowerIndex); From ca66ece5ee462faa98207b9fea01599edac3817b Mon Sep 17 00:00:00 2001 From: serisia Date: Mon, 11 Feb 2019 23:26:39 +0900 Subject: [PATCH 09/10] remove unused function --- src/kernelrecord.cpp | 16 ---------------- src/kernelrecord.h | 1 - 2 files changed, 17 deletions(-) diff --git a/src/kernelrecord.cpp b/src/kernelrecord.cpp index bdad10f1b2b5..f26d37ded546 100644 --- a/src/kernelrecord.cpp +++ b/src/kernelrecord.cpp @@ -23,22 +23,6 @@ bool KernelRecord::showTransaction() /* * Decompose CWallet transaction to model kernel records. */ -vector KernelRecord::decomposeOutput(const COutPoint& output, const interfaces::WalletTxOut& out) -{ - vector parts; - uint256 hash = output.hash; - uint32_t n = output.n; - int64_t nTime = out.time; - int64_t nValue = out.txout.nValue; - CTxDestination address; - std::string addrStr; - ExtractDestination(out.txout.scriptPubKey, address); - addrStr = EncodeDestination(address); - - parts.push_back(KernelRecord(hash, n, nTime, addrStr, nValue)); - return parts; -} - vector KernelRecord::decomposeOutput(const interfaces::WalletTx& wtx) { uint256 hash = wtx.tx->GetHash(); diff --git a/src/kernelrecord.h b/src/kernelrecord.h index c17e9a8f8a79..72a5eab7c185 100644 --- a/src/kernelrecord.h +++ b/src/kernelrecord.h @@ -31,7 +31,6 @@ class KernelRecord } static bool showTransaction(); - static std::vector decomposeOutput(const COutPoint& output, const interfaces::WalletTxOut& out); static std::vector decomposeOutput(const interfaces::WalletTx& wtx); uint256 hash; From 16908668fceb4240299be078b5347814b3d42098 Mon Sep 17 00:00:00 2001 From: serisia Date: Tue, 12 Feb 2019 00:13:51 +0900 Subject: [PATCH 10/10] use emplace_back --- src/kernelrecord.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernelrecord.cpp b/src/kernelrecord.cpp index f26d37ded546..c67af1df59d9 100644 --- a/src/kernelrecord.cpp +++ b/src/kernelrecord.cpp @@ -35,7 +35,7 @@ vector KernelRecord::decomposeOutput(const interfaces::WalletTx& w if(isMine[n] == isminetype::ISMINE_SPENDABLE){ int64_t nValue = outs[n].nValue; std::string addrStr = EncodeDestination(wtx.txout_address[n]); - parts.push_back(KernelRecord(hash, n, nTime, addrStr, nValue)); + parts.emplace_back(hash, n, nTime, addrStr, nValue); } } return parts;