1 #include <transactiondesc.h>
9 // Taken straight from ui.cpp
10 // TODO: Convert to use QStrings, Qt::Escape and tr()
11 // or: refactor and put describeAsHTML() into bitcoin core but that is unneccesary with better
12 // UI<->core API, no need to put display logic in core.
16 static string HtmlEscape(const char* psz, bool fMultiLine=false)
19 for (const char* p = psz; *p; p++)
21 if (*p == '<') len += 4;
22 else if (*p == '>') len += 4;
23 else if (*p == '&') len += 5;
24 else if (*p == '"') len += 6;
25 else if (*p == ' ' && p > psz && p[-1] == ' ' && p[1] == ' ') len += 6;
26 else if (*p == '\n' && fMultiLine) len += 5;
32 for (const char* p = psz; *p; p++)
34 if (*p == '<') str += "<";
35 else if (*p == '>') str += ">";
36 else if (*p == '&') str += "&";
37 else if (*p == '"') str += """;
38 else if (*p == ' ' && p > psz && p[-1] == ' ' && p[1] == ' ') str += " ";
39 else if (*p == '\n' && fMultiLine) str += "<br>\n";
46 static string HtmlEscape(const string& str, bool fMultiLine=false)
48 return HtmlEscape(str.c_str(), fMultiLine);
51 static string FormatTxStatus(const CWalletTx& wtx)
56 if (wtx.nLockTime < 500000000)
57 return strprintf(_("Open for %d blocks"), nBestHeight - wtx.nLockTime);
59 return strprintf(_("Open until %s"), GUIUtil::DateTimeStr(wtx.nLockTime).toStdString().c_str());
63 int nDepth = wtx.GetDepthInMainChain();
64 if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
65 return strprintf(_("%d/offline?"), nDepth);
67 return strprintf(_("%d/unconfirmed"), nDepth);
69 return strprintf(_("%d confirmations"), nDepth);
73 string TransactionDesc::toHTML(CWalletTx &wtx)
76 CRITICAL_BLOCK(cs_mapAddressBook)
78 strHTML.reserve(4000);
79 strHTML += "<html><font face='verdana, arial, helvetica, sans-serif'>";
81 int64 nTime = wtx.GetTxTime();
82 int64 nCredit = wtx.GetCredit();
83 int64 nDebit = wtx.GetDebit();
84 int64 nNet = nCredit - nDebit;
88 strHTML += _("<b>Status:</b> ") + FormatTxStatus(wtx);
89 int nRequests = wtx.GetRequestCount();
93 strHTML += _(", has not been successfully broadcast yet");
94 else if (nRequests == 1)
95 strHTML += strprintf(_(", broadcast through %d node"), nRequests);
97 strHTML += strprintf(_(", broadcast through %d nodes"), nRequests);
101 strHTML += _("<b>Date:</b> ") + (nTime ? GUIUtil::DateTimeStr(nTime).toStdString() : "") + "<br>";
107 if (wtx.IsCoinBase())
109 strHTML += _("<b>Source:</b> Generated<br>");
111 else if (!wtx.mapValue["from"].empty())
113 // Online transaction
114 if (!wtx.mapValue["from"].empty())
115 strHTML += _("<b>From:</b> ") + HtmlEscape(wtx.mapValue["from"]) + "<br>";
119 // Offline transaction
123 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
127 vector<unsigned char> vchPubKey;
128 if (ExtractPubKey(txout.scriptPubKey, true, vchPubKey))
130 string strAddress = PubKeyToAddress(vchPubKey);
131 if (mapAddressBook.count(strAddress))
133 strHTML += string() + _("<b>From:</b> ") + _("unknown") + "<br>";
134 strHTML += _("<b>To:</b> ");
135 strHTML += HtmlEscape(strAddress);
136 if (!mapAddressBook[strAddress].empty())
137 strHTML += _(" (yours, label: ") + mapAddressBook[strAddress] + ")";
139 strHTML += _(" (yours)");
154 if (!wtx.mapValue["to"].empty())
156 // Online transaction
157 strAddress = wtx.mapValue["to"];
158 strHTML += _("<b>To:</b> ");
159 if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty())
160 strHTML += mapAddressBook[strAddress] + " ";
161 strHTML += HtmlEscape(strAddress) + "<br>";
168 if (wtx.IsCoinBase() && nCredit == 0)
173 int64 nUnmatured = 0;
174 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
175 nUnmatured += txout.GetCredit();
176 strHTML += _("<b>Credit:</b> ");
177 if (wtx.IsInMainChain())
178 strHTML += strprintf(_("(%s matures in %d more blocks)"), FormatMoney(nUnmatured).c_str(), wtx.GetBlocksToMaturity());
180 strHTML += _("(not accepted)");
188 strHTML += _("<b>Credit:</b> ") + FormatMoney(nNet) + "<br>";
192 bool fAllFromMe = true;
193 BOOST_FOREACH(const CTxIn& txin, wtx.vin)
194 fAllFromMe = fAllFromMe && txin.IsMine();
196 bool fAllToMe = true;
197 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
198 fAllToMe = fAllToMe && txout.IsMine();
205 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
210 if (wtx.mapValue["to"].empty())
212 // Offline transaction
214 if (ExtractHash160(txout.scriptPubKey, hash160))
216 string strAddress = Hash160ToAddress(hash160);
217 strHTML += _("<b>To:</b> ");
218 if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty())
219 strHTML += mapAddressBook[strAddress] + " ";
220 strHTML += strAddress;
225 strHTML += _("<b>Debit:</b> ") + FormatMoney(-txout.nValue) + "<br>";
231 int64 nChange = wtx.GetChange();
232 int64 nValue = nCredit - nChange;
233 strHTML += _("<b>Debit:</b> ") + FormatMoney(-nValue) + "<br>";
234 strHTML += _("<b>Credit:</b> ") + FormatMoney(nValue) + "<br>";
237 int64 nTxFee = nDebit - wtx.GetValueOut();
239 strHTML += _("<b>Transaction fee:</b> ") + FormatMoney(-nTxFee) + "<br>";
244 // Mixed debit transaction
246 BOOST_FOREACH(const CTxIn& txin, wtx.vin)
248 strHTML += _("<b>Debit:</b> ") + FormatMoney(-txin.GetDebit()) + "<br>";
249 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
251 strHTML += _("<b>Credit:</b> ") + FormatMoney(txout.GetCredit()) + "<br>";
255 strHTML += _("<b>Net amount:</b> ") + FormatMoney(nNet, true) + "<br>";
261 if (!wtx.mapValue["message"].empty())
262 strHTML += string() + "<br><b>" + _("Message:") + "</b><br>" + HtmlEscape(wtx.mapValue["message"], true) + "<br>";
263 if (!wtx.mapValue["comment"].empty())
264 strHTML += string() + "<br><b>" + _("Comment:") + "</b><br>" + HtmlEscape(wtx.mapValue["comment"], true) + "<br>";
266 if (wtx.IsCoinBase())
267 strHTML += string() + "<br>" + _("Generated coins must wait 120 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>";
275 strHTML += "<hr><br>debug print<br><br>";
276 BOOST_FOREACH(const CTxIn& txin, wtx.vin)
278 strHTML += "<b>Debit:</b> " + FormatMoney(-txin.GetDebit()) + "<br>";
279 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
281 strHTML += "<b>Credit:</b> " + FormatMoney(txout.GetCredit()) + "<br>";
283 strHTML += "<br><b>Transaction:</b><br>";
284 strHTML += HtmlEscape(wtx.ToString(), true);
286 strHTML += "<br><b>Inputs:</b><br>";
287 CRITICAL_BLOCK(cs_mapWallet)
289 BOOST_FOREACH(const CTxIn& txin, wtx.vin)
291 COutPoint prevout = txin.prevout;
292 map<uint256, CWalletTx>::iterator mi = mapWallet.find(prevout.hash);
293 if (mi != mapWallet.end())
295 const CWalletTx& prev = (*mi).second;
296 if (prevout.n < prev.vout.size())
298 strHTML += HtmlEscape(prev.ToString(), true);
299 strHTML += " " + FormatTxStatus(prev) + ", ";
300 strHTML = strHTML + "IsMine=" + (prev.vout[prevout.n].IsMine() ? "true" : "false") + "<br>";
309 strHTML += "</font></html>";