Skip to content

z_getbalances: split transparent balance into regular and coinbase; z_listunspent: add 'generated' flag#639

Open
pacu wants to merge 4 commits into
mainfrom
fix-635-transparent-coinbase-balance
Open

z_getbalances: split transparent balance into regular and coinbase; z_listunspent: add 'generated' flag#639
pacu wants to merge 4 commits into
mainfrom
fix-635-transparent-coinbase-balance

Conversation

@pacu

@pacu pacu commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator

Fixes #635.

Summary

z_getbalances now delivers its documented transparent balance contract, and z_listunspent identifies coinbase UTXOs — so integrators (mining pools in particular) can finally read "how much can I pay to a transparent recipient" directly from the wallet.

  • z_getbalances (fe6ce4b): transparent.regular contains only non-coinbase funds; transparent.coinbase is populated (immature coinbase reported as pending, mature as spendable); the account total now includes transparent value in its spendable/pending buckets, so total == sum of parts across all five pools. Previously regular silently included coinbase, coinbase was never emitted, and total.spendable ignored the transparent pool entirely — the combination that halted the reporting pool's payouts with Insufficient balance (have 0, …).
  • z_listunspent (dd87ed2, standalone/cherry-pickable): transparent entries gain "generated": true|false (coinbase origin, mirroring zcashd's listunspent; omitted on shielded entries), replacing the per-UTXO getrawtransaction round-trip integrators needed. Implemented via two disjoint CoinbaseFilter queries; requires no librustzcash changes.
  • Dependency (68ad944): the balance split comes from Split AccountBalance unshielded balance into regular and coinbase buckets librustzcash#2654; [patch.crates-io] (workspace root + both backend workspaces) pins that branch (196f12439a) until a release containing it ships. z_gettotalbalance semantics are intentionally unchanged (pinned by new tests).

Verification

  • cargo test -p zallet-core: 208 passed (14 new unit tests: full rendering matrix for the split incl. dust-counted-once and total-equals-sum-of-parts; semantics pins for z_getbalanceforaccount/z_gettotalbalance; generated serialization contract). Both backends cargo check clean against the pin.
  • End-to-end on a real zebrad+zainod+zallet regtest stack (new wallet_transparent_coinbase_balance.py, see the accompanying integration-tests PR): immature coinbase → coinbase.pending; mature → coinbase.spendable with exact zatoshi sums; post-shield z_sendmany z→t output lands in regular.spendable only; generated flags correct on every entry; z_gettotalbalance cross-check passes.

Notes for review: z_listunspent transparent output ordering changed (non-coinbase before coinbase per address; no ordering was documented). Immature coinbase remains excluded from z_listunspent (upstream maturity clause), while z_getbalances now does show it as pending — intentional and now-documented behavior.

🤖 Generated with Claude Code

https://claude.ai/code/session_017WB1TU6tyLmMa1n4SQ9XgK

Adds a 'generated' boolean to each transparent UTXO in the z_listunspent
response, matching the field zcashd's listunspent uses to mark coinbase
outputs. This lets callers (e.g. mining-pool operators, issue #635)
classify UTXOs without a getrawtransaction round-trip per txid.

The transparent query now runs twice per address, once with
CoinbaseFilter::NonCoinbaseOnly (tagged generated=false) and once with
CoinbaseFilter::CoinbaseOnly (tagged generated=true). The two filters
partition the set previously returned by AllTransparentOutputs: outputs
with an unknown tx_index are treated as non-coinbase by the former and
excluded by the latter, so the union is exact and disjoint. Immature
coinbase outputs remain excluded by the shared upstream maturity clause.
Transparent rows are now ordered non-coinbase-then-coinbase per address;
no output ordering was ever documented.

Shielded outputs omit the field entirely. The transparent entry
construction is extracted into a pure helper so its JSON rendering is
unit-tested without a database.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017WB1TU6tyLmMa1n4SQ9XgK
@pacu
pacu force-pushed the fix-635-transparent-coinbase-balance branch 2 times, most recently from 6599fac to 200bbb8 Compare July 19, 2026 19:18
pacu and others added 3 commits July 19, 2026 17:51
Consumes the upstream AccountBalance split of the unshielded balance
into regular (non-coinbase) and coinbase buckets, via a temporary
[patch.crates-io] path pin to a patched librustzcash worktree (to be
replaced with a git rev once the librustzcash PR branch is pushed, and
removed once released to crates.io). The librustzcash workspace
component crates are patched alongside so Cargo does not resolve
duplicate copies.

z_getbalances now populates both `transparent.regular` and
`transparent.coinbase` per account, and the account `total` now
includes transparent value in its `spendable` and `pending` buckets
(previously only shielded pools contributed). Immature coinbase is
reported as pending rather than spendable. Dust continues to be
sourced from AccountBalance::uneconomic_value, which already spans
both transparent buckets, so it is counted exactly once.

z_getbalanceforaccount and z_gettotalbalance intentionally keep their
combined transparent view (regular + coinbase); unit tests now pin
that behaviour across the upstream change.

Fixes #635.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017WB1TU6tyLmMa1n4SQ9XgK
Point [patch.crates-io] (workspace root and both backend workspaces) at
zcash/librustzcash@47344ee188, the branch providing the transparent
regular/coinbase AccountBalance split consumed by z_getbalances. The
workspace component crates are patched alongside to avoid duplicate
crate resolutions. Remove once a release containing the split ships on
crates.io.

This branch is based on current librustzcash main, so the single
stack-wide pin also carries `WalletDb::transactionally_with_extension`,
which main pinned d09d1f390f for (the atomic z_importkey writes); that
pin is replaced rather than duplicated. Following upstream
zcash/librustzcash#2650, `create_proposed_transactions` takes an
optional expiry-height override; the z_sendmany and z_shieldcoinbase
call sites pass `None`, keeping the builder-derived expiry. The pinned
stack requires zewif 1.0.0-rc.3, so zewif and zewif-zcashd move to
their rc.3 releases together.

Also records the z_getbalances fix and the z_listunspent 'generated'
field in the changelog.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017WB1TU6tyLmMa1n4SQ9XgK
@nuttycom
nuttycom force-pushed the fix-635-transparent-coinbase-balance branch from 6bf5337 to 6a21786 Compare July 19, 2026 23:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

z_getbalances/getbalances: transparent regular balance includes coinbase; coinbase field never populated; total.spendable ignores transparent

2 participants