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