Security
The Generator client runs as a sidecar next to an execution node, not as part of your validator's consensus process. This page covers the security implications of the two deployment shapes operators ask about most: running the Generator on the same machine as your validator, and running it on a separate machine connected over a network.
Same-machine deployment
Running the Generator client on the same machine as your validator (and its execution node) is the default shape and is safe. The Generator client is a separate process with its own key, its own resources, and a one-way relationship with the execution node. It does not touch consensus.
Key separation
The Generator client generates and stores its own operator (delegate) key locally. It never reads, writes, or holds your validator's consensus key or withdrawal key:
| Key | Held by | Used for |
|---|---|---|
| Operator / delegate key | Generator client (local keyring) | Signing block batches, registering on ShinzoHub. |
| Consensus key | Validator client | Signing blocks and participating in consensus. |
| Withdrawal key | Browser wallet (off-machine) | Signing the one-time assertion that links the operator key to your validator during registration. |
The withdrawal key is used exactly once, in a browser wallet, to sign the assertion that ties the operator key to the validator's identity. After that, the Generator client runs on the operator key alone. See Registration and the architecture reference for the full flow.
Because no key material is shared, a compromise of the Generator client's operator key does not expose your validator's consensus or withdrawal keys.
Reject inbound replication
The Generator client is a write-only data producer. It reads blocks from the execution node and publishes signed documents to Hosts over P2P, but it rejects all inbound P2P replication. This is enforced by a replication filter in pkg/generator/replication_filter.go and by defradb.p2p.accept_incoming, which defaults to false. The Generator client never accepts documents from peers, so even a peer that connects to it cannot push data into its database.
See the Generator client reference for details.
Resource isolation
The Generator client is a lightweight sidecar: a ~50 MB binary with its own CPU and memory budget. It is CPU-light but storage-I/O-sensitive, because every block is fetched, structured, signed, and written to its local DefraDB instance before being published. The risk to a co-located validator is resource contention, not protocol interference. The Generator client does not touch consensus (see Key separation), so isolation is an operational concern, not a safety one.
Size the machine for the execution node first, then add the Generator overhead on top. The execution node's footprint dwarfs the Generator client's: a snap-synced full node typically needs over 650 GB of fast SSD storage and at least 16 GB of RAM, and an archive node can exceed 12 TB. The Generator client with pruning enabled keeps its own data bounded at roughly 50 to 100 GB; provision 300 to 500 GB of disk to leave headroom for growth, snapshot serving, and P2P replication. See hardware requirements for the full table.
To keep the two workloads from competing on a shared machine:
- Run the Generator in its own process or container with its own resource limits (Docker
--cpus/--memoryflags, or a cgroup). Do not let it borrow unbounded resources from the execution node under load. - Give the Generator's DefraDB store (
storePath) its own disk or SSD partition, separate from the execution node's data directory. The Generator is storage-I/O-bound; co-locating both data stores on the same device lets the two compete on the same I/O queue and can stall the execution node's block processing under catch-up load. - Decide pruned versus archival deliberately. In archival mode (pruning disabled), the Generator's storage grows linearly with chain history. Running archival on a validator machine risks crowding the execution node's much larger data set. Pruned is the right choice for almost all validator-side deployments.
- Keep
DEFRADB_KEYRING_SECRETstable across restarts. If it changes, the Generator cannot reload its existing DefraDB identity and will fail to start, a reliability risk to your data feed, not to consensus.
For a worked same-machine example, see the Validator with Geth deployment guide.
Separate-machine deployment
When the Generator client and the execution node (or validator) run on different machines, the question becomes which ports to expose across the network boundary. The rule of thumb: expose the P2P port, restrict the management API behind a reverse proxy, and keep the raw database API private.
Topology
The execution node feeds the Generator client over a restricted private link. The Generator client publishes to Host clients over P2P on 9171. Operators and monitoring reach only the safe management paths through a reverse proxy on 443. The raw DefraDB API on 9181 stays bound to localhost and never crosses the firewall.
Port exposure
| Port | Service | Expose publicly? | Recommendation |
|---|---|---|---|
9171 | DefraDB P2P (libp2p) | Yes | Open on the firewall. This is how Hosts subscribe and receive data. |
8080 | Health, metrics, registration, schema | Only behind a reverse proxy | Do not publish raw. Put an nginx (or equivalent) allowlist in front that proxies only the safe paths (/health, /registration, /registration-app, /metrics, /snapshots, /api/v1/schema) and returns 404 for everything else. See the nginx with snapshots example for a working config. |
9181 | DefraDB GraphQL / REST API | No | Bind to localhost or a private network. This port gives raw, unauthenticated read/write access to the local DefraDB database. Publishing it to 0.0.0.0 lets anyone read or mutate the Generator's data. |
The shipped production tooling (docker-compose-prod.yml and indexer-prod-setup.sh in the shinzo-generator-client repo) follows this pattern: it publishes 9171, fronts 8080 with an nginx allowlist, and never publishes 9181.
How this differs from a Host
Host clients intentionally expose 9181 because serving GraphQL queries to subscribers is their job. Generator clients only produce data and have no reason to answer external queries, so their 9181 should stay closed. The two roles have opposite exposure profiles on the same port.
Execution-node side
On the execution node side of the link, restrict its JSON-RPC and WebSocket ports (commonly 8545 and 8546) to the Generator's IP via a private network or VPC firewall. The Generator client only reads from the node; it never writes to it. If the connection must cross a public boundary, authenticate it with an API key or a reverse proxy rather than exposing the node unauthenticated. See the install page's API key guidance for the header configuration.
Schema endpoint auth
The shipped production scripts set SCHEMA_AUTH_MODE=none, which disables authentication on the /api/v1/schema endpoints. This is acceptable when 8080 is already behind a reverse-proxy allowlist that only proxies known-safe paths. If you expose schema management more broadly, switch SCHEMA_AUTH_MODE to token and provide accepted tokens via SCHEMA_API_KEYS. See the config reference for the full set of values.
MEV-boost and block construction
A common question from validators running MEV-boost is whether the Generator interacts with block construction or depends on the block's extraData field. It does not.
For example, on Ethereum Mainnet, MEV-boost builders construct the block header on the validator's behalf. The validator does not control extraData in that flow. Shinzo's validator-identity design deliberately avoids depending on it: identity is read from the AssertionSigned event emitted by the outpost contract on your source chain, then relayed to ShinzoHub, not from the block header. Because the assertion is signed by your withdrawal key and verified on-chain by the outpost, who built the block is irrelevant to how Shinzo identifies you.
The practical consequence of this is that running the Generator does not change your MEV-boost setup, and MEV-boost does not change how Shinzo identifies you. You do not need to disable MEV-boost, modify your builder configuration, or tag extraData to participate in Shinzo.
This point is covered in the outpost reference, where the EVM implementation notes that there is no extraData tagging and no dependency on who built the block.
Need help
- For onboarding and technical support, join the Shinzo Discord.
- To report a documentation bug or request a feature, open an issue in the docs repo.
- For a technical issue with the Generator client, open an issue in the shinzo-generator-client repo.