Current ways to connect to gRPC in the Zcash stack (LWD, Zaino, Zebrad, Zakura, ztreamer)

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

  • GetMempoolTx exclude entries are little-endian txid suffixes.
  • GetMempoolStream sends height 0 for mempool txs.
  • GetTreeState prefers 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.
  • Ping is 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_BYTES rejected before hex-encode.
  • MAX_EXCLUDE_ENTRIES raised 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:443
  • zec.0xrpc.io:443
  • zaino.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 :9067 or Zaino :8137, TLS off-box.
  • New self-host after zcashd EOL: Zebra or Zakura + Zaino (Z3 indexer profile) or LWD. Both work; Zaino is the funded replacement path.
  • One-box Zebra experiment: rpc.lightwalletd_listen_addr from #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

If maintainers want this living somewhere durable (ZecHub page, zebra book appendix), happy to turn it into that next.

9 Likes

This is sick, thank you for this!

ztreamer had another release, but I am still holding out on the next zakura release so I can get rid of my fork.

Do you have any opinions on what a PIR-aware, tachyon ready lightwallet-protocol might need? I have a lot of ideas here I will post about soon. This is what I will want to trojan horse with ztreamer

1 Like