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