Bugfix: Unspendable inputs handling
[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 "txdb.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() || wtx.IsCoinStake())
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() || wtx.IsCoinStake())
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
221         //
222         // Debug view
223         //
224         if (fDebug)
225         {
226             strHTML += "<hr><br>" + tr("Debug information") + "<br><br>";
227             BOOST_FOREACH(const CTxIn& txin, wtx.vin)
228                 if(wallet->IsMine(txin))
229                     strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -wallet->GetDebit(txin)) + "<br>";
230             BOOST_FOREACH(const CTxOut& txout, wtx.vout)
231                 if(wallet->IsMine(txout))
232                     strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, wallet->GetCredit(txout)) + "<br>";
233
234             strHTML += "<br><b>" + tr("Transaction") + ":</b><br>";
235             strHTML += GUIUtil::HtmlEscape(wtx.ToString(), true);
236
237             CTxDB txdb("r"); // To fetch source txouts
238
239             strHTML += "<br><b>" + tr("Inputs") + ":</b>";
240             strHTML += "<ul>";
241
242             {
243                 LOCK(wallet->cs_wallet);
244                 BOOST_FOREACH(const CTxIn& txin, wtx.vin)
245                 {
246                     COutPoint prevout = txin.prevout;
247
248                     CTransaction prev;
249                     if(txdb.ReadDiskTx(prevout.hash, prev))
250                     {
251                         if (prevout.n < prev.vout.size())
252                         {
253                             strHTML += "<li>";
254                             const CTxOut &vout = prev.vout[prevout.n];
255                             CTxDestination address;
256                             if (ExtractDestination(vout.scriptPubKey, address))
257                             {
258                                 if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].empty())
259                                     strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + " ";
260                                 strHTML += QString::fromStdString(CBitcoinAddress(address).ToString());
261                             }
262                             strHTML = strHTML + " " + tr("Amount") + "=" + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, vout.nValue);
263                             strHTML = strHTML + " IsMine=" + (wallet->IsMine(vout) ? tr("true") : tr("false")) + "</li>";
264                         }
265                     }
266                 }
267             }
268
269             strHTML += "</ul>";
270         }
271
272         strHTML += "</font></html>";
273     }
274     return strHTML;
275 }