Dash Core  0.12.2.1
P2P Digital Currency
transactiondesc.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2015 The Bitcoin Core developers
2 // Copyright (c) 2014-2017 The Dash Core developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 
6 #include "transactiondesc.h"
7 
8 #include "bitcoinunits.h"
9 #include "guiutil.h"
10 #include "paymentserver.h"
11 #include "transactionrecord.h"
12 
13 #include "base58.h"
14 #include "consensus/consensus.h"
15 #include "validation.h"
16 #include "script/script.h"
17 #include "timedata.h"
18 #include "util.h"
19 #include "wallet/db.h"
20 #include "wallet/wallet.h"
21 
22 #include "instantx.h"
23 
24 #include <stdint.h>
25 #include <string>
26 
28 {
30  if (!CheckFinalTx(wtx))
31  {
32  if (wtx.nLockTime < LOCKTIME_THRESHOLD)
33  return tr("Open for %n more block(s)", "", wtx.nLockTime - chainActive.Height());
34  else
35  return tr("Open until %1").arg(GUIUtil::dateTimeStr(wtx.nLockTime));
36  }
37  else
38  {
39  int nDepth = wtx.GetDepthInMainChain();
40  if (nDepth < 0) return tr("conflicted");
41 
42  QString strTxStatus;
43  bool fOffline = (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60) && (wtx.GetRequestCount() == 0);
44 
45  if (fOffline) {
46  strTxStatus = tr("%1/offline").arg(nDepth);
47  } else if (nDepth == 0) {
48  strTxStatus = tr("0/unconfirmed, %1").arg((wtx.InMempool() ? tr("in memory pool") : tr("not in memory pool"))) + (wtx.isAbandoned() ? ", "+tr("abandoned") : "");
49  } else if (nDepth < 6) {
50  strTxStatus = tr("%1/unconfirmed").arg(nDepth);
51  } else {
52  strTxStatus = tr("%1 confirmations").arg(nDepth);
53  }
54 
55  if(!instantsend.HasTxLockRequest(wtx.GetHash())) return strTxStatus; // regular tx
56 
57  int nSignatures = instantsend.GetTransactionLockSignatures(wtx.GetHash());
58  int nSignaturesMax = CTxLockRequest(wtx).GetMaxSignatures();
59  // InstantSend
60  strTxStatus += " (";
62  strTxStatus += tr("verified via InstantSend");
63  } else if(!instantsend.IsTxLockCandidateTimedOut(wtx.GetHash())) {
64  strTxStatus += tr("InstantSend verification in progress - %1 of %2 signatures").arg(nSignatures).arg(nSignaturesMax);
65  } else {
66  strTxStatus += tr("InstantSend verification failed");
67  }
68  strTxStatus += ")";
69 
70  return strTxStatus;
71  }
72 }
73 
75 {
76  QString strHTML;
77 
78  LOCK2(cs_main, wallet->cs_wallet);
79  strHTML.reserve(4000);
80  strHTML += "<html><font face='verdana, arial, helvetica, sans-serif'>";
81 
82  int64_t nTime = wtx.GetTxTime();
83  CAmount nCredit = wtx.GetCredit(ISMINE_ALL);
84  CAmount nDebit = wtx.GetDebit(ISMINE_ALL);
85  CAmount nNet = nCredit - nDebit;
86 
87  strHTML += "<b>" + tr("Status") + ":</b> " + FormatTxStatus(wtx);
88  int nRequests = wtx.GetRequestCount();
89  if (nRequests != -1)
90  {
91  if (nRequests == 0)
92  strHTML += tr(", has not been successfully broadcast yet");
93  else if (nRequests > 0)
94  strHTML += tr(", broadcast through %n node(s)", "", nRequests);
95  }
96  strHTML += "<br>";
97 
98  strHTML += "<b>" + tr("Date") + ":</b> " + (nTime ? GUIUtil::dateTimeStr(nTime) : "") + "<br>";
99 
100  //
101  // From
102  //
103  if (wtx.IsCoinBase())
104  {
105  strHTML += "<b>" + tr("Source") + ":</b> " + tr("Generated") + "<br>";
106  }
107  else if (wtx.mapValue.count("from") && !wtx.mapValue["from"].empty())
108  {
109  // Online transaction
110  strHTML += "<b>" + tr("From") + ":</b> " + GUIUtil::HtmlEscape(wtx.mapValue["from"]) + "<br>";
111  }
112  else
113  {
114  // Offline transaction
115  if (nNet > 0)
116  {
117  // Credit
118  if (CBitcoinAddress(rec->address).IsValid())
119  {
120  CTxDestination address = CBitcoinAddress(rec->address).Get();
121  if (wallet->mapAddressBook.count(address))
122  {
123  strHTML += "<b>" + tr("From") + ":</b> " + tr("unknown") + "<br>";
124  strHTML += "<b>" + tr("To") + ":</b> ";
125  strHTML += GUIUtil::HtmlEscape(rec->address);
126  QString addressOwned = (::IsMine(*wallet, address) == ISMINE_SPENDABLE) ? tr("own address") : tr("watch-only");
127  if (!wallet->mapAddressBook[address].name.empty())
128  strHTML += " (" + addressOwned + ", " + tr("label") + ": " + GUIUtil::HtmlEscape(wallet->mapAddressBook[address].name) + ")";
129  else
130  strHTML += " (" + addressOwned + ")";
131  strHTML += "<br>";
132  }
133  }
134  }
135  }
136 
137  //
138  // To
139  //
140  if (wtx.mapValue.count("to") && !wtx.mapValue["to"].empty())
141  {
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].name.empty())
147  strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[dest].name) + " ";
148  strHTML += GUIUtil::HtmlEscape(strAddress) + "<br>";
149  }
150 
151  //
152  // Amount
153  //
154  if (wtx.IsCoinBase() && nCredit == 0)
155  {
156  //
157  // Coinbase
158  //
159  CAmount nUnmatured = 0;
160  BOOST_FOREACH(const CTxOut& txout, wtx.vout)
161  nUnmatured += wallet->GetCredit(txout, ISMINE_ALL);
162  strHTML += "<b>" + tr("Credit") + ":</b> ";
163  if (wtx.IsInMainChain())
164  strHTML += BitcoinUnits::formatHtmlWithUnit(unit, nUnmatured)+ " (" + tr("matures in %n more block(s)", "", wtx.GetBlocksToMaturity()) + ")";
165  else
166  strHTML += "(" + tr("not accepted") + ")";
167  strHTML += "<br>";
168  }
169  else if (nNet > 0)
170  {
171  //
172  // Credit
173  //
174  strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, nNet) + "<br>";
175  }
176  else
177  {
178  isminetype fAllFromMe = ISMINE_SPENDABLE;
179  BOOST_FOREACH(const CTxIn& txin, wtx.vin)
180  {
181  isminetype mine = wallet->IsMine(txin);
182  if(fAllFromMe > mine) fAllFromMe = mine;
183  }
184 
185  isminetype fAllToMe = ISMINE_SPENDABLE;
186  BOOST_FOREACH(const CTxOut& txout, wtx.vout)
187  {
188  isminetype mine = wallet->IsMine(txout);
189  if(fAllToMe > mine) fAllToMe = mine;
190  }
191 
192  if (fAllFromMe)
193  {
194  if(fAllFromMe & ISMINE_WATCH_ONLY)
195  strHTML += "<b>" + tr("From") + ":</b> " + tr("watch-only") + "<br>";
196 
197  //
198  // Debit
199  //
200  BOOST_FOREACH(const CTxOut& txout, wtx.vout)
201  {
202  // Ignore change
203  isminetype toSelf = wallet->IsMine(txout);
204  if ((toSelf == ISMINE_SPENDABLE) && (fAllFromMe == ISMINE_SPENDABLE))
205  continue;
206 
207  if (!wtx.mapValue.count("to") || wtx.mapValue["to"].empty())
208  {
209  // Offline transaction
210  CTxDestination address;
211  if (ExtractDestination(txout.scriptPubKey, address))
212  {
213  strHTML += "<b>" + tr("To") + ":</b> ";
214  if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].name.empty())
215  strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address].name) + " ";
216  strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address).ToString());
217  if(toSelf == ISMINE_SPENDABLE)
218  strHTML += " (own address)";
219  else if(toSelf & ISMINE_WATCH_ONLY)
220  strHTML += " (watch-only)";
221  strHTML += "<br>";
222  }
223  }
224 
225  strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -txout.nValue) + "<br>";
226  if(toSelf)
227  strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, txout.nValue) + "<br>";
228  }
229 
230  if (fAllToMe)
231  {
232  // Payment to self
233  CAmount nChange = wtx.GetChange();
234  CAmount nValue = nCredit - nChange;
235  strHTML += "<b>" + tr("Total debit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -nValue) + "<br>";
236  strHTML += "<b>" + tr("Total credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, nValue) + "<br>";
237  }
238 
239  CAmount nTxFee = nDebit - wtx.GetValueOut();
240  if (nTxFee > 0)
241  strHTML += "<b>" + tr("Transaction fee") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -nTxFee) + "<br>";
242  }
243  else
244  {
245  //
246  // Mixed debit transaction
247  //
248  BOOST_FOREACH(const CTxIn& txin, wtx.vin)
249  if (wallet->IsMine(txin))
250  strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -wallet->GetDebit(txin, ISMINE_ALL)) + "<br>";
251  BOOST_FOREACH(const CTxOut& txout, wtx.vout)
252  if (wallet->IsMine(txout))
253  strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, wallet->GetCredit(txout, ISMINE_ALL)) + "<br>";
254  }
255  }
256 
257  strHTML += "<b>" + tr("Net amount") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, nNet, true) + "<br>";
258 
259  //
260  // Message
261  //
262  if (wtx.mapValue.count("message") && !wtx.mapValue["message"].empty())
263  strHTML += "<br><b>" + tr("Message") + ":</b><br>" + GUIUtil::HtmlEscape(wtx.mapValue["message"], true) + "<br>";
264  if (wtx.mapValue.count("comment") && !wtx.mapValue["comment"].empty())
265  strHTML += "<br><b>" + tr("Comment") + ":</b><br>" + GUIUtil::HtmlEscape(wtx.mapValue["comment"], true) + "<br>";
266 
267  strHTML += "<b>" + tr("Transaction ID") + ":</b> " + TransactionRecord::formatSubTxId(wtx.GetHash(), rec->idx) + "<br>";
268  strHTML += "<b>" + tr("Transaction total size") + ":</b> " + QString::number(wtx.GetTotalSize()) + " bytes<br>";
269 
270  // Message from normal dash:URI (dash:XyZ...?message=example)
271  Q_FOREACH (const PAIRTYPE(std::string, std::string)& r, wtx.vOrderForm)
272  if (r.first == "Message")
273  strHTML += "<br><b>" + tr("Message") + ":</b><br>" + GUIUtil::HtmlEscape(r.second, true) + "<br>";
274 
275  //
276  // PaymentRequest info:
277  //
278  Q_FOREACH (const PAIRTYPE(std::string, std::string)& r, wtx.vOrderForm)
279  {
280  if (r.first == "PaymentRequest")
281  {
282  PaymentRequestPlus req;
283  req.parse(QByteArray::fromRawData(r.second.data(), r.second.size()));
284  QString merchant;
285  if (req.getMerchant(PaymentServer::getCertStore(), merchant))
286  strHTML += "<b>" + tr("Merchant") + ":</b> " + GUIUtil::HtmlEscape(merchant) + "<br>";
287  }
288  }
289 
290  if (wtx.IsCoinBase())
291  {
292  quint32 numBlocksToMaturity = COINBASE_MATURITY + 1;
293  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>";
294  }
295 
296  //
297  // Debug view
298  //
299  if (fDebug)
300  {
301  strHTML += "<hr><br>" + tr("Debug information") + "<br><br>";
302  BOOST_FOREACH(const CTxIn& txin, wtx.vin)
303  if(wallet->IsMine(txin))
304  strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -wallet->GetDebit(txin, ISMINE_ALL)) + "<br>";
305  BOOST_FOREACH(const CTxOut& txout, wtx.vout)
306  if(wallet->IsMine(txout))
307  strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, wallet->GetCredit(txout, ISMINE_ALL)) + "<br>";
308 
309  strHTML += "<br><b>" + tr("Transaction") + ":</b><br>";
310  strHTML += GUIUtil::HtmlEscape(wtx.ToString(), true);
311 
312  strHTML += "<br><b>" + tr("Inputs") + ":</b>";
313  strHTML += "<ul>";
314 
315  BOOST_FOREACH(const CTxIn& txin, wtx.vin)
316  {
317  COutPoint prevout = txin.prevout;
318 
319  CCoins prev;
320  if(pcoinsTip->GetCoins(prevout.hash, prev))
321  {
322  if (prevout.n < prev.vout.size())
323  {
324  strHTML += "<li>";
325  const CTxOut &vout = prev.vout[prevout.n];
326  CTxDestination address;
327  if (ExtractDestination(vout.scriptPubKey, address))
328  {
329  if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].name.empty())
330  strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address].name) + " ";
331  strHTML += QString::fromStdString(CBitcoinAddress(address).ToString());
332  }
333  strHTML = strHTML + " " + tr("Amount") + "=" + BitcoinUnits::formatHtmlWithUnit(unit, vout.nValue);
334  strHTML = strHTML + " IsMine=" + (wallet->IsMine(vout) & ISMINE_SPENDABLE ? tr("true") : tr("false"));
335  strHTML = strHTML + " IsWatchOnly=" + (wallet->IsMine(vout) & ISMINE_WATCH_ONLY ? tr("true") : tr("false")) + "</li>";
336  }
337  }
338  }
339 
340  strHTML += "</ul>";
341  }
342 
343  strHTML += "</font></html>";
344  return strHTML;
345 }
CAmount GetCredit(const isminefilter &filter) const
Definition: wallet.cpp:1824
uint32_t n
Definition: transaction.h:19
bool isAbandoned() const
Definition: wallet.h:267
boost::variant< CNoDestination, CKeyID, CScriptID > CTxDestination
Definition: standard.h:69
const uint32_t nLockTime
Definition: transaction.h:235
bool ExtractDestination(const CScript &scriptPubKey, CTxDestination &addressRet)
Definition: standard.cpp:164
bool GetCoins(const uint256 &txid, CCoins &coins) const
Retrieve the CCoins (unspent transaction outputs) for a given txid.
Definition: coins.cpp:90
Definition: coins.h:73
bool IsTxLockCandidateTimedOut(const uint256 &txHash)
Definition: instantx.cpp:816
bool fDebug
Definition: util.cpp:124
bool IsValid() const
Definition: base58.cpp:247
CCriticalSection cs_main
Definition: validation.cpp:62
isminetype IsMine(const CKeyStore &keystore, const CTxDestination &dest)
bool parse(const QByteArray &data)
CAmount nValue
Definition: transaction.h:136
static const int COINBASE_MATURITY
Definition: consensus.h:23
mapValue_t mapValue
Definition: wallet.h:281
static X509_STORE * getCertStore()
CAmount GetValueOut() const
unsigned int nTimeReceived
Definition: wallet.h:284
CAmount GetChange() const
Definition: wallet.cpp:2023
bool IsInMainChain() const
Definition: wallet.h:263
int64_t CAmount
Definition: amount.h:14
#define AssertLockHeld(cs)
Definition: sync.h:96
static QString formatHtmlWithUnit(int unit, const CAmount &amount, bool plussign=false, SeparatorStyle separators=separatorStandard)
Format as HTML string (with unit)
CCoinsViewCache * pcoinsTip
Definition: validation.cpp:187
#define LOCK2(cs1, cs2)
Definition: sync.h:169
std::vector< CTxOut > vout
unspent transaction outputs; spent outputs are .IsNull(); spent outputs at the end of the array are d...
Definition: coins.h:80
unsigned int GetTotalSize() const
bool CheckFinalTx(const CTransaction &tx, int flags)
Definition: validation.cpp:213
int GetTransactionLockSignatures(const uint256 &txHash)
Definition: instantx.cpp:795
bool getMerchant(X509_STORE *certStore, QString &merchant) const
COutPoint prevout
Definition: transaction.h:61
static QString toHTML(CWallet *wallet, CWalletTx &wtx, TransactionRecord *rec, int unit)
static QString FormatTxStatus(const CWalletTx &wtx)
int64_t GetTxTime() const
Definition: wallet.cpp:1540
int Height() const
Definition: chain.h:397
QString HtmlEscape(const QString &str, bool fMultiLine)
Definition: guiutil.cpp:261
CInstantSend instantsend
Definition: instantx.cpp:30
CAmount GetDebit(const isminefilter &filter) const
filter decides which addresses will count towards the debit
Definition: wallet.cpp:1793
std::vector< std::pair< std::string, std::string > > vOrderForm
Definition: wallet.h:282
bool IsLockedInstantSendTransaction(const uint256 &txHash)
Definition: instantx.cpp:770
CChain chainActive
Definition: validation.cpp:65
Definition: wallet.py:1
CScript scriptPubKey
Definition: transaction.h:137
const std::vector< CTxIn > vin
Definition: transaction.h:233
CTxDestination Get() const
Definition: base58.cpp:260
static QString formatSubTxId(const uint256 &hash, int vout)
const uint256 & GetHash() const
Definition: transaction.h:262
int64_t GetAdjustedTime()
Definition: timedata.cpp:33
std::string ToString() const
bool IsCoinBase() const
Definition: transaction.h:284
const std::vector< CTxOut > vout
Definition: transaction.h:234
bool HasTxLockRequest(const uint256 &txHash)
Definition: instantx.cpp:730
static const unsigned int LOCKTIME_THRESHOLD
Definition: script.h:32
isminetype
Definition: wallet_ismine.h:17
int GetMaxSignatures() const
Definition: instantx.cpp:990
#define PAIRTYPE(t1, t2)
uint256 hash
Definition: transaction.h:18
int GetBlocksToMaturity() const
Definition: wallet.cpp:4449
int GetDepthInMainChain(const CBlockIndex *&pindexRet, bool enableIX=true) const
Definition: wallet.cpp:4416
bool InMempool() const
Definition: wallet.cpp:2032
int GetRequestCount() const
Definition: wallet.cpp:1546
QString dateTimeStr(const QDateTime &date)
Definition: guiutil.cpp:87