2f00fa87526572a52326d507ef4d1b222ce4a5ae
[novacoin.git] / src / qt / transactionrecord.cpp
1 #include "transactionrecord.h"
2
3
4 /* Return positive answer if transaction should be shown in list.
5  */
6 bool TransactionRecord::showTransaction(const CWalletTx &wtx)
7 {
8     if (wtx.IsCoinBase())
9     {
10         // Don't show generated coin until confirmed by at least one block after it
11         // so we don't get the user's hopes up until it looks like it's probably accepted.
12         //
13         // It is not an error when generated blocks are not accepted.  By design,
14         // some percentage of blocks, like 10% or more, will end up not accepted.
15         // This is the normal mechanism by which the network copes with latency.
16         //
17         // We display regular transactions right away before any confirmation
18         // because they can always get into some block eventually.  Generated coins
19         // are special because if their block is not accepted, they are not valid.
20         //
21         if (wtx.GetDepthInMainChain() < 2)
22         {
23             return false;
24         }
25     }
26     return true;
27 }
28
29 /*
30  * Decompose CWallet transaction to model transaction records.
31  */
32 QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWalletTx &wtx)
33 {
34     QList<TransactionRecord> parts;
35     int64 nTime = wtx.nTimeDisplayed = wtx.GetTxTime();
36     int64 nCredit = wtx.GetCredit(true);
37     int64 nDebit = wtx.GetDebit();
38     int64 nNet = nCredit - nDebit;
39     uint256 hash = wtx.GetHash();
40     std::map<std::string, std::string> mapValue = wtx.mapValue;
41
42     if (showTransaction(wtx))
43     {
44         if (nNet > 0 || wtx.IsCoinBase())
45         {
46             //
47             // Credit
48             //
49             TransactionRecord sub(hash, nTime);
50
51             sub.credit = nNet;
52
53             if (wtx.IsCoinBase())
54             {
55                 // Generated
56                 sub.type = TransactionRecord::Generated;
57
58                 if (nCredit == 0)
59                 {
60                     int64 nUnmatured = 0;
61                     BOOST_FOREACH(const CTxOut& txout, wtx.vout)
62                         nUnmatured += txout.GetCredit();
63                     sub.credit = nUnmatured;
64                 }
65             }
66             else if (!mapValue["from"].empty() || !mapValue["message"].empty())
67             {
68                 // Received by IP connection
69                 sub.type = TransactionRecord::RecvFromIP;
70                 if (!mapValue["from"].empty())
71                     sub.address = mapValue["from"];
72             }
73             else
74             {
75                 // Received by Bitcoin Address
76                 sub.type = TransactionRecord::RecvWithAddress;
77                 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
78                 {
79                     if (txout.IsMine())
80                     {
81                         std::vector<unsigned char> vchPubKey;
82                         if (ExtractPubKey(txout.scriptPubKey, true, vchPubKey))
83                         {
84                             sub.address = PubKeyToAddress(vchPubKey);
85                         }
86                         break;
87                     }
88                 }
89             }
90             parts.append(sub);
91         }
92         else
93         {
94             bool fAllFromMe = true;
95             BOOST_FOREACH(const CTxIn& txin, wtx.vin)
96                 fAllFromMe = fAllFromMe && txin.IsMine();
97
98             bool fAllToMe = true;
99             BOOST_FOREACH(const CTxOut& txout, wtx.vout)
100                 fAllToMe = fAllToMe && txout.IsMine();
101
102             if (fAllFromMe && fAllToMe)
103             {
104                 // Payment to self
105                 int64 nChange = wtx.GetChange();
106
107                 parts.append(TransactionRecord(hash, nTime, TransactionRecord::SendToSelf, "",
108                                 -(nDebit - nChange), nCredit - nChange));
109             }
110             else if (fAllFromMe)
111             {
112                 //
113                 // Debit
114                 //
115                 int64 nTxFee = nDebit - wtx.GetValueOut();
116
117                 for (int nOut = 0; nOut < wtx.vout.size(); nOut++)
118                 {
119                     const CTxOut& txout = wtx.vout[nOut];
120                     TransactionRecord sub(hash, nTime);
121                     sub.idx = parts.size();
122
123                     if (txout.IsMine())
124                     {
125                         // Ignore parts sent to self, as this is usually the change
126                         // from a transaction sent back to our own address.
127                         continue;
128                     }
129                     else if (!mapValue["to"].empty())
130                     {
131                         // Sent to IP
132                         sub.type = TransactionRecord::SendToIP;
133                         sub.address = mapValue["to"];
134                     }
135                     else
136                     {
137                         // Sent to Bitcoin Address
138                         sub.type = TransactionRecord::SendToAddress;
139                         uint160 hash160;
140                         if (ExtractHash160(txout.scriptPubKey, hash160))
141                             sub.address = Hash160ToAddress(hash160);
142                     }
143
144                     int64 nValue = txout.nValue;
145                     /* Add fee to first output */
146                     if (nTxFee > 0)
147                     {
148                         nValue += nTxFee;
149                         nTxFee = 0;
150                     }
151                     sub.debit = -nValue;
152
153                     parts.append(sub);
154                 }
155             }
156             else
157             {
158                 //
159                 // Mixed debit transaction, can't break down payees
160                 //
161                 bool fAllMine = true;
162                 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
163                     fAllMine = fAllMine && txout.IsMine();
164                 BOOST_FOREACH(const CTxIn& txin, wtx.vin)
165                     fAllMine = fAllMine && txin.IsMine();
166
167                 parts.append(TransactionRecord(hash, nTime, TransactionRecord::Other, "", nNet, 0));
168             }
169         }
170     }
171
172     return parts;
173 }
174
175 void TransactionRecord::updateStatus(const CWalletTx &wtx)
176 {
177     // Determine transaction status
178
179     // Find the block the tx is in
180     CBlockIndex* pindex = NULL;
181     std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(wtx.hashBlock);
182     if (mi != mapBlockIndex.end())
183         pindex = (*mi).second;
184
185     // Sort order, unrecorded transactions sort to the top
186     status.sortKey = strprintf("%010d-%01d-%010u-%03d",
187         (pindex ? pindex->nHeight : INT_MAX),
188         (wtx.IsCoinBase() ? 1 : 0),
189         wtx.nTimeReceived,
190         idx);
191     status.confirmed = wtx.IsConfirmed();
192     status.depth = wtx.GetDepthInMainChain();
193     status.cur_num_blocks = nBestHeight;
194
195     if (!wtx.IsFinal())
196     {
197         if (wtx.nLockTime < 500000000)
198         {
199             status.status = TransactionStatus::OpenUntilBlock;
200             status.open_for = nBestHeight - wtx.nLockTime;
201         }
202         else
203         {
204             status.status = TransactionStatus::OpenUntilDate;
205             status.open_for = wtx.nLockTime;
206         }
207     }
208     else
209     {
210         if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
211         {
212             status.status = TransactionStatus::Offline;
213         }
214         else if (status.depth < NumConfirmations)
215         {
216             status.status = TransactionStatus::Unconfirmed;
217         }
218         else
219         {
220             status.status = TransactionStatus::HaveConfirmations;
221         }
222     }
223
224     // For generated transactions, determine maturity
225     if(type == TransactionRecord::Generated)
226     {
227         int64 nCredit = wtx.GetCredit(true);
228         if (nCredit == 0)
229         {
230             status.maturity = TransactionStatus::Immature;
231
232             if (wtx.IsInMainChain())
233             {
234                 status.matures_in = wtx.GetBlocksToMaturity();
235
236                 // Check if the block was requested by anyone
237                 if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
238                     status.maturity = TransactionStatus::MaturesWarning;
239             }
240             else
241             {
242                 status.maturity = TransactionStatus::NotAccepted;
243             }
244         }
245         else
246         {
247             status.maturity = TransactionStatus::Mature;
248         }
249     }
250 }
251
252 bool TransactionRecord::statusUpdateNeeded()
253 {
254     return status.cur_num_blocks != nBestHeight;
255 }