v29.4-roots.4 · Commit 25: [PATCH 25/37] 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);
|