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