senderAddress
[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(MINE_ALL);
44         int64 nDebit = wtx.GetDebit(MINE_ALL);
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                                 for (unsigned int i = 0; i < wtx.vin.size(); i++)
88                                 {
89                                     uint256 hash;
90                                     const CTxIn& vin = wtx.vin[i];
91                                     hash.SetHex(vin.prevout.hash.ToString());
92                                     CTransaction wtxPrev;
93                                     uint256 hashBlock = 0;
94                                     if (!GetTransaction(hash, wtxPrev, hashBlock))
95                                     {
96                                         strHTML += "<b>" + tr("From") + ":</b> " + tr("unknown") + "<br>";
97                                         continue; 
98                                     }
99                                     CTxDestination senderAddress;
100                                     if (!ExtractDestination(wtxPrev.vout[vin.prevout.n].scriptPubKey, senderAddress) )
101                                     {
102                                         strHTML += "<b>" + tr("From") + ":</b> " + tr("unknown") + "<br>";
103                                     }
104                                     else
105                                     {
106                                         strHTML += "<b>" + tr("From") + ":</b> ";
107                                         strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(senderAddress).ToString());
108                                         strHTML += "<br>";
109                                     }
110                                 }
111                                 strHTML += "<b>" + tr("To") + ":</b> ";
112                                 strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address).ToString());
113                                 if (!wallet->mapAddressBook[address].empty())
114                                     strHTML += " (" + tr("own address") + ", " + tr("label") + ": " + GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + ")";
115                                 else
116                                     strHTML += " (" + tr("own address") + ")";
117                                 strHTML += "<br>";
118                             }
119                         }
120                         break;
121                     }
122                 }
123             }
124         }
125
126         //
127         // To
128         //
129         if (wtx.mapValue.count("to") && !wtx.mapValue["to"].empty())
130         {
131             // Online transaction
132             std::string strAddress = wtx.mapValue["to"];
133             strHTML += "<b>" + tr("To") + ":</b> ";
134             CTxDestination dest = CBitcoinAddress(strAddress).Get();
135             if (wallet->mapAddressBook.count(dest) && !wallet->mapAddressBook[dest].empty())
136                 strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[dest]) + " ";
137             strHTML += GUIUtil::HtmlEscape(strAddress) + "<br>";
138         }
139
140         //
141         // Amount
142         //
143         if (wtx.IsCoinBase() && nCredit == 0)
144         {
145             //
146             // Coinbase
147             //
148             int64 nUnmatured = 0;
149             BOOST_FOREACH(const CTxOut& txout, wtx.vout)
150                 nUnmatured += wallet->GetCredit(txout, MINE_ALL);
151             strHTML += "<b>" + tr("Credit") + ":</b> ";
152             if (wtx.IsInMainChain())
153                 strHTML += BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nUnmatured)+ " (" + tr("matures in %n more block(s)", "", wtx.GetBlocksToMaturity()) + ")";
154             else
155                 strHTML += "(" + tr("not accepted") + ")";
156             strHTML += "<br>";
157         }
158         else if (nNet > 0)
159         {
160             //
161             // Credit
162             //
163             strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nNet) + "<br>";
164         }
165         else
166         {
167             bool fAllFromMe = true;
168             BOOST_FOREACH(const CTxIn& txin, wtx.vin)
169                 fAllFromMe = fAllFromMe && wallet->IsMine(txin);
170
171             bool fAllToMe = true;
172             BOOST_FOREACH(const CTxOut& txout, wtx.vout)
173                 fAllToMe = fAllToMe && wallet->IsMine(txout);
174
175             if (fAllFromMe)
176             {
177                 //
178                 // Debit
179                 //
180                 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
181                 {
182                     if (wallet->IsMine(txout))
183                         continue;
184
185                     if (!wtx.mapValue.count("to") || wtx.mapValue["to"].empty())
186                     {
187                         // Offline transaction
188                         CTxDestination address;
189                         if (ExtractDestination(txout.scriptPubKey, address))
190                         {
191                             strHTML += "<b>" + tr("To") + ":</b> ";
192                             if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].empty())
193                                 strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + " ";
194                             strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address).ToString());
195                             strHTML += "<br>";
196                         }
197                     }
198
199                     strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -txout.nValue) + "<br>";
200                 }
201
202                 if (fAllToMe)
203                 {
204                     // Payment to self
205                     int64 nChange = wtx.GetChange();
206                     int64 nValue = nCredit - nChange;
207                     strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -nValue) + "<br>";
208                     strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nValue) + "<br>";
209                 }
210
211                 int64 nTxFee = nDebit - wtx.GetValueOut();
212                 if (nTxFee > 0)
213                     strHTML += "<b>" + tr("Transaction fee") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -nTxFee) + "<br>";
214             }
215             else
216             {
217                 //
218                 // Mixed debit transaction
219                 //
220                 BOOST_FOREACH(const CTxIn& txin, wtx.vin)
221                     if (wallet->IsMine(txin))
222                         strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -wallet->GetDebit(txin, MINE_ALL)) + "<br>";
223                 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
224                     if (wallet->IsMine(txout))
225                         strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, wallet->GetCredit(txout, MINE_ALL)) + "<br>";
226             }
227         }
228
229         strHTML += "<b>" + tr("Net amount") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nNet, true) + "<br>";
230
231         //
232         // Message
233         //
234         if (wtx.mapValue.count("message") && !wtx.mapValue["message"].empty())
235             strHTML += "<br><b>" + tr("Message") + ":</b><br>" + GUIUtil::HtmlEscape(wtx.mapValue["message"], true) + "<br>";
236         if (wtx.mapValue.count("comment") && !wtx.mapValue["comment"].empty())
237             strHTML += "<br><b>" + tr("Comment") + ":</b><br>" + GUIUtil::HtmlEscape(wtx.mapValue["comment"], true) + "<br>";
238
239         strHTML += "<b>" + tr("Transaction ID") + ":</b> " + wtx.GetHash().ToString().c_str() + "<br>";
240
241         if (wtx.IsCoinBase() || wtx.IsCoinStake())
242             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>";
243
244         //
245         // Debug view
246         //
247         if (fDebug)
248         {
249             strHTML += "<hr><br>" + tr("Debug information") + "<br><br>";
250             BOOST_FOREACH(const CTxIn& txin, wtx.vin)
251                 if(wallet->IsMine(txin))
252                     strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -wallet->GetDebit(txin, MINE_ALL)) + "<br>";
253             BOOST_FOREACH(const CTxOut& txout, wtx.vout)
254                 if(wallet->IsMine(txout))
255                     strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, wallet->GetCredit(txout, MINE_ALL)) + "<br>";
256
257             strHTML += "<br><b>" + tr("Transaction") + ":</b><br>";
258             strHTML += GUIUtil::HtmlEscape(wtx.ToString(), true);
259
260             CTxDB txdb("r"); // To fetch source txouts
261
262             strHTML += "<br><b>" + tr("Inputs") + ":</b>";
263             strHTML += "<ul>";
264
265             {
266                 LOCK(wallet->cs_wallet);
267                 BOOST_FOREACH(const CTxIn& txin, wtx.vin)
268                 {
269                     COutPoint prevout = txin.prevout;
270
271                     CTransaction prev;
272                     if(txdb.ReadDiskTx(prevout.hash, prev))
273                     {
274                         if (prevout.n < prev.vout.size())
275                         {
276                             strHTML += "<li>";
277                             const CTxOut &vout = prev.vout[prevout.n];
278                             CTxDestination address;
279                             if (ExtractDestination(vout.scriptPubKey, address))
280                             {
281                                 if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].empty())
282                                     strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + " ";
283                                 strHTML += QString::fromStdString(CBitcoinAddress(address).ToString());
284                             }
285                             strHTML = strHTML + " " + tr("Amount") + "=" + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, vout.nValue);
286                             strHTML = strHTML + " IsMine=" + (wallet->IsMine(vout) ? tr("true") : tr("false")) + "</li>";
287                         }
288                     }
289                 }
290             }
291
292             strHTML += "</ul>";
293         }
294
295         strHTML += "</font></html>";
296     }
297     return strHTML;
298 }