BSHA3  0.17.99
P2P Blockchain, based on Bitcoin
transactiondesc.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2018 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #ifdef HAVE_CONFIG_H
7 #endif
8 
9 #include <qt/transactiondesc.h>
10 
11 #include <qt/bitcoinunits.h>
12 #include <qt/guiutil.h>
13 #include <qt/paymentserver.h>
14 #include <qt/transactionrecord.h>
15 
16 #include <consensus/consensus.h>
17 #include <interfaces/node.h>
18 #include <key_io.h>
19 #include <validation.h>
20 #include <script/script.h>
21 #include <timedata.h>
22 #include <util.h>
23 #include <wallet/db.h>
24 #include <wallet/wallet.h>
25 #include <policy/policy.h>
26 
27 #include <stdint.h>
28 #include <string>
29 
30 QString TransactionDesc::FormatTxStatus(const interfaces::WalletTx& wtx, const interfaces::WalletTxStatus& status, bool inMempool, int numBlocks, int64_t adjustedTime)
31 {
32  if (!status.is_final)
33  {
34  if (wtx.tx->nLockTime < LOCKTIME_THRESHOLD)
35  return tr("Open for %n more block(s)", "", wtx.tx->nLockTime - numBlocks);
36  else
37  return tr("Open until %1").arg(GUIUtil::dateTimeStr(wtx.tx->nLockTime));
38  }
39  else
40  {
41  int nDepth = status.depth_in_main_chain;
42  if (nDepth < 0)
43  return tr("conflicted with a transaction with %1 confirmations").arg(-nDepth);
44  else if (nDepth == 0)
45  return tr("0/unconfirmed, %1").arg((inMempool ? tr("in memory pool") : tr("not in memory pool"))) + (status.is_abandoned ? ", "+tr("abandoned") : "");
46  else if (nDepth < 6)
47  return tr("%1/unconfirmed").arg(nDepth);
48  else
49  return tr("%1 confirmations").arg(nDepth);
50  }
51 }
52 
54 {
55  int numBlocks;
56  int64_t adjustedTime;
59  bool inMempool;
60  interfaces::WalletTx wtx = wallet.getWalletTxDetails(rec->hash, status, orderForm, inMempool, numBlocks, adjustedTime);
61 
62  QString strHTML;
63 
64  strHTML.reserve(4000);
65  strHTML += "<html><font face='verdana, arial, helvetica, sans-serif'>";
66 
67  int64_t nTime = wtx.time;
68  CAmount nCredit = wtx.credit;
69  CAmount nDebit = wtx.debit;
70  CAmount nNet = nCredit - nDebit;
71 
72  strHTML += "<b>" + tr("Status") + ":</b> " + FormatTxStatus(wtx, status, inMempool, numBlocks, adjustedTime);
73  strHTML += "<br>";
74 
75  strHTML += "<b>" + tr("Date") + ":</b> " + (nTime ? GUIUtil::dateTimeStr(nTime) : "") + "<br>";
76 
77  //
78  // From
79  //
80  if (wtx.is_coinbase)
81  {
82  strHTML += "<b>" + tr("Source") + ":</b> " + tr("Generated") + "<br>";
83  }
84  else if (wtx.value_map.count("from") && !wtx.value_map["from"].empty())
85  {
86  // Online transaction
87  strHTML += "<b>" + tr("From") + ":</b> " + GUIUtil::HtmlEscape(wtx.value_map["from"]) + "<br>";
88  }
89  else
90  {
91  // Offline transaction
92  if (nNet > 0)
93  {
94  // Credit
96  if (IsValidDestination(address)) {
97  std::string name;
98  isminetype ismine;
99  if (wallet.getAddress(address, &name, &ismine, /* purpose= */ nullptr))
100  {
101  strHTML += "<b>" + tr("From") + ":</b> " + tr("unknown") + "<br>";
102  strHTML += "<b>" + tr("To") + ":</b> ";
103  strHTML += GUIUtil::HtmlEscape(rec->address);
104  QString addressOwned = ismine == ISMINE_SPENDABLE ? tr("own address") : tr("watch-only");
105  if (!name.empty())
106  strHTML += " (" + addressOwned + ", " + tr("label") + ": " + GUIUtil::HtmlEscape(name) + ")";
107  else
108  strHTML += " (" + addressOwned + ")";
109  strHTML += "<br>";
110  }
111  }
112  }
113  }
114 
115  //
116  // To
117  //
118  if (wtx.value_map.count("to") && !wtx.value_map["to"].empty())
119  {
120  // Online transaction
121  std::string strAddress = wtx.value_map["to"];
122  strHTML += "<b>" + tr("To") + ":</b> ";
123  CTxDestination dest = DecodeDestination(strAddress);
124  std::string name;
125  if (wallet.getAddress(
126  dest, &name, /* is_mine= */ nullptr, /* purpose= */ nullptr) && !name.empty())
127  strHTML += GUIUtil::HtmlEscape(name) + " ";
128  strHTML += GUIUtil::HtmlEscape(strAddress) + "<br>";
129  }
130 
131  //
132  // Amount
133  //
134  if (wtx.is_coinbase && nCredit == 0)
135  {
136  //
137  // Coinbase
138  //
139  CAmount nUnmatured = 0;
140  for (const CTxOut& txout : wtx.tx->vout)
141  nUnmatured += wallet.getCredit(txout, ISMINE_ALL);
142  strHTML += "<b>" + tr("Credit") + ":</b> ";
143  if (status.is_in_main_chain)
144  strHTML += BitcoinUnits::formatHtmlWithUnit(unit, nUnmatured)+ " (" + tr("matures in %n more block(s)", "", status.blocks_to_maturity) + ")";
145  else
146  strHTML += "(" + tr("not accepted") + ")";
147  strHTML += "<br>";
148  }
149  else if (nNet > 0)
150  {
151  //
152  // Credit
153  //
154  strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, nNet) + "<br>";
155  }
156  else
157  {
158  isminetype fAllFromMe = ISMINE_SPENDABLE;
159  for (const isminetype mine : wtx.txin_is_mine)
160  {
161  if(fAllFromMe > mine) fAllFromMe = mine;
162  }
163 
164  isminetype fAllToMe = ISMINE_SPENDABLE;
165  for (const isminetype mine : wtx.txout_is_mine)
166  {
167  if(fAllToMe > mine) fAllToMe = mine;
168  }
169 
170  if (fAllFromMe)
171  {
172  if(fAllFromMe & ISMINE_WATCH_ONLY)
173  strHTML += "<b>" + tr("From") + ":</b> " + tr("watch-only") + "<br>";
174 
175  //
176  // Debit
177  //
178  auto mine = wtx.txout_is_mine.begin();
179  for (const CTxOut& txout : wtx.tx->vout)
180  {
181  // Ignore change
182  isminetype toSelf = *(mine++);
183  if ((toSelf == ISMINE_SPENDABLE) && (fAllFromMe == ISMINE_SPENDABLE))
184  continue;
185 
186  if (!wtx.value_map.count("to") || wtx.value_map["to"].empty())
187  {
188  // Offline transaction
189  CTxDestination address;
190  if (ExtractDestination(txout.scriptPubKey, address))
191  {
192  strHTML += "<b>" + tr("To") + ":</b> ";
193  std::string name;
194  if (wallet.getAddress(
195  address, &name, /* is_mine= */ nullptr, /* purpose= */ nullptr) && !name.empty())
196  strHTML += GUIUtil::HtmlEscape(name) + " ";
197  strHTML += GUIUtil::HtmlEscape(EncodeDestination(address));
198  if(toSelf == ISMINE_SPENDABLE)
199  strHTML += " (own address)";
200  else if(toSelf & ISMINE_WATCH_ONLY)
201  strHTML += " (watch-only)";
202  strHTML += "<br>";
203  }
204  }
205 
206  strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -txout.nValue) + "<br>";
207  if(toSelf)
208  strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, txout.nValue) + "<br>";
209  }
210 
211  if (fAllToMe)
212  {
213  // Payment to self
214  CAmount nChange = wtx.change;
215  CAmount nValue = nCredit - nChange;
216  strHTML += "<b>" + tr("Total debit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -nValue) + "<br>";
217  strHTML += "<b>" + tr("Total credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, nValue) + "<br>";
218  }
219 
220  CAmount nTxFee = nDebit - wtx.tx->GetValueOut();
221  if (nTxFee > 0)
222  strHTML += "<b>" + tr("Transaction fee") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -nTxFee) + "<br>";
223  }
224  else
225  {
226  //
227  // Mixed debit transaction
228  //
229  auto mine = wtx.txin_is_mine.begin();
230  for (const CTxIn& txin : wtx.tx->vin) {
231  if (*(mine++)) {
232  strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -wallet.getDebit(txin, ISMINE_ALL)) + "<br>";
233  }
234  }
235  mine = wtx.txout_is_mine.begin();
236  for (const CTxOut& txout : wtx.tx->vout) {
237  if (*(mine++)) {
238  strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, wallet.getCredit(txout, ISMINE_ALL)) + "<br>";
239  }
240  }
241  }
242  }
243 
244  strHTML += "<b>" + tr("Net amount") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, nNet, true) + "<br>";
245 
246  //
247  // Message
248  //
249  if (wtx.value_map.count("message") && !wtx.value_map["message"].empty())
250  strHTML += "<br><b>" + tr("Message") + ":</b><br>" + GUIUtil::HtmlEscape(wtx.value_map["message"], true) + "<br>";
251  if (wtx.value_map.count("comment") && !wtx.value_map["comment"].empty())
252  strHTML += "<br><b>" + tr("Comment") + ":</b><br>" + GUIUtil::HtmlEscape(wtx.value_map["comment"], true) + "<br>";
253 
254  strHTML += "<b>" + tr("Transaction ID") + ":</b> " + rec->getTxHash() + "<br>";
255  strHTML += "<b>" + tr("Transaction total size") + ":</b> " + QString::number(wtx.tx->GetTotalSize()) + " bytes<br>";
256  strHTML += "<b>" + tr("Transaction virtual size") + ":</b> " + QString::number(GetVirtualTransactionSize(*wtx.tx)) + " bytes<br>";
257  strHTML += "<b>" + tr("Output index") + ":</b> " + QString::number(rec->getOutputIndex()) + "<br>";
258 
259  // Message from normal bitcoin:URI (bitcoin:123...?message=example)
260  for (const std::pair<std::string, std::string>& r : orderForm)
261  if (r.first == "Message")
262  strHTML += "<br><b>" + tr("Message") + ":</b><br>" + GUIUtil::HtmlEscape(r.second, true) + "<br>";
263 
264 #ifdef ENABLE_BIP70
265  //
266  // PaymentRequest info:
267  //
268  for (const std::pair<std::string, std::string>& r : orderForm)
269  {
270  if (r.first == "PaymentRequest")
271  {
272  PaymentRequestPlus req;
273  req.parse(QByteArray::fromRawData(r.second.data(), r.second.size()));
274  QString merchant;
275  if (req.getMerchant(PaymentServer::getCertStore(), merchant))
276  strHTML += "<b>" + tr("Merchant") + ":</b> " + GUIUtil::HtmlEscape(merchant) + "<br>";
277  }
278  }
279 #endif
280 
281  if (wtx.is_coinbase)
282  {
283  quint32 numBlocksToMaturity = COINBASE_MATURITY + 1;
284  strHTML += "<br>" + tr("Generated coins must mature %1 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.").arg(QString::number(numBlocksToMaturity)) + "<br>";
285  }
286 
287  //
288  // Debug view
289  //
290  if (node.getLogCategories() != BCLog::NONE)
291  {
292  strHTML += "<hr><br>" + tr("Debug information") + "<br><br>";
293  for (const CTxIn& txin : wtx.tx->vin)
294  if(wallet.txinIsMine(txin))
295  strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -wallet.getDebit(txin, ISMINE_ALL)) + "<br>";
296  for (const CTxOut& txout : wtx.tx->vout)
297  if(wallet.txoutIsMine(txout))
298  strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, wallet.getCredit(txout, ISMINE_ALL)) + "<br>";
299 
300  strHTML += "<br><b>" + tr("Transaction") + ":</b><br>";
301  strHTML += GUIUtil::HtmlEscape(wtx.tx->ToString(), true);
302 
303  strHTML += "<br><b>" + tr("Inputs") + ":</b>";
304  strHTML += "<ul>";
305 
306  for (const CTxIn& txin : wtx.tx->vin)
307  {
308  COutPoint prevout = txin.prevout;
309 
310  Coin prev;
311  if(node.getUnspentOutput(prevout, prev))
312  {
313  {
314  strHTML += "<li>";
315  const CTxOut &vout = prev.out;
316  CTxDestination address;
317  if (ExtractDestination(vout.scriptPubKey, address))
318  {
319  std::string name;
320  if (wallet.getAddress(address, &name, /* is_mine= */ nullptr, /* purpose= */ nullptr) && !name.empty())
321  strHTML += GUIUtil::HtmlEscape(name) + " ";
322  strHTML += QString::fromStdString(EncodeDestination(address));
323  }
324  strHTML = strHTML + " " + tr("Amount") + "=" + BitcoinUnits::formatHtmlWithUnit(unit, vout.nValue);
325  strHTML = strHTML + " IsMine=" + (wallet.txoutIsMine(vout) & ISMINE_SPENDABLE ? tr("true") : tr("false")) + "</li>";
326  strHTML = strHTML + " IsWatchOnly=" + (wallet.txoutIsMine(vout) & ISMINE_WATCH_ONLY ? tr("true") : tr("false")) + "</li>";
327  }
328  }
329  }
330 
331  strHTML += "</ul>";
332  }
333 
334  strHTML += "</font></html>";
335  return strHTML;
336 }
CAmount nValue
Definition: transaction.h:134
int64_t GetVirtualTransactionSize(int64_t nWeight, int64_t nSigOpCost)
Compute the virtual transaction size (weight reinterpreted as bytes).
Definition: policy.cpp:246
virtual bool getAddress(const CTxDestination &dest, std::string *name, isminetype *is_mine, std::string *purpose)=0
Look up address in wallet, return whether exists.
bool ExtractDestination(const CScript &scriptPubKey, CTxDestination &addressRet)
Parse a standard scriptPubKey for the destination address.
Definition: standard.cpp:155
CScript scriptPubKey
Definition: transaction.h:135
A UTXO entry.
Definition: coins.h:29
virtual isminetype txoutIsMine(const CTxOut &txout)=0
Return whether transaction output belongs to wallet.
QString getTxHash() const
Return the unique identifier for this transaction (part)
std::vector< isminetype > txin_is_mine
Definition: wallet.h:333
std::vector< isminetype > txout_is_mine
Definition: wallet.h:334
static QString formatHtmlWithUnit(int unit, const CAmount &amount, bool plussign=false, SeparatorStyle separators=separatorStandard)
Format as HTML string (with unit)
bool IsValidDestination(const CTxDestination &dest)
Check whether a CTxDestination is a CNoDestination.
Definition: standard.cpp:324
CTxOut out
unspent transaction output
Definition: coins.h:33
QString dateTimeStr(const QDateTime &date)
Definition: guiutil.cpp:65
virtual uint32_t getLogCategories()=0
static QString toHTML(interfaces::Node &node, interfaces::Wallet &wallet, TransactionRecord *rec, int unit)
QString HtmlEscape(const QString &str, bool fMultiLine)
Definition: guiutil.cpp:216
CTransactionRef tx
Definition: wallet.h:332
virtual isminetype txinIsMine(const CTxIn &txin)=0
Return whether transaction input belongs to wallet.
int64_t CAmount
Amount in satoshis (Can be negative)
Definition: amount.h:12
int getOutputIndex() const
Return the output index of the subtransaction.
UI model for a transaction.
virtual CAmount getCredit(const CTxOut &txout, isminefilter filter)=0
Return credit amount if transaction input belongs to wallet.
bool getMerchant(X509_STORE *certStore, QString &merchant) const
isminetype
IsMine() return codes.
Definition: ismine.h:17
An input of a transaction.
Definition: transaction.h:61
boost::variant< CNoDestination, CKeyID, CScriptID, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessUnknown > CTxDestination
A txout script template with a specific destination.
Definition: standard.h:123
const char * name
Definition: rest.cpp:37
static QString FormatTxStatus(const interfaces::WalletTx &wtx, const interfaces::WalletTxStatus &status, bool inMempool, int numBlocks, int64_t adjustedTime)
Interface for accessing a wallet.
Definition: wallet.h:46
An output of a transaction.
Definition: transaction.h:131
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:18
bool parse(const QByteArray &data)
virtual CAmount getDebit(const CTxIn &txin, isminefilter filter)=0
Return debit amount if transaction input belongs to wallet.
CTxDestination DecodeDestination(const std::string &str)
Definition: key_io.cpp:214
virtual WalletTx getWalletTxDetails(const uint256 &txid, WalletTxStatus &tx_status, WalletOrderForm &order_form, bool &in_mempool, int &num_blocks, int64_t &adjusted_time)=0
Get transaction details.
std::vector< std::pair< std::string, std::string > > WalletOrderForm
Definition: wallet.h:42
std::string EncodeDestination(const CTxDestination &dest)
Definition: key_io.cpp:209
std::map< std::string, std::string > value_map
Definition: wallet.h:341
COutPoint prevout
Definition: transaction.h:64
Top-level interface for a bitcoin node (bsha3d process).
Definition: node.h:35
Updated transaction status.
Definition: wallet.h:346
virtual bool getUnspentOutput(const COutPoint &output, Coin &coin)=0
Get unspent outputs associated with a transaction.