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