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