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