ZecKit is a containerized development toolkit for Zcash that provides shielded transactions on a local regtest network. It enables developers to test Orchard shielded sends without connecting to testnet or mainnet.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Docker Compose Network β
β (zeckit-network) β
β β
β ββββββββββββββββ ββββββββββββββββ β
β β Zebra β β Faucet β β
β β (Rust) β RPC β (Rust) β β
β β regtest β 8232 β Axum+ β β
β β β β Zingolib β β
β β Auto-mining β β :8080 β β
β ββββββββ¬ββββββββ ββββββββ¬ββββββββ β
β β β β
β β β β
β βΌ βΌ β
β ββββββββββββββββ ββββββββββββββββ β
β β Zaino (Rust) β β Embedded β β
β β gRPC :9067 β β Zingolib β β
β β β β Wallet β β
β ββββββββββββββββ ββββββββββββββββ β
β OR β
β ββββββββββββββββ β
β βLightwalletd β β
β β (Go) β β
β β gRPC :9067 β β
β ββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β²
β
ββββββ΄βββββ
β zeckit β (Rust CLI - test runner)
β test β
βββββββββββ
Technology: Rust
Role: Full Zcash node with internal miner
Port: 8232 (RPC)
Responsibilities:
- Validate and store blockchain
- Provide RPC interface
- Auto-mine blocks (regtest mode)
- Broadcast transactions
Key Features:
- Internal Miner: Automatically generates blocks every 30-60 seconds
- Regtest Mode: Isolated test network with NU6.1 activated
- No Checkpoint Sync: Allows genesis start for clean testing
- Coinbase Mining: Rewards go to faucet's transparent address
Configuration Flow:
zebra.toml
βββ [network] = "Regtest"
βββ [rpc] listen_addr = "0.0.0.0:8232"
βββ [mining]
βββ internal_miner = true
βββ miner_address = "tmBsTi2xWTjUdEXnuTceL7fecEQKeWaPDJd"
Technology: Rust
Role: Light client protocol server (lightwalletd-compatible)
Port: 9067 (gRPC)
Responsibilities:
- Index blockchain data from Zebra
- Serve compact blocks to wallet
- Provide transaction broadcast API
- Cache shielded note commitments
Advantages:
- 30% faster sync than lightwalletd
- Better error messages
- More reliable with rapid block generation
- Memory-safe (Rust)
Data Flow:
Zebra β Zaino β Wallet (Zingolib)
β β
β βββββ Indexes: Blocks, Transactions, Notes
ββββββββββββ Broadcasts: New transactions
Technology: Go
Role: Light client protocol server (original implementation)
Port: 9067 (gRPC)
Responsibilities:
- Index blockchain data from Zebra
- Serve compact blocks to wallet
- Provide transaction broadcast API
- Cache shielded note commitments
Configuration:
Zebra RPC: zebra:8232
gRPC Bind: 0.0.0.0:9067
TLS: Disabled (dev only)
Healthcheck Fix:
- Changed from grpc_health_probe to TCP port check
- More reliable for regtest environment
Technology: Rust + Axum + Zingolib
Role: REST API with embedded shielded wallet
Port: 8080 (HTTP)
Architecture:
ββββββββββββββββββββββββββββ
β Axum HTTP Server β
β :8080 β
ββββββββββ¬ββββββββββββββββββ
β
βΌ
ββββββββββββββββββββββββββββ
β API Handlers β
β β’ /health β
β β’ /stats β
β β’ /address β
β β’ /sync β
β β’ /shield β
β β’ /send β
ββββββββββ¬ββββββββββββββββββ
β
βΌ
ββββββββββββββββββββββββββββ
β WalletManager β
β (Rust wrapper) β
β β’ sync() β
β β’ get_balance() β
β β’ shield_to_orchard() β
β β’ send_transaction() β
ββββββββββ¬ββββββββββββββββββ
β
βΌ
ββββββββββββββββββββββββββββ
β Zingolib LightClient β
β (Embedded library) β
β β’ Create transactions β
β β’ Sign with keys β
β β’ Broadcast via backend β
ββββββββββββββββββββββββββββ
Key Design Decisions:
- Embedded Wallet: No external process, library directly linked
- Async Everything: Tokio runtime for concurrent operations
- Deterministic Seed: Same seed = same addresses (testing)
- Background Sync: Auto-sync every 60 seconds
1. zeckit up --backend zaino
β
βββΊ Start Zebra
β βββ Load regtest config
β βββ Initialize blockchain from genesis
β βββ Start internal miner
β
βββΊ Start Zaino
β βββ Connect to Zebra RPC
β βββ Wait for Zebra to be ready
β βββ Start indexing blocks
β
βββΊ Start Faucet
βββ Wait for Zaino to be ready
βββ Load or create deterministic seed
βββ Initialize Zingolib wallet
βββ Sync with blockchain
βββ Start background sync task
βββ Start HTTP server on :8080
[2-3 minutes later]
β
βββΊ Services ready
β’ Zebra mining blocks
β’ Zaino indexing
β’ Faucet has balance
User Request
β
βββΊ POST /shield
β
βΌ
Faucet API Handler
β
βββΊ wallet.get_balance()
β βββ Check transparent balance > 0
β
βββΊ wallet.shield_to_orchard()
β β
β βββΊ Zingolib: Select transparent UTXOs
β βββΊ Zingolib: Create Orchard note
β βββΊ Zingolib: Generate shielded proof
β βββΊ Zingolib: Sign transaction
β βββΊ Zingolib: Broadcast via Zaino
β
βββΊ Zaino: Forward to Zebra RPC
β
βββΊ Zebra: Add to mempool
β
βββΊ Zebra Internal Miner: Include in next block
β βββ [30-60 seconds]
β
βββΊ Return TXID to user
User Request
β
βββΊ POST /send {address, amount, memo}
β
βΌ
Faucet API Handler
β
βββΊ wallet.get_balance()
β βββ Check Orchard balance >= amount
β
βββΊ wallet.send_transaction(address, amount, memo)
β β
β βββΊ Zingolib: Select Orchard notes
β βββΊ Zingolib: Create output note
β βββΊ Zingolib: Encrypt memo
β βββΊ Zingolib: Generate shielded proof
β βββΊ Zingolib: Sign transaction
β βββΊ Zingolib: Broadcast via Zaino
β
βββΊ Zaino: Forward to Zebra RPC
β
βββΊ Zebra: Add to mempool
β
βββΊ Zebra Internal Miner: Include in next block
β βββ [30-60 seconds]
β
βββΊ Return TXID to user
Name: zeckit-network
Type: Bridge
Subnet: Auto-assigned by Docker
| Service | Internal Port | Host Port | Protocol |
|---|---|---|---|
| Zebra RPC | 8232 | 127.0.0.1:8232 | HTTP |
| Zaino/LWD | 9067 | 127.0.0.1:9067 | gRPC |
| Faucet API | 8080 | 0.0.0.0:8080 | HTTP |
Note: Only Faucet API is exposed to LAN (0.0.0.0). Zebra and backend are localhost-only for security.
All services use Docker DNS for service discovery:
faucet
zaino β http://zebra:8232
lightwalletd β http://zebra:8232
zeckit_zebra-data/
βββ state/
β βββ rocksdb/ # Blockchain database
β βββ blocks/
β βββ state/
β βββ finalized/
zeckit_zaino-data/
βββ db/ # Indexed compact blocks
βββ blocks.db
βββ notes.db
zeckit_lightwalletd-data/
βββ cache/ # Indexed data
βββ compact-blocks/
zeckit_faucet-data/
βββ wallets/ # Wallet database
βββ .wallet_seed # Deterministic seed (24 words)
βββ zingo-wallet.dat # Encrypted wallet state
Default Behavior:
- Volumes persist across zeckit down
- Allows fast restarts (no re-sync needed)
- Wallet retains same addresses
Fresh Start:
zeckit down
docker volume rm zeckit_zebra-data zeckit_zaino-data zeckit_faucet-data
zeckit up --backend zainoZecKit is NOT production-ready
Security Limitations:
- No authentication on any API
- No TLS/HTTPS encryption
- No rate limiting
- No secret management
- Regtest network only (not ZEC)
Internet
β
Host Network
β
βββββββββββββββββββββββββββ
β Docker Bridge β
β β
β Zebra ββ Zaino ββ Faucet
β β
βββββββββββββββββββββββββββ
Exposed Ports:
- Faucet API: 0.0.0.0:8080 (LAN accessible)
- Zebra RPC: 127.0.0.1:8232 (localhost only)
- Zaino/LWD: 127.0.0.1:9067 (localhost only)
ββββββββββββββββββββββββββββββββ
β Tokio Async Runtime β
β β
β ββββββββββββββββββββββββββ β
β β HTTP Server β β
β β (Axum) β β
β β β’ Concurrent requests β β
β β β’ Non-blocking I/O β β
β ββββββββββββββββββββββββββ β
β β
β ββββββββββββββββββββββββββ β
β β Background Tasks β β
β β β’ Wallet sync (60s) β β
β β β’ Health monitoring β β
β ββββββββββββββββββββββββββ β
β β
β ββββββββββββββββββββββββββ β
β β Shared State β β
β β Arc<RwLock<Wallet>> β β
β β β’ Read: Many threads β β
β β β’ Write: Exclusive β β
β ββββββββββββββββββββββββββ β
ββββββββββββββββββββββββββββββββ
Locking Strategy:
- Reads (balance, address): Shared lock (multiple concurrent)
- Writes (send, shield, sync): Exclusive lock (one at a time)
- Background sync: Skips if lock unavailable (no blocking)
| Component | CPU (avg) | Memory | Disk I/O |
|---|---|---|---|
| Zebra | 20-50% | 500MB | Low |
| Zaino | 5-10% | 150MB | Medium |
| Lightwalletd | 5-10% | 200MB | Medium |
| Faucet | 2-5% | 100MB | Low |
Total System:
- CPU: 0.8-1.0 cores
- Memory: 750-850MB
- Disk: 2.5GB
| Operation | Zaino | Lightwalletd |
|---|---|---|
| Cold start | 2-3 min | 3-4 min |
| Warm restart | 30 sec | 30 sec |
| Shield tx | 8 sec | 8 sec |
| Shielded send | 5 sec | 6 sec |
| Block confirmation | 30-60 sec | 30-60 sec |
| Wallet sync | 3-5 sec | 5-8 sec |
Pros:
- Simpler architecture (no external process)
- Better performance (no IPC overhead)
- Direct API access (no CLI parsing)
- Easier error handling
Cons:
- Library dependency (must update zingolib)
- Less flexibility (can't swap wallet implementations)
Decision: Pros outweigh cons for development use case
Pros:
- Predictable addresses for testing
- Easy to reproduce issues
- Simpler documentation (hardcode example addresses)
Cons:
- Not suitable for production
- Users can't generate custom wallets
Decision: Perfect for development, clearly documented as dev-only
Pros:
- Tests compatibility with both implementations
- Developers can choose preferred backend
- Catches backend-specific bugs
Cons:
- More complex docker-compose
- Double the testing matrix
Decision: Worth it for ecosystem compatibility
Scenario: Zaino/LWD can't reach Zebra
Symptoms:
- Sync fails
- Balance shows 0
- Transactions fail
Recovery:
- Services auto-retry connection
- Manual: docker-compose restart faucet
Scenario: Wallet thinks it's ahead of chain
Symptoms:
- "wallet height > chain height" error
- Balance incorrect
Recovery:
zeckit down
docker volume rm zeckit_faucet-data
zeckit up --backend zainoScenario: Zebra stops mining blocks
Symptoms:
- Block count not increasing
- Transactions stuck in mempool
Recovery:
docker-compose restart zebra-
Pre-mined Snapshots:
- Start with 1000+ pre-mined blocks
- Faster startup (under 30 seconds)
-
GitHub Action Integration:
- Reusable workflow
- Automated testing in CI
-
Multi-Wallet Support:
- Test wallet-to-wallet transfers
- Simulate multi-user scenarios
-
Monitoring:
- Prometheus metrics
- Grafana dashboards
- Alert on failures
zebra
β
zaino/lightwalletd (condition: service_healthy)
β
faucet (condition: service_started)
Note: Faucet uses service_started not service_healthy to avoid blocking on slow sync
Zebra:
test: ["CMD-SHELL", "timeout 5 bash -c 'cat < /dev/null > /dev/tcp/127.0.0.1/8232' || exit 1"]
interval: 30s
retries: 10
start_period: 120sZaino:
test: ["CMD-SHELL", "timeout 5 bash -c 'cat < /dev/null > /dev/tcp/127.0.0.1/9067' || exit 1"]
interval: 10s
retries: 60
start_period: 180sLightwalletd:
test: ["CMD-SHELL", "timeout 5 bash -c 'cat < /dev/null > /dev/tcp/127.0.0.1/9067' || exit 1"]
interval: 10s
retries: 30
start_period: 120s- Zebra Architecture
- Zaino Documentation
- Zingolib Documentation
- Zcash Protocol
- ZIP-316: Unified Addresses
Last Updated: February 7, 2026
Version: M2 ( Shielded Transactions)
Status: Complete