qt: Modernize 'confirmed' terminology in shown tx status

These days we regard transactions with one confirmation to be
'Confirmed'.
Waiting for 6 confirmations is a recommendation but should not
keep the transaction shown as unconfirmed.

Misc code sanity:

- Merge maturity/status enums, they had become completely disjunct
- 'confirmed' flag is now called 'countsForBalance' for clarity
This commit is contained in:
Wladimir J. van der Laan 2014-02-20 14:09:09 +01:00
parent 7ac375d1c2
commit f642fd9dd6
3 changed files with 111 additions and 128 deletions

View File

@ -164,7 +164,7 @@ void TransactionRecord::updateStatus(const CWalletTx &wtx)
(wtx.IsCoinBase() ? 1 : 0), (wtx.IsCoinBase() ? 1 : 0),
wtx.nTimeReceived, wtx.nTimeReceived,
idx); idx);
status.confirmed = wtx.IsTrusted(); status.countsForBalance = wtx.IsTrusted() && !(wtx.GetBlocksToMaturity() > 0);
status.depth = wtx.GetDepthInMainChain(); status.depth = wtx.GetDepthInMainChain();
status.cur_num_blocks = chainActive.Height(); status.cur_num_blocks = chainActive.Height();
@ -181,6 +181,31 @@ void TransactionRecord::updateStatus(const CWalletTx &wtx)
status.open_for = wtx.nLockTime; status.open_for = wtx.nLockTime;
} }
} }
// For generated transactions, determine maturity
else if(type == TransactionRecord::Generated)
{
if (wtx.GetBlocksToMaturity() > 0)
{
status.status = TransactionStatus::Immature;
if (wtx.IsInMainChain())
{
status.matures_in = wtx.GetBlocksToMaturity();
// Check if the block was requested by anyone
if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
status.status = TransactionStatus::MaturesWarning;
}
else
{
status.status = TransactionStatus::NotAccepted;
}
}
else
{
status.status = TransactionStatus::Confirmed;
}
}
else else
{ {
if (status.depth < 0) if (status.depth < 0)
@ -191,42 +216,20 @@ void TransactionRecord::updateStatus(const CWalletTx &wtx)
{ {
status.status = TransactionStatus::Offline; status.status = TransactionStatus::Offline;
} }
else if (status.depth < NumConfirmations) else if (status.depth == 0)
{ {
status.status = TransactionStatus::Unconfirmed; status.status = TransactionStatus::Unconfirmed;
} }
else else if (status.depth < RecommendedNumConfirmations)
{ {
status.status = TransactionStatus::HaveConfirmations; status.status = TransactionStatus::Confirming;
}
}
// For generated transactions, determine maturity
if(type == TransactionRecord::Generated)
{
int64_t nCredit = wtx.GetCredit(true);
if (nCredit == 0)
{
status.maturity = TransactionStatus::Immature;
if (wtx.IsInMainChain())
{
status.matures_in = wtx.GetBlocksToMaturity();
// Check if the block was requested by anyone
if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
status.maturity = TransactionStatus::MaturesWarning;
}
else
{
status.maturity = TransactionStatus::NotAccepted;
}
} }
else else
{ {
status.maturity = TransactionStatus::Mature; status.status = TransactionStatus::Confirmed;
} }
} }
} }
bool TransactionRecord::statusUpdateNeeded() bool TransactionRecord::statusUpdateNeeded()

View File

@ -19,33 +19,32 @@ class TransactionStatus
{ {
public: public:
TransactionStatus(): TransactionStatus():
confirmed(false), sortKey(""), maturity(Mature), countsForBalance(false), sortKey(""),
matures_in(0), status(Offline), depth(0), open_for(0), cur_num_blocks(-1) matures_in(0), status(Offline), depth(0), open_for(0), cur_num_blocks(-1)
{ } { }
enum Maturity
{
Immature,
Mature,
MaturesWarning, /**< Transaction will likely not mature because no nodes have confirmed */
NotAccepted
};
enum Status { enum Status {
OpenUntilDate, Confirmed, /**< Have 6 or more confirmations (normal tx) or fully mature (mined tx) **/
OpenUntilBlock, /// Normal (sent/received) transactions
Offline, OpenUntilDate, /**< Transaction not yet final, waiting for date */
Unconfirmed, OpenUntilBlock, /**< Transaction not yet final, waiting for block */
HaveConfirmations, Offline, /**< Not sent to any other nodes **/
Conflicted Unconfirmed, /**< Not yet mined into a block **/
Confirming, /**< Confirmed, but waiting for the recommended number of confirmations **/
Conflicted, /**< Conflicts with other transaction or mempool **/
/// Generated (mined) transactions
Immature, /**< Mined but waiting for maturity */
MaturesWarning, /**< Transaction will likely not mature because no nodes have confirmed */
NotAccepted /**< Mined but not accepted */
}; };
bool confirmed; /// Transaction counts towards available balance
bool countsForBalance;
/// Sorting key based on status
std::string sortKey; std::string sortKey;
/** @name Generated (mined) transactions /** @name Generated (mined) transactions
@{*/ @{*/
Maturity maturity;
int matures_in; int matures_in;
/**@}*/ /**@}*/
@ -79,8 +78,8 @@ public:
SendToSelf SendToSelf
}; };
/** Number of confirmation needed for transaction */ /** Number of confirmation recommended for accepting a transaction */
static const int NumConfirmations = 6; static const int RecommendedNumConfirmations = 6;
TransactionRecord(): TransactionRecord():
hash(), time(0), type(Other), address(""), debit(0), credit(0), idx(0) hash(), time(0), type(Other), address(""), debit(0), credit(0), idx(0)

View File

@ -285,45 +285,38 @@ QString TransactionTableModel::formatTxStatus(const TransactionRecord *wtx) cons
{ {
QString status; QString status;
if(wtx->type == TransactionRecord::Generated) switch(wtx->status.status)
{ {
switch(wtx->status.maturity) case TransactionStatus::OpenUntilBlock:
{ status = tr("Open for %n more block(s)","",wtx->status.open_for);
case TransactionStatus::Immature: break;
status = tr("Immature (%1 confirmations, will be available after %2)").arg(wtx->status.depth).arg(wtx->status.depth + wtx->status.matures_in); case TransactionStatus::OpenUntilDate:
break; status = tr("Open until %1").arg(GUIUtil::dateTimeStr(wtx->status.open_for));
case TransactionStatus::Mature: break;
status = tr("Confirmed (%1 confirmations)").arg(wtx->status.depth); case TransactionStatus::Offline:
break; status = tr("Offline");
case TransactionStatus::MaturesWarning: break;
status = tr("This block was not received by any other nodes and will probably not be accepted!"); case TransactionStatus::Unconfirmed:
break; status = tr("Unconfirmed");
case TransactionStatus::NotAccepted: break;
status = tr("Generated but not accepted"); case TransactionStatus::Confirming:
break; status = tr("Confirming (%1 of %2 recommended confirmations)").arg(wtx->status.depth).arg(TransactionRecord::RecommendedNumConfirmations);
} break;
} else { case TransactionStatus::Confirmed:
switch(wtx->status.status) status = tr("Confirmed (%1 confirmations)").arg(wtx->status.depth);
{ break;
case TransactionStatus::OpenUntilBlock: case TransactionStatus::Conflicted:
status = tr("Open for %n more block(s)","",wtx->status.open_for); status = tr("Conflicted");
break; break;
case TransactionStatus::OpenUntilDate: case TransactionStatus::Immature:
status = tr("Open until %1").arg(GUIUtil::dateTimeStr(wtx->status.open_for)); status = tr("Immature (%1 confirmations, will be available after %2)").arg(wtx->status.depth).arg(wtx->status.depth + wtx->status.matures_in);
break; break;
case TransactionStatus::Offline: case TransactionStatus::MaturesWarning:
status = tr("Offline"); status = tr("This block was not received by any other nodes and will probably not be accepted!");
break; break;
case TransactionStatus::Unconfirmed: case TransactionStatus::NotAccepted:
status = tr("Unconfirmed (%1 of %2 confirmations)").arg(wtx->status.depth).arg(TransactionRecord::NumConfirmations); status = tr("Generated but not accepted");
break; break;
case TransactionStatus::HaveConfirmations:
status = tr("Confirmed (%1 confirmations)").arg(wtx->status.depth);
break;
case TransactionStatus::Conflicted:
status = tr("Conflicted");
break;
}
} }
return status; return status;
@ -441,7 +434,7 @@ QString TransactionTableModel::formatTxAmount(const TransactionRecord *wtx, bool
QString str = BitcoinUnits::format(walletModel->getOptionsModel()->getDisplayUnit(), wtx->credit + wtx->debit); QString str = BitcoinUnits::format(walletModel->getOptionsModel()->getDisplayUnit(), wtx->credit + wtx->debit);
if(showUnconfirmed) if(showUnconfirmed)
{ {
if(!wtx->status.confirmed || wtx->status.maturity != TransactionStatus::Mature) if(!wtx->status.countsForBalance)
{ {
str = QString("[") + str + QString("]"); str = QString("[") + str + QString("]");
} }
@ -451,46 +444,36 @@ QString TransactionTableModel::formatTxAmount(const TransactionRecord *wtx, bool
QVariant TransactionTableModel::txStatusDecoration(const TransactionRecord *wtx) const QVariant TransactionTableModel::txStatusDecoration(const TransactionRecord *wtx) const
{ {
if(wtx->type == TransactionRecord::Generated) switch(wtx->status.status)
{ {
switch(wtx->status.maturity) case TransactionStatus::OpenUntilBlock:
case TransactionStatus::OpenUntilDate:
return QColor(64,64,255);
case TransactionStatus::Offline:
return QColor(192,192,192);
case TransactionStatus::Unconfirmed:
return QIcon(":/icons/transaction_0");
case TransactionStatus::Confirming:
switch(wtx->status.depth)
{ {
case TransactionStatus::Immature: { case 1: return QIcon(":/icons/transaction_1");
int total = wtx->status.depth + wtx->status.matures_in; case 2: return QIcon(":/icons/transaction_2");
int part = (wtx->status.depth * 4 / total) + 1; case 3: return QIcon(":/icons/transaction_3");
return QIcon(QString(":/icons/transaction_%1").arg(part)); case 4: return QIcon(":/icons/transaction_4");
} default: return QIcon(":/icons/transaction_5");
case TransactionStatus::Mature: };
return QIcon(":/icons/transaction_confirmed"); case TransactionStatus::Confirmed:
case TransactionStatus::MaturesWarning: return QIcon(":/icons/transaction_confirmed");
case TransactionStatus::NotAccepted: case TransactionStatus::Conflicted:
return QIcon(":/icons/transaction_0"); return QIcon(":/icons/transaction_conflicted");
} case TransactionStatus::Immature: {
} int total = wtx->status.depth + wtx->status.matures_in;
else int part = (wtx->status.depth * 4 / total) + 1;
{ return QIcon(QString(":/icons/transaction_%1").arg(part));
switch(wtx->status.status)
{
case TransactionStatus::OpenUntilBlock:
case TransactionStatus::OpenUntilDate:
return QColor(64,64,255);
case TransactionStatus::Offline:
return QColor(192,192,192);
case TransactionStatus::Unconfirmed:
switch(wtx->status.depth)
{
case 0: return QIcon(":/icons/transaction_0");
case 1: return QIcon(":/icons/transaction_1");
case 2: return QIcon(":/icons/transaction_2");
case 3: return QIcon(":/icons/transaction_3");
case 4: return QIcon(":/icons/transaction_4");
default: return QIcon(":/icons/transaction_5");
};
case TransactionStatus::HaveConfirmations:
return QIcon(":/icons/transaction_confirmed");
case TransactionStatus::Conflicted:
return QIcon(":/icons/transaction_conflicted");
} }
case TransactionStatus::MaturesWarning:
case TransactionStatus::NotAccepted:
return QIcon(":/icons/transaction_0");
} }
return QColor(0,0,0); return QColor(0,0,0);
} }
@ -557,8 +540,8 @@ QVariant TransactionTableModel::data(const QModelIndex &index, int role) const
case Qt::TextAlignmentRole: case Qt::TextAlignmentRole:
return column_alignments[index.column()]; return column_alignments[index.column()];
case Qt::ForegroundRole: case Qt::ForegroundRole:
// Non-confirmed transactions are grey // Non-confirmed (but not immature) as transactions are grey
if(!rec->status.confirmed) if(!rec->status.countsForBalance && rec->status.status != TransactionStatus::Immature)
{ {
return COLOR_UNCONFIRMED; return COLOR_UNCONFIRMED;
} }
@ -586,9 +569,7 @@ QVariant TransactionTableModel::data(const QModelIndex &index, int role) const
case TxIDRole: case TxIDRole:
return rec->getTxID(); return rec->getTxID();
case ConfirmedRole: case ConfirmedRole:
// Return True if transaction counts for balance return rec->status.countsForBalance;
return rec->status.confirmed && !(rec->type == TransactionRecord::Generated &&
rec->status.maturity != TransactionStatus::Mature);
case FormattedAmountRole: case FormattedAmountRole:
return formatTxAmount(rec, false); return formatTxAmount(rec, false);
case StatusRole: case StatusRole: