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);
|