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. The two line-number columns refer to before and after.
src/wallet/interfaces.cpp
CHANGED
|
@@ -119,10 +119,23 @@ WalletTxOut MakeWalletTxOut(const CWallet& wallet,
|
|
|
119
119
|
int depth) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
|
|
120
120
|
{
|
|
121
121
|
WalletTxOut result;
|
|
122
|
+
result.outpoint = COutPoint{wtx.GetHash(), static_cast<uint32_t>(n)};
|
|
122
123
|
result.txout = wtx.tx->vout[n];
|
|
123
124
|
result.time = wtx.GetTxTime();
|
|
124
125
|
result.depth_in_main_chain = depth;
|
|
125
|
-
result.is_spent = wallet.IsSpent(COutPoint(wtx.GetHash(), n));
|
|
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
|
+
}
|
|
126
139
|
return result;
|
|
127
140
|
}
|
|
128
141
|
|
|
@@ -130,10 +143,31 @@ WalletTxOut MakeWalletTxOut(const CWallet& wallet,
|
|
|
130
143
|
const COutput& output) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
|
|
131
144
|
{
|
|
132
145
|
WalletTxOut result;
|
|
146
|
+
result.outpoint = output.outpoint;
|
|
133
147
|
result.txout = output.txout;
|
|
134
148
|
result.time = output.time;
|
|
135
149
|
result.depth_in_main_chain = output.depth;
|
|
136
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
|
+
}
|
|
137
171
|
return result;
|
|
138
172
|
}
|
|
139
173
|
|
|
@@ -527,13 +561,32 @@ public:
|
|
|
527
561
|
}
|
|
528
562
|
return result;
|
|
529
563
|
}
|
|
530
|
-
std::vector<WalletTxOut> getCoins(const std::vector<COutPoint>& outputs) override
|
|
564
|
+
std::vector<WalletTxOut> getCoins(const std::vector<COutPoint>& outputs, const std::optional<CFeeRate>& feerate) override
|
|
531
565
|
{
|
|
532
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
|
+
|
|
533
581
|
std::vector<WalletTxOut> result;
|
|
534
582
|
result.reserve(outputs.size());
|
|
535
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
|
+
}
|
|
536
588
|
result.emplace_back();
|
|
589
|
+
result.back().outpoint = output;
|
|
537
590
|
auto it = m_wallet->mapWallet.find(output.hash);
|
|
538
591
|
if (it != m_wallet->mapWallet.end()) {
|
|
539
592
|
int depth = m_wallet->GetTxDepthInMainChain(it->second);
|