This is a snapshot as of September 2026 of how clients actually talk gRPC in the Zcash ecosystem: what implements CompactTxStreamer, what is a different gRPC surface, how you transport it, and the tradeoffs.
Corrections welcome if I have a port, completeness claim, or status wrong.
This is sourced from grok.
The wallet contract
Almost every light wallet still speaks one service:
cash.z.wallet.sdk.rpc.CompactTxStreamer
Canonical protos: zcash/lightwallet-protocol (ZIP-307). Current methods include compact blocks / nullifiers, tx fetch + submit, transparent address queries, mempool streams, tree/subtree state, UTXOs, GetLightdInfo. Ironwood (NU6.3) fields are in the current proto.
If you are wiring a wallet SDK, this is the API. Everything below is “who serves it” and “how the bytes get there.”
JSON-RPC on zebrad/zakura :8232, Zaino :8237, or hosted “Zcash RPC” gateways (Tatum, QuickNode, etc.) is a different protocol. Do not point CompactTxStreamerClient at those.
Zebrad also has a second gRPC service, zebra.indexer.rpc.Indexer (rpc.indexer_listen_addr). That is for indexers and trusted sync, not for Zashi/Ywallet. Do not confuse it with CompactTxStreamer.
CompactTxStreamer servers
| lightwalletd | Zaino (zainod) | zebrad native LWD | ztreamer | lightwalletd-rs | Zinder compat | |
|---|---|---|---|---|---|---|
| What | Original Go compact-block server | Rust indexer replacing LWD + a zcashd JSON-RPC subset | Zebra serving CompactTxStreamer in-process (#10953) | CompactTxStreamer + P2Pv2 on embedded Zakura | Rust LWD rewrite | Compat plane in front of Zinder WalletQuery |
| Repo | zcash/lightwalletd |
zingolabs/zaino |
ZcashFoundation/zebra (zebra_rpc::lightwalletd) |
distractedm1nd/ztreamer |
jpgonzalezra/lightwalletd-rs |
gustavovalverde/zinder |
| Age | ~2019–2020; latest v0.5.4 (Aug 2026) | Grant work 2024; LWD-compat pre-release Nov 2024; 0.2.0 ~Sep 2025; 0.8.0 Aug 2026 | Merged 18 Aug 2026. Not the 2024 Zebra 1.6 scanner/indexer gRPC | v0.0.1 announced 2 Sep 2026 | Forum announce Jul 2026, beta | 2026, early |
| Process | Separate Go daemon | Separate Rust daemon | Same process as zebrad | Same process as embedded Zakura | Separate Rust daemon | Separate reader |
| Default gRPC | 127.0.0.1:9067 |
127.0.0.1:8137 |
[rpc] lightwalletd_listen_addr (often :9067) |
configurable; docs use :9067 |
TLS on by default | compat ~:19067 |
| Backend | JSON-RPC → zcashd / zebrad / zakura (0.5.1+) | rpc = JSON-RPC to node (default, remote-ok); direct = Zebra state DB (same host) |
In-process read-state + mempool; wallet-shaped RPCs reused from JSON-RPC RpcImpl |
In-process Zakura | zebrad JSON-RPC or co-located state | Own RocksDB projections |
| Protocol coverage | Full + Ironwood in 0.5.0 | Full list in docs/rpc_api.md |
18 methods. Ping disabled to match production LWD. Ironwood in-tree. See wire-compat notes below |
All methods except GetMempoolTx. GetBlock omits transparent data; GetBlockRange rejects transparent filters |
Claims full CompactTxStreamer + darkside | Compat shim; certify per wallet |
| Other APIs | optional HTTP debug | JSON-RPC explorer/wallet subset (:8237) |
zebrad JSON-RPC :8232 + separate indexer gRPC |
24/27 of Zaino-direct JSON-RPCs | Prometheus, reflection | Native zinder.v1.wallet.WalletQuery |
| TLS | Production certs expected; --no-tls-very-insecure is local-only |
Public bind requires TLS unless no_tls_use_unencrypted_traffic |
None. Plaintext HTTP/2, no cookie auth | Plaintext default; PEM cert/key flags | TLS on by default | Bind loopback; TLS on your proxy |
| Wallet compat | What Zashi/ZODL, Ywallet, Zingo, Ledger utils assume | Drop-in for LWD clients; Z3 indexer profile | Same proto with documented LWD wire quirks; do not put public wallets on it yet | Same proto with the deviations above | Same proto, unaudited | Only after end-to-end cert |
| Public hosts | zec.rocks:443, Cake, 0xRPC, … |
zaino.unsafe.zec.rocks:443 (+ testnet twin) |
none intended | none known | none known | none known |
| Pros | Longest production history; every shipping light wallet already speaks it; Zakura recognized as backend | Unified LWD + JSON-RPC; Rust; Z3/Zallet path; TLS enforcement; remote rpc backend |
Fewest moving parts; no second daemon; no compact-cache rebuild; DoS hardening in-tree | Fastest advertised historical index (author: 92s genesis→serve, ~16 GiB index); first P2P CompactTxStreamer | Rust, TLS defaults, metrics | Epoch-pinned reads; scale read plane separately |
| Cons | Extra daemon + compact cache; another failure domain | Still 0.x; direct is same-machine only; public hosts marked unsafe |
Experimental; no TLS/auth; almost no production exposure; ZF: not for services you run for others | Brand new; proto deviations break t-addr/mempool clients; single-maintainer | Beta, not audited | Early; CompactTxStreamer is a translation layer |
| Use when | You want existing wallets to just work | Post-zcashd indexer / explorer RPC / Z3 | Dev/regtest or loopback behind your own TLS proxy | You’re on Zakura and care about index speed or P2P light clients | Rust LWD and you accept beta | Building on WalletQuery, need LWD during migration |
Zakura itself is not a CompactTxStreamer server. It is the full node (Zebra fork). LWD and ztreamer consume it. Zakura 1.3+/1.4+ specifically sped up the JSON-RPC that LWD polls (getblockchaininfo, historic tree frontiers for pruned / P2Pv2 nodes).
Shielded Labs Zero vendors zebra + zaino + zallet + lightwalletd. Same protocols, packaged for operators. No new gRPC API.
Zebrad native CompactTxStreamer in detail
Source: ZcashFoundation/zebra#10953 — feat(rpc)!: add lightwalletd-compatible gRPC server implementing CompactTxStreamer, merged 18 Aug 2026.
This is not the Zebra 1.6 (Feb 2024) shielded-scanning gRPC, and it is not rpc.indexer_listen_addr. Those are a different service (zebra.indexer.rpc.Indexer).
Enable:
[rpc]
lightwalletd_listen_addr = '127.0.0.1:9067'
Disabled by default. Implementation: zebra_rpc::lightwalletd, tonic, protos vendored from LWD into zebra-rpc/proto/. Compact blocks and mempool streams come from Zebra read-state / mempool in-process. Wallet-shaped calls (GetTreeState, GetTaddressBalance, SendTransaction, …) reuse existing JSON-RPC RpcImpl.
Wire-compat, verified against Go LWD (including two places LWD contradicts its own proto comments):
GetMempoolTxexclude entries are little-endian txid suffixes.GetMempoolStreamsends height 0 for mempool txs.GetTreeStateprefers hash over height and uses internal little-endian hash order. That diverges from LWD because of zcash/lightwalletd#512; Zebra treats the LWD behavior as the bug.Pingis disabled, matching production LWD instances.- Missing Sapling/Orchard tree →
ABORTED, not size 0 (size 0 would corrupt client note positions across a reorg). Missing Ironwood tree pre-activation is treated as zero. - Ironwood fields taken from
zcash/lightwallet-protocol; Ironwood tree reads gated on activation.
Hardening in the PR
- Streamed t-addrs validated as they arrive (no unbounded buffer on
GetTaddressBalanceStream). - Raw tx larger than
MAX_BLOCK_BYTESrejected before hex-encode. MAX_EXCLUDE_ENTRIESraised to 20,000 with suffix-length bucketing.- Request tracing Tower layer aligned with JSON-RPC / Jaeger.
Still experimental. Plaintext HTTP/2, no TLS, no cookie auth. ZF book: do not run this on end-user machines; do not offer it as a public service without a TLS-terminating proxy and a loopback/private bind. The supported production path remains a separate lightwalletd in front of zebrad JSON-RPC. See Zebra book: lightwalletd.
Other gRPC surfaces (not the wallet proto)
| Zebra / Zakura indexer gRPC | Zinder WalletQuery | gRPC-web gateway | P2Pv2 CompactTxStreamer | |
|---|---|---|---|---|
| Service | zebra.indexer.rpc.Indexer |
zinder.v1.wallet.WalletQuery |
CompactTxStreamer, different transport | CompactTxStreamer over Zakura P2Pv2 |
| Age | ~Zebra 1.6 (Feb 2024) scanning gRPC → current indexer API | 2026 | Constraint is old; packaged Envoy stack is 2026 grant work | ztreamer 0.0.1 (Sep 2026) |
| Who connects | Indexers, TrustedChainSync, historical backfill — not Zashi | New wallet integrations | Browser wallets (WebZjs) | Future P2P light wallets |
| Listen | [rpc] indexer_listen_addr e.g. :8230, feature indexer |
native query port (Zinder docs ~:19106) |
Envoy → upstream LWD or Zaino | Advertised as a P2P service |
| Methods | ChainTipChange, NonFinalizedStateChange, MempoolChange, GetBlock; Zakura adds streaming GetBlockRange |
Native query API | Proxied CompactTxStreamer | Whatever ztreamer implements |
| Pros | Streaming tip/mempool; no compact-block transform | Designed query semantics | Only way browsers can talk to LWD/Zaino | No trusted LWD operator |
| Cons | Private / unauthenticated; not ZIP-307 | Existing SDKs don’t speak it | Extra hop; CORS / rate-limit / TLS | Experimental P2P; no shipping mobile wallet |
| Use when | Building an indexer against zebrad/zakura | Greenfield wallet API | Browser / extension | Research / Tachyon-shaped clients |
Zaino’s validator_grpc_listen_address in some configs is this node hop (Zaino → validator), not the wallet-facing :8137.
Transports
Same CompactTxStreamer, different pipe.
| Transport | Pros | Cons |
|---|---|---|
Native gRPC/HTTP2 + TLS (host:443) |
What every current mobile/desktop light wallet uses | Not browsers |
Native gRPC plaintext (:9067 / :8137) |
Fine on loopback / private net | Address queries visible; anyone who can reach the port can submit txs |
Reverse proxy (nginx grpc_pass, Envoy, haproxy) |
TLS, rate limits, hide plaintext backend | Need large HTTP/2 frames + long stream timeouts |
| gRPC-web (Envoy) | Browsers work | Don’t give WebZjs an unproxied LWD URL |
Tor (Arti in zcash_client_backend) |
Hides client IP from the indexer | Does not hide what you query; extra latency |
| P2Pv2 service discovery | No central LWD | New; unused by shipping wallets |
Quick checks:
# local LWD
grpcurl -plaintext localhost:9067 cash.z.wallet.sdk.rpc.CompactTxStreamer/GetLightdInfo
# local Zaino
grpcurl -plaintext localhost:8137 list
grpcurl -plaintext -d '{}' localhost:8137 cash.z.wallet.sdk.rpc.CompactTxStreamer/GetLatestBlock
# zebrad native CompactTxStreamer (if enabled)
grpcurl -plaintext localhost:9067 cash.z.wallet.sdk.rpc.CompactTxStreamer/GetLightdInfo
# public TLS
grpcurl zec.rocks:443 cash.z.wallet.sdk.rpc.CompactTxStreamer/GetLightdInfo
Client libraries that already speak this: zcash_client_backend CompactTxStreamerClient (tonic, lightwalletd-tonic), zingolib, Zashi/ZODL SDKs, Ywallet, @ledgerhq/zcash-utils. zecd defaults to zebrad JSON-RPC and can take a lightwalletd gRPC URL since 0.6.0.
Topologies
Production-shaped:
wallet --TLS gRPC--> lightwalletd:9067 --JSON-RPC--> zebrad|zakura :8232
wallet --TLS gRPC--> zainod:8137 --JSON-RPC--> zebrad|zakura :8232
wallet --TLS gRPC--> zainod:8137 --direct----> zebra state dir (same host)
Experimental one-process:
wallet --gRPC--> zebrad :9067 # rpc.lightwalletd_listen_addr, plaintext, #10953
wallet --gRPC--> ztreamerd # embedded Zakura
Z3 Compose: Zebra + optional Zaino (indexer profile, mainnet gRPC 8137) + Zallet. Zallet embeds Zaino libraries and talks Zebra JSON-RPC; external light wallets still hit standalone Zaino gRPC.
Do not expose zebrad lightwalletd_listen_addr or indexer :8230 to the internet.
Public CompactTxStreamer endpoints
Check hosh.zec.rocks / status.zec.rocks rather than a static list. At last write-up:
zec.rocks:443(+na/eu/ap/sa.zec.rocks)zec-node.cakewallet.com:443zec.0xrpc.io:443zaino.unsafe.zec.rocks:443(experimental — the hostname is the warning)testnet.zec.rocks:443,zaino.testnet.unsafe.zec.rocks
Tor hides your IP from these operators. It does not hide the addresses you query. Running your own server is the other trust model.
Practical pick
- Existing wallet, public or self-hosted server: lightwalletd
:9067or Zaino:8137, TLS off-box. - New self-host after zcashd EOL: Zebra or Zakura + Zaino (Z3
indexerprofile) or LWD. Both work; Zaino is the funded replacement path. - One-box Zebra experiment:
rpc.lightwalletd_listen_addrfrom #10953. Loopback + your own TLS proxy, or don’t. - One-box Zakura experiment: ztreamer. Don’t point Zashi at it until mempool + transparent behavior match the proto.
- Browser: Envoy gRPC-web in front of LWD or Zaino.
- Building an indexer, not a wallet: Zebra/Zakura indexer gRPC, not CompactTxStreamer.
References
- Protocol: GitHub - zcash/lightwallet-protocol: The canonical source of truth for the Zcash light wallet GRPC interface and associated protobuf definitions. · GitHub
- LWD: GitHub - zcash/lightwalletd: Lightwalletd is a backend service that provides a bandwidth-efficient interface to the Zcash blockchain · GitHub
- LWD
GetTreeStatehash-order bug: `GetLatestBlock` hash response has been broken for 2.5 years without anyone noticing · Issue #512 · zcash/lightwalletd · GitHub - Zaino RPC list: zaino/docs/rpc_api.md at dev · zingolabs/zaino · GitHub
- Zebrad native CompactTxStreamer: feat(rpc)!: add lightwalletd-compatible gRPC server implementing CompactTxStreamer by arya2 · Pull Request #10953 · ZcashFoundation/zebra · GitHub
- Zebra book (LWD + experimental native server): Lightwalletd - The Zebra Book
- Z3: GitHub - ZcashFoundation/z3: Repository to iterate on the grand unification of Zebra, Zaino and Zallet · GitHub
- Zakura (node, not LWD): Introducing Zakura — Zakura
- ztreamer: GitHub - distractedm1nd/ztreamer: heavily optimized zcash indexer · GitHub
- ZecHub lightwallet nodes / public servers: zechub/site/Zcash_Tech/Lightwallet_Nodes.md at main · ZecHub/zechub · GitHub
- Shielded Labs Zero: GitHub - ShieldedLabs/zero: Enterprise Zcash · GitHub
If maintainers want this living somewhere durable (ZecHub page, zebra book appendix), happy to turn it into that next.
