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