Khromosome Validator Operator Guide (chain 777001, public beta)
Audience: an experienced Ethereum node operator who has never seen Khromosome before. Read the whole guide before you apply (
APPLICATION.md).Honest status, 2026-10-04. The network is a public beta on a testnet-grade genesis. 16 validators were in genesis. 8 are active, and all 8 run on one host operated by the founder (opensolara). The other 8 (indices 8–15) were exited after a July 2026 network split. A second full node (openclaw-vps) follows the chain without validating. You would be the first independent operator. That is the point of this programme, and it is also why the steps below include several that the founder has to complete before you can join.
Testnet KHROME has no monetary value and will not carry over to mainnet. Mainnet is a fresh genesis (
docs/raise/tokenomics-v2.md§3).
1. Network facts (read from the live beacon node, 2026-10-04)
| Item | Value |
|---|---|
| Chain ID / network ID | 777001 |
| Consensus | Standard Ethereum PoS (Casper FFG + LMD-GHOST). No custom consensus |
| Clients in production | Reth v1.8.0 (ghcr.io/paradigmxyz/reth:v1.8.0) + Lighthouse v8.2.2 (sigp/lighthouse@sha256:9a62bb8705455136e1cf96613460960f80dc2faa9d75b5c16a3bfcc9210dcdd1) |
| Slot / epoch | 12 s / 32 slots (≈ 6.4 min); finality lags about 2 epochs |
| Genesis time | 1779709290 (2026-05-25 UTC) |
| Genesis validators root | 0x0bafbe731b2a76a84656a89c4ecfd6b410dee12803d23fb47548856ea3f4270b |
| Fork versions | GENESIS 0x10000777, ALTAIR 0x20000777, BELLATRIX 0x30000777, CAPELLA 0x40000777, DENEB 0x50000777 (current), ELECTRA 0x60000777 scheduled at epoch 2,000,000,000 (i.e. not active) |
| EL forks | Shanghai and Cancun at genesis; pragueTime is set far in the future (Prague not active) |
| Deposit contract | 0x4242424242424242424242424242424242424242 (standard deposit contract bytecode, injected by the genesis generator) |
| Stake per validator | 32 KHROME (MIN_ACTIVATION_BALANCE = MAX_EFFECTIVE_BALANCE = 32 KHROME; ejection at 16) |
| Activation churn | MIN_PER_EPOCH_CHURN_LIMIT 4, CHURN_LIMIT_QUOTIENT 65536, so at most 4 activations per epoch |
| Deposit processing | Pre-Electra Eth1-data voting: ETH1_FOLLOW_DISTANCE 2048 blocks, EPOCHS_PER_ETH1_VOTING_PERIOD 64 |
| Exit rules | SHARD_COMMITTEE_PERIOD 256 epochs (≈ 27 h) after activation before a voluntary exit is accepted; MIN_VALIDATOR_WITHDRAWABILITY_DELAY 256 epochs |
| Public endpoints | RPC https://rpc.khromosome.xyz, WS wss://ws.khromosome.xyz, explorer https://explorer.khromosome.network |
The deposit path has never been used on this chain. The head block's
eth1_data.deposit_countis 0: all 16 validators came from the genesis state, and no deposit has ever been made through the contract. The first external activation is therefore also the first live test of deposit processing on 777001. We will do it with one validator first (§6).
2. Hardware and hosting
From docs/l1/03-infrastructure.md §2. These are minimums for a validator node
running EL + CL + VC:
| Resource | Minimum | Notes |
|---|---|---|
| CPU | 4 cores / 8 threads | |
| RAM | 16 GB (32 GB preferred) | Reth ~4–8 GB, Lighthouse BN ~2–4 GB |
| Disk | 512 GB NVMe | Not SATA, not HDD. Reth is IOPS-sensitive |
| Network | 1 Gbit, ≥ 20 TB/mo or unmetered | Public IPv4 with TCP+UDP 9000 and TCP+UDP 30303 reachable |
| OS | Ubuntu 24.04 LTS (what the runbooks assume) | Docker or systemd; both are covered below |
Diversity requests (they affect selection; see APPLICATION.md):
- Hosting provider: today every founder node is on Contabo. Any other
provider (Hetzner, OVH, AWS, bare metal, home lab with a good uplink)
improves the network's resilience.
- Region / jurisdiction: non-US preferred for the first operators.
- Client: Reth + Lighthouse is the only pair proven on this chain. A
Geth + Prysm template exists (node/clients/docker-compose.geth-prysm.yml)
but is unvalidated. If you want to run it, plan it with us as a
separate, deliberate test.
3. Get the genesis files and peers
3.1 The genesis set (published by the founder; not in this repo)
The chain runs from five files that the founder holds on the production
hosts at /root/khrome-node/testnet/:
| File | SHA-256 (production copy, 2026-10-04) |
|---|---|
genesis.json (EL) |
db43e9941046216088c18d96896fd47a75be49fe35c93ac548b9e355b640e9f4 |
config.yaml (CL) |
34908657b7b5832d15d11a307d149158f808316336e234c464356a5d6524a14f |
genesis.ssz (CL state) |
53c5bc3f7fe3492c0021a80366545c8b4246048e5a6b4d6cf6f54fbdc57e5a2f |
deploy_block.txt |
d9b2aefb1febe2dd6e403f634e18917a8c0dd1a440c976e9fe126b465ae9fc8d |
deposit_contract_block.txt |
9a271f2a916b0b6ee6cecb2426f0b3206ef074578be55d9bc94f6f3fe3ab86aa |
Do not use
docs/l1/genesis/genesis.jsonordocs/l1/genesis/config.yamlfrom this repo. Those are the original templates, with placeholder allocations andMIN_GENESIS_TIME: 0. They do not produce the live chain.
Founder action F1: publish these five files at a stable HTTPS URL
(referred to below as $GENESIS_URL) and confirm the hashes above.
Until that happens, the founder sends them to you directly.
sudo mkdir -p /opt/khrome/testnet && cd /opt/khrome/testnet
for f in genesis.json config.yaml genesis.ssz deploy_block.txt deposit_contract_block.txt; do
curl -fsSLO "$GENESIS_URL/$f"
done
sha256sum * # must match the table above exactly. Stop if any differs
openssl rand -hex 32 | sudo tee /opt/khrome/jwt.hex >/dev/null && sudo chmod 600 /opt/khrome/jwt.hex
3.2 Peers (the honest blocker)
The founder's nodes currently peer over a private Tailscale tailnet
(100.x addresses). Their ENR and enode advertise tailnet IPs, and
validator hosts have no public p2p inbound by design (docs/l1/03 §4).
An outside operator cannot reach them as things stand.
Founder action F2: one of the following:
- (preferred) stand up a public sentry/bootnode: a non-validating
Reth + Lighthouse node with public p2p ports and no validator keys.
Publish its ENR and enode. Validator hosts stay closed; the sentry
relays gossip.
- or invite each operator into the tailnet with an ACL limited to
tag:khrome-validator p2p ports (30303 and 9000) only.
You will receive:
- BOOT_ENR: a beacon ENR (enr:-…)
- BOOT_PEER_ID + multiaddr: for --libp2p-addresses / --trusted-peers
- EL_ENODE: an enode://…@host:30303
Production uses static peering on both layers (reth --trusted-peers,
Lighthouse --libp2p-addresses + --trusted-peers). After the July 2026
split we treat static peering as mandatory: discovery alone is not enough
on a network this small.
4. Run the node
This mirrors the founder's production containers (host networking, the same
images, the same flags), with your own IP and fee recipient. PUBLIC_IP is
your host's public IPv4. FEE_RECIPIENT is an EVM address you control
(it collects priority fees from blocks you propose).
export PUBLIC_IP=203.0.113.10 # yours
export FEE_RECIPIENT=0xYourAddress # yours. Never 0x3333…3333
export BOOT_ENR='enr:-...' BOOT_PEER_ID=16Uiu2... BOOT_MULTIADDR=/ip4/x.x.x.x/tcp/9000/p2p/16Uiu2...
export EL_ENODE='enode://...@x.x.x.x:30303'
# Stable EL identity: keep the p2p key on the host (see node/scripts/recreate-reth.sh:
# a rotating discovery secret silently broke trusted peering on 2026-05-31).
openssl rand -hex 32 | sudo tee /opt/khrome/p2p-secret >/dev/null && sudo chmod 600 /opt/khrome/p2p-secret
docker run -d --name khrome-reth --restart unless-stopped --network host \
-v khrome-reth-data:/data -v /opt/khrome/testnet:/testnet:ro \
-v /opt/khrome/jwt.hex:/jwt.hex:ro -v /opt/khrome/p2p-secret:/p2p-secret:ro \
ghcr.io/paradigmxyz/reth:v1.8.0 node \
--chain /testnet/genesis.json --datadir /data --full \
--p2p-secret-key /p2p-secret \
--authrpc.addr 127.0.0.1 --authrpc.port 8551 --authrpc.jwtsecret /jwt.hex \
--http --http.addr 127.0.0.1 --http.port 8545 --http.api eth,net,web3 \
--metrics 127.0.0.1:9101 \
--port 30303 --nat "extip:$PUBLIC_IP" --trusted-peers "$EL_ENODE"
docker run -d --name khrome-lh-bn --restart unless-stopped --network host \
-v khrome-lh-data:/data -v /opt/khrome/testnet:/testnet:ro -v /opt/khrome/jwt.hex:/jwt.hex:ro \
sigp/lighthouse:v8.2.2 lighthouse beacon_node \
--testnet-dir /testnet --datadir /data \
--execution-endpoint http://127.0.0.1:8551 --execution-jwt /jwt.hex \
--http --http-address 127.0.0.1 --http-port 5052 \
--metrics --metrics-address 127.0.0.1 --metrics-port 5054 \
--listen-address 0.0.0.0 --port 9000 --discovery-port 9000 \
--enr-address "$PUBLIC_IP" --enr-udp-port 9000 --enr-tcp-port 9000 --disable-upnp \
--boot-nodes "$BOOT_ENR" --libp2p-addresses "$BOOT_MULTIADDR" --trusted-peers "$BOOT_PEER_ID" \
--suggested-fee-recipient "$FEE_RECIPIENT"
The systemd equivalents are in docs/l1/04-deploy/systemd/. Use those
units with --testnet-dir /etc/khrome/testnet, replacing the placeholders
<BOOTNODE_ENR> and <FEE_RECIPIENT>.
Sync. Lighthouse syncs from genesis (there is no public checkpoint-sync endpoint today; the founder can expose one read-only later). The chain is young (about 950k slots), so a full sync from genesis is practical.
Check that you are synced before importing any key:
curl -s 127.0.0.1:5052/eth/v1/node/syncing | jq # is_syncing:false, is_optimistic:false
curl -s 127.0.0.1:5052/eth/v1/node/peer_count | jq # connected ≥ 1 (ideally ≥ 2)
curl -s 127.0.0.1:5052/eth/v1/beacon/states/head/finality_checkpoints | jq
curl -s -X POST 127.0.0.1:8545 -H 'content-type: application/json' \
--data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'
# compare with https://rpc.khromosome.xyz. Head should match within a slot or two
Firewall: open only TCP+UDP 9000 and TCP+UDP 30303. Keep 8545, 8551,
5052, and every metrics port bound to 127.0.0.1. Never expose the Engine
API (8551).
5. Generate validator keys (offline, for a custom chain)
You generate and keep your own keys. The founder never sees your mnemonic or keystores, and you should never send them to anyone.
Option A (recommended): Lighthouse validator-manager. It reads the
chain's own config.yaml, so the deposit signature is computed for
Khromosome's fork version and you do not have to type it in by hand:
# on an offline machine with the same genesis set copied over
lighthouse validator-manager create \
--testnet-dir /opt/khrome/testnet \
--first-index 0 --count 1 \
--eth1-withdrawal-address 0xWITHDRAWAL_ADDRESS \
--suggested-fee-recipient 0xYourAddress \
--output-path ./khrome-validators
# → validators.json (keystores, for import) and deposits.json (public deposit data)
Option B: ethstaker-deposit-cli (v1.x, the maintained successor
to staking-deposit-cli) with a custom-chain setting. --devnet_chain_setting
takes network_name, genesis_fork_version, exit_fork_version, and an
optional genesis_validator_root.
Critical: recent
ethstaker-deposit-clireleases default to--compounding(0x02 credentials). Compounding credentials are an Electra feature, and Electra is not active on 777001. Always pass--regular_withdrawal(0x01) and--amount 32. A 0x02 deposit on a Deneb chain is not something to experiment with on someone else's stake.
./deposit new-mnemonic --num_validators 1 \
--regular_withdrawal --amount 32 \
--withdrawal_address 0xWITHDRAWAL_ADDRESS \
--devnet_chain_setting '{"network_name":"khromosome","genesis_fork_version":"10000777","exit_fork_version":"40000777","genesis_validator_root":"0x0bafbe731b2a76a84656a89c4ecfd6b410dee12803d23fb47548856ea3f4270b"}'
Notes:
- Deposit signatures use GENESIS_FORK_VERSION 0x10000777. If a tool
signs with Ethereum mainnet's 0x00000000, the deposit is silently
ignored by the beacon chain, and the 32 KHROME is lost to the contract.
Verify deposits.json has fork_version 10000777 before anything is submitted.
- Voluntary exits are signed with the CAPELLA fork version (0x40000777)
under EIP-7044.
- Withdrawal credentials: use 0x01 (execution address). On the
testnet the 32 KHROME stake is provided by the founder (§6), so the
withdrawal address is agreed in writing before the deposit: either a
founder-designated address (the stake goes back to the foundation on exit)
or your own address under a disclosed delegation. Withdrawal credentials
cannot be changed after the deposit.
- Write the mnemonic on paper or steel, keep it offline, and keep two
physical copies (docs/l1/04-deploy/KEYS.md §2).
Import (on the validator host, after sync). If you used Option B
(keystore files), use account validator import as shown. If you used Option A
(validators.json), start the VC below with --http --http-address 127.0.0.1
first. Then run lighthouse validator-manager import --validators-file
validators.json --vc-url http://127.0.0.1:5062 --vc-token <api-token.txt>.
Check the exact flags against lighthouse validator-manager import --help
for v8.2.2.
docker run --rm -it --network host -v khrome-vc-data:/data -v /opt/khrome/testnet:/testnet:ro \
-v "$PWD/khrome-validators":/in:ro sigp/lighthouse:v8.2.2 \
lighthouse account validator import --testnet-dir /testnet --datadir /data --directory /in
shred -u khrome-validators/*keystore* 2>/dev/null # remove the transferred copy
docker run -d --name khrome-lh-vc --restart unless-stopped --network host \
-v khrome-vc-data:/data -v /opt/khrome/testnet:/testnet:ro sigp/lighthouse:v8.2.2 \
lighthouse validator_client --testnet-dir /testnet --datadir /data \
--beacon-nodes http://127.0.0.1:5052 --suggested-fee-recipient "$FEE_RECIPIENT" \
--enable-doppelganger-protection \
--metrics --metrics-address 127.0.0.1 --metrics-port 5064
Start the VC before the deposit is processed, so it is ready the moment the validator activates.
6. How an outside validator is activated: the actual path
Khromosome is an unmodified Ethereum beacon chain, so activation works exactly as it does on Ethereum. There is no allow-list, and no admin key can activate or reject a validator. Anyone who sends a valid 32-KHROME deposit to the deposit contract becomes a validator once the deposit is processed. The founder's role is practical, not a permission:
| Step | Who | What |
|---|---|---|
| 1 | You | Run a synced node (§4) and generate keys (§5). Send the founder only deposits.json, which is public data (pubkey, withdrawal credentials, signature, deposit_data_root). |
| 2 | Founder (F3) | Supply the stake. The entire testnet KHROME supply sits in the founder's Trezor, so there is no other source of 32 KHROME. Either (a) the founder submits your deposit directly from his wallet, or (b) he sends you 32 KHROME + gas and you submit it yourself. With (a), your keys never leave you, which is the intended split. |
| 3 | Whoever submits | Call the deposit contract: cast send 0x4242424242424242424242424242424242424242 "deposit(bytes,bytes,bytes,bytes32)" <pubkey> <withdrawal_credentials> <signature> <deposit_data_root> --value 32ether --rpc-url https://rpc.khromosome.xyz (values from deposits.json, 0x-prefixed). |
| 4 | Protocol | The beacon chain waits ETH1_FOLLOW_DISTANCE (2048 EL blocks, ≈ 6.8 h). Proposers then vote the new deposit root in through Eth1-data voting (a majority within a 64-epoch period, ≈ 6.8 h). The deposit is included in a beacon block, and the validator enters the activation queue (≤ 4 per epoch). It becomes active a few epochs after its eligibility epoch is finalized. Expect roughly 14 hours or more from deposit to active_ongoing, based on the live parameters. |
| 5 | You | Watch status: curl -s 127.0.0.1:5052/eth/v1/beacon/states/head/validators/<pubkey> \| jq .data.status moves through pending_initialized → pending_queued → active_ongoing. |
Founder action F4: dry run first. Because deposit_count is 0, the
founder should first activate one new founder-owned validator through
this exact path on a separate host. That proves Eth1-data voting and deposit
inclusion work on 777001 before an operator's deposit relies on them.
Exited validators cannot be revived. Indices 8–15 are withdrawal_done.
In Ethereum PoS an exit is permanent: a validator that has exited can never
become active again, and a new deposit to an exited pubkey only adds balance
that is then swept to its withdrawal address. Every new operator needs new
keys and a new deposit. Never reuse those pubkeys.
Liveness math. Finality needs more than 2/3 of active stake attesting.
Today that is 8 validators, all on one host. With you added (say 4
validators), the founder holds 8/12. Taking either party offline would leave
the other below 2/3, so finality would stop (blocks would still be
produced). Real fault tolerance needs at least 3 operators, with none
holding 1/3 or more. That is the target topology in
docs/superpowers/specs/2026-06-29-C-decentralization-credible-neutrality-design.md §2.
7. Rewards: what you will (and will not) earn
Be clear-eyed. On the testnet there is no meaningful income from validating.
- Consensus-layer rewards are effectively zero by design. Live
balances after four months are 32.000002 KHROME per validator. The
monetary design moves issuance to the execution layer (zero-point
MonetaryController), and that is not live (devnet only). - Priority fees go to your
--suggested-fee-recipientfor blocks you propose. They are tiny on a beta chain. ValidatorRewards(app-layer pool). This contract pays an equal share per enrolled address on a geometric-decay curve (3% of the remaining pool per 30 days;docs/l1/11-validator-rewards.md). Enrollment: 1. Founder action F5: theKhromeChainprotocolAdmincallssetValidator(<your EVM address>, true)on KhromeChain (0x37dda7af04436c502f629c0b2ad97a6a0221e951). 2. You callenroll()on ValidatorRewards from that address. (The staking UI atstaking.khromosome.networkwraps this.) Later you callclaim().- Today the testnet ValidatorRewards (
0x7deEb51540d6E473742DdcB61C6061f04D545b2a) is unfunded and not started (balance 0,started() == false, checked 2026-10-04). Founder action F6: fund it and callstart()if testnet rewards are to be offered. - v1 rewards membership, not measured beacon participation. A
KhromeChainvalidator address is separate from your BLS validator key; linking them is an honour-system mapping we record innode/validators/operators.json. - Mainnet: the validator-rewards bucket is 15% of the 777M supply
(
docs/raise/tokenomics-v2.md§2.5). Early independent operators are the people this bucket exists for, but no mainnet allocation is promised by this guide. Any operator incentive will be in a written agreement reviewed by counsel.
8. Slashing protection: read twice
- Never run the same key on two machines, even briefly, even "for failover."
This is the classic self-slashing mistake (
KEYS.md§2). - Never restore a VC from an old backup without its slashing-protection
database. If you move hosts: stop the old VC, wait at least two epochs,
export the EIP-3076 interchange (
lighthouse account validator slashing-protection export), import it on the new host, and only then start. - Keep
--enable-doppelganger-protectionon. It costs about 2 epochs of missed duties at every start, and in exchange it catches a key running somewhere else. - Network splits are a slashing trap. In July 2026 the two founder hosts partitioned and each half built its own fork. Reconnecting validators that attested on both sides can produce conflicting votes. If the founder announces a split, stop your VC and wait for instructions. Do not "fix" it by restarting against whichever peer you can reach.
- Slashing (on top of being forcibly exited) burns part of the 32 KHROME stake. On the testnet the stake is founder-funded, but a slashing is still a public event.
9. Monitoring
Minimum checks, scripted every minute and alerted to you:
| Check | Command / metric | Alert when |
|---|---|---|
| Beacon synced | /eth/v1/node/syncing |
is_syncing or is_optimistic true for more than 5 min |
| Peers | /eth/v1/node/peer_count |
connected < 1 |
| Finality | /eth/v1/beacon/states/head/finality_checkpoints |
finalized epoch flat for more than 4 epochs |
| Your validator | /eth/v1/beacon/states/head/validators/<index> |
status ≠ active_ongoing or balance falling |
| EL head | eth_blockNumber vs rpc.khromosome.xyz |
lag > 3 blocks |
| Disk | df |
> 80% |
Prometheus endpoints (localhost only): Reth :9101, Lighthouse BN
:5054, VC :5064. The founder's detector scripts/monitor/khrome-watch.py
watches stalls and privileged actions. The public validator dashboard is
node/validators/index.html.
10. Operator commitments (what we ask of you)
These are targets for a public beta, not a paid SLA. They become contractual only in a written mainnet operator agreement.
- Uptime ≥ 99% for each validator, measured over 30 days by attestation participation.
- 24 hours' notice for planned downtime; never take more than one host down at once if you run several.
- Client upgrades within 72 hours of a coordinated release announcement. Hard forks happen on the announced schedule.
- Incident response: acknowledge a chain-incident page within 4 hours.
Follow the split/stall playbooks (
docs/l1/14-operations.md§3). - Key custody is yours alone. No shared keys, and no remote signer you do not control.
- Identity: consent to be listed by name (or a pseudonym that we know
privately) in
node/validators/operators.jsonand, optionally, inOperatorRegistrywith a KYC hash. A registry entry is a disclosure overlay. It is not a consensus gate. - Sanctions: you are not a sanctioned person, and you will not operate from a comprehensively sanctioned jurisdiction.
- Exit: give 7 days' notice. Then run
lighthouse account validator exit(allowed only afterSHARD_COMMITTEE_PERIOD, ≈ 27 h after activation). The stake returns to the agreed withdrawal address after the withdrawability delay.
11. Founder-side checklist (must be done before the first outside operator)
| # | Action | Why |
|---|---|---|
| F1 | Publish the 5-file genesis set + SHA-256 at a stable URL | Operators cannot start a node without it |
| F2 | Public sentry/bootnode (no keys) or tailnet invites with p2p-only ACL; publish ENR / peer-ID / enode | Current peering is tailnet-only |
| F3 | Fund each approved operator's 32-KHROME deposit (submit their deposits.json) |
All testnet KHROME is in the founder's Trezor |
| F4 | Dry-run one founder-owned deposit activation end to end | deposit_count is 0; the path has never been used |
| F5 | KhromeChain.setValidator(operatorAddr, true) per operator |
Needed for ValidatorRewards.enroll() |
| F6 | Fund + start() testnet ValidatorRewards (optional) |
It is currently empty and not started |
| F7 | Expose the beacon API read-only at beacon.khromosome.xyz (Caddy, GET-only allow-list) |
The public dashboard needs it |
| F8 | Replace the production fee recipient 0x3333…3333 with a real address |
Production BN/VC use this placeholder today |
| F9 | Update node/validators/operators.json when each operator activates |
Keeps the public dashboard honest |