feat(sidecar): evm-logical-digest task + shared S3 emission seal + task panic isolation#211
Conversation
…sk panic isolation Add the offline full-keyspace digest gate (sei-chain#3611's seidb evm-logical-digest) as a discrete sidecar task — the per-segment boundary seal that closes the touched-key comparator's cold-state blind spot. Plus three seams the systems-engineering review called for; no producer abstraction (extract at the 3rd producer, not the 2nd). - sidecar/s3/emit.go: single S3 emission helper (StreamGzipNDJSON/JSON/Func), collapsing 3 duplicated gzip-pipe paths. Twofold integrity seal: an aws-chunked SHA-256 wire checksum over the compressed body (streaming preserved) + an uncompressed-payload SHA-256 surfaced via EmitResult for out-of-band verification. result_compare/result_export now call it. - sidecar/engine: recover() in runTask converts a handler panic into a failed TaskResult (+ seictl_task_panics_total) instead of crashing the sidecar. - sidecar/tasks/evm_logical_digest.go: the discrete task. Shells out to seidb for flatkv + memiavl (semantic + translator), asserts BOTH backends' opened version == requested height (fail-closed; no wrong-height false match), parses the FINAL_DIGEST/per-bucket contract, and publishes an EndpointDigestRecord. axes_proved deliberately omits balance (the semantic account digest zeroes it — that axis stays the per-block comparator's job). Cross-reviewed (systems-engineer + idiomatic): symmetric memiavl version assertion, a recover() inside the s3 writer goroutine (a panic there escapes the engine's handler recover), and the empty-by-construction uncompressed hash dropped from the published record (its seal is out-of-band). seidb is shelled out to (configurable path), not vendored. Trigger is the out-of-band task API; no controller/CRD change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
PR SummaryMedium Risk Overview Introduces The task engine now Reviewed by Cursor Bugbot for commit bd67199. Bugbot is set up for automated code reviews on this repo. Configure here. |
…gbot) exportPage routed every StreamGzipFunc error through ClassifyS3Error, so a collectResults failure (block_results RPC, marshaling, ctx cancel) surfaced as a misleading S3 access error. Capture the producer error and return it as-is; ClassifyS3Error now wraps only a genuine upload failure. Also document that runSeidb leaves cmd.Stderr nil so Output() captures stderr into ExitError.Stderr (verified: the existing stderrTail already works — the second Bugbot finding was a false positive). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Addressed both Bugbot findings in 073ff7b:
|
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 073ff7b. Configure here.
…es (Bugbot) The prior fix returned collectErr whenever set, which dropped ClassifyS3Error's Retryable hint when S3 failed mid-stream (the upload closes the pipe, surfacing a wrapped write error in collectErr while uploadErr holds the real S3 cause). Tag the sink-write path in collectResults with errSinkWrite so exportPage can tell a genuine producer fault (RPC/marshal/ctx -> return as-is) from a downstream sink/S3 fault (-> ClassifyS3Error on uploadErr, retaining Retryable). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Regression tests for the twice-flagged path: a block_results RPC fault is returned unclassified; a genuine upload failure keeps its ClassifyS3Error (Operation S3) treatment. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Third finding (S3 errors misreported on export) — fixed in bd67199, good catch. The prior fix over-corrected: returning |

Adds the full-keyspace digest gate (sei-chain#3611's
seidb evm-logical-digest) as a discrete sidecar task — the per-segment boundary seal that closes the touched-key comparator's cold-state blind spot (a key migrated wrong and never touched again is invisible to per-block Layer 2). Plus three seams the systems-engineering review called for. No "ShadowResultProducer" abstraction — that's deferred to the 3rd producer (YAGNI).What's here
sidecar/s3/emit.go— one S3 emission helper (StreamGzipNDJSON/StreamGzipJSON/StreamGzipFunc), collapsing 3 duplicated gzip-pipe paths. Twofold integrity seal: an aws-chunked SHA-256 wire checksum over the compressed body (io.Pipe streaming/backpressure preserved) + an uncompressed-payload SHA-256 surfaced viaEmitResultfor out-of-band verification.result_compare/result_exportrefactored onto it (no behavior change).sidecar/engine—recover()inrunTaskturns a handler panic into a failedTaskResult(+seictl_task_panics_total) instead of crashing the sidecar.sidecar/tasks/evm_logical_digest.go— the discrete task: shells out toseidbfor flatkv + memiavl (semantic+translator), asserts both backends' opened version== height(fail-closed — no wrong-height false match), parses theFINAL_DIGEST/per-bucket contract, publishes anEndpointDigestRecord.axes_proveddeliberately omits balance (the semantic account digest zeroes it — that axis stays the per-block comparator's job).Cross-review (systems-engineer + idiomatic-reviewer) — applied
recover()inside the s3 writer goroutine — a panic there (e.g.MarshalJSONover chain data) runs on a task-spawned goroutine outside the engine's handler recover; converted to a returned error so the upload aborts (no truncated-but-valid object) and the process survives.uncompressed_sha256from the published record (a record can't carry the hash of its own bytes; the seal is out-of-band in the log/TaskResult).version:-line length guard.Notes
seidbis shelled out to (configurableseidbPath), not vendored. #3611 also needs a one-line registration fix (EvmLogicalDigestCmd()isn't inseidb's rootAddCommand) — flagged to the author.ResultExportConfigone-way door)."evm-logical-digest", the param field names, and theEndpointDigestRecordschema.GOWORK=off go build ./...clean;go test ./sidecar/...green (incl. new memiavl-version-mismatch + writer-panic regression tests);gofmt -sclean.🤖 Generated with Claude Code