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. The two line-number columns refer to before and after.
src/wallet/interfaces.cpp
CHANGED
|
@@ -118,10 +118,23 @@ WalletTxOut MakeWalletTxOut(const CWallet& wallet,
|
|
|
118
118
|
int depth) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
|
|
119
119
|
{
|
|
120
120
|
WalletTxOut result;
|
|
121
|
+
result.outpoint = COutPoint{wtx.GetHash(), static_cast<uint32_t>(n)};
|
|
121
122
|
result.txout = wtx.tx->vout[n];
|
|
122
123
|
result.time = wtx.GetTxTime();
|
|
123
124
|
result.depth_in_main_chain = depth;
|
|
124
|
-
result.is_spent = wallet.IsSpent(COutPoint(wtx.GetHash(), n));
|
|
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
|
+
}
|
|
125
138
|
return result;
|
|
126
139
|
}
|
|
127
140
|
|
|
@@ -129,10 +142,31 @@ WalletTxOut MakeWalletTxOut(const CWallet& wallet,
|
|
|
129
142
|
const COutput& output) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
|
|
130
143
|
{
|
|
131
144
|
WalletTxOut result;
|
|
145
|
+
result.outpoint = output.outpoint;
|
|
132
146
|
result.txout = output.txout;
|
|
133
147
|
result.time = output.time;
|
|
134
148
|
result.depth_in_main_chain = output.depth;
|
|
135
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
|
+
}
|
|
136
170
|
return result;
|
|
137
171
|
}
|
|
138
172
|
|
|
@@ -502,13 +536,32 @@ public:
|
|
|
502
536
|
}
|
|
503
537
|
return result;
|
|
504
538
|
}
|
|
505
|
-
std::vector<WalletTxOut> getCoins(const std::vector<COutPoint>& outputs) override
|
|
539
|
+
std::vector<WalletTxOut> getCoins(const std::vector<COutPoint>& outputs, const std::optional<CFeeRate>& feerate) override
|
|
506
540
|
{
|
|
507
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
|
+
|
|
508
556
|
std::vector<WalletTxOut> result;
|
|
509
557
|
result.reserve(outputs.size());
|
|
510
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
|
+
}
|
|
511
563
|
result.emplace_back();
|
|
564
|
+
result.back().outpoint = output;
|
|
512
565
|
auto it = m_wallet->mapWallet.find(output.hash);
|
|
513
566
|
if (it != m_wallet->mapWallet.end()) {
|
|
514
567
|
int depth = m_wallet->GetTxDepthInMainChain(it->second);
|