1 #include "transactiondesc.h"
4 #include "bitcoinunits.h"
9 #include "ui_interface.h"
15 QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx)
19 if (wtx.nLockTime < LOCKTIME_THRESHOLD)
20 return tr("Open for %n block(s)", "", nBestHeight - wtx.nLockTime);
22 return tr("Open until %1").arg(GUIUtil::dateTimeStr(wtx.nLockTime));
26 int nDepth = wtx.GetDepthInMainChain();
27 if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
28 return tr("%1/offline").arg(nDepth);
30 return tr("%1/unconfirmed").arg(nDepth);
32 return tr("%1 confirmations").arg(nDepth);
36 QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx)
41 LOCK(wallet->cs_wallet);
42 strHTML.reserve(4000);
43 strHTML += "<html><font face='verdana, arial, helvetica, sans-serif'>";
45 int64_t nTime = wtx.GetTxTime();
46 int64_t nCredit = wtx.GetCredit(MINE_ALL);
47 int64_t nDebit = wtx.GetDebit(MINE_ALL);
48 int64_t nNet = nCredit - nDebit;
50 strHTML += "<b>" + tr("Status") + ":</b> " + FormatTxStatus(wtx);
51 int nRequests = wtx.GetRequestCount();
55 strHTML += tr(", has not been successfully broadcast yet");
56 else if (nRequests > 0)
57 strHTML += tr(", broadcast through %n node(s)", "", nRequests);
61 strHTML += "<b>" + tr("Date") + ":</b> " + (nTime ? GUIUtil::dateTimeStr(nTime) : "") + "<br>";
66 if (wtx.IsCoinBase() || wtx.IsCoinStake())
68 strHTML += "<b>" + tr("Source") + ":</b> " + tr("Generated") + "<br>";
70 else if (wtx.mapValue.count("from") && !wtx.mapValue["from"].empty())
73 strHTML += "<b>" + tr("From") + ":</b> " + GUIUtil::HtmlEscape(wtx.mapValue["from"]) + "<br>";
77 // Offline transaction
81 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
83 if (wallet->IsMine(txout))
85 CTxDestination address;
86 if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address))
88 if (wallet->mapAddressBook.count(address))
90 std::vector<CTxDestination> addedAddresses;
91 for (unsigned int i = 0; i < wtx.vin.size(); i++)
94 const CTxIn& vin = wtx.vin[i];
95 hash.SetHex(vin.prevout.hash.ToString());
97 uint256 hashBlock = 0;
98 if (!GetTransaction(hash, wtxPrev, hashBlock))
100 strHTML += "<b>" + tr("From") + ":</b> " + tr("unknown") + "<br>";
103 CTxDestination senderAddress;
104 if (!ExtractDestination(wtxPrev.vout[vin.prevout.n].scriptPubKey, senderAddress) )
106 strHTML += "<b>" + tr("From") + ":</b> " + tr("unknown") + "<br>";
108 else if(std::find(addedAddresses.begin(), addedAddresses.end(), senderAddress)
109 == addedAddresses.end() )
111 addedAddresses.push_back(senderAddress);
112 strHTML += "<b>" + tr("From") + ":</b> ";
113 strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(senderAddress).ToString());
114 if(wallet->mapAddressBook.find(senderAddress) != wallet->mapAddressBook.end())
115 if (!wallet->mapAddressBook[senderAddress].empty())
117 strHTML += " (" + tr("label") + ": " + GUIUtil::HtmlEscape(wallet->mapAddressBook[senderAddress]) + ")";
122 strHTML += "<b>" + tr("To") + ":</b> ";
123 strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address).ToString());
124 if (!wallet->mapAddressBook[address].empty())
125 strHTML += " (" + tr("own address") + ", " + tr("label") + ": " + GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + ")";
127 strHTML += " (" + tr("own address") + ")";
140 if (wtx.mapValue.count("to") && !wtx.mapValue["to"].empty())
142 // Online transaction
143 std::string strAddress = wtx.mapValue["to"];
144 strHTML += "<b>" + tr("To") + ":</b> ";
145 CTxDestination dest = CBitcoinAddress(strAddress).Get();
146 if (wallet->mapAddressBook.count(dest) && !wallet->mapAddressBook[dest].empty())
147 strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[dest]) + " ";
148 strHTML += GUIUtil::HtmlEscape(strAddress) + "<br>";
154 if (wtx.IsCoinBase() && nCredit == 0)
159 int64_t nUnmatured = 0;
160 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
161 nUnmatured += wallet->GetCredit(txout, MINE_ALL);
162 strHTML += "<b>" + tr("Credit") + ":</b> ";
163 if (wtx.IsInMainChain())
164 strHTML += BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nUnmatured)+ " (" + tr("matures in %n more block(s)", "", wtx.GetBlocksToMaturity()) + ")";
166 strHTML += "(" + tr("not accepted") + ")";
174 strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nNet) + "<br>";
178 bool fAllFromMe = true;
179 BOOST_FOREACH(const CTxIn& txin, wtx.vin)
180 fAllFromMe = fAllFromMe && wallet->IsMine(txin);
182 bool fAllToMe = true;
183 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
184 fAllToMe = fAllToMe && wallet->IsMine(txout);
191 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
193 if (wallet->IsMine(txout))
196 if (!wtx.mapValue.count("to") || wtx.mapValue["to"].empty())
198 // Offline transaction
199 CTxDestination address;
200 if (ExtractDestination(txout.scriptPubKey, address))
202 strHTML += "<b>" + tr("To") + ":</b> ";
203 if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].empty())
204 strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + " ";
205 strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address).ToString());
210 strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -txout.nValue) + "<br>";
216 int64_t nChange = wtx.GetChange();
217 int64_t nValue = nCredit - nChange;
218 strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -nValue) + "<br>";
219 strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nValue) + "<br>";
222 int64_t nTxFee = nDebit - wtx.GetValueOut();
224 strHTML += "<b>" + tr("Transaction fee") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -nTxFee) + "<br>";
229 // Mixed debit transaction
231 BOOST_FOREACH(const CTxIn& txin, wtx.vin)
232 if (wallet->IsMine(txin))
233 strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -wallet->GetDebit(txin, MINE_ALL)) + "<br>";
234 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
235 if (wallet->IsMine(txout))
236 strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, wallet->GetCredit(txout, MINE_ALL)) + "<br>";
240 strHTML += "<b>" + tr("Net amount") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nNet, true) + "<br>";
245 if (wtx.mapValue.count("message") && !wtx.mapValue["message"].empty())
246 strHTML += "<br><b>" + tr("Message") + ":</b><br>" + GUIUtil::HtmlEscape(wtx.mapValue["message"], true) + "<br>";
247 if (wtx.mapValue.count("comment") && !wtx.mapValue["comment"].empty())
248 strHTML += "<br><b>" + tr("Comment") + ":</b><br>" + GUIUtil::HtmlEscape(wtx.mapValue["comment"], true) + "<br>";
250 strHTML += "<b>" + tr("Transaction ID") + ":</b> " + wtx.GetHash().ToString().c_str() + "<br>";
252 if (wtx.IsCoinBase() || wtx.IsCoinStake())
253 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>";
260 strHTML += "<hr><br>" + tr("Debug information") + "<br><br>";
261 BOOST_FOREACH(const CTxIn& txin, wtx.vin)
262 if(wallet->IsMine(txin))
263 strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -wallet->GetDebit(txin, MINE_ALL)) + "<br>";
264 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
265 if(wallet->IsMine(txout))
266 strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, wallet->GetCredit(txout, MINE_ALL)) + "<br>";
268 strHTML += "<br><b>" + tr("Transaction") + ":</b><br>";
269 strHTML += GUIUtil::HtmlEscape(wtx.ToString(), true);
271 CTxDB txdb("r"); // To fetch source txouts
273 strHTML += "<br><b>" + tr("Inputs") + ":</b>";
277 LOCK(wallet->cs_wallet);
278 BOOST_FOREACH(const CTxIn& txin, wtx.vin)
280 COutPoint prevout = txin.prevout;
283 if(txdb.ReadDiskTx(prevout.hash, prev))
285 if (prevout.n < prev.vout.size())
288 const CTxOut &vout = prev.vout[prevout.n];
289 CTxDestination address;
290 if (ExtractDestination(vout.scriptPubKey, address))
292 if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].empty())
293 strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + " ";
294 strHTML += QString::fromStdString(CBitcoinAddress(address).ToString());
296 strHTML = strHTML + " " + tr("Amount") + "=" + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, vout.nValue);
297 strHTML = strHTML + " IsMine=" + (wallet->IsMine(vout) ? tr("true") : tr("false")) + "</li>";
306 strHTML += "</font></html>";