diff options
author | Gavin Andresen <gavinandresen@gmail.com> | 2014-02-14 14:40:32 -0500 |
---|---|---|
committer | Gavin Andresen <gavinandresen@gmail.com> | 2014-02-14 14:40:32 -0500 |
commit | 05d3ded072d782036c31c1d773c0441b87de843e (patch) | |
tree | 1dcdec2f37f61415aa5d1b71da101e0cfbd035fd /src | |
parent | e051e65c219cc72a2bba768f3d5e043ad055b48e (diff) | |
parent | 9a3d936fc2e98b1e8234bf27e09cf7bc22811bee (diff) |
Merge pull request #3669 from gavinandresen/dead_txns
Handle "conflicted" transactions properly
Diffstat (limited to 'src')
-rw-r--r-- | src/main.cpp | 10 | ||||
-rw-r--r-- | src/main.h | 9 | ||||
-rw-r--r-- | src/qt/Makefile.am | 1 | ||||
-rw-r--r-- | src/qt/bitcoin.qrc | 1 | ||||
-rw-r--r-- | src/qt/overviewpage.cpp | 1 | ||||
-rw-r--r-- | src/qt/res/icons/transaction_conflicted.png | bin | 0 -> 474 bytes | |||
-rw-r--r-- | src/qt/transactiondesc.cpp | 4 | ||||
-rw-r--r-- | src/qt/transactionfilterproxy.cpp | 13 | ||||
-rw-r--r-- | src/qt/transactionfilterproxy.h | 4 | ||||
-rw-r--r-- | src/qt/transactionrecord.cpp | 6 | ||||
-rw-r--r-- | src/qt/transactionrecord.h | 3 | ||||
-rw-r--r-- | src/qt/transactiontablemodel.cpp | 10 | ||||
-rw-r--r-- | src/qt/transactiontablemodel.h | 4 | ||||
-rw-r--r-- | src/qt/walletmodel.cpp | 8 | ||||
-rw-r--r-- | src/rpcwallet.cpp | 14 | ||||
-rw-r--r-- | src/wallet.cpp | 6 | ||||
-rw-r--r-- | src/wallet.h | 10 |
17 files changed, 87 insertions, 17 deletions
diff --git a/src/main.cpp b/src/main.cpp index 1df9a24d55..36dd03a2b1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -872,7 +872,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa } -int CMerkleTx::GetDepthInMainChain(CBlockIndex* &pindexRet) const +int CMerkleTx::GetDepthInMainChainINTERNAL(CBlockIndex* &pindexRet) const { if (hashBlock == 0 || nIndex == -1) return 0; @@ -897,6 +897,14 @@ int CMerkleTx::GetDepthInMainChain(CBlockIndex* &pindexRet) const return chainActive.Height() - pindex->nHeight + 1; } +int CMerkleTx::GetDepthInMainChain(CBlockIndex* &pindexRet) const +{ + int nResult = GetDepthInMainChainINTERNAL(pindexRet); + if (nResult == 0 && !mempool.exists(GetHash())) + return -1; // Not in chain, not in mempool + + return nResult; +} int CMerkleTx::GetBlocksToMaturity() const { diff --git a/src/main.h b/src/main.h index 05210e5164..09250e4a3e 100644 --- a/src/main.h +++ b/src/main.h @@ -423,6 +423,8 @@ public: /** A transaction with a merkle branch linking it to the block chain. */ class CMerkleTx : public CTransaction { +private: + int GetDepthInMainChainINTERNAL(CBlockIndex* &pindexRet) const; public: uint256 hashBlock; std::vector<uint256> vMerkleBranch; @@ -461,9 +463,14 @@ public: int SetMerkleBranch(const CBlock* pblock=NULL); + + // Return depth of transaction in blockchain: + // -1 : not in blockchain, and not in memory pool (conflicted transaction) + // 0 : in memory pool, waiting to be included in a block + // >=1 : this many blocks deep in the main chain int GetDepthInMainChain(CBlockIndex* &pindexRet) const; int GetDepthInMainChain() const { CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet); } - bool IsInMainChain() const { return GetDepthInMainChain() > 0; } + bool IsInMainChain() const { CBlockIndex *pindexRet; return GetDepthInMainChainINTERNAL(pindexRet) > 0; } int GetBlocksToMaturity() const; bool AcceptToMemoryPool(bool fLimitFree=true); }; diff --git a/src/qt/Makefile.am b/src/qt/Makefile.am index 7de47291cc..030804db6e 100644 --- a/src/qt/Makefile.am +++ b/src/qt/Makefile.am @@ -243,6 +243,7 @@ RES_ICONS = \ res/icons/toolbar_testnet.png \ res/icons/transaction0.png \ res/icons/transaction2.png \ + res/icons/transaction_conflicted.png \ res/icons/tx_inout.png \ res/icons/tx_input.png \ res/icons/tx_output.png \ diff --git a/src/qt/bitcoin.qrc b/src/qt/bitcoin.qrc index 746b5a4092..7c3a7756b7 100644 --- a/src/qt/bitcoin.qrc +++ b/src/qt/bitcoin.qrc @@ -12,6 +12,7 @@ <file alias="connect_4">res/icons/connect4_16.png</file> <file alias="transaction_0">res/icons/transaction0.png</file> <file alias="transaction_confirmed">res/icons/transaction2.png</file> + <file alias="transaction_conflicted">res/icons/transaction_conflicted.png</file> <file alias="transaction_1">res/icons/clock1.png</file> <file alias="transaction_2">res/icons/clock2.png</file> <file alias="transaction_3">res/icons/clock3.png</file> diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index 016097c5a0..1a9d1de571 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -175,6 +175,7 @@ void OverviewPage::setWalletModel(WalletModel *model) filter->setLimit(NUM_ITEMS); filter->setDynamicSortFilter(true); filter->setSortRole(Qt::EditRole); + filter->setShowInactive(false); filter->sort(TransactionTableModel::Status, Qt::DescendingOrder); ui->listTransactions->setModel(filter); diff --git a/src/qt/res/icons/transaction_conflicted.png b/src/qt/res/icons/transaction_conflicted.png Binary files differnew file mode 100644 index 0000000000..51fff649ab --- /dev/null +++ b/src/qt/res/icons/transaction_conflicted.png diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index c76b29861d..9f18d79089 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -30,7 +30,9 @@ QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx) else { int nDepth = wtx.GetDepthInMainChain(); - if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0) + if (nDepth < 0) + return tr("conflicted"); + else if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0) return tr("%1/offline").arg(nDepth); else if (nDepth < 6) return tr("%1/unconfirmed").arg(nDepth); diff --git a/src/qt/transactionfilterproxy.cpp b/src/qt/transactionfilterproxy.cpp index a14e74a469..f9546fddb5 100644 --- a/src/qt/transactionfilterproxy.cpp +++ b/src/qt/transactionfilterproxy.cpp @@ -5,6 +5,7 @@ #include "transactionfilterproxy.h" #include "transactiontablemodel.h" +#include "transactionrecord.h" #include <cstdlib> @@ -22,7 +23,8 @@ TransactionFilterProxy::TransactionFilterProxy(QObject *parent) : addrPrefix(), typeFilter(ALL_TYPES), minAmount(0), - limitRows(-1) + limitRows(-1), + showInactive(true) { } @@ -35,7 +37,10 @@ bool TransactionFilterProxy::filterAcceptsRow(int sourceRow, const QModelIndex & QString address = index.data(TransactionTableModel::AddressRole).toString(); QString label = index.data(TransactionTableModel::LabelRole).toString(); qint64 amount = llabs(index.data(TransactionTableModel::AmountRole).toLongLong()); + int status = index.data(TransactionTableModel::StatusRole).toInt(); + if(!showInactive && status == TransactionStatus::Conflicted) + return false; if(!(TYPE(type) & typeFilter)) return false; if(datetime < dateFrom || datetime > dateTo) @@ -78,6 +83,12 @@ void TransactionFilterProxy::setLimit(int limit) this->limitRows = limit; } +void TransactionFilterProxy::setShowInactive(bool showInactive) +{ + this->showInactive = showInactive; + invalidateFilter(); +} + int TransactionFilterProxy::rowCount(const QModelIndex &parent) const { if(limitRows != -1) diff --git a/src/qt/transactionfilterproxy.h b/src/qt/transactionfilterproxy.h index 6d1644d48d..9919bc3fd6 100644 --- a/src/qt/transactionfilterproxy.h +++ b/src/qt/transactionfilterproxy.h @@ -36,6 +36,9 @@ public: /** Set maximum number of rows returned, -1 if unlimited. */ void setLimit(int limit); + /** Set whether to show conflicted transactions. */ + void setShowInactive(bool showInactive); + int rowCount(const QModelIndex &parent = QModelIndex()) const; protected: @@ -48,6 +51,7 @@ private: quint32 typeFilter; qint64 minAmount; int limitRows; + bool showInactive; }; #endif // TRANSACTIONFILTERPROXY_H diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp index b6614fc371..345ecfb196 100644 --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -183,7 +183,11 @@ void TransactionRecord::updateStatus(const CWalletTx &wtx) } else { - if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0) + if (status.depth < 0) + { + status.status = TransactionStatus::Conflicted; + } + else if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0) { status.status = TransactionStatus::Offline; } diff --git a/src/qt/transactionrecord.h b/src/qt/transactionrecord.h index 8a7c9044e3..d7be0bc438 100644 --- a/src/qt/transactionrecord.h +++ b/src/qt/transactionrecord.h @@ -36,7 +36,8 @@ public: OpenUntilBlock, Offline, Unconfirmed, - HaveConfirmations + HaveConfirmations, + Conflicted }; bool confirmed; diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index b29be7e0cb..9386d46272 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -312,7 +312,7 @@ QString TransactionTableModel::formatTxStatus(const TransactionRecord *wtx) cons status = tr("Open until %1").arg(GUIUtil::dateTimeStr(wtx->status.open_for)); break; case TransactionStatus::Offline: - status = tr("Offline (%1 confirmations)").arg(wtx->status.depth); + status = tr("Offline"); break; case TransactionStatus::Unconfirmed: status = tr("Unconfirmed (%1 of %2 confirmations)").arg(wtx->status.depth).arg(TransactionRecord::NumConfirmations); @@ -320,6 +320,9 @@ QString TransactionTableModel::formatTxStatus(const TransactionRecord *wtx) cons case TransactionStatus::HaveConfirmations: status = tr("Confirmed (%1 confirmations)").arg(wtx->status.depth); break; + case TransactionStatus::Conflicted: + status = tr("Conflicted"); + break; } } @@ -471,7 +474,6 @@ QVariant TransactionTableModel::txStatusDecoration(const TransactionRecord *wtx) case TransactionStatus::OpenUntilBlock: case TransactionStatus::OpenUntilDate: return QColor(64,64,255); - break; case TransactionStatus::Offline: return QColor(192,192,192); case TransactionStatus::Unconfirmed: @@ -486,6 +488,8 @@ QVariant TransactionTableModel::txStatusDecoration(const TransactionRecord *wtx) }; case TransactionStatus::HaveConfirmations: return QIcon(":/icons/transaction_confirmed"); + case TransactionStatus::Conflicted: + return QIcon(":/icons/transaction_conflicted"); } } return QColor(0,0,0); @@ -587,6 +591,8 @@ QVariant TransactionTableModel::data(const QModelIndex &index, int role) const rec->status.maturity != TransactionStatus::Mature); case FormattedAmountRole: return formatTxAmount(rec, false); + case StatusRole: + return rec->status.status; } return QVariant(); } diff --git a/src/qt/transactiontablemodel.h b/src/qt/transactiontablemodel.h index c23c606c31..7b9cf09cbe 100644 --- a/src/qt/transactiontablemodel.h +++ b/src/qt/transactiontablemodel.h @@ -53,7 +53,9 @@ public: /** Is transaction confirmed? */ ConfirmedRole, /** Formatted amount, without brackets when unconfirmed */ - FormattedAmountRole + FormattedAmountRole, + /** Transaction status (TransactionRecord::Status) */ + StatusRole }; int rowCount(const QModelIndex &parent) const; diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index ddc8c6ea79..fabe292b44 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -494,7 +494,9 @@ void WalletModel::getOutputs(const std::vector<COutPoint>& vOutpoints, std::vect BOOST_FOREACH(const COutPoint& outpoint, vOutpoints) { if (!wallet->mapWallet.count(outpoint.hash)) continue; - COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, wallet->mapWallet[outpoint.hash].GetDepthInMainChain()); + int nDepth = wallet->mapWallet[outpoint.hash].GetDepthInMainChain(); + if (nDepth < 0) continue; + COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth); vOutputs.push_back(out); } } @@ -513,7 +515,9 @@ void WalletModel::listCoins(std::map<QString, std::vector<COutput> >& mapCoins) BOOST_FOREACH(const COutPoint& outpoint, vLockedCoins) { if (!wallet->mapWallet.count(outpoint.hash)) continue; - COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, wallet->mapWallet[outpoint.hash].GetDepthInMainChain()); + int nDepth = wallet->mapWallet[outpoint.hash].GetDepthInMainChain(); + if (nDepth < 0) continue; + COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth); vCoins.push_back(out); } diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index bcbae06682..2b49762d4a 100644 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -45,7 +45,7 @@ void WalletTxToJSON(const CWalletTx& wtx, Object& entry) entry.push_back(Pair("confirmations", confirms)); if (wtx.IsCoinBase()) entry.push_back(Pair("generated", true)); - if (confirms) + if (confirms > 0) { entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex())); entry.push_back(Pair("blockindex", wtx.nIndex)); @@ -1109,7 +1109,10 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe Object entry; entry.push_back(Pair("account", strSentAccount)); MaybePushAddress(entry, s.first); - entry.push_back(Pair("category", "send")); + if (wtx.GetDepthInMainChain() < 0) + entry.push_back(Pair("category", "conflicted")); + else + entry.push_back(Pair("category", "send")); entry.push_back(Pair("amount", ValueFromAmount(-s.second))); entry.push_back(Pair("fee", ValueFromAmount(-nFee))); if (fLong) @@ -1141,7 +1144,12 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe entry.push_back(Pair("category", "generate")); } else - entry.push_back(Pair("category", "receive")); + { + if (wtx.GetDepthInMainChain() < 0) + entry.push_back(Pair("category", "conflicted")); + else + entry.push_back(Pair("category", "receive")); + } entry.push_back(Pair("amount", ValueFromAmount(r.second))); if (fLong) WalletTxToJSON(wtx, entry); diff --git a/src/wallet.cpp b/src/wallet.cpp index 1ba70c1160..b579480f7d 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -1021,11 +1021,15 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0) continue; + int nDepth = pcoin->GetDepthInMainChain(); + if (nDepth < 0) + continue; + for (unsigned int i = 0; i < pcoin->vout.size(); i++) { if (!(pcoin->IsSpent(i)) && IsMine(pcoin->vout[i]) && !IsLockedCoin((*it).first, i) && pcoin->vout[i].nValue > 0 && (!coinControl || !coinControl->HasSelected() || coinControl->IsSelected((*it).first, i))) - vCoins.push_back(COutput(pcoin, i, pcoin->GetDepthInMainChain())); + vCoins.push_back(COutput(pcoin, i, nDepth)); } } } diff --git a/src/wallet.h b/src/wallet.h index a8f1a81b3c..dc709632b4 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -701,8 +701,11 @@ public: // Quick answer in most cases if (!IsFinalTx(*this)) return false; - if (GetDepthInMainChain() >= 1) + int nDepth = GetDepthInMainChain(); + if (nDepth >= 1) return true; + if (nDepth < 0) + return false; if (!bSpendZeroConfChange || !IsFromMe()) // using wtx's cached debit return false; @@ -718,8 +721,11 @@ public: if (!IsFinalTx(*ptx)) return false; - if (ptx->GetDepthInMainChain() >= 1) + int nPDepth = ptx->GetDepthInMainChain(); + if (nPDepth >= 1) continue; + if (nPDepth < 0) + return false; if (!pwallet->IsFromMe(*ptx)) return false; |