Branch data Line data Source code
1 : : // Copyright (c) 2021-2022 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 <consensus/amount.h>
6 : : #include <consensus/consensus.h>
7 : : #include <wallet/receive.h>
8 : : #include <wallet/transaction.h>
9 : : #include <wallet/wallet.h>
10 : :
11 : : namespace wallet {
12 : 973 : isminetype InputIsMine(const CWallet& wallet, const CTxIn& txin)
13 : : {
14 : 973 : AssertLockHeld(wallet.cs_wallet);
15 : 973 : const CWalletTx* prev = wallet.GetWalletTx(txin.prevout.hash);
16 [ + + + - ]: 973 : if (prev && txin.prevout.n < prev->tx->vout.size()) {
17 : 563 : return wallet.IsMine(prev->tx->vout[txin.prevout.n]);
18 : : }
19 : : return ISMINE_NO;
20 : : }
21 : :
22 : 223 : bool AllInputsMine(const CWallet& wallet, const CTransaction& tx, const isminefilter& filter)
23 : : {
24 : 223 : LOCK(wallet.cs_wallet);
25 [ + + ]: 752 : for (const CTxIn& txin : tx.vin) {
26 [ + - + + ]: 531 : if (!(InputIsMine(wallet, txin) & filter)) return false;
27 : : }
28 : : return true;
29 : 223 : }
30 : :
31 : 102092 : CAmount OutputGetCredit(const CWallet& wallet, const CTxOut& txout, const isminefilter& filter)
32 : : {
33 [ - + ]: 102092 : if (!MoneyRange(txout.nValue))
34 [ # # # # ]: 0 : throw std::runtime_error(std::string(__func__) + ": value out of range");
35 : 102092 : LOCK(wallet.cs_wallet);
36 [ + - + + : 102092 : return ((wallet.IsMine(txout) & filter) ? txout.nValue : 0);
+ - ]
37 : 102092 : }
38 : :
39 : 19745 : CAmount TxGetCredit(const CWallet& wallet, const CTransaction& tx, const isminefilter& filter)
40 : : {
41 : 19745 : CAmount nCredit = 0;
42 [ + + ]: 59179 : for (const CTxOut& txout : tx.vout)
43 : : {
44 : 39434 : nCredit += OutputGetCredit(wallet, txout, filter);
45 [ - + ]: 39434 : if (!MoneyRange(nCredit))
46 [ # # # # ]: 0 : throw std::runtime_error(std::string(__func__) + ": value out of range");
47 : : }
48 : 19745 : return nCredit;
49 : : }
50 : :
51 : 4350 : bool ScriptIsChange(const CWallet& wallet, const CScript& script)
52 : : {
53 : : // TODO: fix handling of 'change' outputs. The assumption is that any
54 : : // payment to a script that is ours, but is not in the address book
55 : : // is change. That assumption is likely to break when we implement multisignature
56 : : // wallets that return change back into a multi-signature-protected address;
57 : : // a better way of identifying which outputs are 'the send' and which are
58 : : // 'the change' will need to be implemented (maybe extend CWalletTx to remember
59 : : // which output, if any, was change).
60 : 4350 : AssertLockHeld(wallet.cs_wallet);
61 [ + + ]: 4350 : if (wallet.IsMine(script))
62 : : {
63 : 2820 : CTxDestination address;
64 [ + - + + ]: 2820 : if (!ExtractDestination(script, address))
65 : : return true;
66 [ + - + + ]: 2815 : if (!wallet.FindAddressBookEntry(address)) {
67 : : return true;
68 : : }
69 : 2820 : }
70 : : return false;
71 : : }
72 : :
73 : 2731 : bool OutputIsChange(const CWallet& wallet, const CTxOut& txout)
74 : : {
75 : 2731 : return ScriptIsChange(wallet, txout.scriptPubKey);
76 : : }
77 : :
78 : 0 : CAmount OutputGetChange(const CWallet& wallet, const CTxOut& txout)
79 : : {
80 : 0 : AssertLockHeld(wallet.cs_wallet);
81 [ # # ]: 0 : if (!MoneyRange(txout.nValue))
82 [ # # # # ]: 0 : throw std::runtime_error(std::string(__func__) + ": value out of range");
83 [ # # ]: 0 : return (OutputIsChange(wallet, txout) ? txout.nValue : 0);
84 : : }
85 : :
86 : 0 : CAmount TxGetChange(const CWallet& wallet, const CTransaction& tx)
87 : : {
88 : 0 : LOCK(wallet.cs_wallet);
89 : 0 : CAmount nChange = 0;
90 [ # # ]: 0 : for (const CTxOut& txout : tx.vout)
91 : : {
92 [ # # ]: 0 : nChange += OutputGetChange(wallet, txout);
93 [ # # ]: 0 : if (!MoneyRange(nChange))
94 [ # # # # ]: 0 : throw std::runtime_error(std::string(__func__) + ": value out of range");
95 : : }
96 [ # # ]: 0 : return nChange;
97 : 0 : }
98 : :
99 : 1250738 : static CAmount GetCachableAmount(const CWallet& wallet, const CWalletTx& wtx, CWalletTx::AmountType type, const isminefilter& filter)
100 : : {
101 : 1250738 : auto& amount = wtx.m_amounts[type];
102 [ + + ]: 1250738 : if (!amount.m_cached[filter]) {
103 [ + + ]: 68204 : amount.Set(filter, type == CWalletTx::DEBIT ? wallet.GetDebit(*wtx.tx, filter) : TxGetCredit(wallet, *wtx.tx, filter));
104 : 68204 : wtx.m_is_cache_empty = false;
105 : : }
106 : 1250738 : return amount.m_value[filter];
107 : : }
108 : :
109 : 683 : CAmount CachedTxGetCredit(const CWallet& wallet, const CWalletTx& wtx, const isminefilter& filter)
110 : : {
111 : 683 : AssertLockHeld(wallet.cs_wallet);
112 : :
113 : : // Must wait until coinbase is safely deep enough in the chain before valuing it
114 [ + + ]: 683 : if (wallet.IsTxImmatureCoinBase(wtx))
115 : : return 0;
116 : :
117 : 672 : CAmount credit = 0;
118 : 672 : const isminefilter get_amount_filter{filter & ISMINE_ALL};
119 [ + - ]: 672 : if (get_amount_filter) {
120 : : // GetBalance can assume transactions in mapWallet won't change
121 : 672 : credit += GetCachableAmount(wallet, wtx, CWalletTx::CREDIT, get_amount_filter);
122 : : }
123 : : return credit;
124 : : }
125 : :
126 : 1152526 : CAmount CachedTxGetDebit(const CWallet& wallet, const CWalletTx& wtx, const isminefilter& filter)
127 : : {
128 [ + - ]: 1152526 : if (wtx.tx->vin.empty())
129 : : return 0;
130 : :
131 : 1152526 : CAmount debit = 0;
132 : 1152526 : const isminefilter get_amount_filter{filter & ISMINE_ALL};
133 [ + - ]: 1152526 : if (get_amount_filter) {
134 : 1152526 : debit += GetCachableAmount(wallet, wtx, CWalletTx::DEBIT, get_amount_filter);
135 : : }
136 : : return debit;
137 : : }
138 : :
139 : 0 : CAmount CachedTxGetChange(const CWallet& wallet, const CWalletTx& wtx)
140 : : {
141 [ # # ]: 0 : if (wtx.fChangeCached)
142 : 0 : return wtx.nChangeCached;
143 : 0 : wtx.nChangeCached = TxGetChange(wallet, *wtx.tx);
144 : 0 : wtx.fChangeCached = true;
145 : 0 : return wtx.nChangeCached;
146 : : }
147 : :
148 : 325844 : CAmount CachedTxGetImmatureCredit(const CWallet& wallet, const CWalletTx& wtx, const isminefilter& filter)
149 : : {
150 : 325844 : AssertLockHeld(wallet.cs_wallet);
151 : :
152 [ + + ]: 325844 : if (wallet.IsTxImmatureCoinBase(wtx) && wtx.isConfirmed()) {
153 : 97540 : return GetCachableAmount(wallet, wtx, CWalletTx::IMMATURE_CREDIT, filter);
154 : : }
155 : :
156 : : return 0;
157 : : }
158 : :
159 : 325845 : CAmount CachedTxGetAvailableCredit(const CWallet& wallet, const CWalletTx& wtx, const isminefilter& filter)
160 : : {
161 : 325845 : AssertLockHeld(wallet.cs_wallet);
162 : :
163 : : // Avoid caching ismine for NO or ALL cases (could remove this check and simplify in the future).
164 : 325845 : bool allow_cache = (filter & ISMINE_ALL) && (filter & ISMINE_ALL) != ISMINE_ALL;
165 : :
166 : : // Must wait until coinbase is safely deep enough in the chain before valuing it
167 [ + + ]: 325845 : if (wallet.IsTxImmatureCoinBase(wtx))
168 : : return 0;
169 : :
170 [ + - + + : 419573 : if (allow_cache && wtx.m_amounts[CWalletTx::AVAILABLE_CREDIT].m_cached[filter]) {
+ + ]
171 : 191612 : return wtx.m_amounts[CWalletTx::AVAILABLE_CREDIT].m_value[filter];
172 : : }
173 : :
174 [ + + + + ]: 36349 : bool allow_used_addresses = (filter & ISMINE_USED) || !wallet.IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE);
175 : 36349 : CAmount nCredit = 0;
176 : 36349 : Txid hashTx = wtx.GetHash();
177 [ + + ]: 119864 : for (unsigned int i = 0; i < wtx.tx->vout.size(); i++) {
178 : 83515 : const CTxOut& txout = wtx.tx->vout[i];
179 [ + + + + : 83515 : if (!wallet.IsSpent(COutPoint(hashTx, i)) && (allow_used_addresses || !wallet.IsSpentKey(txout.scriptPubKey))) {
+ + ]
180 : 62658 : nCredit += OutputGetCredit(wallet, txout, filter);
181 [ - + ]: 62658 : if (!MoneyRange(nCredit))
182 [ # # # # ]: 0 : throw std::runtime_error(std::string(__func__) + " : value out of range");
183 : : }
184 : : }
185 : :
186 [ + - ]: 36349 : if (allow_cache) {
187 : 36349 : wtx.m_amounts[CWalletTx::AVAILABLE_CREDIT].Set(filter, nCredit);
188 : 36349 : wtx.m_is_cache_empty = false;
189 : : }
190 : :
191 : : return nCredit;
192 : : }
193 : :
194 : 23704 : void CachedTxGetAmounts(const CWallet& wallet, const CWalletTx& wtx,
195 : : std::list<COutputEntry>& listReceived,
196 : : std::list<COutputEntry>& listSent, CAmount& nFee, const isminefilter& filter,
197 : : bool include_change)
198 : : {
199 : 23704 : nFee = 0;
200 : 23704 : listReceived.clear();
201 : 23704 : listSent.clear();
202 : :
203 : : // Compute fee:
204 : 23704 : CAmount nDebit = CachedTxGetDebit(wallet, wtx, filter);
205 [ + + ]: 23704 : if (nDebit > 0) // debit>0 means we signed/sent this transaction
206 : : {
207 : 1330 : CAmount nValueOut = wtx.tx->GetValueOut();
208 : 1330 : nFee = nDebit - nValueOut;
209 : : }
210 : :
211 : 23704 : LOCK(wallet.cs_wallet);
212 : : // Sent/received.
213 [ + + ]: 70715 : for (unsigned int i = 0; i < wtx.tx->vout.size(); ++i)
214 : : {
215 [ + - ]: 47011 : const CTxOut& txout = wtx.tx->vout[i];
216 [ + - ]: 47011 : isminetype fIsMine = wallet.IsMine(txout);
217 : : // Only need to handle txouts if AT LEAST one of these is true:
218 : : // 1) they debit from us (sent)
219 : : // 2) the output is to us (received)
220 [ + + ]: 47011 : if (nDebit > 0)
221 : : {
222 [ + + + - : 2274 : if (!include_change && OutputIsChange(wallet, txout))
+ + ]
223 : 727 : continue;
224 : : }
225 [ + + ]: 44737 : else if (!(fIsMine & filter))
226 : 22388 : continue;
227 : :
228 : : // In either case, we need to get the destination address
229 : 23896 : CTxDestination address;
230 : :
231 [ + - + + : 23896 : if (!ExtractDestination(txout.scriptPubKey, address) && !txout.scriptPubKey.IsUnspendable())
- + ]
232 : : {
233 [ # # ]: 0 : wallet.WalletLogPrintf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n",
234 [ # # # # ]: 0 : wtx.GetHash().ToString());
235 : 0 : address = CNoDestination();
236 : : }
237 : :
238 [ + - ]: 23896 : COutputEntry output = {address, txout.nValue, (int)i};
239 : :
240 : : // If we are debited by the transaction, add the output as a "sent" entry
241 [ + + ]: 23896 : if (nDebit > 0)
242 [ + - ]: 1547 : listSent.push_back(output);
243 : :
244 : : // If we are receiving the output, add it as a "received" entry
245 [ + + ]: 23896 : if (fIsMine & filter)
246 [ + - ]: 22753 : listReceived.push_back(output);
247 : 23896 : }
248 : :
249 : 23704 : }
250 : :
251 : 1128139 : bool CachedTxIsFromMe(const CWallet& wallet, const CWalletTx& wtx, const isminefilter& filter)
252 : : {
253 : 1128139 : return (CachedTxGetDebit(wallet, wtx, filter) > 0);
254 : : }
255 : :
256 : : // NOLINTNEXTLINE(misc-no-recursion)
257 : 1248456 : bool CachedTxIsTrusted(const CWallet& wallet, const CWalletTx& wtx, std::set<uint256>& trusted_parents)
258 : : {
259 : 1248456 : AssertLockHeld(wallet.cs_wallet);
260 [ + + ]: 1248456 : if (wtx.isConfirmed()) return true;
261 [ + + ]: 181764 : if (wtx.isBlockConflicted()) return false;
262 : : // using wtx's cached debit
263 [ + + + + ]: 181613 : if (!wallet.m_spend_zero_conf_change || !CachedTxIsFromMe(wallet, wtx, ISMINE_ALL)) return false;
264 : :
265 : : // Don't trust unconfirmed transactions from us unless they are in the mempool.
266 [ + + ]: 176186 : if (!wtx.InMempool()) return false;
267 : :
268 : : // Trusted if all inputs are from us and are in the mempool:
269 [ + + ]: 363019 : for (const CTxIn& txin : wtx.tx->vin)
270 : : {
271 : : // Transactions not sent by us: not trusted
272 : 187808 : const CWalletTx* parent = wallet.GetWalletTx(txin.prevout.hash);
273 [ + + ]: 187808 : if (parent == nullptr) return false;
274 : 187790 : const CTxOut& parentOut = parent->tx->vout[txin.prevout.n];
275 : : // Check that this specific input being spent is trusted
276 [ + + ]: 187790 : if (wallet.IsMine(parentOut) != ISMINE_SPENDABLE) return false;
277 : : // If we've already trusted this parent, continue
278 [ + + ]: 187724 : if (trusted_parents.count(parent->GetHash())) continue;
279 : : // Recurse to check that the parent is also trusted
280 [ + + ]: 152543 : if (!CachedTxIsTrusted(wallet, *parent, trusted_parents)) return false;
281 : 151845 : trusted_parents.insert(parent->GetHash());
282 : : }
283 : : return true;
284 : : }
285 : :
286 : 1274 : bool CachedTxIsTrusted(const CWallet& wallet, const CWalletTx& wtx)
287 : : {
288 [ + - ]: 1274 : std::set<uint256> trusted_parents;
289 [ + - ]: 1274 : LOCK(wallet.cs_wallet);
290 [ + - + - ]: 1274 : return CachedTxIsTrusted(wallet, wtx, trusted_parents);
291 : 1274 : }
292 : :
293 : 3194 : Balance GetBalance(const CWallet& wallet, const int min_depth, bool avoid_reuse)
294 : : {
295 : 3194 : Balance ret;
296 [ + + ]: 3194 : isminefilter reuse_filter = avoid_reuse ? ISMINE_NO : ISMINE_USED;
297 : 3194 : {
298 : 3194 : LOCK(wallet.cs_wallet);
299 : 3194 : std::set<uint256> trusted_parents;
300 [ + + ]: 166115 : for (const auto& entry : wallet.mapWallet)
301 : : {
302 : 162921 : const CWalletTx& wtx = entry.second;
303 [ + - ]: 162921 : const bool is_trusted{CachedTxIsTrusted(wallet, wtx, trusted_parents)};
304 [ + - ]: 162921 : const int tx_depth{wallet.GetTxDepthInMainChain(wtx)};
305 [ + - ]: 162921 : const CAmount tx_credit_mine{CachedTxGetAvailableCredit(wallet, wtx, ISMINE_SPENDABLE | reuse_filter)};
306 [ + - ]: 162921 : const CAmount tx_credit_watchonly{CachedTxGetAvailableCredit(wallet, wtx, ISMINE_WATCH_ONLY | reuse_filter)};
307 [ + + ]: 162921 : if (is_trusted && tx_depth >= min_depth) {
308 : 161523 : ret.m_mine_trusted += tx_credit_mine;
309 : 161523 : ret.m_watchonly_trusted += tx_credit_watchonly;
310 : : }
311 [ + + + - : 162921 : if (!is_trusted && tx_depth == 0 && wtx.InMempool()) {
+ + ]
312 : 997 : ret.m_mine_untrusted_pending += tx_credit_mine;
313 : 997 : ret.m_watchonly_untrusted_pending += tx_credit_watchonly;
314 : : }
315 [ + - ]: 162921 : ret.m_mine_immature += CachedTxGetImmatureCredit(wallet, wtx, ISMINE_SPENDABLE);
316 [ + - ]: 162921 : ret.m_watchonly_immature += CachedTxGetImmatureCredit(wallet, wtx, ISMINE_WATCH_ONLY);
317 : : }
318 [ + - ]: 3194 : }
319 : 3194 : return ret;
320 : : }
321 : :
322 : 6 : std::map<CTxDestination, CAmount> GetAddressBalances(const CWallet& wallet)
323 : : {
324 [ + - ]: 6 : std::map<CTxDestination, CAmount> balances;
325 : :
326 : 6 : {
327 [ + - ]: 6 : LOCK(wallet.cs_wallet);
328 : 6 : std::set<uint256> trusted_parents;
329 [ + + ]: 446 : for (const auto& walletEntry : wallet.mapWallet)
330 : : {
331 : 440 : const CWalletTx& wtx = walletEntry.second;
332 : :
333 [ + - - + ]: 440 : if (!CachedTxIsTrusted(wallet, wtx, trusted_parents))
334 : 0 : continue;
335 : :
336 [ + - + + ]: 440 : if (wallet.IsTxImmatureCoinBase(wtx))
337 : 400 : continue;
338 : :
339 [ + - ]: 40 : int nDepth = wallet.GetTxDepthInMainChain(wtx);
340 [ + - + + : 68 : if (nDepth < (CachedTxIsFromMe(wallet, wtx, ISMINE_ALL) ? 0 : 1))
+ - ]
341 : 0 : continue;
342 : :
343 [ + + ]: 118 : for (unsigned int i = 0; i < wtx.tx->vout.size(); i++) {
344 [ + - ]: 78 : const auto& output = wtx.tx->vout[i];
345 : 78 : CTxDestination addr;
346 [ + - + + ]: 78 : if (!wallet.IsMine(output))
347 : 40 : continue;
348 [ + - - + ]: 38 : if(!ExtractDestination(output.scriptPubKey, addr))
349 : 0 : continue;
350 : :
351 [ + - + + ]: 38 : CAmount n = wallet.IsSpent(COutPoint(Txid::FromUint256(walletEntry.first), i)) ? 0 : output.nValue;
352 [ + - ]: 38 : balances[addr] += n;
353 : 78 : }
354 : : }
355 [ + - ]: 6 : }
356 : :
357 : 6 : return balances;
358 : 0 : }
359 : :
360 : 6 : std::set< std::set<CTxDestination> > GetAddressGroupings(const CWallet& wallet)
361 : : {
362 : 6 : AssertLockHeld(wallet.cs_wallet);
363 : 6 : std::set< std::set<CTxDestination> > groupings;
364 : 6 : std::set<CTxDestination> grouping;
365 : :
366 [ + + ]: 446 : for (const auto& walletEntry : wallet.mapWallet)
367 : : {
368 : 440 : const CWalletTx& wtx = walletEntry.second;
369 : :
370 [ + - ]: 440 : if (wtx.tx->vin.size() > 0)
371 : : {
372 : 440 : bool any_mine = false;
373 : : // group all input addresses with each other
374 [ + + ]: 882 : for (const CTxIn& txin : wtx.tx->vin)
375 : : {
376 : 442 : CTxDestination address;
377 [ + - + + ]: 442 : if(!InputIsMine(wallet, txin)) /* If this input isn't mine, ignore it */
378 : 428 : continue;
379 [ + - + - : 14 : if(!ExtractDestination(wallet.mapWallet.at(txin.prevout.hash).tx->vout[txin.prevout.n].scriptPubKey, address))
- + ]
380 : 0 : continue;
381 [ + - ]: 14 : grouping.insert(address);
382 : 14 : any_mine = true;
383 : 442 : }
384 : :
385 : : // group change with input addresses
386 [ + + ]: 440 : if (any_mine)
387 : : {
388 [ + + ]: 34 : for (const CTxOut& txout : wtx.tx->vout)
389 [ + - + + ]: 22 : if (OutputIsChange(wallet, txout))
390 : : {
391 : 10 : CTxDestination txoutAddr;
392 [ + - - + ]: 10 : if(!ExtractDestination(txout.scriptPubKey, txoutAddr))
393 : 0 : continue;
394 [ + - ]: 10 : grouping.insert(txoutAddr);
395 : 10 : }
396 : : }
397 [ + + ]: 440 : if (grouping.size() > 0)
398 : : {
399 [ + - ]: 12 : groupings.insert(grouping);
400 : 12 : grouping.clear();
401 : : }
402 : : }
403 : :
404 : : // group lone addrs by themselves
405 [ + + ]: 1318 : for (const auto& txout : wtx.tx->vout)
406 [ + - + + ]: 878 : if (wallet.IsMine(txout))
407 : : {
408 : 438 : CTxDestination address;
409 [ + - - + ]: 438 : if(!ExtractDestination(txout.scriptPubKey, address))
410 : 0 : continue;
411 [ + - ]: 438 : grouping.insert(address);
412 [ + - ]: 438 : groupings.insert(grouping);
413 : 438 : grouping.clear();
414 : 438 : }
415 : : }
416 : :
417 : 6 : std::set< std::set<CTxDestination>* > uniqueGroupings; // a set of pointers to groups of addresses
418 : 6 : std::map< CTxDestination, std::set<CTxDestination>* > setmap; // map addresses to the unique group containing it
419 [ + + ]: 56 : for (const std::set<CTxDestination>& _grouping : groupings)
420 : : {
421 : : // make a set of all the groups hit by this new group
422 : 50 : std::set< std::set<CTxDestination>* > hits;
423 : 50 : std::map< CTxDestination, std::set<CTxDestination>* >::iterator it;
424 [ + + ]: 112 : for (const CTxDestination& address : _grouping)
425 [ + + ]: 62 : if ((it = setmap.find(address)) != setmap.end())
426 [ + - ]: 24 : hits.insert((*it).second);
427 : :
428 : : // merge all hit groups into a new single group and delete old groups
429 [ + - + - ]: 50 : std::set<CTxDestination>* merged = new std::set<CTxDestination>(_grouping);
430 [ + + ]: 74 : for (std::set<CTxDestination>* hit : hits)
431 : : {
432 [ + - ]: 24 : merged->insert(hit->begin(), hit->end());
433 : 24 : uniqueGroupings.erase(hit);
434 [ + - ]: 48 : delete hit;
435 : : }
436 [ + - ]: 50 : uniqueGroupings.insert(merged);
437 : :
438 : : // update setmap
439 [ + + ]: 124 : for (const CTxDestination& element : *merged)
440 [ + - ]: 74 : setmap[element] = merged;
441 : 50 : }
442 : :
443 : 6 : std::set< std::set<CTxDestination> > ret;
444 [ + + ]: 32 : for (const std::set<CTxDestination>* uniqueGrouping : uniqueGroupings)
445 : : {
446 [ + - ]: 26 : ret.insert(*uniqueGrouping);
447 [ + - ]: 52 : delete uniqueGrouping;
448 : : }
449 : :
450 : 6 : return ret;
451 : 6 : }
452 : : } // namespace wallet
|