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