Skip to content
Bitcoin Roots

v29.4-roots.3 · Commit 25: [PATCH 25/30] feat(wallet): expose advanced coin control facts

src/wallet/interfaces.cpp

Before: src/wallet/interfaces.cpp · After: src/wallet/interfaces.cpp

File metadata
index 10bbd25e6dc0e4eb6401c6b910de9a6db0c0cc6c..8294d1a3cc1534031a41b2ef3332c300dec02f33 100644

Download original patch · Release notes

Diff rows 1–88 of 88. Line numbers refer to the original before/after files.

+ Added− RemovedUnmarked lines are context.

Scroll the code area horizontally to read long lines. Before is on the left; after is on the right. Unified view fits narrow screens more easily.

src/wallet/interfaces.cpp CHANGED
@@ -119,10 +119,23 @@ WalletTxOut MakeWalletTxOut(const CWallet& wallet,
119
  int depth) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
120
  {
121
  WalletTxOut result;
 
122
  result.txout = wtx.tx->vout[n];
123
  result.time = wtx.GetTxTime();
124
  result.depth_in_main_chain = depth;
125
- result.is_spent = wallet.IsSpent(COutPoint(wtx.GetHash(), n));
 
 
 
 
 
 
 
 
 
 
 
 
126
  return result;
127
  }
128
 
@@ -130,10 +143,31 @@ WalletTxOut MakeWalletTxOut(const CWallet& wallet,
130
  const COutput& output) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
131
  {
132
  WalletTxOut result;
 
133
  result.txout = output.txout;
134
  result.time = output.time;
135
  result.depth_in_main_chain = output.depth;
136
  result.is_spent = wallet.IsSpent(output.outpoint);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
137
  return result;
138
  }
139
 
@@ -527,13 +561,32 @@ public:
527
  }
528
  return result;
529
  }
530
- std::vector<WalletTxOut> getCoins(const std::vector<COutPoint>& outputs) override
531
  {
532
  LOCK(m_wallet->cs_wallet);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
533
  std::vector<WalletTxOut> result;
534
  result.reserve(outputs.size());
535
  for (const auto& output : outputs) {
 
 
 
 
536
  result.emplace_back();
 
537
  auto it = m_wallet->mapWallet.find(output.hash);
538
  if (it != m_wallet->mapWallet.end()) {
539
  int depth = m_wallet->GetTxDepthInMainChain(it->second);
 
119
  int depth) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
120
  {
121
  WalletTxOut result;
122
+ result.outpoint = COutPoint{wtx.GetHash(), static_cast<uint32_t>(n)};
123
  result.txout = wtx.tx->vout[n];
124
  result.time = wtx.GetTxTime();
125
  result.depth_in_main_chain = depth;
126
+ result.is_spent = wallet.IsSpent(result.outpoint);
127
+ result.is_locked = wallet.IsLockedCoin(result.outpoint);
128
+ result.is_reused = wallet.IsSpentKey(result.txout.scriptPubKey);
129
+ result.is_immature = wallet.IsTxImmatureCoinBase(wtx);
130
+ result.is_change = OutputIsChange(wallet, result.txout);
131
+ ExtractDestination(result.txout.scriptPubKey, result.address);
132
+ if (const auto* entry = wallet.FindAddressBookEntry(result.address)) {
133
+ result.label = entry->GetLabel();
134
+ }
135
+ CTxDestination grouping_address;
136
+ if (ExtractDestination(FindNonChangeParentOutput(wallet, result.outpoint).scriptPubKey, grouping_address)) {
137
+ result.grouping_address = grouping_address;
138
+ }
139
  return result;
140
  }
141
 
 
143
  const COutput& output) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
144
  {
145
  WalletTxOut result;
146
+ result.outpoint = output.outpoint;
147
  result.txout = output.txout;
148
  result.time = output.time;
149
  result.depth_in_main_chain = output.depth;
150
  result.is_spent = wallet.IsSpent(output.outpoint);
151
+ result.input_bytes = output.input_bytes;
152
+ if (output.HasEffectiveValue()) result.effective_value = output.GetEffectiveValue();
153
+ result.ancestor_bump_fees = output.ancestor_bump_fees;
154
+ result.is_spendable = output.spendable;
155
+ result.is_solvable = output.solvable;
156
+ result.is_safe = output.safe;
157
+ result.is_locked = wallet.IsLockedCoin(output.outpoint);
158
+ result.is_reused = wallet.IsSpentKey(output.txout.scriptPubKey);
159
+ if (const CWalletTx* wtx = wallet.GetWalletTx(output.outpoint.hash)) {
160
+ result.is_immature = wallet.IsTxImmatureCoinBase(*wtx);
161
+ }
162
+ result.is_change = OutputIsChange(wallet, output.txout);
163
+ ExtractDestination(output.txout.scriptPubKey, result.address);
164
+ if (const auto* entry = wallet.FindAddressBookEntry(result.address)) {
165
+ result.label = entry->GetLabel();
166
+ }
167
+ CTxDestination grouping_address;
168
+ if (ExtractDestination(FindNonChangeParentOutput(wallet, output.outpoint).scriptPubKey, grouping_address)) {
169
+ result.grouping_address = grouping_address;
170
+ }
171
  return result;
172
  }
173
 
 
561
  }
562
  return result;
563
  }
564
+ std::vector<WalletTxOut> getCoins(const std::vector<COutPoint>& outputs, const std::optional<CFeeRate>& feerate) override
565
  {
566
  LOCK(m_wallet->cs_wallet);
567
+ CCoinControl coin_control;
568
+ // Expose factual state rather than applying a caller's transaction
569
+ // policy. In particular, dirty, locked, unsafe, watch-only, and
570
+ // immature coins need to be inspectable even when not selectable.
571
+ coin_control.m_avoid_address_reuse = false;
572
+ CoinFilterParams params;
573
+ params.only_spendable = false;
574
+ params.include_immature_coinbase = true;
575
+ params.skip_locked = false;
576
+ std::map<COutPoint, COutput> available_coins;
577
+ for (const COutput& coin : AvailableCoins(*m_wallet, &coin_control, feerate, params).All()) {
578
+ available_coins.emplace(coin.outpoint, coin);
579
+ }
580
+
581
  std::vector<WalletTxOut> result;
582
  result.reserve(outputs.size());
583
  for (const auto& output : outputs) {
584
+ if (const auto coin = available_coins.find(output); coin != available_coins.end()) {
585
+ result.emplace_back(MakeWalletTxOut(*m_wallet, coin->second));
586
+ continue;
587
+ }
588
  result.emplace_back();
589
+ result.back().outpoint = output;
590
  auto it = m_wallet->mapWallet.find(output.hash);
591
  if (it != m_wallet->mapWallet.end()) {
592
  int depth = m_wallet->GetTxDepthInMainChain(it->second);