transactionrecord.cpp raw
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
5 #include <qt/transactionrecord.h>
6
7 #include <chain.h>
8 #include <interfaces/wallet.h>
9 #include <key_io.h>
10
11 #include <cstdint>
12
13 #include <QDateTime>
14
15 /* Return positive answer if transaction should be shown in list.
16 */
17 bool TransactionRecord::showTransaction()
18 {
19 // There are currently no cases where we hide transactions, but
20 // we may want to use this in the future for things like RBF.
21 return true;
22 }
23
24 /*
25 * Decompose CWallet transaction to model transaction records.
26 */
27 QList<TransactionRecord> TransactionRecord::decomposeTransaction(const interfaces::WalletTx& wtx)
28 {
29 QList<TransactionRecord> parts;
30 int64_t nTime = wtx.time;
31 CAmount nCredit = wtx.credit;
32 CAmount nDebit = wtx.debit;
33 CAmount nNet = nCredit - nDebit;
34 Txid hash = wtx.tx->GetHash();
35
36 bool all_from_me = true;
37 bool any_from_me = false;
38 if (wtx.is_coinbase) {
39 all_from_me = false;
40 } else {
41 for (const bool mine : wtx.txin_is_mine)
42 {
43 all_from_me = all_from_me && mine;
44 if (mine) any_from_me = true;
45 }
46 }
47
48 if (all_from_me || !any_from_me) {
49 CAmount nTxFee = nDebit - wtx.tx->GetValueOut();
50
51 for(unsigned int i = 0; i < wtx.tx->vout.size(); i++)
52 {
53 const CTxOut& txout = wtx.tx->vout[i];
54
55 if (all_from_me) {
56 // Change is only really possible if we're the sender
57 // Otherwise, someone just sent bitcoins to a change address, which should be shown
58 if (wtx.txout_is_change[i]) {
59 continue;
60 }
61
62 //
63 // Debit
64 //
65
66 TransactionRecord sub(hash, nTime);
67 sub.idx = i;
68
69 if (!std::get_if<CNoDestination>(&wtx.txout_address[i]))
70 {
71 // Sent to Bitcoin Address
72 sub.type = TransactionRecord::SendToAddress;
73 sub.address = EncodeDestination(wtx.txout_address[i]);
74 }
75 else
76 {
77 // Sent to IP, or other non-address transaction like OP_EVAL
78 sub.type = TransactionRecord::SendToOther;
79 sub.address = wtx.comment_to.value_or("");
80 }
81
82 CAmount nValue = txout.nValue;
83 /* Add fee to first output */
84 if (nTxFee > 0)
85 {
86 nValue += nTxFee;
87 nTxFee = 0;
88 }
89 sub.debit = -nValue;
90
91 parts.append(sub);
92 }
93
94 bool mine = wtx.txout_is_mine[i];
95 if(mine)
96 {
97 //
98 // Credit
99 //
100
101 TransactionRecord sub(hash, nTime);
102 sub.idx = i; // vout index
103 sub.credit = txout.nValue;
104 if (wtx.txout_address_is_mine[i])
105 {
106 // Received by Bitcoin Address
107 sub.type = TransactionRecord::RecvWithAddress;
108 sub.address = EncodeDestination(wtx.txout_address[i]);
109 }
110 else
111 {
112 // Received by IP connection (deprecated features), or a multisignature or other non-simple transaction
113 sub.type = TransactionRecord::RecvFromOther;
114 sub.address = wtx.from.value_or("");
115 }
116 if (wtx.is_coinbase)
117 {
118 // Generated
119 sub.type = TransactionRecord::Generated;
120 }
121
122 parts.append(sub);
123 }
124 }
125 } else {
126 //
127 // Mixed debit transaction, can't break down payees
128 //
129 parts.append(TransactionRecord(hash, nTime, TransactionRecord::Other, "", nNet, 0));
130 }
131
132 return parts;
133 }
134
135 void TransactionRecord::updateStatus(const interfaces::WalletTxStatus& wtx, const uint256& block_hash, int numBlocks, int64_t block_time)
136 {
137 // Determine transaction status
138
139 // Sort order, unrecorded transactions sort to the top
140 int typesort;
141 switch (type) {
142 case SendToAddress: case SendToOther:
143 typesort = 2; break;
144 case RecvWithAddress: case RecvFromOther:
145 typesort = 3; break;
146 default:
147 typesort = 9;
148 }
149 status.sortKey = strprintf("%010d-%01d-%010u-%03d-%d",
150 wtx.block_height,
151 wtx.is_coinbase ? 1 : 0,
152 wtx.time_received,
153 idx,
154 typesort);
155 status.countsForBalance = wtx.is_trusted && !(wtx.blocks_to_maturity > 0);
156 status.depth = wtx.depth_in_main_chain;
157 status.m_cur_block_hash = block_hash;
158
159 // For generated transactions, determine maturity
160 if (type == TransactionRecord::Generated) {
161 if (wtx.blocks_to_maturity > 0)
162 {
163 status.status = TransactionStatus::Immature;
164
165 if (wtx.is_in_main_chain)
166 {
167 status.matures_in = wtx.blocks_to_maturity;
168 }
169 else
170 {
171 status.status = TransactionStatus::NotAccepted;
172 }
173 }
174 else
175 {
176 status.status = TransactionStatus::Confirmed;
177 }
178 }
179 else
180 {
181 if (status.depth < 0)
182 {
183 status.status = TransactionStatus::Conflicted;
184 }
185 else if (status.depth == 0)
186 {
187 status.status = TransactionStatus::Unconfirmed;
188 if (wtx.is_abandoned)
189 status.status = TransactionStatus::Abandoned;
190 }
191 else if (status.depth < RecommendedNumConfirmations)
192 {
193 status.status = TransactionStatus::Confirming;
194 }
195 else
196 {
197 status.status = TransactionStatus::Confirmed;
198 }
199 }
200 status.needsUpdate = false;
201 }
202
203 bool TransactionRecord::statusUpdateNeeded(const uint256& block_hash) const
204 {
205 assert(!block_hash.IsNull());
206 return status.m_cur_block_hash != block_hash || status.needsUpdate;
207 }
208
209 QString TransactionRecord::getTxHash() const
210 {
211 return QString::fromStdString(hash.ToString());
212 }
213
214 int TransactionRecord::getOutputIndex() const
215 {
216 return idx;
217 }
218