Bitcoin Core 32.99.0
P2P Digital Currency
Loading...
Searching...
No Matches
transactiondesc.cpp
Go to the documentation of this file.
1// Copyright (c) 2011-present 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
6
7#include <qt/bitcoinunits.h>
8#include <qt/guiutil.h>
10
11#include <common/system.h>
12#include <consensus/consensus.h>
13#include <interfaces/node.h>
14#include <interfaces/wallet.h>
15#include <key_io.h>
16#include <policy/policy.h>
17#include <util/log.h>
18#include <validation.h>
19
20#include <cstdint>
21#include <string>
22
23#include <QLatin1String>
24
26{
27 int depth = status.depth_in_main_chain;
28 if (depth < 0) {
29 /*: Text explaining the current status of a transaction, shown in the
30 status field of the details window for this transaction. This status
31 represents an unconfirmed transaction that conflicts with a confirmed
32 transaction. */
33 return tr("conflicted with a transaction with %1 confirmations").arg(-depth);
34 } else if (depth == 0) {
35 QString s;
36 if (inMempool) {
37 /*: Text explaining the current status of a transaction, shown in the
38 status field of the details window for this transaction. This status
39 represents an unconfirmed transaction that is in the memory pool. */
40 s = tr("0/unconfirmed, in memory pool");
41 } else {
42 /*: Text explaining the current status of a transaction, shown in the
43 status field of the details window for this transaction. This status
44 represents an unconfirmed transaction that is not in the memory pool. */
45 s = tr("0/unconfirmed, not in memory pool");
46 }
47 if (status.is_abandoned) {
48 /*: Text explaining the current status of a transaction, shown in the
49 status field of the details window for this transaction. This
50 status represents an abandoned transaction. */
51 s += QLatin1String(", ") + tr("abandoned");
52 }
53 return s;
54 } else if (depth < 6) {
55 /*: Text explaining the current status of a transaction, shown in the
56 status field of the details window for this transaction. This
57 status represents a transaction confirmed in at least one block,
58 but less than 6 blocks. */
59 return tr("%1/unconfirmed").arg(depth);
60 } else {
61 /*: Text explaining the current status of a transaction, shown in the
62 status field of the details window for this transaction. This status
63 represents a transaction confirmed in 6 or more blocks. */
64 return tr("%1 confirmations").arg(depth);
65 }
66}
67
69{
70 int numBlocks;
72 bool inMempool;
73 std::vector<std::string> messages;
74 std::vector<std::string> payment_requests;
75 interfaces::WalletTx wtx = wallet.getWalletTxDetails(rec->hash, status, messages, payment_requests, inMempool, numBlocks);
76
78
79 strHTML.reserve(4000);
80 strHTML += "<html><font face='verdana, arial, helvetica, sans-serif'>";
81
82 int64_t nTime = wtx.time;
84 CAmount nDebit = wtx.debit;
86
87 strHTML += "<b>" + tr("Status") + ":</b> " + FormatTxStatus(status, inMempool);
88 strHTML += "<br>";
89
90 strHTML += "<b>" + tr("Date") + ":</b> " + (nTime ? GUIUtil::dateTimeStr(nTime) : "") + "<br>";
91
92 //
93 // From
94 //
95 if (wtx.is_coinbase)
96 {
97 strHTML += "<b>" + tr("Source") + ":</b> " + tr("Generated") + "<br>";
98 } else if (wtx.from) {
99 // Online transaction
100 strHTML += "<b>" + tr("From") + ":</b> " + GUIUtil::HtmlEscape(*wtx.from) + "<br>";
101 }
102 else
103 {
104 // Offline transaction
105 if (nNet > 0)
106 {
107 // Credit
109 if (IsValidDestination(address)) {
110 std::string name;
111 if (wallet.getAddress(address, &name, /*purpose=*/nullptr))
112 {
113 strHTML += "<b>" + tr("From") + ":</b> " + tr("unknown") + "<br>";
114 strHTML += "<b>" + tr("To") + ":</b> ";
116 QString addressOwned = tr("own address");
117 if (!name.empty())
118 strHTML += " (" + addressOwned + ", " + tr("label") + ": " + GUIUtil::HtmlEscape(name) + ")";
119 else
120 strHTML += " (" + addressOwned + ")";
121 strHTML += "<br>";
122 }
123 }
124 }
125 }
126
127 //
128 // To
129 //
130 if (wtx.comment_to) {
131 // Online transaction
132 std::string strAddress = *wtx.comment_to;
133 strHTML += "<b>" + tr("To") + ":</b> ";
135 std::string name;
136 if (wallet.getAddress(
137 dest, &name, /*purpose=*/nullptr) && !name.empty())
140 }
141
142 //
143 // Amount
144 //
145 if (wtx.is_coinbase && nCredit == 0)
146 {
147 //
148 // Coinbase
149 //
151 for (const CTxOut& txout : wtx.tx->vout)
152 nUnmatured += wallet.getCredit(txout);
153 strHTML += "<b>" + tr("Credit") + ":</b> ";
154 if (status.is_in_main_chain)
155 strHTML += BitcoinUnits::formatHtmlWithUnit(unit, nUnmatured)+ " (" + tr("matures in %n more block(s)", "", status.blocks_to_maturity) + ")";
156 else
157 strHTML += "(" + tr("not accepted") + ")";
158 strHTML += "<br>";
159 }
160 else if (nNet > 0)
161 {
162 //
163 // Credit
164 //
165 strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, nNet) + "<br>";
166 }
167 else
168 {
169 bool all_from_me = std::all_of(wtx.txin_is_mine.begin(), wtx.txin_is_mine.end(), [](bool mine) { return mine; });
170 bool all_to_me = std::all_of(wtx.txout_is_mine.begin(), wtx.txout_is_mine.end(), [](bool mine) { return mine; });
171
172 if (all_from_me)
173 {
174 // Debit
175 //
176 auto mine = wtx.txout_is_mine.begin();
177 for (const CTxOut& txout : wtx.tx->vout)
178 {
179 // Ignore change
180 bool toSelf = *(mine++);
181 if (toSelf && all_from_me)
182 continue;
183
184 if (!wtx.comment_to) {
185 // Offline transaction
186 CTxDestination address;
187 if (ExtractDestination(txout.scriptPubKey, address))
188 {
189 strHTML += "<b>" + tr("To") + ":</b> ";
190 std::string name;
191 if (wallet.getAddress(
192 address, &name, /*purpose=*/nullptr) && !name.empty())
195 if(toSelf)
196 strHTML += " (" + tr("own address") + ")";
197 strHTML += "<br>";
198 }
199 }
200
201 strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -txout.nValue) + "<br>";
202 if(toSelf)
203 strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, txout.nValue) + "<br>";
204 }
205
206 if (all_to_me)
207 {
208 // Payment to self
209 CAmount nChange = wtx.change;
210 CAmount nValue = nCredit - nChange;
211 strHTML += "<b>" + tr("Total debit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -nValue) + "<br>";
212 strHTML += "<b>" + tr("Total credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, nValue) + "<br>";
213 }
214
215 CAmount nTxFee = nDebit - wtx.tx->GetValueOut();
216 if (nTxFee > 0)
217 strHTML += "<b>" + tr("Transaction fee") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -nTxFee) + "<br>";
218 }
219 else
220 {
221 //
222 // Mixed debit transaction
223 //
224 auto mine = wtx.txin_is_mine.begin();
225 for (const CTxIn& txin : wtx.tx->vin) {
226 if (*(mine++)) {
227 strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -wallet.getDebit(txin)) + "<br>";
228 }
229 }
230 mine = wtx.txout_is_mine.begin();
231 for (const CTxOut& txout : wtx.tx->vout) {
232 if (*(mine++)) {
233 strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, wallet.getCredit(txout)) + "<br>";
234 }
235 }
236 }
237 }
238
239 strHTML += "<b>" + tr("Net amount") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, nNet, true) + "<br>";
240
241 //
242 // Message
243 //
244 if (wtx.message) {
245 strHTML += "<br><b>" + tr("Message") + ":</b><br>" + GUIUtil::HtmlEscape(*wtx.message, true) + "<br>";
246 }
247 if (wtx.comment) {
248 strHTML += "<br><b>" + tr("Comment") + ":</b><br>" + GUIUtil::HtmlEscape(*wtx.comment, true) + "<br>";
249 }
250
251 strHTML += "<b>" + tr("Transaction ID") + ":</b> " + rec->getTxHash() + "<br>";
252 strHTML += "<b>" + tr("Transaction total size") + ":</b> " + QString::number(wtx.tx->ComputeTotalSize()) + " bytes<br>";
253 strHTML += "<b>" + tr("Transaction virtual size") + ":</b> " + QString::number(GetVirtualTransactionSize(*wtx.tx)) + " bytes<br>";
254 strHTML += "<b>" + tr("Output index") + ":</b> " + QString::number(rec->getOutputIndex()) + "<br>";
255
256 // Message from normal bitcoin:URI (bitcoin:123...?message=example)
257 for (const std::string& msg : messages) {
258 strHTML += "<br><b>" + tr("Message") + ":</b><br>" + GUIUtil::HtmlEscape(msg, true) + "<br>";
259 }
260
261 if (wtx.is_coinbase)
262 {
264 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>";
265 }
266
267 //
268 // Debug view
269 //
270 if (node.getLogCategories() != BCLog::NONE)
271 {
272 strHTML += "<hr><br>" + tr("Debug information") + "<br><br>";
273 for (const CTxIn& txin : wtx.tx->vin)
274 if(wallet.txinIsMine(txin))
275 strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -wallet.getDebit(txin)) + "<br>";
276 for (const CTxOut& txout : wtx.tx->vout)
277 if(wallet.txoutIsMine(txout))
278 strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, wallet.getCredit(txout)) + "<br>";
279
280 strHTML += "<br><b>" + tr("Transaction") + ":</b><br>";
281 strHTML += GUIUtil::HtmlEscape(wtx.tx->ToString(), true);
282
283 strHTML += "<br><b>" + tr("Inputs") + ":</b>";
284 strHTML += "<ul>";
285
286 for (const CTxIn& txin : wtx.tx->vin)
287 {
288 COutPoint prevout = txin.prevout;
289
290 if (auto prev{node.getUnspentOutput(prevout)}) {
291 {
292 strHTML += "<li>";
293 const CTxOut& vout = prev->out;
294 CTxDestination address;
295 if (ExtractDestination(vout.scriptPubKey, address))
296 {
297 std::string name;
298 if (wallet.getAddress(address, &name, /*purpose=*/nullptr) && !name.empty())
300 strHTML += QString::fromStdString(EncodeDestination(address));
301 }
302 strHTML = strHTML + " " + tr("Amount") + "=" + BitcoinUnits::formatHtmlWithUnit(unit, vout.nValue);
303 strHTML = strHTML + " IsMine=" + (wallet.txoutIsMine(vout) ? tr("true") : tr("false")) + "</li>";
304 }
305 }
306 }
307
308 strHTML += "</ul>";
309 }
310
311 strHTML += "</font></html>";
312 return strHTML;
313}
bool ExtractDestination(const CScript &scriptPubKey, CTxDestination &addressRet)
Parse a scriptPubKey for the destination.
bool IsValidDestination(const CTxDestination &dest)
Check whether a CTxDestination corresponds to one with an address.
std::variant< CNoDestination, PubKeyDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessV1Taproot, PayToAnchor, WitnessUnknown > CTxDestination
A txout script categorized into standard templates.
int64_t CAmount
Amount in satoshis (Can be negative)
Definition amount.h:12
static QString formatHtmlWithUnit(Unit unit, const CAmount &amount, bool plussign=false, SeparatorStyle separators=SeparatorStyle::STANDARD)
Format as HTML string (with unit)
Unit
Bitcoin units.
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition transaction.h:30
An input of a transaction.
Definition transaction.h:63
An output of a transaction.
CScript scriptPubKey
CAmount nValue
static QString FormatTxStatus(const interfaces::WalletTxStatus &status, bool inMempool)
static QString toHTML(interfaces::Node &node, interfaces::Wallet &wallet, TransactionRecord *rec, BitcoinUnit unit)
UI model for a transaction.
int getOutputIndex() const
Return the output index of the subtransaction
QString getTxHash() const
Return the unique identifier for this transaction (part)
Top-level interface for a bitcoin node (bitcoind process).
Definition node.h:66
Interface for accessing a wallet.
Definition wallet.h:65
constexpr int COINBASE_MATURITY
Coinbase transaction outputs can only be spent after this number of new blocks (network rule)
Definition consensus.h:19
CTxDestination DecodeDestination(const std::string &str, std::string &error_msg, std::vector< int > *error_locations)
Definition key_io.cpp:297
std::string EncodeDestination(const CTxDestination &dest)
Definition key_io.cpp:292
QString HtmlEscape(const QString &str, bool fMultiLine)
Definition guiutil.cpp:249
QString dateTimeStr(const QDateTime &date)
Definition guiutil.cpp:90
int64_t GetVirtualTransactionSize(int64_t nWeight, int64_t nSigOpCost, unsigned int bytes_per_sigop)
Compute the virtual transaction size (weight reinterpreted as bytes).
Definition policy.cpp:395
const char * name
Definition rest.cpp:71
std::vector< bool > txin_is_mine
Definition wallet.h:396
std::optional< std::string > comment
Definition wallet.h:407
CTransactionRef tx
Definition wallet.h:395
std::optional< std::string > comment_to
Definition wallet.h:408
std::vector< bool > txout_is_mine
Definition wallet.h:397
std::optional< std::string > message
Definition wallet.h:406
std::optional< std::string > from
Definition wallet.h:405
Updated transaction status.
Definition wallet.h:416
constexpr auto Ticks(Dur2 d)
Helper to count the seconds of a duration/time_point.
Definition time.h:82