4c3071984f14fb0997de81c0eacf19610e048630
[novacoin.git] / src / qt / transactionrecord.cpp
1 #include "transactionrecord.h"
2
3 #include "wallet.h"
4 #include "base58.h"
5
6 /* Return positive answer if transaction should be shown in list.
7  */
8 bool TransactionRecord::showTransaction(const CWalletTx &wtx)
9 {
10     if (wtx.IsCoinBase())
11     {
12         // Ensures we show generated coins / mined transactions at depth 1
13         if (!wtx.IsInMainChain())
14         {
15             return false;
16         }
17     }
18     return true;
19 }
20
21 /*
22  * Decompose CWallet transaction to model transaction records.
23  */
24 QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *wallet, const CWalletTx &wtx)
25 {
26     QList<TransactionRecord> parts;
27     int64 nTime = wtx.GetTxTime();
28     int64 nCredit = wtx.GetCredit(true);
29     int64 nDebit = wtx.GetDebit();
30     int64 nNet = nCredit - nDebit;
31     uint256 hash = wtx.GetHash();
32     std::map<std::string, std::string> mapValue = wtx.mapValue;
33
34     if (nNet > 0 || wtx.IsCoinBase())
35     {
36         //
37         // Credit
38         //
39         BOOST_FOREACH(const CTxOut& txout, wtx.vout)
40         {
41             if(wallet->IsMine(txout))
42             {
43                 TransactionRecord sub(hash, nTime);
44                 CTxDestination address;
45                 sub.idx = parts.size(); // sequence number
46                 sub.credit = txout.nValue;
47                 if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address))
48                 {
49                     // Received by Bitcoin Address
50                     sub.type = TransactionRecord::RecvWithAddress;
51                     sub.address = CBitcoinAddress(address).ToString();
52                 }
53                 else
54                 {
55                     // Received by IP connection (deprecated features), or a multisignature or other non-simple transaction
56                     sub.type = TransactionRecord::RecvFromOther;
57                     sub.address = mapValue["from"];
58                 }
59                 if (wtx.IsCoinBase())
60                 {
61                     // Generated
62                     sub.type = TransactionRecord::Generated;
63                 }
64
65                 parts.append(sub);
66             }
67         }
68     }
69     else
70     {
71         bool fAllFromMe = true;
72         BOOST_FOREACH(const CTxIn& txin, wtx.vin)
73             fAllFromMe = fAllFromMe && wallet->IsMine(txin);
74
75         bool fAllToMe = true;
76         BOOST_FOREACH(const CTxOut& txout, wtx.vout)
77             fAllToMe = fAllToMe && wallet->IsMine(txout);
78
79         if (fAllFromMe && fAllToMe)
80         {
81             // Payment to self
82             int64 nChange = wtx.GetChange();
83
84             parts.append(TransactionRecord(hash, nTime, TransactionRecord::SendToSelf, "",
85                             -(nDebit - nChange), nCredit - nChange));
86         }
87         else if (fAllFromMe)
88         {
89             //
90             // Debit
91             //
92             int64 nTxFee = nDebit - wtx.GetValueOut();
93
94             for (unsigned int nOut = 0; nOut < wtx.vout.size(); nOut++)
95             {
96                 const CTxOut& txout = wtx.vout[nOut];
97                 TransactionRecord sub(hash, nTime);
98                 sub.idx = parts.size();
99
100                 if(wallet->IsMine(txout))
101                 {
102                     // Ignore parts sent to self, as this is usually the change
103                     // from a transaction sent back to our own address.
104                     continue;
105                 }
106
107                 CTxDestination address;
108                 if (ExtractDestination(txout.scriptPubKey, address))
109                 {
110                     // Sent to Bitcoin Address
111                     sub.type = TransactionRecord::SendToAddress;
112                     sub.address = CBitcoinAddress(address).ToString();
113                 }
114                 else
115                 {
116                     // Sent to IP, or other non-address transaction like OP_EVAL
117                     sub.type = TransactionRecord::SendToOther;
118                     sub.address = mapValue["to"];
119                 }
120
121                 int64 nValue = txout.nValue;
122                 /* Add fee to first output */
123                 if (nTxFee > 0)
124                 {
125                     nValue += nTxFee;
126                     nTxFee = 0;
127                 }
128                 sub.debit = -nValue;
129
130                 parts.append(sub);
131             }
132         }
133         else
134         {
135             //
136             // Mixed debit transaction, can't break down payees
137             //
138             parts.append(TransactionRecord(hash, nTime, TransactionRecord::Other, "", nNet, 0));
139         }
140     }
141
142     return parts;
143 }
144
145 void TransactionRecord::updateStatus(const CWalletTx &wtx)
146 {
147     // Determine transaction status
148
149     // Find the block the tx is in
150     CBlockIndex* pindex = NULL;
151     std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(wtx.hashBlock);
152     if (mi != mapBlockIndex.end())
153         pindex = (*mi).second;
154
155     // Sort order, unrecorded transactions sort to the top
156     status.sortKey = strprintf("%010d-%01d-%010u-%03d",
157         (pindex ? pindex->nHeight : std::numeric_limits<int>::max()),
158         (wtx.IsCoinBase() ? 1 : 0),
159         wtx.nTimeReceived,
160         idx);
161     status.confirmed = wtx.IsConfirmed();
162     status.depth = wtx.GetDepthInMainChain();
163     status.cur_num_blocks = nBestHeight;
164
165     if (!wtx.IsFinal())
166     {
167         if (wtx.nLockTime < LOCKTIME_THRESHOLD)
168         {
169             status.status = TransactionStatus::OpenUntilBlock;
170             status.open_for = nBestHeight - wtx.nLockTime;
171         }
172         else
173         {
174             status.status = TransactionStatus::OpenUntilDate;
175             status.open_for = wtx.nLockTime;
176         }
177     }
178     else
179     {
180         if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
181         {
182             status.status = TransactionStatus::Offline;
183         }
184         else if (status.depth < NumConfirmations)
185         {
186             status.status = TransactionStatus::Unconfirmed;
187         }
188         else
189         {
190             status.status = TransactionStatus::HaveConfirmations;
191         }
192     }
193
194     // For generated transactions, determine maturity
195     if(type == TransactionRecord::Generated)
196     {
197         int64 nCredit = wtx.GetCredit(true);
198         if (nCredit == 0)
199         {
200             status.maturity = TransactionStatus::Immature;
201
202             if (wtx.IsInMainChain())
203             {
204                 status.matures_in = wtx.GetBlocksToMaturity();
205
206                 // Check if the block was requested by anyone
207                 if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
208                     status.maturity = TransactionStatus::MaturesWarning;
209             }
210             else
211             {
212                 status.maturity = TransactionStatus::NotAccepted;
213             }
214         }
215         else
216         {
217             status.maturity = TransactionStatus::Mature;
218         }
219     }
220 }
221
222 bool TransactionRecord::statusUpdateNeeded()
223 {
224     return status.cur_num_blocks != nBestHeight;
225 }
226
227 std::string TransactionRecord::getTxID()
228 {
229     return hash.ToString() + strprintf("-%03d", idx);
230 }
231