Skip to content
Bitcoin Roots

v30.3-roots.1 · Commit 25: [PATCH 25/68] feat(wallet): expose advanced coin control facts

src/wallet/interfaces.cpp

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

File metadata
index fe27c0b897c33dd2f5b51857fd891cacd66c0c4e..b1daafb60b88755b329a528532ccc1b58731f907 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
@@ -118,10 +118,23 @@ WalletTxOut MakeWalletTxOut(const CWallet& wallet,
118
  int depth) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
119
  {
120
  WalletTxOut result;
 
121
  result.txout = wtx.tx->vout[n];
122
  result.time = wtx.GetTxTime();
123
  result.depth_in_main_chain = depth;
124
- result.is_spent = wallet.IsSpent(COutPoint(wtx.GetHash(), n));
 
 
 
 
 
 
 
 
 
 
 
 
125
  return result;
126
  }
127
 
@@ -129,10 +142,31 @@ WalletTxOut MakeWalletTxOut(const CWallet& wallet,
129
  const COutput& output) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
130
  {
131
  WalletTxOut result;
 
132
  result.txout = output.txout;
133
  result.time = output.time;
134
  result.depth_in_main_chain = output.depth;
135
  result.is_spent = wallet.IsSpent(output.outpoint);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
136
  return result;
137
  }
138
 
@@ -502,13 +536,32 @@ public:
502
  }
503
  return result;
504
  }
505
- std::vector<WalletTxOut> getCoins(const std::vector<COutPoint>& outputs) override
506
  {
507
  LOCK(m_wallet->cs_wallet);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
508
  std::vector<WalletTxOut> result;
509
  result.reserve(outputs.size());
510
  for (const auto& output : outputs) {
 
 
 
 
511
  result.emplace_back();
 
512
  auto it = m_wallet->mapWallet.find(output.hash);
513
  if (it != m_wallet->mapWallet.end()) {
514
  int depth = m_wallet->GetTxDepthInMainChain(it->second);
 
118
  int depth) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
119
  {
120
  WalletTxOut result;
121
+ result.outpoint = COutPoint{wtx.GetHash(), static_cast<uint32_t>(n)};
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(result.outpoint);
126
+ result.is_locked = wallet.IsLockedCoin(result.outpoint);
127
+ result.is_reused = wallet.IsSpentKey(result.txout.scriptPubKey);
128
+ result.is_immature = wallet.IsTxImmatureCoinBase(wtx);
129
+ result.is_change = OutputIsChange(wallet, result.txout);
130
+ ExtractDestination(result.txout.scriptPubKey, result.address);
131
+ if (const auto* entry = wallet.FindAddressBookEntry(result.address)) {
132
+ result.label = entry->GetLabel();
133
+ }
134
+ CTxDestination grouping_address;
135
+ if (ExtractDestination(FindNonChangeParentOutput(wallet, result.outpoint).scriptPubKey, grouping_address)) {
136
+ result.grouping_address = grouping_address;
137
+ }
138
  return result;
139
  }
140
 
 
142
  const COutput& output) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
143
  {
144
  WalletTxOut result;
145
+ result.outpoint = output.outpoint;
146
  result.txout = output.txout;
147
  result.time = output.time;
148
  result.depth_in_main_chain = output.depth;
149
  result.is_spent = wallet.IsSpent(output.outpoint);
150
+ result.input_bytes = output.input_bytes;
151
+ if (output.HasEffectiveValue()) result.effective_value = output.GetEffectiveValue();
152
+ result.ancestor_bump_fees = output.ancestor_bump_fees;
153
+ result.is_spendable = wallet.IsMine(output.txout);
154
+ result.is_solvable = output.solvable;
155
+ result.is_safe = output.safe;
156
+ result.is_locked = wallet.IsLockedCoin(output.outpoint);
157
+ result.is_reused = wallet.IsSpentKey(output.txout.scriptPubKey);
158
+ if (const CWalletTx* wtx = wallet.GetWalletTx(output.outpoint.hash)) {
159
+ result.is_immature = wallet.IsTxImmatureCoinBase(*wtx);
160
+ }
161
+ result.is_change = OutputIsChange(wallet, output.txout);
162
+ ExtractDestination(output.txout.scriptPubKey, result.address);
163
+ if (const auto* entry = wallet.FindAddressBookEntry(result.address)) {
164
+ result.label = entry->GetLabel();
165
+ }
166
+ CTxDestination grouping_address;
167
+ if (ExtractDestination(FindNonChangeParentOutput(wallet, output.outpoint).scriptPubKey, grouping_address)) {
168
+ result.grouping_address = grouping_address;
169
+ }
170
  return result;
171
  }
172
 
 
536
  }
537
  return result;
538
  }
539
+ std::vector<WalletTxOut> getCoins(const std::vector<COutPoint>& outputs, const std::optional<CFeeRate>& feerate) override
540
  {
541
  LOCK(m_wallet->cs_wallet);
542
+ CCoinControl coin_control;
543
+ // Expose factual state rather than applying a caller's transaction
544
+ // policy. In particular, dirty, locked, unsafe, watch-only, and
545
+ // immature coins need to be inspectable even when not selectable.
546
+ coin_control.m_avoid_address_reuse = false;
547
+ CoinFilterParams params;
548
+ params.check_version_trucness = false;
549
+ params.include_immature_coinbase = true;
550
+ params.skip_locked = false;
551
+ std::map<COutPoint, COutput> available_coins;
552
+ for (const COutput& coin : AvailableCoins(*m_wallet, &coin_control, feerate, params).All()) {
553
+ available_coins.emplace(coin.outpoint, coin);
554
+ }
555
+
556
  std::vector<WalletTxOut> result;
557
  result.reserve(outputs.size());
558
  for (const auto& output : outputs) {
559
+ if (const auto coin = available_coins.find(output); coin != available_coins.end()) {
560
+ result.emplace_back(MakeWalletTxOut(*m_wallet, coin->second));
561
+ continue;
562
+ }
563
  result.emplace_back();
564
+ result.back().outpoint = output;
565
  auto it = m_wallet->mapWallet.find(output.hash);
566
  if (it != m_wallet->mapWallet.end()) {
567
  int depth = m_wallet->GetTxDepthInMainChain(it->second);