1 #include "transactiondesc.h"
3 #include "bitcoinunits.h"
6 #include "txdb-leveldb.h"
13 QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx)
17 if (wtx.nLockTime < LOCKTIME_THRESHOLD)
18 return tr("Open for %n block(s)", "", nBestHeight - wtx.nLockTime);
20 return tr("Open until %1").arg(GUIUtil::dateTimeStr(wtx.nLockTime));
24 int nDepth = wtx.GetDepthInMainChain();
25 if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
26 return tr("%1/offline").arg(nDepth);
28 return tr("%1/unconfirmed").arg(nDepth);
30 return tr("%1 confirmations").arg(nDepth);
34 QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx)
39 LOCK(wallet->cs_wallet);
40 strHTML.reserve(4000);
41 strHTML += "<html><font face='verdana, arial, helvetica, sans-serif'>";
43 int64_t nTime = wtx.GetTxTime();
44 int64_t nCredit = wtx.GetCredit(MINE_ALL);
45 int64_t nDebit = wtx.GetDebit(MINE_ALL);
46 int64_t nNet = nCredit - nDebit;
48 strHTML += "<b>" + tr("Status") + ":</b> " + FormatTxStatus(wtx);
49 int nRequests = wtx.GetRequestCount();
53 strHTML += tr(", has not been successfully broadcast yet");
54 else if (nRequests > 0)
55 strHTML += tr(", broadcast through %n node(s)", "", nRequests);
59 strHTML += "<b>" + tr("Date") + ":</b> " + (nTime ? GUIUtil::dateTimeStr(nTime) : "") + "<br>";
64 if (wtx.IsCoinBase() || wtx.IsCoinStake())
66 strHTML += "<b>" + tr("Source") + ":</b> " + tr("Generated") + "<br>";
68 else if (wtx.mapValue.count("from") && !wtx.mapValue["from"].empty())
71 strHTML += "<b>" + tr("From") + ":</b> " + GUIUtil::HtmlEscape(wtx.mapValue["from"]) + "<br>";
75 // Offline transaction
79 for (const CTxOut& txout : wtx.vout)
81 if (wallet->IsMine(txout))
83 CTxDestination address;
84 if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address))
86 if (wallet->mapAddressBook.count(address))
88 std::vector<CTxDestination> addedAddresses;
89 for (unsigned int i = 0; i < wtx.vin.size(); i++)
92 const CTxIn& vin = wtx.vin[i];
93 hash.SetHex(vin.prevout.hash.ToString());
95 uint256 hashBlock = 0;
96 if (!GetTransaction(hash, wtxPrev, hashBlock))
98 strHTML += "<b>" + tr("From") + ":</b> " + tr("unknown") + "<br>";
101 CTxDestination senderAddress;
102 if (!ExtractDestination(wtxPrev.vout[vin.prevout.n].scriptPubKey, senderAddress) )
104 strHTML += "<b>" + tr("From") + ":</b> " + tr("unknown") + "<br>";
106 else if(std::find(addedAddresses.begin(), addedAddresses.end(), senderAddress)
107 == addedAddresses.end() )
109 addedAddresses.push_back(senderAddress);
110 strHTML += "<b>" + tr("From") + ":</b> ";
111 strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(senderAddress).ToString());
112 if(wallet->mapAddressBook.find(senderAddress) != wallet->mapAddressBook.end())
113 if (!wallet->mapAddressBook[senderAddress].empty())
115 strHTML += " (" + tr("label") + ": " + GUIUtil::HtmlEscape(wallet->mapAddressBook[senderAddress]) + ")";
120 strHTML += "<b>" + tr("To") + ":</b> ";
121 strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address).ToString());
122 if (!wallet->mapAddressBook[address].empty())
123 strHTML += " (" + tr("own address") + ", " + tr("label") + ": " + GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + ")";
125 strHTML += " (" + tr("own address") + ")";
138 if (wtx.mapValue.count("to") && !wtx.mapValue["to"].empty())
140 // Online transaction
141 std::string strAddress = wtx.mapValue["to"];
142 strHTML += "<b>" + tr("To") + ":</b> ";
143 CBitcoinAddress addr(strAddress);
144 if (wallet->mapAddressBook.count(addr) && !wallet->mapAddressBook[addr].empty())
145 strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[addr]) + " ";
146 strHTML += GUIUtil::HtmlEscape(strAddress) + "<br>";
152 if (wtx.IsCoinBase() && nCredit == 0)
157 int64_t nUnmatured = 0;
158 for (const CTxOut& txout : wtx.vout)
159 nUnmatured += wallet->GetCredit(txout, MINE_ALL);
160 strHTML += "<b>" + tr("Credit") + ":</b> ";
161 if (wtx.IsInMainChain())
162 strHTML += BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nUnmatured)+ " (" + tr("matures in %n more block(s)", "", wtx.GetBlocksToMaturity()) + ")";
164 strHTML += "(" + tr("not accepted") + ")";
172 strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nNet) + "<br>";
176 bool fAllFromMe = true;
177 for (const CTxIn& txin : wtx.vin)
178 fAllFromMe = fAllFromMe && wallet->IsMine(txin);
180 bool fAllToMe = true;
181 for (const CTxOut& txout : wtx.vout)
182 fAllToMe = fAllToMe && wallet->IsMine(txout);
189 for (const CTxOut& txout : wtx.vout)
191 if (wallet->IsMine(txout))
194 if (!wtx.mapValue.count("to") || wtx.mapValue["to"].empty())
196 // Offline transaction
197 CTxDestination address;
198 if (ExtractDestination(txout.scriptPubKey, address))
200 strHTML += "<b>" + tr("To") + ":</b> ";
201 if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].empty())
202 strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + " ";
203 strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address).ToString());
208 strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -txout.nValue) + "<br>";
214 int64_t nChange = wtx.GetChange();
215 int64_t nValue = nCredit - nChange;
216 strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -nValue) + "<br>";
217 strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nValue) + "<br>";
220 int64_t nTxFee = nDebit - wtx.GetValueOut();
222 strHTML += "<b>" + tr("Transaction fee") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -nTxFee) + "<br>";
227 // Mixed debit transaction
229 for (const CTxIn& txin : wtx.vin)
230 if (wallet->IsMine(txin))
231 strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -wallet->GetDebit(txin, MINE_ALL)) + "<br>";
232 for (const CTxOut& txout : wtx.vout)
233 if (wallet->IsMine(txout))
234 strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, wallet->GetCredit(txout, MINE_ALL)) + "<br>";
238 strHTML += "<b>" + tr("Net amount") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nNet, true) + "<br>";
243 if (wtx.mapValue.count("message") && !wtx.mapValue["message"].empty())
244 strHTML += "<br><b>" + tr("Message") + ":</b><br>" + GUIUtil::HtmlEscape(wtx.mapValue["message"], true) + "<br>";
245 if (wtx.mapValue.count("comment") && !wtx.mapValue["comment"].empty())
246 strHTML += "<br><b>" + tr("Comment") + ":</b><br>" + GUIUtil::HtmlEscape(wtx.mapValue["comment"], true) + "<br>";
248 strHTML += "<b>" + tr("Transaction ID") + ":</b> " + wtx.GetHash().ToString().c_str() + "<br>";
250 if (wtx.IsCoinBase() || wtx.IsCoinStake())
251 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>";
258 strHTML += "<hr><br>" + tr("Debug information") + "<br><br>";
259 for (const CTxIn& txin : wtx.vin)
260 if(wallet->IsMine(txin))
261 strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -wallet->GetDebit(txin, MINE_ALL)) + "<br>";
262 for (const CTxOut& txout : wtx.vout)
263 if(wallet->IsMine(txout))
264 strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, wallet->GetCredit(txout, MINE_ALL)) + "<br>";
266 strHTML += "<br><b>" + tr("Transaction") + ":</b><br>";
267 strHTML += GUIUtil::HtmlEscape(wtx.ToString(), true);
269 CTxDB txdb("r"); // To fetch source txouts
271 strHTML += "<br><b>" + tr("Inputs") + ":</b>";
275 LOCK(wallet->cs_wallet);
276 for (const CTxIn& txin : wtx.vin)
278 COutPoint prevout = txin.prevout;
281 if(txdb.ReadDiskTx(prevout.hash, prev))
283 if (prevout.n < prev.vout.size())
286 const CTxOut &vout = prev.vout[prevout.n];
287 CTxDestination address;
288 if (ExtractDestination(vout.scriptPubKey, address))
290 if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].empty())
291 strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + " ";
292 strHTML += QString::fromStdString(CBitcoinAddress(address).ToString());
294 strHTML = strHTML + " " + tr("Amount") + "=" + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, vout.nValue);
295 strHTML = strHTML + " IsMine=" + (wallet->IsMine(vout) ? tr("true") : tr("false")) + "</li>";
304 strHTML += "</font></html>";