Support nodeKey on all SeiNode spec types (fullNode, archive, replayer)
Nobody has claimed this yet.
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 58/100
- Issue type
- Feature
- Clarity
- Mostly clear
- Activity status
- Quiet
- Tech stack
- go, kubernetes
- Domain
- devops, infrastructure
Research direction
Start with api/v1alpha1/seinode_types.go, the nodeKeyVolumes/nodeKeyMounts helpers, and validatorPlanner.Validate; compare their current validator.nodeKey wiring with PR #140. Then inspect the existing pod-spec and bootstrap tests before covering fullNode, archive, replayer, and validator behavior. Done means the field and CEL rule are relocated, all mode and bootstrap tests pass, and the LLD documents the generalization.
Written by the indexing model from the issue text.
Description
Problem
PR #140 added validator.nodeKey to support stable P2P node identity for migrating validators, but the field lives only on ValidatorSpec. Other SeiNode modes — fullNode, archive, and replayer — auto-generate a fresh node_key.json on every PVC creation, giving them a new node ID on every fresh deployment. Operators migrating fullNodes (RPC, sentry) or archive nodes from EC2 to K8s face the same impersonation-signal problem the validator feature solved: their permanent libp2p identity changes on cutover, persistent_peers entries elsewhere in the network become stale, peer reputation accumulated on the EC2 host is lost, and any topology tracker mapping node IDs to monikers shows a discontinuity.
Impact
- fullNode migrations break sentry topology. Sentries are often pinned in validators'
private_peer_idsconfigs by node ID. A new node ID on the K8s sentry silently breaks the gossip-shielding link to the validator. Same breakage shape as the validator case, potentially affecting more infrastructure since fullNodes are typically the public-facing tier. - Archive nodes and snapshotters lose accumulated peer reputation. These are long-lived; the network has learned which IDs to trust and route to. Regen drops that.
- Inconsistent migration UX. Validators get a clean cutover path via PR #140; everything else has to either regenerate node IDs (operationally painful) or accept the loss (operationally inconvenient).
- Operators today work around it manually by scraping
node_key.jsonfrom the EC2 host andkubectl cp-ing it onto the new PVC after deployment — out-of-band, no audit trail, no immutability guarantee.
Relevant experts
kubernetes-specialist— pod-spec mutation across all modes; bootstrap-vs-production policy uniformityplatform-engineer— API placement (top-levelSeiNodeSpec.nodeKeyvs. per-mode duplication); cross-field coupling rules with the existing validatorsigningKeyproduct-manager— scope cut: which modes ship in v1, what to defer
Proposed approach
The cleanest API is to promote nodeKey from ValidatorSpec up to SeiNodeSpec — node identity is orthogonal to mode (every Tendermint node has a node_key.json regardless of role). This is technically a breaking change to the just-shipped validator.nodeKey field, but PR #140 hasn't been live long enough for any operator to depend on it; the migration cost is essentially zero if we move now.
// api/v1alpha1/seinode_types.go
type SeiNodeSpec struct {
// existing fields...
// NodeKey declares the source of this node's P2P node key
// (node_key.json). Universal across modes — fullNode, archive,
// replayer, and validator. When omitted, seid auto-generates a
// fresh node_key.json on first start.
// +optional
NodeKey *NodeKeySource `json:"nodeKey,omitempty"`
}
ValidatorSpec loses its NodeKey field; SigningKey stays where it is. The signingKey ↔ nodeKey coupling rule lifts to SeiNodeSpec level:
!has(self.validator) || !has(self.validator.signingKey) || has(self.nodeKey)
(Reads as: "If validator.signingKey is set, nodeKey must be set." validatorPlanner.Validate gets the same Go-side mirror.)
Pod-spec wiring is mostly a path change. buildNodePodSpec already calls nodeKeyVolumes(node) / nodeKeyMounts(node); the helpers' nodeKeySecretSource path-checks node.Spec.Validator.NodeKey today and would change to node.Spec.NodeKey. One field-path change in the helper; callers unchanged.
Bootstrap-pod policy: production-only across all modes. The same peer-reputation argument that produced the production-only mount for validators applies to other modes — bootstrap pods crash, halt, restart, and their misbehavior shouldn't attribute to the node's permanent libp2p identity.
Replayer caveat. Replayers are ephemeral by design — restore from snapshot, replay, exit. They typically don't need a stable node ID. Allow the field structurally (it's optional everywhere) but document in the godoc that replayers usually don't set it.
Acceptance criteria
-
nodeKeymoves fromValidatorSpectoSeiNodeSpec; the validator field is removed - Pod-spec helpers updated to read from
spec.nodeKeyinstead ofspec.validator.nodeKey -
signingKey ↔ nodeKeycoupling rule lifted toSeiNodeSpecCEL;validatorPlanner.Validatemirrors - Pod-spec test coverage: each mode (fullNode, archive, replayer) has a test confirming
nodeKeyvolume + mount when set, and absence when unset - Bootstrap-pod regression guard extended: every bootstrap path verifies
nodeKeyabsence even whenSeiNodeSpec.nodeKeyis set - Integration test: fullNode SeiNode with
nodeKeyset boots production pod withnode_key.jsonmounted at expected path - LLD updated (or new mini-LLD added) documenting the cross-mode generalization and the field-relocation breaking change
Out of scope
- Adding
signingKeyto non-validator modes.signingKeyis consensus-specific and stays onValidatorSpec. - Drift detection for mid-life
nodeKeypatch on Running nodes. Covered by #137 — would extend naturally to all modes oncenodeKeyis atSeiNodeSpeclevel. - ConfigMap variant for
nodeKey. Defer; Secret-grade is the v1 shape. - Auto-rotation. Like
signingKey,nodeKey.secret.secretNameis immutable; rotation requires delete-and-recreate.
References
- PR #140 — initial
nodeKeysupport on validator - Issue #138 — original
nodeKeydesign with bootstrap-vs-production discussion - Issue #137 — drift detection (cross-cutting follow-up)
- LLD: docs/design-seinode-validator-signing-key-lld.md (currently validator-scoped; would generalize)
- Dominant language
- Go
- Stars
- 1
- Forks
- 2
- Avg merge
- 2h 29m
- Merged PRs (30d)
- 56
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from sei-protocol/sei-k8s-controller
-
Difficulty 5/5 Over a week Newbie friendliness 32/100
-
Difficulty 5/5 Over a week Newbie friendliness 32/100
sei-protocol/sei-k8s-controller#457 · 2 comments ·
-
Difficulty 3/5 1-2 days Newbie friendliness 68/100
-
Difficulty 4/5 3-5 days Newbie friendliness 45/100
-
Difficulty 3/5 1-2 days Newbie friendliness 65/100
All issues in sei-protocol/sei-k8s-controller
Similar issues
-
optimization optimization:agents-md-curator
Difficulty 2/5 1-3 hours Newbie friendliness 86/100
githubnext/gh-aw-cao#13143 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
blinklabs-io/bursa#904 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
yanet-platform/ipfw-go#129 ·
-
bug confmap/provider/googlesecretmanagerprovider needs triage
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
open-telemetry/opentelemetry-collector-contrib#51273 · 2 comments ·
-
bug: AI Gateway client filter lists "Unknown" twice when NULL and literal Unknown clients coexist Openbug
Difficulty 2/5 1-3 hours Newbie friendliness 90/100