1 #include "transactiondesc.h"
4 #include "bitcoinunits.h"
10 #include "ui_interface.h"
16 QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx)
20 if (wtx.nLockTime < LOCKTIME_THRESHOLD)
21 return tr("Open for %n block(s)", "", nBestHeight - wtx.nLockTime);
23 return tr("Open until %1").arg(GUIUtil::dateTimeStr(wtx.nLockTime));
27 int nDepth = wtx.GetDepthInMainChain();
28 if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
29 return tr("%1/offline").arg(nDepth);
31 return tr("%1/unconfirmed").arg(nDepth);
33 return tr("%1 confirmations").arg(nDepth);
37 QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx)
42 LOCK(wallet->cs_wallet);
43 strHTML.reserve(4000);
44 strHTML += "<html><font face='verdana, arial, helvetica, sans-serif'>";
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;
51 strHTML += "<b>" + tr("Status") + ":</b> " + FormatTxStatus(wtx);
52 int nRequests = wtx.GetRequestCount();
56 strHTML += tr(", has not been successfully broadcast yet");
57 else if (nRequests > 0)
58 strHTML += tr(", broadcast through %n node(s)", "", nRequests);
62 strHTML += "<b>" + tr("Date") + ":</b> " + (nTime ? GUIUtil::dateTimeStr(nTime) : "") + "<br>";
67 if (wtx.IsCoinBase() || wtx.IsCoinStake())
69 strHTML += "<b>" + tr("Source") + ":</b> " + tr("Generated") + "<br>";
71 else if (wtx.mapValue.count("from") && !wtx.mapValue["from"].empty())
74 strHTML += "<b>" + tr("From") + ":</b> " + GUIUtil::HtmlEscape(wtx.mapValue["from"]) + "<br>";
78 // Offline transaction
82 for(const CTxOut& txout : wtx.vout)
84 if (wallet->IsMine(txout))
86 CTxDestination address;
87 if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address))
89 if (wallet->mapAddressBook.count(address))
91 std::vector<CTxDestination> addedAddresses;
92 for (unsigned int i = 0; i < wtx.vin.size(); i++)
95 const CTxIn& vin = wtx.vin[i];
96 hash.SetHex(vin.prevout.hash.ToString());
98 uint256 hashBlock = 0;
99 if (!GetTransaction(hash, wtxPrev, hashBlock))
101 strHTML += "<b>" + tr("From") + ":</b> " + tr("unknown") + "<br>";
104 CTxDestination senderAddress;
105 if (!ExtractDestination(wtxPrev.vout[vin.prevout.n].scriptPubKey, senderAddress) )
107 strHTML += "<b>" + tr("From") + ":</b> " + tr("unknown") + "<br>";
109 else if(std::find(addedAddresses.begin(), addedAddresses.end(), senderAddress)
110 == addedAddresses.end() )
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())
118 strHTML += " (" + tr("label") + ": " + GUIUtil::HtmlEscape(wallet->mapAddressBook[senderAddress]) + ")";
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]) + ")";
128 strHTML += " (" + tr("own address") + ")";
141 if (wtx.mapValue.count("to") && !wtx.mapValue["to"].empty())
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>";
155 if (wtx.IsCoinBase() && nCredit == 0)
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()) + ")";
167 strHTML += "(" + tr("not accepted") + ")";
175 strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nNet) + "<br>";
179 bool fAllFromMe = true;
180 for(const CTxIn& txin : wtx.vin)
181 fAllFromMe = fAllFromMe && wallet->IsMine(txin);
183 bool fAllToMe = true;
184 for(const CTxOut& txout : wtx.vout)
185 fAllToMe = fAllToMe && wallet->IsMine(txout);
192 for(const CTxOut& txout : wtx.vout)
194 if (wallet->IsMine(txout))
197 if (!wtx.mapValue.count("to") || wtx.mapValue["to"].empty())
199 // Offline transaction
200 CTxDestination address;
201 if (ExtractDestination(txout.scriptPubKey, address))
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());
211 strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -txout.nValue) + "<br>";
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>";
223 int64_t nTxFee = nDebit - wtx.GetValueOut();
225 strHTML += "<b>" + tr("Transaction fee") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -nTxFee) + "<br>";
230 // Mixed debit transaction
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>";
241 strHTML += "<b>" + tr("Net amount") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nNet, true) + "<br>";
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>";
251 strHTML += "<b>" + tr("Transaction ID") + ":</b> " + wtx.GetHash().ToString().c_str() + "<br>";
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>";
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>";
269 strHTML += "<br><b>" + tr("Transaction") + ":</b><br>";
270 strHTML += GUIUtil::HtmlEscape(wtx.ToString(), true);
272 CTxDB txdb("r"); // To fetch source txouts
274 strHTML += "<br><b>" + tr("Inputs") + ":</b>";
278 LOCK(wallet->cs_wallet);
279 for(const CTxIn& txin : wtx.vin)
281 COutPoint prevout = txin.prevout;
284 if(txdb.ReadDiskTx(prevout.hash, prev))
286 if (prevout.n < prev.vout.size())
289 const CTxOut &vout = prev.vout[prevout.n];
290 CTxDestination address;
291 if (ExtractDestination(vout.scriptPubKey, address))
293 if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].empty())
294 strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + " ";
295 strHTML += QString::fromStdString(CBitcoinAddress(address).ToString());
297 strHTML = strHTML + " " + tr("Amount") + "=" + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, vout.nValue);
298 strHTML = strHTML + " IsMine=" + (wallet->IsMine(vout) ? tr("true") : tr("false")) + "</li>";
307 strHTML += "</font></html>";