Show unconfirmed addresses in the balances table

This commit is contained in:
Aditya Kulkarni
2019-10-26 19:09:16 -07:00
parent a70d2677b6
commit deff437c1d
6 changed files with 59 additions and 44 deletions

View File

@@ -14,11 +14,11 @@ void BalancesTableModel::setNewData(const QList<QString> zaddrs, const QList<QSt
int currentRows = rowCount(QModelIndex()); int currentRows = rowCount(QModelIndex());
// Copy over the utxos for our use // Copy over the utxos for our use
delete utxos; delete unspentOutputs;
utxos = new QList<UnspentOutput>(); unspentOutputs = new QList<UnspentOutput>();
// This is a QList deep copy. // This is a QList deep copy.
*utxos = outputs; *unspentOutputs = outputs;
// Process the address balances into a list // Process the address balances into a list
delete modeldata; delete modeldata;
@@ -50,7 +50,7 @@ void BalancesTableModel::setNewData(const QList<QString> zaddrs, const QList<QSt
BalancesTableModel::~BalancesTableModel() { BalancesTableModel::~BalancesTableModel() {
delete modeldata; delete modeldata;
delete utxos; delete unspentOutputs;
} }
int BalancesTableModel::rowCount(const QModelIndex&) const int BalancesTableModel::rowCount(const QModelIndex&) const
@@ -83,8 +83,9 @@ QVariant BalancesTableModel::data(const QModelIndex &index, int role) const
if (role == Qt::ForegroundRole) { if (role == Qt::ForegroundRole) {
// If any of the UTXOs for this address has zero confirmations, paint it in red // If any of the UTXOs for this address has zero confirmations, paint it in red
const auto& addr = std::get<0>(modeldata->at(index.row())); const auto& addr = std::get<0>(modeldata->at(index.row()));
for (auto utxo : *utxos) { for (auto unconfirmedOutput : *unspentOutputs) {
if (utxo.address == addr && !utxo.spendable) { if (unconfirmedOutput.address == addr &&
(!unconfirmedOutput.spendable || unconfirmedOutput.pending)) {
QBrush b; QBrush b;
b.setColor(Qt::red); b.setColor(Qt::red);
return b; return b;

View File

@@ -18,8 +18,8 @@ public:
QVariant headerData(int section, Qt::Orientation orientation, int role) const; QVariant headerData(int section, Qt::Orientation orientation, int role) const;
private: private:
QList<std::tuple<QString, qint64>>* modeldata = nullptr; QList<std::tuple<QString, qint64>>* modeldata = nullptr;
QList<UnspentOutput>* utxos = nullptr; QList<UnspentOutput>* unspentOutputs = nullptr;
bool loading = true; bool loading = true;
}; };

View File

@@ -254,26 +254,30 @@ void Controller::updateUI(bool anyUnconfirmed) {
}; };
// Function to process reply of the listunspent and z_listunspent API calls, used below. // Function to process reply of the listunspent and z_listunspent API calls, used below.
bool Controller::processUnspent(const json& reply, QMap<QString, qint64>* balancesMap, QList<UnspentOutput>* newUtxos) { void Controller::processUnspent(const json& reply, QMap<QString, qint64>* balancesMap, QList<UnspentOutput>* unspentOutputs) {
bool anyUnconfirmed = false; auto processFn = [=](const json& array) -> bool {
auto processFn = [=](const json& array) {
for (auto& it : array) { for (auto& it : array) {
QString qsAddr = QString::fromStdString(it["address"]); QString qsAddr = QString::fromStdString(it["address"]);
int block = it["created_in_block"].get<json::number_unsigned_t>(); int block = it["created_in_block"].get<json::number_unsigned_t>();
QString txid = QString::fromStdString(it["created_in_txid"]); QString txid = QString::fromStdString(it["created_in_txid"]);
QString amount = Settings::getDecimalString(it["value"].get<json::number_unsigned_t>()); QString amount = Settings::getDecimalString(it["value"].get<json::number_unsigned_t>());
newUtxos->push_back(UnspentOutput{ qsAddr, txid, amount, block, true }); bool spendable = it["unconfirmed_spent"].is_null() && it["spent"].is_null(); // TODO: Wait for 4 confirmations
bool pending = !it["unconfirmed_spent"].is_null();
(*balancesMap)[qsAddr] = (*balancesMap)[qsAddr] + it["value"].get<json::number_unsigned_t>(); qDebug() << "For address" << qsAddr << "spendable, pending" << spendable << ":" << pending;
}
unspentOutputs->push_back(UnspentOutput{ qsAddr, txid, amount, block, spendable, pending });
if (spendable) {
(*balancesMap)[qsAddr] = (*balancesMap)[qsAddr] + it["value"].get<json::number_unsigned_t>();
}
}
}; };
processFn(reply["unspent_notes"].get<json::array_t>()); processFn(reply["unspent_notes"].get<json::array_t>());
processFn(reply["utxos"].get<json::array_t>()); processFn(reply["utxos"].get<json::array_t>());
processFn(reply["pending_notes"].get<json::array_t>());
return anyUnconfirmed; processFn(reply["pending_utxos"].get<json::array_t>());
}; };
void Controller::refreshBalances() { void Controller::refreshBalances() {
@@ -300,16 +304,22 @@ void Controller::refreshBalances() {
// 2. Get the UTXOs // 2. Get the UTXOs
// First, create a new UTXO list. It will be replacing the existing list when everything is processed. // First, create a new UTXO list. It will be replacing the existing list when everything is processed.
auto newUtxos = new QList<UnspentOutput>(); auto newUnspentOutputs = new QList<UnspentOutput>();
auto newBalances = new QMap<QString, qint64>(); auto newBalances = new QMap<QString, qint64>();
// Call the Transparent and Z unspent APIs serially and then, once they're done, update the UI // Call the Transparent and Z unspent APIs serially and then, once they're done, update the UI
zrpc->fetchUnspent([=] (json reply) { zrpc->fetchUnspent([=] (json reply) {
auto anyUnconfirmed = processUnspent(reply, newBalances, newUtxos); processUnspent(reply, newBalances, newUnspentOutputs);
// Swap out the balances and UTXOs // Swap out the balances and UTXOs
model->replaceBalances(newBalances); model->replaceBalances(newBalances);
model->replaceUTXOs(newUtxos); model->replaceUTXOs(newUnspentOutputs);
// Find if any output is not spendable or is pending
bool anyUnconfirmed = std::find_if(newUnspentOutputs->constBegin(), newUnspentOutputs->constEnd(),
[=](const UnspentOutput& u) -> bool {
return !u.spendable || u.pending;
}) != newUnspentOutputs->constEnd();
updateUI(anyUnconfirmed); updateUI(anyUnconfirmed);

View File

@@ -78,7 +78,7 @@ private:
void refreshTransactions(); void refreshTransactions();
bool processUnspent (const json& reply, QMap<QString, qint64>* newBalances, QList<UnspentOutput>* newUtxos); void processUnspent (const json& reply, QMap<QString, qint64>* newBalances, QList<UnspentOutput>* newUnspentOutputs);
void updateUI (bool anyUnconfirmed); void updateUI (bool anyUnconfirmed);
void getInfoThenRefresh(bool force); void getInfoThenRefresh(bool force);
@@ -89,7 +89,7 @@ private:
BalancesTableModel* balancesTableModel = nullptr; BalancesTableModel* balancesTableModel = nullptr;
DataModel* model; DataModel* model;
LiteInterface* zrpc; LiteInterface* zrpc;
QTimer* timer; QTimer* timer;
QTimer* txTimer; QTimer* txTimer;

View File

@@ -10,6 +10,7 @@ struct UnspentOutput {
QString amount; QString amount;
int blockCreated; int blockCreated;
bool spendable; bool spendable;
bool pending;
}; };

View File

@@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>968</width> <width>1274</width>
<height>616</height> <height>779</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@@ -22,7 +22,7 @@
<item row="0" column="0"> <item row="0" column="0">
<widget class="QTabWidget" name="tabWidget"> <widget class="QTabWidget" name="tabWidget">
<property name="currentIndex"> <property name="currentIndex">
<number>2</number> <number>0</number>
</property> </property>
<widget class="QWidget" name="tab"> <widget class="QWidget" name="tab">
<attribute name="title"> <attribute name="title">
@@ -148,26 +148,13 @@
</item> </item>
</layout> </layout>
</item> </item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item> <item>
<widget class="QLabel" name="lblSyncWarning"> <widget class="QLabel" name="lblSyncWarning">
<property name="styleSheet"> <property name="styleSheet">
<string notr="true">color:red;</string> <string notr="true">color:red;</string>
</property> </property>
<property name="text"> <property name="text">
<string>Your node is still syncing, balances may not be updated</string> <string>Your node is still syncing, balances may not be updated.</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -186,10 +173,26 @@
<string notr="true">color: red;</string> <string notr="true">color: red;</string>
</property> </property>
<property name="text"> <property name="text">
<string>Some transactions are not yet confirmed</string> <string>Some transactions are not yet confirmed. Balances may change.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property> </property>
</widget> </widget>
</item> </item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout> </layout>
</item> </item>
</layout> </layout>
@@ -359,8 +362,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>920</width> <width>1162</width>
<height>301</height> <height>344</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="sendToLayout"> <layout class="QVBoxLayout" name="sendToLayout">
@@ -1051,8 +1054,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>968</width> <width>1274</width>
<height>22</height> <height>39</height>
</rect> </rect>
</property> </property>
<widget class="QMenu" name="menuFile"> <widget class="QMenu" name="menuFile">