Skip to content

Commit 0cd97d8

Browse files
authored
feat: genesis ceremony task handlers and deterministic task IDs (#41)
## Summary - **Genesis task handlers**: Implements the four sidecar task handlers needed for genesis ceremony orchestration: - `generate-identity` — runs `seid init` to create validator keys and node identity - `generate-gentx` — three-step pipeline: `keys add` → `add-genesis-account` → `gentx` - `upload-genesis-artifacts` — uploads gentx and identity manifest to S3 per-node - `assemble-and-upload-genesis` — downloads all node gentxs from S3, runs `collect-gentxs`, uploads assembled genesis.json - **Deterministic task IDs**: Engine now accepts caller-provided UUIDs for idempotent task submission with deduplication. `ErrInvalidTaskID` sentinel for non-UUID IDs. `TaskMeta` struct embedded in all 16 client task types for ID propagation. - **Client ergonomics**: Typed `Submit*Task` convenience methods on `SidecarClient` for all four new genesis tasks. `CommandRunner` abstraction for testable `seid` CLI invocations. ## Test plan - [x] `generate-identity`: seid init args, idempotency via marker, missing params, seid failure - [x] `generate-gentx`: full 3-step flow, idempotency, missing params, keys add failure - [x] `upload-genesis-artifacts`: gentx + identity upload, idempotency, missing params, no gentx file - [x] `assemble-and-upload-genesis`: full flow with S3 mock, idempotency, missing params, S3 download failure, collect-gentxs failure - [x] Engine: caller-provided ID, invalid ID validation (`ErrInvalidTaskID`), dedup active/completed/scheduled - [x] Server: HTTP-level invalid ID → 400, dedup returns existing ID - [x] Full test suite passes (`go test ./...`)
1 parent 8016d84 commit 0cd97d8

19 files changed

Lines changed: 1684 additions & 54 deletions

serve.go

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -45,18 +45,22 @@ var serveCmd = cli.Command{
4545
}
4646

4747
handlers := map[engine.TaskType]engine.TaskHandler{
48-
engine.TaskSnapshotRestore: tasks.NewSnapshotRestorer(homeDir, nil).Handler(),
49-
engine.TaskDiscoverPeers: tasks.NewPeerDiscoverer(homeDir, nil, nil).Handler(),
50-
engine.TaskConfigPatch: tasks.NewConfigPatcher(homeDir).Handler(),
51-
engine.TaskConfigApply: tasks.NewConfigApplier(homeDir).Handler(),
52-
engine.TaskConfigValidate: tasks.NewConfigValidator(homeDir).Handler(),
53-
engine.TaskConfigReload: tasks.NewConfigReloader(homeDir).Handler(),
54-
engine.TaskMarkReady: tasks.MarkReadyHandler(),
55-
engine.TaskConfigureGenesis: tasks.NewGenesisFetcher(homeDir, chainID, nil).Handler(),
56-
engine.TaskConfigureStateSync: tasks.NewStateSyncConfigurer(homeDir, nil).Handler(),
57-
engine.TaskSnapshotUpload: tasks.NewSnapshotUploader(homeDir, nil).Handler(),
58-
engine.TaskResultExport: tasks.NewResultExporter(homeDir, nil).Handler(),
59-
engine.TaskAwaitCondition: tasks.NewConditionWaiter(nil).Handler(),
48+
engine.TaskSnapshotRestore: tasks.NewSnapshotRestorer(homeDir, nil).Handler(),
49+
engine.TaskDiscoverPeers: tasks.NewPeerDiscoverer(homeDir, nil, nil).Handler(),
50+
engine.TaskConfigPatch: tasks.NewConfigPatcher(homeDir).Handler(),
51+
engine.TaskConfigApply: tasks.NewConfigApplier(homeDir).Handler(),
52+
engine.TaskConfigValidate: tasks.NewConfigValidator(homeDir).Handler(),
53+
engine.TaskConfigReload: tasks.NewConfigReloader(homeDir).Handler(),
54+
engine.TaskMarkReady: tasks.MarkReadyHandler(),
55+
engine.TaskConfigureGenesis: tasks.NewGenesisFetcher(homeDir, chainID, nil).Handler(),
56+
engine.TaskConfigureStateSync: tasks.NewStateSyncConfigurer(homeDir, nil).Handler(),
57+
engine.TaskSnapshotUpload: tasks.NewSnapshotUploader(homeDir, nil).Handler(),
58+
engine.TaskResultExport: tasks.NewResultExporter(homeDir, nil).Handler(),
59+
engine.TaskAwaitCondition: tasks.NewConditionWaiter(nil).Handler(),
60+
engine.TaskGenerateIdentity: tasks.NewIdentityGenerator(homeDir, nil).Handler(),
61+
engine.TaskGenerateGentx: tasks.NewGentxGenerator(homeDir, nil).Handler(),
62+
engine.TaskUploadGenesisArtifacts: tasks.NewGenesisArtifactUploader(homeDir, nil).Handler(),
63+
engine.TaskAssembleAndUploadGenesis: tasks.NewGenesisAssembler(homeDir, nil, nil, nil).Handler(),
6064
}
6165

6266
eng := engine.NewEngine(ctx, handlers)

sidecar/api/openapi.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,14 @@ components:
132132
type: object
133133
required: [type]
134134
properties:
135+
id:
136+
type: string
137+
format: uuid
138+
description: >
139+
Caller-provided task identifier. When set, the engine uses this
140+
as the canonical ID (enabling deterministic IDs from the controller).
141+
If a task with this ID already exists, the request is idempotent
142+
and returns the existing ID. When omitted, a random UUID is generated.
135143
type:
136144
type: string
137145
description: Task type identifier.

sidecar/client/client.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,3 +323,31 @@ func (c *SidecarClient) SubmitAwaitConditionTask(ctx context.Context, task Await
323323
}
324324
return c.SubmitTask(ctx, task.ToTaskRequest())
325325
}
326+
327+
func (c *SidecarClient) SubmitGenerateIdentityTask(ctx context.Context, task GenerateIdentityTask) (uuid.UUID, error) {
328+
if err := task.Validate(); err != nil {
329+
return uuid.Nil, fmt.Errorf("task validation failed: %w", err)
330+
}
331+
return c.SubmitTask(ctx, task.ToTaskRequest())
332+
}
333+
334+
func (c *SidecarClient) SubmitGenerateGentxTask(ctx context.Context, task GenerateGentxTask) (uuid.UUID, error) {
335+
if err := task.Validate(); err != nil {
336+
return uuid.Nil, fmt.Errorf("task validation failed: %w", err)
337+
}
338+
return c.SubmitTask(ctx, task.ToTaskRequest())
339+
}
340+
341+
func (c *SidecarClient) SubmitUploadGenesisArtifactsTask(ctx context.Context, task UploadGenesisArtifactsTask) (uuid.UUID, error) {
342+
if err := task.Validate(); err != nil {
343+
return uuid.Nil, fmt.Errorf("task validation failed: %w", err)
344+
}
345+
return c.SubmitTask(ctx, task.ToTaskRequest())
346+
}
347+
348+
func (c *SidecarClient) SubmitAssembleAndUploadGenesisTask(ctx context.Context, task AssembleAndUploadGenesisTask) (uuid.UUID, error) {
349+
if err := task.Validate(); err != nil {
350+
return uuid.Nil, fmt.Errorf("task validation failed: %w", err)
351+
}
352+
return c.SubmitTask(ctx, task.ToTaskRequest())
353+
}

sidecar/client/sidecar.gen.go

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)