diff options
Diffstat (limited to 'src/qt/transactionrecord.cpp')
| -rw-r--r-- | src/qt/transactionrecord.cpp | 153 |
1 files changed, 91 insertions, 62 deletions
diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp index 160973638..7f1db58e5 100644 --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -1,7 +1,18 @@ +// Copyright (c) 2011-2014 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "transactionrecord.h" -#include "wallet.h" #include "base58.h" +#include "consensus/consensus.h" +#include "main.h" +#include "timedata.h" +#include "wallet/wallet.h" + +#include <stdint.h> + +#include <boost/foreach.hpp> /* Return positive answer if transaction should be shown in list. */ @@ -9,18 +20,8 @@ bool TransactionRecord::showTransaction(const CWalletTx &wtx) { if (wtx.IsCoinBase()) { - // Don't show generated coin until confirmed by at least one block after it - // so we don't get the user's hopes up until it looks like it's probably accepted. - // - // It is not an error when generated blocks are not accepted. By design, - // some percentage of blocks, like 10% or more, will end up not accepted. - // This is the normal mechanism by which the network copes with latency. - // - // We display regular transactions right away before any confirmation - // because they can always get into some block eventually. Generated coins - // are special because if their block is not accepted, they are not valid. - // - if (wtx.GetDepthInMainChain() < 2) + // Ensures we show generated coins / mined transactions at depth 1 + if (!wtx.IsInMainChain()) { return false; } @@ -34,10 +35,10 @@ bool TransactionRecord::showTransaction(const CWalletTx &wtx) QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *wallet, const CWalletTx &wtx) { QList<TransactionRecord> parts; - int64 nTime = wtx.GetTxTime(); - int64 nCredit = wtx.GetCredit(true); - int64 nDebit = wtx.GetDebit(); - int64 nNet = nCredit - nDebit; + int64_t nTime = wtx.GetTxTime(); + CAmount nCredit = wtx.GetCredit(ISMINE_ALL); + CAmount nDebit = wtx.GetDebit(ISMINE_ALL); + CAmount nNet = nCredit - nDebit; uint256 hash = wtx.GetHash(); std::map<std::string, std::string> mapValue = wtx.mapValue; @@ -48,18 +49,15 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet * // BOOST_FOREACH(const CTxOut& txout, wtx.vout) { - if(wallet->IsMine(txout)) + isminetype mine = wallet->IsMine(txout); + if(mine) { TransactionRecord sub(hash, nTime); CTxDestination address; sub.idx = parts.size(); // sequence number sub.credit = txout.nValue; - if (wtx.IsCoinBase()) - { - // Generated - sub.type = TransactionRecord::Generated; - } - else if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address)) + sub.involvesWatchAddress = mine == ISMINE_WATCH_ONLY; + if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address)) { // Received by Bitcoin Address sub.type = TransactionRecord::RecvWithAddress; @@ -71,6 +69,11 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet * sub.type = TransactionRecord::RecvFromOther; sub.address = mapValue["from"]; } + if (wtx.IsCoinBase()) + { + // Generated + sub.type = TransactionRecord::Generated; + } parts.append(sub); } @@ -78,34 +81,45 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet * } else { - bool fAllFromMe = true; + bool involvesWatchAddress = false; + isminetype fAllFromMe = ISMINE_SPENDABLE; BOOST_FOREACH(const CTxIn& txin, wtx.vin) - fAllFromMe = fAllFromMe && wallet->IsMine(txin); + { + isminetype mine = wallet->IsMine(txin); + if(mine == ISMINE_WATCH_ONLY) involvesWatchAddress = true; + if(fAllFromMe > mine) fAllFromMe = mine; + } - bool fAllToMe = true; + isminetype fAllToMe = ISMINE_SPENDABLE; BOOST_FOREACH(const CTxOut& txout, wtx.vout) - fAllToMe = fAllToMe && wallet->IsMine(txout); + { + isminetype mine = wallet->IsMine(txout); + if(mine == ISMINE_WATCH_ONLY) involvesWatchAddress = true; + if(fAllToMe > mine) fAllToMe = mine; + } if (fAllFromMe && fAllToMe) { // Payment to self - int64 nChange = wtx.GetChange(); + CAmount nChange = wtx.GetChange(); parts.append(TransactionRecord(hash, nTime, TransactionRecord::SendToSelf, "", -(nDebit - nChange), nCredit - nChange)); + parts.last().involvesWatchAddress = involvesWatchAddress; // maybe pass to TransactionRecord as constructor argument } else if (fAllFromMe) { // // Debit // - int64 nTxFee = nDebit - wtx.GetValueOut(); + CAmount nTxFee = nDebit - wtx.GetValueOut(); for (unsigned int nOut = 0; nOut < wtx.vout.size(); nOut++) { const CTxOut& txout = wtx.vout[nOut]; TransactionRecord sub(hash, nTime); sub.idx = parts.size(); + sub.involvesWatchAddress = involvesWatchAddress; if(wallet->IsMine(txout)) { @@ -128,7 +142,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet * sub.address = mapValue["to"]; } - int64 nValue = txout.nValue; + CAmount nValue = txout.nValue; /* Add fee to first output */ if (nTxFee > 0) { @@ -146,6 +160,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet * // Mixed debit transaction, can't break down payees // parts.append(TransactionRecord(hash, nTime, TransactionRecord::Other, "", nNet, 0)); + parts.last().involvesWatchAddress = involvesWatchAddress; } } @@ -154,11 +169,12 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet * void TransactionRecord::updateStatus(const CWalletTx &wtx) { + AssertLockHeld(cs_main); // Determine transaction status // Find the block the tx is in CBlockIndex* pindex = NULL; - std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(wtx.hashBlock); + BlockMap::iterator mi = mapBlockIndex.find(wtx.hashBlock); if (mi != mapBlockIndex.end()) pindex = (*mi).second; @@ -168,16 +184,16 @@ void TransactionRecord::updateStatus(const CWalletTx &wtx) (wtx.IsCoinBase() ? 1 : 0), wtx.nTimeReceived, idx); - status.confirmed = wtx.IsConfirmed(); + status.countsForBalance = wtx.IsTrusted() && !(wtx.GetBlocksToMaturity() > 0); status.depth = wtx.GetDepthInMainChain(); - status.cur_num_blocks = nBestHeight; + status.cur_num_blocks = chainActive.Height(); - if (!wtx.IsFinal()) + if (!IsFinalTx(wtx, chainActive.Height() + 1)) { if (wtx.nLockTime < LOCKTIME_THRESHOLD) { status.status = TransactionStatus::OpenUntilBlock; - status.open_for = nBestHeight - wtx.nLockTime; + status.open_for = wtx.nLockTime - chainActive.Height(); } else { @@ -185,29 +201,12 @@ void TransactionRecord::updateStatus(const CWalletTx &wtx) status.open_for = wtx.nLockTime; } } - else - { - if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0) - { - status.status = TransactionStatus::Offline; - } - else if (status.depth < NumConfirmations) - { - status.status = TransactionStatus::Unconfirmed; - } - else - { - status.status = TransactionStatus::HaveConfirmations; - } - } - // For generated transactions, determine maturity - if(type == TransactionRecord::Generated) + else if(type == TransactionRecord::Generated) { - int64 nCredit = wtx.GetCredit(true); - if (nCredit == 0) + if (wtx.GetBlocksToMaturity() > 0) { - status.maturity = TransactionStatus::Immature; + status.status = TransactionStatus::Immature; if (wtx.IsInMainChain()) { @@ -215,27 +214,57 @@ void TransactionRecord::updateStatus(const CWalletTx &wtx) // Check if the block was requested by anyone if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0) - status.maturity = TransactionStatus::MaturesWarning; + status.status = TransactionStatus::MaturesWarning; } else { - status.maturity = TransactionStatus::NotAccepted; + status.status = TransactionStatus::NotAccepted; } } else { - status.maturity = TransactionStatus::Mature; + status.status = TransactionStatus::Confirmed; + } + } + else + { + if (status.depth < 0) + { + status.status = TransactionStatus::Conflicted; + } + else if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0) + { + status.status = TransactionStatus::Offline; + } + else if (status.depth == 0) + { + status.status = TransactionStatus::Unconfirmed; + } + else if (status.depth < RecommendedNumConfirmations) + { + status.status = TransactionStatus::Confirming; + } + else + { + status.status = TransactionStatus::Confirmed; } } + } bool TransactionRecord::statusUpdateNeeded() { - return status.cur_num_blocks != nBestHeight; + AssertLockHeld(cs_main); + return status.cur_num_blocks != chainActive.Height(); +} + +QString TransactionRecord::getTxID() const +{ + return formatSubTxId(hash, idx); } -std::string TransactionRecord::getTxID() +QString TransactionRecord::formatSubTxId(const uint256 &hash, int vout) { - return hash.ToString() + strprintf("-%03d", idx); + return QString::fromStdString(hash.ToString() + strprintf("-%03d", vout)); } |