Files
universe/k8s/zoo-mainnet/zood-mv-statefulset.yaml
zeekayandHanzo Dev 619f3853b1 chain RPC is /v1/chain/c; luxd dropped /v1/bc in v1.36.179
zood pinned v1.36.68 and the wallet still offered /mainnet/ext/bc/C/rpc for both
Lux and Hanzo. luxd removed those spellings in v1.36.179, so the wallet was
handing users chain endpoints that no current node answers.

zood and the wallet now name the chain one way, on v1.36.181.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-09 12:18:00 -07:00

185 lines
6.0 KiB
YAML

# Zoo mainnet validators — Zoo EVM chainID 200200 on Lux primary networkID 1.
#
# THIS FILE EXISTS BECAUSE THE STATEFULSET DID NOT. zood-mv ran for months with
# no manifest anywhere in any repo: it was created by hand and every subsequent
# change was a `kubectl patch`, so the cluster was the only record of what Zoo
# mainnet actually was. Generated from the live object and reconciled — keep it
# that way, and change Zoo mainnet by editing this file and applying it.
#
# THE TWO IMAGES BELOW ARE ONE VALUE. init.sh does
# cp /luxd/build/plugins/* /data/plugins/
# and the node runs --plugin-dir=/data/plugins, so the INIT container's image —
# not the node's — decides which EVM plugin binary gets loaded, on every restart.
# When init sat at v1.36.2 under a v1.36.55 node, every C-Chain init died with
# VM initialization failed error="zap decode initialize response: unexpected EOF"
# while the plugin itself logged "ZAP VM initialized successfully": the plugin was
# healthy, the CLIENT could not decode a reply carrying a field (quasarExport) that
# the older plugin never emitted. 200200 had no C-Chain at all until they matched.
#
# LIVENESS MUST NOT DEPEND ON THE C-CHAIN. Liveness KILLS. It was an
# `eth_blockNumber` exec probe, so a node that had not finished bootstrapping was
# SIGTERMed at 300s + 10*30s = 600s, and a node killed every 600s never finishes
# bootstrapping — the probe suppressed the thing that would have cleared it.
# "Is the process wedged?" (liveness) and "should this node serve RPC?"
# (readiness, which only de-registers from the Service) are different questions.
apiVersion: apps/v1
kind: StatefulSet
metadata:
labels:
app: zood-mv
name: zood-mv
spec:
persistentVolumeClaimRetentionPolicy:
whenDeleted: Retain
whenScaled: Retain
podManagementPolicy: Parallel
replicas: 5
revisionHistoryLimit: 10
selector:
matchLabels:
app: zood-mv
serviceName: zood-mv
template:
metadata:
labels:
app: zood-mv
spec:
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- podAffinityTerm:
labelSelector:
matchLabels:
app: zood-mv
topologyKey: kubernetes.io/hostname
weight: 100
containers:
- command:
- /bin/sh
- /scripts/startup.sh
image: ghcr.io/luxfi/node:v1.36.181@sha256:3ff4841e76b407e774b59ea33cdb691bc0b5b6dfdebc0e5ea71bd1119d059cad
imagePullPolicy: IfNotPresent
livenessProbe:
failureThreshold: 6
httpGet:
path: /v1/health/liveness
port: 9630
scheme: HTTP
initialDelaySeconds: 120
periodSeconds: 30
successThreshold: 1
timeoutSeconds: 10
name: zood
# GOMEMLIMIT is the SOFT ceiling that makes Go GC harder as it nears the
# cgroup limit instead of sailing into a SIGKILL. Its absence is not a
# restart-noise problem: an OOM landing mid-write can leave a node holding
# a divergent CONSENSUS-CERTIFIED chain, which it then GOSSIPS — that is
# what took hanzo-mainnet down for hours on 2026-08-06 and needed a
# node-by-node state transplant to clear. Held below the 3Gi hard limit.
env:
- name: GOMEMLIMIT
value: 2GiB
ports:
- containerPort: 9630
name: http
protocol: TCP
- containerPort: 9631
name: staking
protocol: TCP
readinessProbe:
failureThreshold: 6
httpGet:
path: /v1/health/liveness
port: 9630
scheme: HTTP
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 5
resources:
limits:
cpu: '2'
memory: 3Gi
requests:
cpu: 300m
memory: 900Mi
startupProbe:
failureThreshold: 60
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
tcpSocket:
port: 9630
timeoutSeconds: 1
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /data
name: data
- mountPath: /scripts
name: scripts
- mountPath: /genesis
name: genesis
readOnly: true
dnsPolicy: ClusterFirst
imagePullSecrets:
- name: ghcr-zooai
- name: ghcr-secret
- name: hanzo
initContainers:
- command:
- /bin/sh
- /scripts/init.sh
image: ghcr.io/luxfi/node:v1.36.181@sha256:3ff4841e76b407e774b59ea33cdb691bc0b5b6dfdebc0e5ea71bd1119d059cad
imagePullPolicy: IfNotPresent
name: setup
resources: {}
securityContext:
runAsGroup: 0
runAsUser: 0
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /data
name: data
- mountPath: /scripts
name: scripts
- mountPath: /staking-keys
name: staking
readOnly: true
restartPolicy: Always
schedulerName: default-scheduler
securityContext:
fsGroup: 1000
runAsGroup: 1000
runAsUser: 1000
terminationGracePeriodSeconds: 30
volumes:
- configMap:
defaultMode: 493
name: zood-mv-startup
name: scripts
- configMap:
defaultMode: 420
name: zood-mv-genesis
name: genesis
- name: staking
secret:
defaultMode: 256
secretName: zood-mv-staking
updateStrategy:
type: RollingUpdate
volumeClaimTemplates:
- apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 40Gi
storageClassName: do-block-storage
volumeMode: Filesystem