Handle "conflicted" transactions properly
[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 (nDepth < 0)
25             return tr("conflicted");
26         else if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
27             return tr("%1/offline").arg(nDepth);
28         else if (nDepth < 6)
29             return tr("%1/unconfirmed").arg(nDepth);
30         else
31             return tr("%1 confirmations").arg(nDepth);
32     }
33 }
34
35 QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx)
36 {
37     QString strHTML;
38
39     {
40         LOCK(wallet->cs_wallet);
41         strHTML.reserve(4000);
42         strHTML += "<html><font face='verdana, arial, helvetica, sans-serif'>";
43
44         int64 nTime = wtx.GetTxTime();
45         int64 nCredit = wtx.GetCredit();
46         int64 nDebit = wtx.GetDebit();
47         int64 nNet = nCredit - nDebit;
48
49         strHTML += "<b>" + tr("Status") + ":</b> " + FormatTxStatus(wtx);
50         int nRequests = wtx.GetRequestCount();
51         if (nRequests != -1)
52         {
53             if (nRequests == 0)
54                 strHTML += tr(", has not been successfully broadcast yet");
55             else if (nRequests > 0)
56                 strHTML += tr(", broadcast through %n node(s)", "", nRequests);
57         }
58         strHTML += "<br>";
59
60         strHTML += "<b>" + tr("Date") + ":</b> " + (nTime ? GUIUtil::dateTimeStr(nTime) : "") + "<br>";
61
62         //
63         // From
64         //
65         if (wtx.IsCoinBase())
66         {
67             strHTML += "<b>" + tr("Source") + ":</b> " + tr("Generated") + "<br>";
68         }
69         else if (wtx.mapValue.count("from") && !wtx.mapValue["from"].empty())
70         {
71             // Online transaction
72             strHTML += "<b>" + tr("From") + ":</b> " + GUIUtil::HtmlEscape(wtx.mapValue["from"]) + "<br>";
73         }
74         else
75         {
76             // Offline transaction
77             if (nNet > 0)
78             {
79                 // Credit
80                 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
81                 {
82                     if (wallet->IsMine(txout))
83                     {
84                         CTxDestination address;
85                         if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address))
86                         {
87                             if (wallet->mapAddressBook.count(address))
88                             {
89                                 strHTML += "<b>" + tr("From") + ":</b> " + tr("unknown") + "<br>";
90                                 strHTML += "<b>" + tr("To") + ":</b> ";
91                                 strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address).ToString());
92                                 if (!wallet->mapAddressBook[address].empty())
93                                     strHTML += " (" + tr("own address") + ", " + tr("label") + ": " + GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + ")";
94                                 else
95                                     strHTML += " (" + tr("own address") + ")";
96                                 strHTML += "<br>";
97                             }
98                         }
99                         break;
100                     }
101                 }
102             }
103         }
104
105         //
106         // To
107         //
108         if (wtx.mapValue.count("to") && !wtx.mapValue["to"].empty())
109         {
110             // Online transaction
111             std::string strAddress = wtx.mapValue["to"];
112             strHTML += "<b>" + tr("To") + ":</b> ";
113             CTxDestination dest = CBitcoinAddress(strAddress).Get();
114             if (wallet->mapAddressBook.count(dest) && !wallet->mapAddressBook[dest].empty())
115                 strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[dest]) + " ";
116             strHTML += GUIUtil::HtmlEscape(strAddress) + "<br>";
117         }
118
119         //
120         // Amount
121         //
122         if (wtx.IsCoinBase() && nCredit == 0)
123         {
124             //
125             // Coinbase
126             //
127             int64 nUnmatured = 0;
128             BOOST_FOREACH(const CTxOut& txout, wtx.vout)
129                 nUnmatured += wallet->GetCredit(txout);
130             strHTML += "<b>" + tr("Credit") + ":</b> ";
131             if (wtx.IsInMainChain())
132                 strHTML += BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nUnmatured)+ " (" + tr("matures in %n more block(s)", "", wtx.GetBlocksToMaturity()) + ")";
133             else
134                 strHTML += "(" + tr("not accepted") + ")";
135             strHTML += "<br>";
136         }
137         else if (nNet > 0)
138         {
139             //
140             // Credit
141             //
142             strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nNet) + "<br>";
143         }
144         else
145         {
146             bool fAllFromMe = true;
147             BOOST_FOREACH(const CTxIn& txin, wtx.vin)
148                 fAllFromMe = fAllFromMe && wallet->IsMine(txin);
149
150             bool fAllToMe = true;
151             BOOST_FOREACH(const CTxOut& txout, wtx.vout)
152                 fAllToMe = fAllToMe && wallet->IsMine(txout);
153
154             if (fAllFromMe)
155             {
156                 //
157                 // Debit
158                 //
159                 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
160                 {
161                     if (wallet->IsMine(txout))
162                         continue;
163
164                     if (!wtx.mapValue.count("to") || wtx.mapValue["to"].empty())
165                     {
166                         // Offline transaction
167                         CTxDestination address;
168                         if (ExtractDestination(txout.scriptPubKey, address))
169                         {
170                             strHTML += "<b>" + tr("To") + ":</b> ";
171                             if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].empty())
172                                 strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + " ";
173                             strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address).ToString());
174                             strHTML += "<br>";
175                         }
176                     }
177
178                     strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -txout.nValue) + "<br>";
179                 }
180
181                 if (fAllToMe)
182                 {
183                     // Payment to self
184                     int64 nChange = wtx.GetChange();
185                     int64 nValue = nCredit - nChange;
186                     strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -nValue) + "<br>";
187                     strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nValue) + "<br>";
188                 }
189
190                 int64 nTxFee = nDebit - wtx.GetValueOut();
191                 if (nTxFee > 0)
192                     strHTML += "<b>" + tr("Transaction fee") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -nTxFee) + "<br>";
193             }
194             else
195             {
196                 //
197                 // Mixed debit transaction
198                 //
199                 BOOST_FOREACH(const CTxIn& txin, wtx.vin)
200                     if (wallet->IsMine(txin))
201                         strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -wallet->GetDebit(txin)) + "<br>";
202                 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
203                     if (wallet->IsMine(txout))
204                         strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, wallet->GetCredit(txout)) + "<br>";
205             }
206         }
207
208         strHTML += "<b>" + tr("Net amount") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nNet, true) + "<br>";
209
210         //
211         // Message
212         //
213         if (wtx.mapValue.count("message") && !wtx.mapValue["message"].empty())
214             strHTML += "<br><b>" + tr("Message") + ":</b><br>" + GUIUtil::HtmlEscape(wtx.mapValue["message"], true) + "<br>";
215         if (wtx.mapValue.count("comment") && !wtx.mapValue["comment"].empty())
216             strHTML += "<br><b>" + tr("Comment") + ":</b><br>" + GUIUtil::HtmlEscape(wtx.mapValue["comment"], true) + "<br>";
217
218         strHTML += "<b>" + tr("Transaction ID") + ":</b> " + wtx.GetHash().ToString().c_str() + "<br>";
219
220         if (wtx.IsCoinBase() || wtx.IsCoinStake())
221             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>";
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             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                     CCoins prev;
249                     if(pcoinsTip->GetCoins(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 }