Show unconfirmed addresses in the balances table
This commit is contained in:
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ struct UnspentOutput {
|
|||||||
QString amount;
|
QString amount;
|
||||||
int blockCreated;
|
int blockCreated;
|
||||||
bool spendable;
|
bool spendable;
|
||||||
|
bool pending;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
Reference in New Issue
Block a user