Code cleanup
[novacoin.git] / src / qt / transactiondesc.cpp
1 #include "transactiondesc.h"
2
3 #include "guiutil.h"
4 #include "bitcoinunits.h"
5
6 #include "main.h"
7 #include "wallet.h"
8 #include "txdb.h"
9 #include "ui_interface.h"
10 #include "base58.h"
11
12 #include <vector>
13 #include <algorithm>
14
15 QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx)
16 {
17     if (!wtx.IsFinal())
18     {
19         if (wtx.nLockTime < LOCKTIME_THRESHOLD)
20             return tr("Open for %n block(s)", "", nBestHeight - wtx.nLockTime);
21         else
22             return tr("Open until %1").arg(GUIUtil::dateTimeStr(wtx.nLockTime));
23     }
24     else
25     {
26         int nDepth = wtx.GetDepthInMainChain();
27         if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
28             return tr("%1/offline").arg(nDepth);
29         else if (nDepth < 6)
30             return tr("%1/unconfirmed").arg(nDepth);
31         else
32             return tr("%1 confirmations").arg(nDepth);
33     }
34 }
35
36 QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx)
37 {
38     QString strHTML;
39
40     {
41         LOCK(wallet->cs_wallet);
42         strHTML.reserve(4000);
43         strHTML += "<html><font face='verdana, arial, helvetica, sans-serif'>";
44
45         int64_t nTime = wtx.GetTxTime();
46         int64_t nCredit = wtx.GetCredit(MINE_ALL);
47         int64_t nDebit = wtx.GetDebit(MINE_ALL);
48         int64_t nNet = nCredit - nDebit;
49
50         strHTML += "<b>" + tr("Status") + ":</b> " + FormatTxStatus(wtx);
51         int nRequests = wtx.GetRequestCount();
52         if (nRequests != -1)
53         {
54             if (nRequests == 0)
55                 strHTML += tr(", has not been successfully broadcast yet");
56             else if (nRequests > 0)
57                 strHTML += tr(", broadcast through %n node(s)", "", nRequests);
58         }
59         strHTML += "<br>";
60
61         strHTML += "<b>" + tr("Date") + ":</b> " + (nTime ? GUIUtil::dateTimeStr(nTime) : "") + "<br>";
62
63         //
64         // From
65         //
66         if (wtx.IsCoinBase() || wtx.IsCoinStake())
67         {
68             strHTML += "<b>" + tr("Source") + ":</b> " + tr("Generated") + "<br>";
69         }
70         else if (wtx.mapValue.count("from") && !wtx.mapValue["from"].empty())
71         {
72             // Online transaction
73             strHTML += "<b>" + tr("From") + ":</b> " + GUIUtil::HtmlEscape(wtx.mapValue["from"]) + "<br>";
74         }
75         else
76         {
77             // Offline transaction
78             if (nNet > 0)
79             {
80                 // Credit
81                 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
82                 {
83                     if (wallet->IsMine(txout))
84                     {
85                         CTxDestination address;
86                         if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address))
87                         {
88                             if (wallet->mapAddressBook.count(address))
89                             {
90                                 std::vector<CTxDestination> addedAddresses;
91                                 for (unsigned int i = 0; i < wtx.vin.size(); i++)
92                                 {
93                                     uint256 hash;
94                                     const CTxIn& vin = wtx.vin[i];
95                                     hash.SetHex(vin.prevout.hash.ToString());
96                                     CTransaction wtxPrev;
97                                     uint256 hashBlock = 0;
98                                     if (!GetTransaction(hash, wtxPrev, hashBlock))
99                                     {
100                                         strHTML += "<b>" + tr("From") + ":</b> " + tr("unknown") + "<br>";
101                                         continue; 
102                                     }
103                                     CTxDestination senderAddress;
104                                     if (!ExtractDestination(wtxPrev.vout[vin.prevout.n].scriptPubKey, senderAddress) )
105                                     {
106                                         strHTML += "<b>" + tr("From") + ":</b> " + tr("unknown") + "<br>";
107                                     }
108                                     else if(std::find(addedAddresses.begin(), addedAddresses.end(), senderAddress) 
109                                             == addedAddresses.end() )
110                                     {
111                                         addedAddresses.push_back(senderAddress);
112                                         strHTML += "<b>" + tr("From") + ":</b> ";
113                                         strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(senderAddress).ToString());
114                                         if(wallet->mapAddressBook.find(senderAddress) !=  wallet->mapAddressBook.end())
115                                             if (!wallet->mapAddressBook[senderAddress].empty())
116                                             {
117                                                 strHTML += " (" + tr("label") + ": " + GUIUtil::HtmlEscape(wallet->mapAddressBook[senderAddress]) + ")";
118                                             }
119                                         strHTML += "<br>";
120                                     }
121                                 }
122                                 strHTML += "<b>" + tr("To") + ":</b> ";
123                                 strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address).ToString());
124                                 if (!wallet->mapAddressBook[address].empty())
125                                     strHTML += " (" + tr("own address") + ", " + tr("label") + ": " + GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + ")";
126                                 else
127                                     strHTML += " (" + tr("own address") + ")";
128                                 strHTML += "<br>";
129                             }
130                         }
131                         break;
132                     }
133                 }
134             }
135         }
136
137         //
138         // To
139         //
140         if (wtx.mapValue.count("to") && !wtx.mapValue["to"].empty())
141         {
142             // Online transaction
143             std::string strAddress = wtx.mapValue["to"];
144             strHTML += "<b>" + tr("To") + ":</b> ";
145             CTxDestination dest = CBitcoinAddress(strAddress).Get();
146             if (wallet->mapAddressBook.count(dest) && !wallet->mapAddressBook[dest].empty())
147                 strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[dest]) + " ";
148             strHTML += GUIUtil::HtmlEscape(strAddress) + "<br>";
149         }
150
151         //
152         // Amount
153         //
154         if (wtx.IsCoinBase() && nCredit == 0)
155         {
156             //
157             // Coinbase
158             //
159             int64_t nUnmatured = 0;
160             BOOST_FOREACH(const CTxOut& txout, wtx.vout)
161                 nUnmatured += wallet->GetCredit(txout, MINE_ALL);
162             strHTML += "<b>" + tr("Credit") + ":</b> ";
163             if (wtx.IsInMainChain())
164                 strHTML += BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nUnmatured)+ " (" + tr("matures in %n more block(s)", "", wtx.GetBlocksToMaturity()) + ")";
165             else
166                 strHTML += "(" + tr("not accepted") + ")";
167             strHTML += "<br>";
168         }
169         else if (nNet > 0)
170         {
171             //
172             // Credit
173             //
174             strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nNet) + "<br>";
175         }
176         else
177         {
178             bool fAllFromMe = true;
179             BOOST_FOREACH(const CTxIn& txin, wtx.vin)
180                 fAllFromMe = fAllFromMe && wallet->IsMine(txin);
181
182             bool fAllToMe = true;
183             BOOST_FOREACH(const CTxOut& txout, wtx.vout)
184                 fAllToMe = fAllToMe && wallet->IsMine(txout);
185
186             if (fAllFromMe)
187             {
188                 //
189                 // Debit
190                 //
191                 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
192                 {
193                     if (wallet->IsMine(txout))
194                         continue;
195
196                     if (!wtx.mapValue.count("to") || wtx.mapValue["to"].empty())
197                     {
198                         // Offline transaction
199                         CTxDestination address;
200                         if (ExtractDestination(txout.scriptPubKey, address))
201                         {
202                             strHTML += "<b>" + tr("To") + ":</b> ";
203                             if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].empty())
204                                 strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + " ";
205                             strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address).ToString());
206                             strHTML += "<br>";
207                         }
208                     }
209
210                     strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -txout.nValue) + "<br>";
211                 }
212
213                 if (fAllToMe)
214                 {
215                     // Payment to self
216                     int64_t nChange = wtx.GetChange();
217                     int64_t nValue = nCredit - nChange;
218                     strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -nValue) + "<br>";
219                     strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nValue) + "<br>";
220                 }
221
222                 int64_t nTxFee = nDebit - wtx.GetValueOut();
223                 if (nTxFee > 0)
224                     strHTML += "<b>" + tr("Transaction fee") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -nTxFee) + "<br>";
225             }
226             else
227             {
228                 //
229                 // Mixed debit transaction
230                 //
231                 BOOST_FOREACH(const CTxIn& txin, wtx.vin)
232                     if (wallet->IsMine(txin))
233                         strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -wallet->GetDebit(txin, MINE_ALL)) + "<br>";
234                 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
235                     if (wallet->IsMine(txout))
236                         strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, wallet->GetCredit(txout, MINE_ALL)) + "<br>";
237             }
238         }
239
240         strHTML += "<b>" + tr("Net amount") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nNet, true) + "<br>";
241
242         //
243         // Message
244         //
245         if (wtx.mapValue.count("message") && !wtx.mapValue["message"].empty())
246             strHTML += "<br><b>" + tr("Message") + ":</b><br>" + GUIUtil::HtmlEscape(wtx.mapValue["message"], true) + "<br>";
247         if (wtx.mapValue.count("comment") && !wtx.mapValue["comment"].empty())
248             strHTML += "<br><b>" + tr("Comment") + ":</b><br>" + GUIUtil::HtmlEscape(wtx.mapValue["comment"], true) + "<br>";
249
250         strHTML += "<b>" + tr("Transaction ID") + ":</b> " + wtx.GetHash().ToString().c_str() + "<br>";
251
252         if (wtx.IsCoinBase() || wtx.IsCoinStake())
253             strHTML += "<br>" + tr("Generated coins must mature 520 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to \"not accepted\" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.") + "<br>";
254
255         //
256         // Debug view
257         //
258         if (fDebug)
259         {
260             strHTML += "<hr><br>" + tr("Debug information") + "<br><br>";
261             BOOST_FOREACH(const CTxIn& txin, wtx.vin)
262                 if(wallet->IsMine(txin))
263                     strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -wallet->GetDebit(txin, MINE_ALL)) + "<br>";
264             BOOST_FOREACH(const CTxOut& txout, wtx.vout)
265                 if(wallet->IsMine(txout))
266                     strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, wallet->GetCredit(txout, MINE_ALL)) + "<br>";
267
268             strHTML += "<br><b>" + tr("Transaction") + ":</b><br>";
269             strHTML += GUIUtil::HtmlEscape(wtx.ToString(), true);
270
271             CTxDB txdb("r"); // To fetch source txouts
272
273             strHTML += "<br><b>" + tr("Inputs") + ":</b>";
274             strHTML += "<ul>";
275
276             {
277                 LOCK(wallet->cs_wallet);
278                 BOOST_FOREACH(const CTxIn& txin, wtx.vin)
279                 {
280                     COutPoint prevout = txin.prevout;
281
282                     CTransaction prev;
283                     if(txdb.ReadDiskTx(prevout.hash, prev))
284                     {
285                         if (prevout.n < prev.vout.size())
286                         {
287                             strHTML += "<li>";
288                             const CTxOut &vout = prev.vout[prevout.n];
289                             CTxDestination address;
290                             if (ExtractDestination(vout.scriptPubKey, address))
291                             {
292                                 if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].empty())
293                                     strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + " ";
294                                 strHTML += QString::fromStdString(CBitcoinAddress(address).ToString());
295                             }
296                             strHTML = strHTML + " " + tr("Amount") + "=" + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, vout.nValue);
297                             strHTML = strHTML + " IsMine=" + (wallet->IsMine(vout) ? tr("true") : tr("false")) + "</li>";
298                         }
299                     }
300                 }
301             }
302
303             strHTML += "</ul>";
304         }
305
306         strHTML += "</font></html>";
307     }
308     return strHTML;
309 }