You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
add trace contex, el headers and failure replay (#70)
* feat(server): extract W3C trace context from incoming HTTP requests
Replace the default TraceLayer span with a custom MakeSpan that, when the
otel feature is enabled, extracts traceparent/tracestate from request
headers via the global propagator and sets the result as the request
span's parent. The whole existing explicit-parent chain (request span ->
handler -> request_proof -> fetch_witness / prove) now joins the caller's
distributed trace. The request span is also promoted from the debug-level
tower-http default to info level so it survives info-level filters.
Without the otel feature the custom MakeSpan only creates the span, with
no OpenTelemetry dependency.
Verified by a new otel-gated test using an in-memory span exporter that
asserts the exported request span keeps the caller's trace id and is
parented under the caller's span id.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(server): record cluster job_id on the prove span and in logs
Declare an empty job_id field on the per-attempt prove span and pass that
span explicitly through zkVMInstance::prove into the zisk cluster backend,
which records the id on it as soon as the cluster assigns one, so traces
correlate a prove span with the cluster-side job. Recording on the
explicitly passed span rather than Span::current() means the id cannot
silently land elsewhere if an intermediate span is ever introduced.
Also emit an info log with the job id at creation so the correlation is
available in plain logs without the otel feature.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(server): support custom HTTP headers for EL JSON-RPC requests
Add an optional top-level el_headers map (default empty) next to
el_endpoint, applied as reqwest default headers when constructing the
ElClient, so every EL JSON-RPC request (chain config, blocks, witnesses)
carries them, e.g. for authenticated endpoints.
Since header values typically carry credentials they are kept out of any
Debug output: the parsed HeaderValues are marked sensitive, and Config
implements Debug manually so el_headers values format as "<redacted>".
Config validation fails at startup on invalid header names or values, and
rejects keys that differ only in case (header names are case-insensitive;
HashMap iteration order would otherwise decide which duplicate wins).
ElClient::new now propagates HTTP-client construction errors instead of
panicking, so all startup failures surface as errors.
Documented in the README and the example configs; covered by config
tests.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(client): propagate W3C trace context on outbound requests
Behind a new otel cargo feature, inject the current tracing span's
OpenTelemetry context (traceparent/tracestate) into the headers of every
outbound request (request_proof, subscribe_proof_events, get_proof,
verify_proof) via the global propagator, using a hand-rolled
HeaderInjector mirroring ere_server_client's OtelPropagation middleware
and the server crate's HeaderExtractor. For the SSE subscription the
context is captured eagerly at call time, not at first poll. Without the
feature the helper returns an empty header map, so default builds change
no behavior and pull in no OpenTelemetry dependencies.
The crate docs call out that the calling application must install a
global text-map propagator (the OpenTelemetry default is a no-op), or no
traceparent header is emitted even with the feature enabled.
This completes the propagation chain for external callers such as
proofessoor: caller span -> zkboost-client traceparent -> zkboost server
request span -> ere zkVM server.
Verified by an otel-gated integration test that serves requests on a
local listener and asserts both a unary request and the SSE subscribe
arrive with a traceparent carrying the active span's trace id.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(server): set otel span kind and HTTP attributes on the request span
Set otel.kind=server and basic HTTP semantic-convention attributes
(http.request.method, url.path, url.query) on the request span. They are
recorded as OTLP-only attributes, not tracing fields, so the log format
of default-feature builds is unchanged.
Also move the request-span trace-context test into its own
integration-test binary (tests/otel_request_span.rs): it installs a
process-global tracing subscriber so spans created on the server's tasks
are observed, and sharing a process with parallel tests both raced on the
global subscriber and poisoned the global callsite interest cache, which
previously required a warm-up/retry workaround. The relocated test
additionally asserts the span kind and HTTP attributes.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(server): replay proof failures to late SSE subscribers
Previously only completed proofs were cached and replayed on subscribe;
a subscriber that missed a live proof_failure broadcast could never learn
the terminal outcome of a request. Terminal failures are now cached in a
bounded LRU (same size as the completed-proof cache) and replayed to
per-root SSE subscribers exactly like completions, with unchanged event
shapes. A later successful proof for the same (root, proof_type) evicts
the stale failure entry so both outcomes are never replayed.
Event delivery on the subscribe endpoint is at-least-once with
latest-wins semantics: a replayed stale failure can still precede the
completion of a retry that has already succeeded, and subscribers must
treat the most recent terminal event per (root, proof_type) as
authoritative. This is documented on the handler and in the README.
Tests: subscribe-after-failure receives the replayed failure (handler
unit test + end-to-end re-subscribe assertions for proving error and
timeout), LRU bound eviction, cached-vs-broadcast event equality, and
completion evicting a stale failure.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* chore(client): simplify unused dependency lint
* fix(server): clear stale failure on retry admission
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
# Optional HTTP headers applied to every EL JSON-RPC request (e.g. authentication).
58
+
# Header names are case-insensitive; names differing only in case are rejected.
59
+
# [el_headers]
60
+
# Authorization = "Bearer <token>"
61
+
57
62
# Optional local EL chain config JSON file.
58
63
# chain_config_path = "path/to/chain_config.json"
59
64
@@ -129,6 +134,13 @@ The following endpoints are available:
129
134
|`GET`|`/health`| Health check |
130
135
|`GET`|`/metrics`| Prometheus metrics |
131
136
137
+
Proof events on the SSE stream are delivered at-least-once with latest-wins semantics:
138
+
terminal results (completions and failures) that happened before subscribing are replayed
139
+
from bounded caches. Admitting a retry evicts its previous failure, although a concurrent
140
+
subscription that already snapshotted that failure may still deliver it before the retry's
141
+
terminal event. Clients should treat the most recent terminal event per
142
+
`(new_payload_request_root, proof_type)` as authoritative.
143
+
132
144
See [openapi.json](openapi.json) for the full API specification ([rendered](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/eth-act/zkboost/master/openapi.json)).
0 commit comments