Dogecoin Core  1.14.2
P2P Digital Currency
transactiondesc.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2016 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 #include "transactiondesc.h"
6 
7 #include "bitcoinunits.h"
8 #include "guiutil.h"
9 #include "paymentserver.h"
10 #include "transactionrecord.h"
11 
12 #include "base58.h"
13 #include "chainparams.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 <stdint.h>
23 #include <string>
24 
26 {
28  if (!CheckFinalTx(wtx))
29  {
30  if (wtx.tx->nLockTime < LOCKTIME_THRESHOLD)
31  return tr("Open for %n more block(s)", "", wtx.tx->nLockTime - chainActive.Height());
32  else
33  return tr("Open until %1").arg(GUIUtil::dateTimeStr(wtx.tx->nLockTime));
34  }
35  else
36  {
37  int nDepth = wtx.GetDepthInMainChain();
38  if (nDepth < 0)
39  return tr("conflicted with a transaction with %1 confirmations").arg(-nDepth);
40  else if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
41  return tr("%1/offline").arg(nDepth);
42  else if (nDepth == 0)
43  return tr("0/unconfirmed, %1").arg((wtx.InMempool() ? tr("in memory pool") : tr("not in memory pool"))) + (wtx.isAbandoned() ? ", "+tr("abandoned") : "");
44  else if (nDepth < 6)
45  return tr("%1/unconfirmed").arg(nDepth);
46  else
47  return tr("%1 confirmations").arg(nDepth);
48  }
49 }
50 
51 QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionRecord *rec, int unit)
52 {
53  QString strHTML;
54 
55  LOCK2(cs_main, wallet->cs_wallet);
56  strHTML.reserve(4000);
57  strHTML += "<html><font face='verdana, arial, helvetica, sans-serif'>";
58 
59  int64_t nTime = wtx.GetTxTime();
60  CAmount nCredit = wtx.GetCredit(ISMINE_ALL);
61  CAmount nDebit = wtx.GetDebit(ISMINE_ALL);
62  CAmount nNet = nCredit - nDebit;
63 
64  strHTML += "<b>" + tr("Status") + ":</b> " + FormatTxStatus(wtx);
65  int nRequests = wtx.GetRequestCount();
66  if (nRequests != -1)
67  {
68  if (nRequests == 0)
69  strHTML += tr(", has not been successfully broadcast yet");
70  else if (nRequests > 0)
71  strHTML += tr(", broadcast through %n node(s)", "", nRequests);
72  }
73  strHTML += "<br>";
74 
75  strHTML += "<b>" + tr("Date") + ":</b> " + (nTime ? GUIUtil::dateTimeStr(nTime) : "") + "<br>";
76 
77  //
78  // From
79  //
80  if (wtx.IsCoinBase())
81  {
82  strHTML += "<b>" + tr("Source") + ":</b> " + tr("Generated") + "<br>";
83  }
84  else if (wtx.mapValue.count("from") && !wtx.mapValue["from"].empty())
85  {
86  // Online transaction
87  strHTML += "<b>" + tr("From") + ":</b> " + GUIUtil::HtmlEscape(wtx.mapValue["from"]) + "<br>";
88  }
89  else
90  {
91  // Offline transaction
92  if (nNet > 0)
93  {
94  // Credit
95  if (CBitcoinAddress(rec->address).IsValid())
96  {
97  CTxDestination address = CBitcoinAddress(rec->address).Get();
98  if (wallet->mapAddressBook.count(address))
99  {
100  strHTML += "<b>" + tr("From") + ":</b> " + tr("unknown") + "<br>";
101  strHTML += "<b>" + tr("To") + ":</b> ";
102  strHTML += GUIUtil::HtmlEscape(rec->address);
103  QString addressOwned = (::IsMine(*wallet, address) == ISMINE_SPENDABLE) ? tr("own address") : tr("watch-only");
104  if (!wallet->mapAddressBook[address].name.empty())
105  strHTML += " (" + addressOwned + ", " + tr("label") + ": " + GUIUtil::HtmlEscape(wallet->mapAddressBook[address].name) + ")";
106  else
107  strHTML += " (" + addressOwned + ")";
108  strHTML += "<br>";
109  }
110  }
111  }
112  }
113 
114  //
115  // To
116  //
117  if (wtx.mapValue.count("to") && !wtx.mapValue["to"].empty())
118  {
119  // Online transaction
120  std::string strAddress = wtx.mapValue["to"];
121  strHTML += "<b>" + tr("To") + ":</b> ";
122  CTxDestination dest = CBitcoinAddress(strAddress).Get();
123  if (wallet->mapAddressBook.count(dest) && !wallet->mapAddressBook[dest].name.empty())
124  strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[dest].name) + " ";
125  strHTML += GUIUtil::HtmlEscape(strAddress) + "<br>";
126  }
127 
128  //
129  // Amount
130  //
131  if (wtx.IsCoinBase() && nCredit == 0)
132  {
133  //
134  // Coinbase
135  //
136  CAmount nUnmatured = 0;
137  BOOST_FOREACH(const CTxOut& txout, wtx.tx->vout)
138  nUnmatured += wallet->GetCredit(txout, ISMINE_ALL);
139  strHTML += "<b>" + tr("Credit") + ":</b> ";
140  if (wtx.IsInMainChain())
141  strHTML += BitcoinUnits::formatHtmlWithUnit(unit, nUnmatured)+ " (" + tr("matures in %n more block(s)", "", wtx.GetBlocksToMaturity()) + ")";
142  else
143  strHTML += "(" + tr("not accepted") + ")";
144  strHTML += "<br>";
145  }
146  else if (nNet > 0)
147  {
148  //
149  // Credit
150  //
151  strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, nNet) + "<br>";
152  }
153  else
154  {
155  isminetype fAllFromMe = ISMINE_SPENDABLE;
156  BOOST_FOREACH(const CTxIn& txin, wtx.tx->vin)
157  {
158  isminetype mine = wallet->IsMine(txin);
159  if(fAllFromMe > mine) fAllFromMe = mine;
160  }
161 
162  isminetype fAllToMe = ISMINE_SPENDABLE;
163  BOOST_FOREACH(const CTxOut& txout, wtx.tx->vout)
164  {
165  isminetype mine = wallet->IsMine(txout);
166  if(fAllToMe > mine) fAllToMe = mine;
167  }
168 
169  if (fAllFromMe)
170  {
171  if(fAllFromMe & ISMINE_WATCH_ONLY)
172  strHTML += "<b>" + tr("From") + ":</b> " + tr("watch-only") + "<br>";
173 
174  //
175  // Debit
176  //
177  BOOST_FOREACH(const CTxOut& txout, wtx.tx->vout)
178  {
179  // Ignore change
180  isminetype toSelf = wallet->IsMine(txout);
181  if ((toSelf == ISMINE_SPENDABLE) && (fAllFromMe == ISMINE_SPENDABLE))
182  continue;
183 
184  if (!wtx.mapValue.count("to") || wtx.mapValue["to"].empty())
185  {
186  // Offline transaction
187  CTxDestination address;
188  if (ExtractDestination(txout.scriptPubKey, address))
189  {
190  strHTML += "<b>" + tr("To") + ":</b> ";
191  if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].name.empty())
192  strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address].name) + " ";
193  strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address).ToString());
194  if(toSelf == ISMINE_SPENDABLE)
195  strHTML += " (own address)";
196  else if(toSelf & ISMINE_WATCH_ONLY)
197  strHTML += " (watch-only)";
198  strHTML += "<br>";
199  }
200  }
201 
202  strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -txout.nValue) + "<br>";
203  if(toSelf)
204  strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, txout.nValue) + "<br>";
205  }
206 
207  if (fAllToMe)
208  {
209  // Payment to self
210  CAmount nChange = wtx.GetChange();
211  CAmount nValue = nCredit - nChange;
212  strHTML += "<b>" + tr("Total debit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -nValue) + "<br>";
213  strHTML += "<b>" + tr("Total credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, nValue) + "<br>";
214  }
215 
216  CAmount nTxFee = nDebit - wtx.tx->GetValueOut();
217  if (nTxFee > 0)
218  strHTML += "<b>" + tr("Transaction fee") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -nTxFee) + "<br>";
219  }
220  else
221  {
222  //
223  // Mixed debit transaction
224  //
225  BOOST_FOREACH(const CTxIn& txin, wtx.tx->vin)
226  if (wallet->IsMine(txin))
227  strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -wallet->GetDebit(txin, ISMINE_ALL)) + "<br>";
228  BOOST_FOREACH(const CTxOut& txout, wtx.tx->vout)
229  if (wallet->IsMine(txout))
230  strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, wallet->GetCredit(txout, ISMINE_ALL)) + "<br>";
231  }
232  }
233 
234  strHTML += "<b>" + tr("Net amount") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, nNet, true) + "<br>";
235 
236  //
237  // Message
238  //
239  if (wtx.mapValue.count("message") && !wtx.mapValue["message"].empty())
240  strHTML += "<br><b>" + tr("Message") + ":</b><br>" + GUIUtil::HtmlEscape(wtx.mapValue["message"], true) + "<br>";
241  if (wtx.mapValue.count("comment") && !wtx.mapValue["comment"].empty())
242  strHTML += "<br><b>" + tr("Comment") + ":</b><br>" + GUIUtil::HtmlEscape(wtx.mapValue["comment"], true) + "<br>";
243 
244  strHTML += "<b>" + tr("Transaction ID") + ":</b> " + rec->getTxID() + "<br>";
245  strHTML += "<b>" + tr("Transaction total size") + ":</b> " + QString::number(wtx.tx->GetTotalSize()) + " bytes<br>";
246  strHTML += "<b>" + tr("Output index") + ":</b> " + QString::number(rec->getOutputIndex()) + "<br>";
247 
248  // Message from normal bitcoin:URI (bitcoin:123...?message=example)
249  Q_FOREACH (const PAIRTYPE(std::string, std::string)& r, wtx.vOrderForm)
250  if (r.first == "Message")
251  strHTML += "<br><b>" + tr("Message") + ":</b><br>" + GUIUtil::HtmlEscape(r.second, true) + "<br>";
252 
253  //
254  // PaymentRequest info:
255  //
256  Q_FOREACH (const PAIRTYPE(std::string, std::string)& r, wtx.vOrderForm)
257  {
258  if (r.first == "PaymentRequest")
259  {
260  PaymentRequestPlus req;
261  req.parse(QByteArray::fromRawData(r.second.data(), r.second.size()));
262  QString merchant;
263  if (req.getMerchant(PaymentServer::getCertStore(), merchant))
264  strHTML += "<b>" + tr("Merchant") + ":</b> " + GUIUtil::HtmlEscape(merchant) + "<br>";
265  }
266  }
267 
268  if (wtx.IsCoinBase())
269  {
270  quint32 nCoinbaseMaturity = Params().GetConsensus(chainActive.Height()).nCoinbaseMaturity + 1;
271  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(nCoinbaseMaturity)) + "<br>";
272  }
273 
274  //
275  // Debug view
276  //
277  if (fDebug)
278  {
279  strHTML += "<hr><br>" + tr("Debug information") + "<br><br>";
280  BOOST_FOREACH(const CTxIn& txin, wtx.tx->vin)
281  if(wallet->IsMine(txin))
282  strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -wallet->GetDebit(txin, ISMINE_ALL)) + "<br>";
283  BOOST_FOREACH(const CTxOut& txout, wtx.tx->vout)
284  if(wallet->IsMine(txout))
285  strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, wallet->GetCredit(txout, ISMINE_ALL)) + "<br>";
286 
287  strHTML += "<br><b>" + tr("Transaction") + ":</b><br>";
288  strHTML += GUIUtil::HtmlEscape(wtx.tx->ToString(), true);
289 
290  strHTML += "<br><b>" + tr("Inputs") + ":</b>";
291  strHTML += "<ul>";
292 
293  BOOST_FOREACH(const CTxIn& txin, wtx.tx->vin)
294  {
295  COutPoint prevout = txin.prevout;
296 
297  CCoins prev;
298  if(pcoinsTip->GetCoins(prevout.hash, prev))
299  {
300  if (prevout.n < prev.vout.size())
301  {
302  strHTML += "<li>";
303  const CTxOut &vout = prev.vout[prevout.n];
304  CTxDestination address;
305  if (ExtractDestination(vout.scriptPubKey, address))
306  {
307  if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].name.empty())
308  strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address].name) + " ";
309  strHTML += QString::fromStdString(CBitcoinAddress(address).ToString());
310  }
311  strHTML = strHTML + " " + tr("Amount") + "=" + BitcoinUnits::formatHtmlWithUnit(unit, vout.nValue);
312  strHTML = strHTML + " IsMine=" + (wallet->IsMine(vout) & ISMINE_SPENDABLE ? tr("true") : tr("false")) + "</li>";
313  strHTML = strHTML + " IsWatchOnly=" + (wallet->IsMine(vout) & ISMINE_WATCH_ONLY ? tr("true") : tr("false")) + "</li>";
314  }
315  }
316  }
317 
318  strHTML += "</ul>";
319  }
320 
321  strHTML += "</font></html>";
322  return strHTML;
323 }
int64_t CAmount
Amount in satoshis (Can be negative)
Definition: amount.h:15
const CChainParams & Params()
Return the currently selected parameters.
static QString formatHtmlWithUnit(int unit, const CAmount &amount, bool plussign=false, SeparatorStyle separators=separatorStandard)
Format as HTML string (with unit)
base58-encoded Bitcoin addresses.
Definition: base58.h:104
CTxDestination Get() const
Definition: base58.cpp:260
bool IsValid() const
Definition: base58.cpp:247
int Height() const
Return the maximal height in the chain.
Definition: chain.h:474
const Consensus::Params & GetConsensus(uint32_t nTargetHeight) const
Definition: chainparams.h:59
Pruned version of CTransaction: only retains metadata and unspent transaction outputs.
Definition: coins.h:75
std::vector< CTxOut > vout
unspent transaction outputs; spent outputs are .IsNull(); spent outputs at the end of the array are d...
Definition: coins.h:81
bool GetCoins(const uint256 &txid, CCoins &coins) const
Retrieve the CCoins (unspent transaction outputs) for a given txid.
Definition: coins.cpp:90
int GetDepthInMainChain(const CBlockIndex *&pindexRet) const
Return depth of transaction in blockchain: <0 : conflicts with a transaction this deep in the blockch...
Definition: auxpow.cpp:45
bool isAbandoned() const
Definition: auxpow.h:110
bool IsCoinBase() const
Definition: auxpow.h:114
int GetBlocksToMaturity() const
Definition: auxpow.cpp:64
bool IsInMainChain() const
Definition: auxpow.h:105
CTransactionRef tx
Definition: auxpow.h:37
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:20
uint32_t n
Definition: transaction.h:23
uint256 hash
Definition: transaction.h:22
An input of a transaction.
Definition: transaction.h:63
COutPoint prevout
Definition: transaction.h:65
An output of a transaction.
Definition: transaction.h:133
CScript scriptPubKey
Definition: transaction.h:136
CAmount nValue
Definition: transaction.h:135
A CWallet is an extension of a keystore, which also maintains a set of transactions and balances,...
Definition: wallet.h:493
std::map< CTxDestination, CAddressBookData > mapAddressBook
Definition: wallet.h:624
CCriticalSection cs_wallet
Definition: wallet.h:559
A transaction with a bunch of additional info that only the owner cares about.
Definition: wallet.h:177
mapValue_t mapValue
Definition: wallet.h:182
std::vector< std::pair< std::string, std::string > > vOrderForm
Definition: wallet.h:183
unsigned int nTimeReceived
time received by this node
Definition: wallet.h:185
bool getMerchant(X509_STORE *certStore, QString &merchant) const
bool parse(const QByteArray &data)
static X509_STORE * getCertStore()
static QString toHTML(CWallet *wallet, CWalletTx &wtx, TransactionRecord *rec, int unit)
static QString FormatTxStatus(const CWalletTx &wtx)
UI model for a transaction.
int getOutputIndex() const
Return the output index of the subtransaction
QString getTxID() const
Return the unique identifier for this transaction (part)
CAmount GetCredit(const isminefilter &filter) const
Definition: wallet.cpp:1695
isminetype IsMine(const CTxIn &txin) const
Definition: wallet.cpp:1201
CAmount GetDebit(const CTxIn &txin, const isminefilter &filter) const
Returns amount of debit if the input matches the filter, otherwise returns 0.
Definition: wallet.cpp:1218
CAmount GetChange() const
Definition: wallet.cpp:1815
CAmount GetDebit(const isminefilter &filter) const
filter decides which addresses will count towards the debit
Definition: wallet.cpp:1664
CAmount GetCredit(const CTxOut &txout, const isminefilter &filter) const
Definition: wallet.cpp:1239
int64_t GetTxTime() const
Definition: wallet.cpp:1407
bool InMempool() const
Definition: wallet.cpp:1824
int GetRequestCount() const
Definition: wallet.cpp:1413
isminetype IsMine(const CKeyStore &keystore, const CScript &scriptPubKey, SigVersion sigversion)
Definition: ismine.cpp:32
isminetype
IsMine() return codes.
Definition: ismine.h:18
@ ISMINE_ALL
Definition: ismine.h:26
@ ISMINE_SPENDABLE
Definition: ismine.h:25
@ ISMINE_WATCH_ONLY
Definition: ismine.h:24
QString HtmlEscape(const QString &str, bool fMultiLine)
Definition: guiutil.cpp:255
QString dateTimeStr(const QDateTime &date)
Definition: guiutil.cpp:86
bool ExtractDestination(const CScript &scriptPubKey, CTxDestination &addressRet)
Definition: standard.cpp:182
boost::variant< CNoDestination, CKeyID, CScriptID > CTxDestination
A txout script template with a specific destination.
Definition: standard.h:71
uint32_t nCoinbaseMaturity
Definition: params.h:61
#define LOCK2(cs1, cs2)
Definition: sync.h:178
#define AssertLockHeld(cs)
Definition: sync.h:86
int64_t GetAdjustedTime()
Definition: timedata.cpp:36
bool fDebug
Definition: util.cpp:113
#define PAIRTYPE(t1, t2)
This is needed because the foreach macro can't get over the comma in pair<t1, t2>
CCoinsViewCache * pcoinsTip
Global variable that points to the active CCoinsView (protected by cs_main)
Definition: validation.cpp:223
CCriticalSection cs_main
Global state.
Definition: validation.cpp:61
bool CheckFinalTx(const CTransaction &tx, int flags)
Check if transaction will be final in the next block to be created.
Definition: validation.cpp:250
CChain chainActive
The currently-connected chain of blocks (protected by cs_main).
Definition: validation.cpp:64