Skip to content

feat(sidecar/assemble-genesis): apply spec.genesis.overrides to assembled genesis.json#181

Merged
bdchatham merged 1 commit into
mainfrom
feat/genesis-overrides
May 18, 2026
Merged

feat(sidecar/assemble-genesis): apply spec.genesis.overrides to assembled genesis.json#181
bdchatham merged 1 commit into
mainfrom
feat/genesis-overrides

Conversation

@bdchatham
Copy link
Copy Markdown
Contributor

@bdchatham bdchatham commented May 18, 2026

Summary

SIP-3 testing needs a fresh test cluster whose staking.params.unbonding_time is 600s, not the cosmos default of 21 days. The controller already accepts SeiNodeDeployment.spec.genesis.overrides and propagates them through, but the sidecar was dropping them on the floor at the assemble-genesis step. This PR closes that gap.

Wire contract

AssembleGenesisRequest gains:

Overrides map[string]json.RawMessage `json:"overrides,omitempty"`

Keys are dotted snake_case paths into genesis.app_state. The first segment is the cosmos module name (a top-level key in app_state); subsequent segments walk into that module's JSON tree and replace the leaf verbatim. Values are raw JSON, so callers can override scalars, numbers, or whole objects:

key value
staking.params.unbonding_time "600s"
gov.params.max_deposit_period "60s"
staking.params.max_validators 50
gov.params.voting_params {"voting_period":"60s","quorum":"0.4"}

Validator-side flow change

GenesisAssembler.Handler() order is now:

downloadGentxFiles
  -> addMissingGenesisAccounts
  -> addExternalGenesisAccounts
  -> collectGentxs
  -> applyOverrides   <-- new
  -> uploadGenesis
  -> uploadPeers

Overrides are applied after collect-gentxs so any validator-derived state and persistent peers baked in by genutil.GenAppStateFromConfig are already in place — the override step is an in-place JSON patch on the final assembled genesis.json.

Design anchors (from the coral round)

  • Single SND-level dispatch; no per-node fan-out for overrides.
  • Bootstrap-only — the sidecar doesn't enforce immutability; the controller does that via CEL.
  • Fails loudly on bad keys (empty, single-token, trailing/double dot, empty value, unknown module, non-object intermediates) so misconfiguration surfaces as a FailedTaskDetail on the owning SeiNodeDeployment rather than as a silently-ignored field.
  • No cosmos-sdk module allowlist — the chain will fail loud on garbage at InitGenesis.

Other changes

  • Drops the dead GenesisParams field from GenerateGentxRequest and its client-side mirror. The "reserved for future genesis customization" comment is now the dedicated Overrides path on the SND-level assemble task.
  • New helper applyGenesisOverrides lives in sidecar/tasks/genesis_overrides.go; GenesisAssembler.applyOverrides is the disk-I/O glue that re-reads config/genesis.json, calls the helper, and writes back via genutil.ExportGenesisFile.

Companion change

The controller-side wiring (populating assembleParams.Overrides from SeiNodeDeployment.spec.genesis.overrides in internal/planner/group.go) is being implemented in parallel in sei-protocol/sei-k8s-controller. See sei-protocol/sei-k8s-controller#270.

Test plan

  • go test ./sidecar/tasks/... -count=1 passes
  • make test passes
  • make lint clean
  • Unit coverage in genesis_overrides_test.go: string/number/object leaves, deep nesting, cross-module, missing intermediate, idempotency, all error surfaces
  • Disk-level coverage in assemble_genesis_test.go: applyOverrides mutates genesis.json and bubbles bad-key errors
  • Wire round-trip test for AssembleGenesisRequest.Overrides
  • Integration: SIP-3 test cluster boots with unbonding_time=600s and observes the resulting validator un-bonding behavior end-to-end

…bled genesis.json

Extends AssembleGenesisRequest with an Overrides map (dotted-path key to
json.RawMessage value) and applies it to the final genesis.json after
collect-gentxs runs and before the upload step. The first dotted segment
selects a top-level key in app_state (the cosmos module); subsequent
segments walk into that module's JSON tree and replace the leaf verbatim.

The new helper applyGenesisOverrides lives in sidecar/tasks/
genesis_overrides.go alongside unit coverage for happy paths (string /
number / object leaves, deep nesting, multi-module, missing
intermediate), idempotency, and error surfaces (empty key, single-token
key, trailing/double dot, empty value, unknown module, non-object
intermediate via scalar or array). assemble_genesis_test.go gains
disk-level coverage that the genesis.json on disk actually changes after
applyOverrides and that bad keys bubble through to the task error.

Also removes the dead GenesisParams field from GenerateGentxRequest and
its client-side mirror; the feature it reserved is now the dedicated
Overrides path on the SND-level assemble task.

Motivation: SIP-3 testing needs a fresh chain with
staking.params.unbonding_time = 600s instead of the cosmos default
21 days. Companion controller-side change in sei-k8s-controller wires
SeiNodeDeployment.spec.genesis.overrides into this request.
@cursor
Copy link
Copy Markdown

cursor Bot commented May 18, 2026

You have used all Bugbot PR reviews included in your free trial for your GitHub account on this workspace.

To continue using Bugbot reviews, enable Bugbot for your team in the Cursor dashboard.

@bdchatham bdchatham merged commit 2b64dde into main May 18, 2026
2 checks passed
@bdchatham bdchatham deleted the feat/genesis-overrides branch May 18, 2026 19:57
bdchatham added a commit that referenced this pull request May 18, 2026
Release the genesis-overrides feature (PR #181) plus the other six
commits that have accumulated since v0.0.49: trusted-header authn
(#179), gov-software-upgrade handler (#177), gov-vote handler (#175),
`/tx?hash=` discriminator hardening (#173), sign-tx foundation (#170),
production keyring backend (#168).

The Releaser workflow (.github/workflows/uci-release-publish.yml)
triggers on push to version.json and tags this commit as v0.0.50.
bdchatham added a commit that referenced this pull request May 18, 2026
## Summary

Closes #183. Adds a dedicated `seictl nd apply --genesis-override
<key>=<value>` flag that writes flat dotted-key entries into
`spec.genesis.overrides` on the rendered SeiNodeDeployment. Mirrors the
existing `--override` flag (which targets
`spec.template.spec.overrides`).

## Why

`spec.genesis.overrides` (shipped this morning via #181 +
sei-k8s-controller#270) requires a flat `map[string]<JSON>` with dotted
cosmos-module keys (`"staking.params.unbonding_time": "600s"`). The
sidecar's `applyGenesisOverrides` enforces this: keys must be
`module.field[.field...]`, first segment must be a cosmos module in
`app_state`.

`seictl --set spec.genesis.overrides.<path>=<value>` cannot emit that
shape — `--set`'s path parser splits unconditionally on `.` and builds a
nested map. Today's first attempt at the field
(sei-protocol/harbor-engineering-workspace#14) shipped the nested-map
shape and the sidecar rejected it on every retry with `key "app_state"
must be of the form module.field[.field...]`. Required a manual
`yq`-patching workaround (sei-protocol/harbor-engineering-workspace#16).

## What this PR does

```sh
seictl nd apply <name> --preset genesis-chain \
  --chain-id <id> --image <ref> \
  --genesis-override staking.params.unbonding_time=600s \
  --genesis-override bank.params.default_send_enabled=true \
  --genesis-override gov.params.voting_period_seconds=120 \
  --genesis-override mint.params.inflation='{"min":0.05,"max":0.2}' \
  -n eng-<alias>
```

Renders:

```yaml
spec:
  genesis:
    overrides:
      "staking.params.unbonding_time": "600s"
      "bank.params.default_send_enabled": true
      "gov.params.voting_period_seconds": 120
      "mint.params.inflation":
        min: 0.05
        max: 0.2
```

- Keys are stored as literal map-key strings — no path splitting
- Values parse as JSON when they parse (numbers, bools, objects,
arrays); otherwise as raw strings
- Local key-shape validation (`module.field[.field...]`) fails fast at
apply time rather than after the SND has stalled
- Rejected when `--preset != genesis-chain` (rpc preset has no
`spec.genesis`)
- Repeatable, distinct from `--override`

## Tests

- `TestRender_GenesisOverrideFlag` — string / bool / number / object
values all round-trip correctly through the renderer
- `TestRender_GenesisOverrideRejectsNonGenesisPreset`
- `TestApplyGenesisOverride_Errors` — missing `=`, empty key,
single-segment key, empty path segment
- `TestApplyGenesisOverride_PreservesExistingKeys` — multiple flag uses
accumulate into one map

`make test` passes.

## Follow-ups

After this releases (v0.0.51?), the harbor-dev skill docs in
sei-protocol/Tide get a follow-up PR that replaces the manual-`yq`
workaround with the canonical `--genesis-override` invocation. Will land
separately.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant