Remove headers.h
[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 "db.h"
9 #include "ui_interface.h"
10
11 #include <QString>
12
13 using namespace std;
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 %1 blocks").arg(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 nTime = wtx.GetTxTime();
46         int64 nCredit = wtx.GetCredit();
47         int64 nDebit = wtx.GetDebit();
48         int64 nNet = nCredit - nDebit;
49
50         strHTML += tr("<b>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 == 1)
57                 strHTML += tr(", broadcast through %1 node").arg(nRequests);
58             else
59                 strHTML += tr(", broadcast through %1 nodes").arg(nRequests);
60         }
61         strHTML += "<br>";
62
63         strHTML += tr("<b>Date:</b> ") + (nTime ? GUIUtil::dateTimeStr(nTime) : QString("")) + "<br>";
64
65         //
66         // From
67         //
68         if (wtx.IsCoinBase())
69         {
70             strHTML += tr("<b>Source:</b> Generated<br>");
71         }
72         else if (!wtx.mapValue["from"].empty())
73         {
74             // Online transaction
75             if (!wtx.mapValue["from"].empty())
76                 strHTML += tr("<b>From:</b> ") + GUIUtil::HtmlEscape(wtx.mapValue["from"]) + "<br>";
77         }
78         else
79         {
80             // Offline transaction
81             if (nNet > 0)
82             {
83                 // Credit
84                 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
85                 {
86                     if (wallet->IsMine(txout))
87                     {
88                         CBitcoinAddress address;
89                         if (ExtractAddress(txout.scriptPubKey, address) && wallet->HaveKey(address))
90                         {
91                             if (wallet->mapAddressBook.count(address))
92                             {
93                                 strHTML += tr("<b>From:</b> ") + tr("unknown") + "<br>";
94                                 strHTML += tr("<b>To:</b> ");
95                                 strHTML += GUIUtil::HtmlEscape(address.ToString());
96                                 if (!wallet->mapAddressBook[address].empty())
97                                     strHTML += tr(" (yours, label: ") + GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + ")";
98                                 else
99                                     strHTML += tr(" (yours)");
100                                 strHTML += "<br>";
101                             }
102                         }
103                         break;
104                     }
105                 }
106             }
107         }
108
109         //
110         // To
111         //
112         string strAddress;
113         if (!wtx.mapValue["to"].empty())
114         {
115             // Online transaction
116             strAddress = wtx.mapValue["to"];
117             strHTML += tr("<b>To:</b> ");
118             if (wallet->mapAddressBook.count(strAddress) && !wallet->mapAddressBook[strAddress].empty())
119                 strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[strAddress]) + " ";
120             strHTML += GUIUtil::HtmlEscape(strAddress) + "<br>";
121         }
122
123         //
124         // Amount
125         //
126         if (wtx.IsCoinBase() && nCredit == 0)
127         {
128             //
129             // Coinbase
130             //
131             int64 nUnmatured = 0;
132             BOOST_FOREACH(const CTxOut& txout, wtx.vout)
133                 nUnmatured += wallet->GetCredit(txout);
134             strHTML += tr("<b>Credit:</b> ");
135             if (wtx.IsInMainChain())
136                 strHTML += tr("(%1 matures in %2 more blocks)")
137                         .arg(BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nUnmatured))
138                         .arg(wtx.GetBlocksToMaturity());
139             else
140                 strHTML += tr("(not accepted)");
141             strHTML += "<br>";
142         }
143         else if (nNet > 0)
144         {
145             //
146             // Credit
147             //
148             strHTML += tr("<b>Credit:</b> ") + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nNet) + "<br>";
149         }
150         else
151         {
152             bool fAllFromMe = true;
153             BOOST_FOREACH(const CTxIn& txin, wtx.vin)
154                 fAllFromMe = fAllFromMe && wallet->IsMine(txin);
155
156             bool fAllToMe = true;
157             BOOST_FOREACH(const CTxOut& txout, wtx.vout)
158                 fAllToMe = fAllToMe && wallet->IsMine(txout);
159
160             if (fAllFromMe)
161             {
162                 //
163                 // Debit
164                 //
165                 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
166                 {
167                     if (wallet->IsMine(txout))
168                         continue;
169
170                     if (wtx.mapValue["to"].empty())
171                     {
172                         // Offline transaction
173                         CBitcoinAddress address;
174                         if (ExtractAddress(txout.scriptPubKey, address))
175                         {
176                             strHTML += tr("<b>To:</b> ");
177                             if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].empty())
178                                 strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + " ";
179                             strHTML += GUIUtil::HtmlEscape(address.ToString());
180                             strHTML += "<br>";
181                         }
182                     }
183
184                     strHTML += tr("<b>Debit:</b> ") + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -txout.nValue) + "<br>";
185                 }
186
187                 if (fAllToMe)
188                 {
189                     // Payment to self
190                     int64 nChange = wtx.GetChange();
191                     int64 nValue = nCredit - nChange;
192                     strHTML += tr("<b>Debit:</b> ") + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -nValue) + "<br>";
193                     strHTML += tr("<b>Credit:</b> ") + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nValue) + "<br>";
194                 }
195
196                 int64 nTxFee = nDebit - wtx.GetValueOut();
197                 if (nTxFee > 0)
198                     strHTML += tr("<b>Transaction fee:</b> ") + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC,-nTxFee) + "<br>";
199             }
200             else
201             {
202                 //
203                 // Mixed debit transaction
204                 //
205                 BOOST_FOREACH(const CTxIn& txin, wtx.vin)
206                     if (wallet->IsMine(txin))
207                         strHTML += tr("<b>Debit:</b> ") + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC,-wallet->GetDebit(txin)) + "<br>";
208                 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
209                     if (wallet->IsMine(txout))
210                         strHTML += tr("<b>Credit:</b> ") + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC,wallet->GetCredit(txout)) + "<br>";
211             }
212         }
213
214         strHTML += tr("<b>Net amount:</b> ") + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC,nNet, true) + "<br>";
215
216         //
217         // Message
218         //
219         if (!wtx.mapValue["message"].empty())
220             strHTML += QString("<br><b>") + tr("Message:") + "</b><br>" + GUIUtil::HtmlEscape(wtx.mapValue["message"], true) + "<br>";
221         if (!wtx.mapValue["comment"].empty())
222             strHTML += QString("<br><b>") + tr("Comment:") + "</b><br>" + GUIUtil::HtmlEscape(wtx.mapValue["comment"], true) + "<br>";
223
224         strHTML += QString("<b>") + tr("Transaction ID:") + "</b> " + wtx.GetHash().ToString().c_str() + "<br>";
225
226         if (wtx.IsCoinBase())
227             strHTML += QString("<br>") + tr("Generated coins must wait 120 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, it will change to \"not accepted\" and not be spendable.  This may occasionally happen if another node generates a block within a few seconds of yours.") + "<br>";
228
229         //
230         // Debug view
231         //
232         if (fDebug)
233         {
234             strHTML += "<hr><br>Debug information<br><br>";
235             BOOST_FOREACH(const CTxIn& txin, wtx.vin)
236                 if(wallet->IsMine(txin))
237                     strHTML += "<b>Debit:</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC,-wallet->GetDebit(txin)) + "<br>";
238             BOOST_FOREACH(const CTxOut& txout, wtx.vout)
239                 if(wallet->IsMine(txout))
240                     strHTML += "<b>Credit:</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC,wallet->GetCredit(txout)) + "<br>";
241
242             strHTML += "<br><b>Transaction:</b><br>";
243             strHTML += GUIUtil::HtmlEscape(wtx.ToString(), true);
244
245             CTxDB txdb("r"); // To fetch source txouts
246
247             strHTML += "<br><b>Inputs:</b>";
248             strHTML += "<ul>";
249
250             {
251                 LOCK(wallet->cs_wallet);
252                 BOOST_FOREACH(const CTxIn& txin, wtx.vin)
253                 {
254                     COutPoint prevout = txin.prevout;
255
256                     CTransaction prev;
257                     if(txdb.ReadDiskTx(prevout.hash, prev))
258                     {
259                         if (prevout.n < prev.vout.size())
260                         {
261                             strHTML += "<li>";
262                             const CTxOut &vout = prev.vout[prevout.n];
263                             CBitcoinAddress address;
264                             if (ExtractAddress(vout.scriptPubKey, address))
265                             {
266                                 if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].empty())
267                                     strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + " ";
268                                 strHTML += QString::fromStdString(address.ToString());
269                             }
270                             strHTML = strHTML + " Amount=" + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC,vout.nValue);
271                             strHTML = strHTML + " IsMine=" + (wallet->IsMine(vout) ? "true" : "false") + "</li>";
272                         }
273                     }
274                 }
275             }
276             strHTML += "</ul>";
277         }
278
279         strHTML += "</font></html>";
280     }
281     return strHTML;
282 }