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