#include "transactionrecord.h"
-#include "headers.h"
+#include "wallet.h"
+#include "base58.h"
/* Return positive answer if transaction should be shown in list.
*/
{
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;
}
QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *wallet, const CWalletTx &wtx)
{
QList<TransactionRecord> parts;
- int64 nTime = wtx.nTimeDisplayed = wtx.GetTxTime();
+ int64 nTime = wtx.GetTxTime();
int64 nCredit = wtx.GetCredit(true);
- int64 nDebit = wtx.GetDebit();
+ int64 nDebit = wtx.GetDebit(MINE_ALL);
int64 nNet = nCredit - nDebit;
- uint256 hash = wtx.GetHash();
+ uint256 hash = wtx.GetHash(), hashPrev = 0;
std::map<std::string, std::string> mapValue = wtx.mapValue;
- if (showTransaction(wtx))
+ if (nNet > 0 || wtx.IsCoinBase() || wtx.IsCoinStake())
{
- if (nNet > 0 || wtx.IsCoinBase())
+ //
+ // Credit
+ //
+ BOOST_FOREACH(const CTxOut& txout, wtx.vout)
{
- //
- // Credit
- //
- TransactionRecord sub(hash, nTime);
-
- sub.credit = nNet;
-
- if (wtx.IsCoinBase())
+ if(wallet->IsMine(txout))
{
- // Generated
- sub.type = TransactionRecord::Generated;
-
- if (nCredit == 0)
+ TransactionRecord sub(hash, nTime);
+ CTxDestination address;
+ sub.idx = parts.size(); // sequence number
+ sub.credit = txout.nValue;
+ if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address))
{
- int64 nUnmatured = 0;
- BOOST_FOREACH(const CTxOut& txout, wtx.vout)
- nUnmatured += wallet->GetCredit(txout);
- sub.credit = nUnmatured;
+ // Received by Bitcoin Address
+ sub.type = TransactionRecord::RecvWithAddress;
+ sub.address = CBitcoinAddress(address).ToString();
}
- }
- else if (!mapValue["from"].empty() || !mapValue["message"].empty())
- {
- // Received by IP connection
- sub.type = TransactionRecord::RecvFromIP;
- if (!mapValue["from"].empty())
+ else
+ {
+ // Received by IP connection (deprecated features), or a multisignature or other non-simple transaction
+ sub.type = TransactionRecord::RecvFromOther;
sub.address = mapValue["from"];
- }
- else
- {
- // Received by Bitcoin Address
- sub.type = TransactionRecord::RecvWithAddress;
- BOOST_FOREACH(const CTxOut& txout, wtx.vout)
+ }
+ if (wtx.IsCoinBase())
+ {
+ // Generated (proof-of-work)
+ sub.type = TransactionRecord::Generated;
+ }
+ if (wtx.IsCoinStake())
{
- if(wallet->IsMine(txout))
- {
- CBitcoinAddress address;
- if (ExtractAddress(txout.scriptPubKey, wallet, address))
- {
- sub.address = address.ToString();
- }
- break;
- }
+ // Generated (proof-of-stake)
+
+ if (hashPrev == hash)
+ continue; // last coinstake output
+
+ sub.type = TransactionRecord::Generated;
+ sub.credit = nNet > 0 ? nNet : wtx.GetValueOut() - nDebit;
+ hashPrev = hash;
}
+
+ parts.append(sub);
}
- parts.append(sub);
}
- else
- {
- bool fAllFromMe = true;
- BOOST_FOREACH(const CTxIn& txin, wtx.vin)
- fAllFromMe = fAllFromMe && wallet->IsMine(txin);
+ }
+ else
+ {
+ bool fAllFromMe = true;
+ BOOST_FOREACH(const CTxIn& txin, wtx.vin)
+ fAllFromMe = fAllFromMe && wallet->IsMine(txin);
- bool fAllToMe = true;
- BOOST_FOREACH(const CTxOut& txout, wtx.vout)
- fAllToMe = fAllToMe && wallet->IsMine(txout);
+ bool fAllToMe = true;
+ BOOST_FOREACH(const CTxOut& txout, wtx.vout)
+ fAllToMe = fAllToMe && wallet->IsMine(txout);
- if (fAllFromMe && fAllToMe)
- {
- // Payment to self
- int64 nChange = wtx.GetChange();
+ if (fAllFromMe && fAllToMe)
+ {
+ // Payment to self
+ int64 nChange = wtx.GetChange();
- parts.append(TransactionRecord(hash, nTime, TransactionRecord::SendToSelf, "",
- -(nDebit - nChange), nCredit - nChange));
- }
- else if (fAllFromMe)
+ parts.append(TransactionRecord(hash, nTime, TransactionRecord::SendToSelf, "",
+ -(nDebit - nChange), nCredit - nChange));
+ }
+ else if (fAllFromMe)
+ {
+ //
+ // Debit
+ //
+ int64 nTxFee = nDebit - wtx.GetValueOut();
+
+ for (unsigned int nOut = 0; nOut < wtx.vout.size(); nOut++)
{
- //
- // Debit
- //
- int64 nTxFee = nDebit - wtx.GetValueOut();
+ const CTxOut& txout = wtx.vout[nOut];
+ TransactionRecord sub(hash, nTime);
+ sub.idx = parts.size();
- for (int nOut = 0; nOut < wtx.vout.size(); nOut++)
+ if(wallet->IsMine(txout))
{
- const CTxOut& txout = wtx.vout[nOut];
- TransactionRecord sub(hash, nTime);
- sub.idx = parts.size();
-
- if(wallet->IsMine(txout))
- {
- // Ignore parts sent to self, as this is usually the change
- // from a transaction sent back to our own address.
- continue;
- }
- else if(!mapValue["to"].empty())
- {
- // Sent to IP
- sub.type = TransactionRecord::SendToIP;
- sub.address = mapValue["to"];
- }
- else
- {
- // Sent to Bitcoin Address
- sub.type = TransactionRecord::SendToAddress;
- CBitcoinAddress address;
- if (ExtractAddress(txout.scriptPubKey, 0, address))
- {
- sub.address = address.ToString();
- }
- }
+ // Ignore parts sent to self, as this is usually the change
+ // from a transaction sent back to our own address.
+ continue;
+ }
- int64 nValue = txout.nValue;
- /* Add fee to first output */
- if (nTxFee > 0)
- {
- nValue += nTxFee;
- nTxFee = 0;
- }
- sub.debit = -nValue;
+ CTxDestination address;
+ if (ExtractDestination(txout.scriptPubKey, address))
+ {
+ // Sent to Bitcoin Address
+ sub.type = TransactionRecord::SendToAddress;
+ sub.address = CBitcoinAddress(address).ToString();
+ }
+ else
+ {
+ // Sent to IP, or other non-address transaction like OP_EVAL
+ sub.type = TransactionRecord::SendToOther;
+ sub.address = mapValue["to"];
+ }
- parts.append(sub);
+ int64 nValue = txout.nValue;
+ /* Add fee to first output */
+ if (nTxFee > 0)
+ {
+ nValue += nTxFee;
+ nTxFee = 0;
}
- }
- else
- {
- //
- // Mixed debit transaction, can't break down payees
- //
- bool fAllMine = true;
- BOOST_FOREACH(const CTxOut& txout, wtx.vout)
- fAllMine = fAllMine && wallet->IsMine(txout);
- BOOST_FOREACH(const CTxIn& txin, wtx.vin)
- fAllMine = fAllMine && wallet->IsMine(txin);
+ sub.debit = -nValue;
- parts.append(TransactionRecord(hash, nTime, TransactionRecord::Other, "", nNet, 0));
+ parts.append(sub);
}
}
+ else
+ {
+ //
+ // Mixed debit transaction, can't break down payees
+ //
+ parts.append(TransactionRecord(hash, nTime, TransactionRecord::Other, "", nNet, 0));
+ }
}
return parts;
// Sort order, unrecorded transactions sort to the top
status.sortKey = strprintf("%010d-%01d-%010u-%03d",
- (pindex ? pindex->nHeight : INT_MAX),
+ (pindex ? pindex->nHeight : std::numeric_limits<int>::max()),
(wtx.IsCoinBase() ? 1 : 0),
wtx.nTimeReceived,
idx);
- status.confirmed = wtx.IsConfirmed();
+ status.confirmed = wtx.IsTrusted();
status.depth = wtx.GetDepthInMainChain();
status.cur_num_blocks = nBestHeight;
// For generated transactions, determine maturity
if(type == TransactionRecord::Generated)
{
+/*
int64 nCredit = wtx.GetCredit(true);
if (nCredit == 0)
{
{
status.maturity = TransactionStatus::Mature;
}
+*/
+
+ if (wtx.GetBlocksToMaturity() > 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
+ {
+ status.maturity = TransactionStatus::Mature;
+ }
}
}