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