fix(market): populate combined address list so portfolio sees addresses

The Market-tab portfolio (editor checklist + SumPortfolioBalance) reads the
combined WalletState::addresses view, but the full-node refresh path only ever
updated the authoritative z_addresses/t_addresses lists — rebuildAddressList()
was never called, so `addresses` stayed empty. Result: the manage-portfolio
modal showed no addresses to pick, and addresses added via the overview
right-click menu contributed no value to their entry (SumPortfolioBalance
found nothing in the empty combined list).

Rebuild the combined view in NetworkRefreshService::applyAddressRefreshResult
(the sole bulk updater of the address lists), and push newly created addresses
into the combined view immediately in the full-node create paths for
zero-latency parity with the overview (matching the lite branch). This also
repairs two other silently-broken full-node consumers of state.addresses: the
auto-shield target-address finder and the pool-mining transparent fallback.

Add a regression test (testWalletStateAddressListRebuild) covering the
empty-before / union-after rebuild and pending-send delta reflection.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-02 03:27:44 -05:00
parent e3b53258b7
commit 530bf24abf
3 changed files with 48 additions and 0 deletions

View File

@@ -1980,6 +1980,7 @@ void App::createNewZAddress(std::function<void(const std::string&)> callback)
info.type = "shielded";
info.balance = 0.0;
state_.z_addresses.push_back(info);
state_.addresses.push_back(info); // keep combined view in sync immediately
address_list_dirty_ = true;
// Also trigger full refresh to get proper balances
addresses_dirty_ = true;
@@ -2027,6 +2028,7 @@ void App::createNewTAddress(std::function<void(const std::string&)> callback)
info.type = "transparent";
info.balance = 0.0;
state_.t_addresses.push_back(info);
state_.addresses.push_back(info); // keep combined view in sync immediately
address_list_dirty_ = true;
// Also trigger full refresh to get proper balances
addresses_dirty_ = true;

View File

@@ -1255,6 +1255,11 @@ void NetworkRefreshService::applyAddressRefreshResult(WalletState& state,
{
state.z_addresses = std::move(result.shieldedAddresses);
state.t_addresses = std::move(result.transparentAddresses);
// Keep the combined `addresses` view in sync with the authoritative z/t lists.
// Consumers that read state.addresses (Market-tab portfolio, auto-shield target
// selection, pool-mining transparent fallback) depend on this being rebuilt — the
// full-node refresh path is the only place that bulk-updates the address lists.
state.rebuildAddressList();
}
void NetworkRefreshService::applyTransactionRefreshResult(WalletState& state,