feat(jobs): expose ash/ocr hex on awaiting_signature JobStatus result - #195
Merged
Merged
Conversation
…_signature job result
A pure-TypeScript wallet must know account_state_hash (ash) and
output_coins_root (ocr) to sign the send commitment, but until now the
awaiting_signature JobStatus carried only proof_id. The hashes were
reachable solely via GET /api/proof/{id} as a binary bincode CoinProof
blob that only Rust/wasm can decode — breaking the thin-client rule
(wallet = key only, trusts the node, no heavy client-side logic).
This change writes ash + ocr as lowercase hex into the job result when a
send job transitions to awaiting_signature, so GET /api/jobs/:id and the
SSE stream surface them under result.account_state_hash /
result.output_coins_root — the exact keys @zkcoins/sdk's pay() reads.
ash/ocr come from the same source the completed mint/commit results use:
ProofData::from_field_elements over the send proof's public inputs,
hex-encoded via digest_to_bytes. Extraction is factored into a shared
flow::send_commit_hashes helper that mint_flow, send_flow, and
commit_flow all call, so the hex is bit-identical to what
createCommitment expects and commit_flow re-derives.
Purely additive: completed result shape, proof_id top-level field, and
the JobStatusResponse wire schema (result is already free-form JSON) are
unchanged. No new endpoint, env var, or migration. set_awaiting_signature
stores the result in the existing response_body column (the terminal
complete body overwrites it later); the GET handler and SSE initial frame
now surface result for awaiting_signature in addition to completed, and a
post-restart resume re-publishes the persisted hashes.
Tests: api_remote send roundtrip asserts the awaiting_signature result
hex equals the proof-decoded ash/ocr; job_store + router unit tests cover
the new persistence and snapshot paths (100% line + function gate green).
TaprootFreak
marked this pull request as ready for review
June 3, 2026 16:01
3 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
A pure-TypeScript wallet (
@zkcoins/sdk) needsaccount_state_hash(ash) +output_coins_root(ocr) to sign the send commitment. Until now theawaiting_signatureJobStatus carried onlyproof_id; ash/ocr were reachable solely viaGET /api/proof/{id}as a binary bincodeCoinProofblob that only Rust/wasm can decode. That breaks the thin-client rule (wallet = key only, trusts the node, no heavy client-side logic; see CONTRIBUTING "Trust model").What
When a send job transitions to
awaiting_signature, ash + ocr are written as lowercase hex into the jobresult, soGET /api/jobs/:idand the SSE stream surface them underresult.account_state_hash/result.output_coins_root— the exact keys the SDK'spay()already reads. This closes the pure-TS commit loop without any binary proof decode.Where ash/ocr come from
The same source the
completedmint/commit results use:ProofData::from_field_elementsover the send proof's public inputs, hex-encoded viadigest_to_bytes. Extraction is factored into a sharedflow::send_commit_hasheshelper thatmint_flow,send_flow, andcommit_flowall call, so the hex is bit-identical to whatcreateCommitmentexpects andcommit_flowre-derives from the same proof.Additive / minimal
completedresult shape, top-levelproof_id, and theJobStatusResponsewire schema (resultis already free-form JSON) are unchanged.set_awaiting_signaturestores the result in the existingresponse_bodycolumn (the terminalcompletebody overwrites it later). The GET handler and SSE initial frame now surfaceresultforawaiting_signaturein addition tocompleted; a post-restart resume re-publishes the persisted hashes.Tests / gates
api_remotesend roundtrip now asserts theawaiting_signatureresulthex equals the proof-decoded ash/ocr (contract check; runs in deploy-dev /ci:full).job_store+routerunit tests cover the new persistence + snapshot paths.nodepackage (442 tests passed),cargo fmt --check, clippy (MVP + all-features)-D warnings, andcargo check --workspace --all-featuresall clean.