1 #include <transactiondesc.h>
4 #include "bitcoinunits.h"
11 #include <QTextDocument> // For Qt::escape
15 QString TransactionDesc::HtmlEscape(const QString& str, bool fMultiLine)
17 QString escaped = Qt::escape(str);
20 escaped = escaped.replace("\n", "<br>\n");
25 QString TransactionDesc::HtmlEscape(const std::string& str, bool fMultiLine)
27 return HtmlEscape(QString::fromStdString(str), fMultiLine);
30 QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx)
34 if (wtx.nLockTime < LOCKTIME_THRESHOLD)
35 return tr("Open for %1 blocks").arg(nBestHeight - wtx.nLockTime);
37 return tr("Open until %1").arg(GUIUtil::dateTimeStr(wtx.nLockTime));
41 int nDepth = wtx.GetDepthInMainChain();
42 if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
43 return tr("%1/offline?").arg(nDepth);
45 return tr("%1/unconfirmed").arg(nDepth);
47 return tr("%1 confirmations").arg(nDepth);
51 QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx)
54 CRITICAL_BLOCK(wallet->cs_wallet)
56 strHTML.reserve(4000);
57 strHTML += "<html><font face='verdana, arial, helvetica, sans-serif'>";
59 qint64 nTime = wtx.GetTxTime();
60 qint64 nCredit = wtx.GetCredit();
61 qint64 nDebit = wtx.GetDebit();
62 qint64 nNet = nCredit - nDebit;
64 strHTML += tr("<b>Status:</b> ") + FormatTxStatus(wtx);
65 int nRequests = wtx.GetRequestCount();
69 strHTML += tr(", has not been successfully broadcast yet");
70 else if (nRequests == 1)
71 strHTML += tr(", broadcast through %1 node").arg(nRequests);
73 strHTML += tr(", broadcast through %1 nodes").arg(nRequests);
77 strHTML += tr("<b>Date:</b> ") + (nTime ? GUIUtil::dateTimeStr(nTime) : QString("")) + "<br>";
84 strHTML += tr("<b>Source:</b> Generated<br>");
86 else if (!wtx.mapValue["from"].empty())
89 if (!wtx.mapValue["from"].empty())
90 strHTML += tr("<b>From:</b> ") + HtmlEscape(wtx.mapValue["from"]) + "<br>";
94 // Offline transaction
98 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
100 if (wallet->IsMine(txout))
102 CBitcoinAddress address;
103 if (ExtractAddress(txout.scriptPubKey, wallet, address))
105 if (wallet->mapAddressBook.count(address))
107 strHTML += tr("<b>From:</b> ") + tr("unknown") + "<br>";
108 strHTML += tr("<b>To:</b> ");
109 strHTML += HtmlEscape(address.ToString());
110 if (!wallet->mapAddressBook[address].empty())
111 strHTML += tr(" (yours, label: ") + HtmlEscape(wallet->mapAddressBook[address]) + ")";
113 strHTML += tr(" (yours)");
127 if (!wtx.mapValue["to"].empty())
129 // Online transaction
130 strAddress = wtx.mapValue["to"];
131 strHTML += tr("<b>To:</b> ");
132 if (wallet->mapAddressBook.count(strAddress) && !wallet->mapAddressBook[strAddress].empty())
133 strHTML += HtmlEscape(wallet->mapAddressBook[strAddress]) + " ";
134 strHTML += HtmlEscape(strAddress) + "<br>";
140 if (wtx.IsCoinBase() && nCredit == 0)
145 qint64 nUnmatured = 0;
146 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
147 nUnmatured += wallet->GetCredit(txout);
148 strHTML += tr("<b>Credit:</b> ");
149 if (wtx.IsInMainChain())
150 strHTML += tr("(%1 matures in %2 more blocks)")
151 .arg(BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nUnmatured))
152 .arg(wtx.GetBlocksToMaturity());
154 strHTML += tr("(not accepted)");
162 strHTML += tr("<b>Credit:</b> ") + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nNet) + "<br>";
166 bool fAllFromMe = true;
167 BOOST_FOREACH(const CTxIn& txin, wtx.vin)
168 fAllFromMe = fAllFromMe && wallet->IsMine(txin);
170 bool fAllToMe = true;
171 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
172 fAllToMe = fAllToMe && wallet->IsMine(txout);
179 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
181 if (wallet->IsMine(txout))
184 if (wtx.mapValue["to"].empty())
186 // Offline transaction
187 CBitcoinAddress address;
188 if (ExtractAddress(txout.scriptPubKey, 0, address))
190 strHTML += tr("<b>To:</b> ");
191 if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].empty())
192 strHTML += HtmlEscape(wallet->mapAddressBook[address]) + " ";
193 strHTML += HtmlEscape(address.ToString());
198 strHTML += tr("<b>Debit:</b> ") + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -txout.nValue) + "<br>";
204 qint64 nChange = wtx.GetChange();
205 qint64 nValue = nCredit - nChange;
206 strHTML += tr("<b>Debit:</b> ") + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -nValue) + "<br>";
207 strHTML += tr("<b>Credit:</b> ") + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nValue) + "<br>";
210 qint64 nTxFee = nDebit - wtx.GetValueOut();
212 strHTML += tr("<b>Transaction fee:</b> ") + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC,-nTxFee) + "<br>";
217 // Mixed debit transaction
219 BOOST_FOREACH(const CTxIn& txin, wtx.vin)
220 if (wallet->IsMine(txin))
221 strHTML += tr("<b>Debit:</b> ") + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC,-wallet->GetDebit(txin)) + "<br>";
222 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
223 if (wallet->IsMine(txout))
224 strHTML += tr("<b>Credit:</b> ") + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC,wallet->GetCredit(txout)) + "<br>";
228 strHTML += tr("<b>Net amount:</b> ") + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC,nNet, true) + "<br>";
233 if (!wtx.mapValue["message"].empty())
234 strHTML += QString("<br><b>") + tr("Message:") + "</b><br>" + HtmlEscape(wtx.mapValue["message"], true) + "<br>";
235 if (!wtx.mapValue["comment"].empty())
236 strHTML += QString("<br><b>") + tr("Comment:") + "</b><br>" + HtmlEscape(wtx.mapValue["comment"], true) + "<br>";
238 if (wtx.IsCoinBase())
239 strHTML += QString("<br>") + tr("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>";
246 strHTML += "<hr><br>Debug information<br><br>";
247 BOOST_FOREACH(const CTxIn& txin, wtx.vin)
248 if(wallet->IsMine(txin))
249 strHTML += "<b>Debit:</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC,-wallet->GetDebit(txin)) + "<br>";
250 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
251 if(wallet->IsMine(txout))
252 strHTML += "<b>Credit:</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC,wallet->GetCredit(txout)) + "<br>";
254 strHTML += "<br><b>Transaction:</b><br>";
255 strHTML += HtmlEscape(wtx.ToString(), true);
257 CTxDB txdb("r"); // To fetch source txouts
259 strHTML += "<br><b>Inputs:</b>";
261 CRITICAL_BLOCK(wallet->cs_wallet)
263 BOOST_FOREACH(const CTxIn& txin, wtx.vin)
265 COutPoint prevout = txin.prevout;
268 if(txdb.ReadDiskTx(prevout.hash, prev))
270 if (prevout.n < prev.vout.size())
273 const CTxOut &vout = prev.vout[prevout.n];
274 CBitcoinAddress address;
275 if (ExtractAddress(vout.scriptPubKey, 0, address))
277 if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].empty())
278 strHTML += HtmlEscape(wallet->mapAddressBook[address]) + " ";
279 strHTML += QString::fromStdString(address.ToString());
281 strHTML = strHTML + " Amount=" + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC,vout.nValue);
282 strHTML = strHTML + " IsMine=" + (wallet->IsMine(vout) ? "true" : "false") + "</li>";
290 strHTML += "</font></html>";