Skip to content

feat: forward chain_metadata and expose digests in HTTP gateway#287

Merged
prasanna-anchorage merged 4 commits into
mainfrom
worktree-5016d101
May 13, 2026
Merged

feat: forward chain_metadata and expose digests in HTTP gateway#287
prasanna-anchorage merged 4 commits into
mainfrom
worktree-5016d101

Conversation

@pepe-anchor
Copy link
Copy Markdown
Contributor

@pepe-anchor pepe-anchor commented May 8, 2026

Why am I making this PR?

The HTTP gateway was dropping chain_metadata from parse requests and not returning metadata_digest / input_payload_digest in responses. Clients sending ABI/IDL context got no benefit from it, and the digests needed for signature verification were never surfaced.

What am I changing?

  • Wire chain_metadata through to the gRPC backend
  • Return metadataDigest and inputPayloadDigest in TurnkeyPayload
  • Use the empty-SHA256 sentinel in error responses (spec requirement for digest fields)
  • Map fields (abiMappings, idlMappings) can now be omitted from JSON requests
  • Unit tests for the above

What is the Linear ticket?

N/A

What are the rollback steps?

Revert this PR. No database or config changes.

Is this change backwards compatible?

Yes for requests. chain_metadata is optional so existing clients continue to work.

For responses: metadataDigest and inputPayloadDigest are new fields. Clients with lenient JSON parsing are unaffected; strict schema validation will see two new fields.

Does this require cross-team/service coordination?

No. The gRPC backend already supports these fields.

How do I know it works as designed? Which tests exercise this code?

cargo test -p parser_gateway
make -C src test
make -C src lint

Co-authored with Claude.

The gateway was hardcoding chain_metadata: None in ParseRequest and
only returning signable_payload from the response. This wires up the
full round-trip:

- TurnkeyRequest now accepts chain_metadata (optional), using a local
  ChainMetadataInput tagged enum to avoid untagged-serde ambiguity
  between Ethereum/Solana (both have networkId)
- ParseRequest forwards chain_metadata to the gRPC backend
- TurnkeyPayload now includes metadata_digest and input_payload_digest
  from the backend response
- error_response uses the spec-mandated empty-SHA256 sentinel for
  digest fields instead of empty string

Also fixes the serde_derive feature in the generated crate: the
previous blanket .type_attribute(".parser", ...) applied serde to
QosParserRequest/QosParserResponse which embed health/rpc types that
don't implement serde. Replaced with explicit per-type attributes,
excluding the QOS types. Removed orphaned parser.v1.rs (not included
in _include.rs and never compiled).

Co-Authored-By: Claude <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the HTTP gateway to correctly forward chain_metadata into gRPC parse requests and to return metadataDigest / inputPayloadDigest in HTTP responses, while also fixing the generated crate’s serde_derive feature by scoping serde attributes to only compatible parser types.

Changes:

  • Gateway: forward chain_metadata to ParseRequest, add metadataDigest and inputPayloadDigest to the HTTP response payload, and use an empty-SHA256 sentinel in error responses.
  • Codegen / generated outputs: enable and repair serde_derive by applying serde only to selected .parser types and scoping serde(untagged) to ChainMetadata’s oneof.
  • Cleanup: remove an orphaned, uncompiled generated file (parser.v1.rs).

Reviewed changes

Copilot reviewed 3 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/parser/gateway/src/main.rs Forwards chain_metadata, exposes digest fields in HTTP responses, and adds a tagged JSON input wrapper for chain metadata.
src/parser/gateway/Cargo.toml Enables generated/serde_derive for the gateway.
src/codegen/src/main.rs Narrows serde application to specific parser types; scopes serde(untagged) to the ChainMetadata oneof only.
src/generated/src/generated/parser.rs Regenerated output reflecting scoped serde derives and the corrected oneof untagged behavior.
src/generated/src/generated/grpc.health.v1.rs Removes unintended serde(untagged) attribute from health enums.
src/generated/src/generated/google.rpc.rs Removes unintended serde(untagged) attribute from google RPC enums.
src/generated/src/generated/parser.v1.rs Deletes orphaned generated file that was not included/compiled.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/parser/gateway/src/main.rs Outdated
Comment thread src/parser/gateway/src/main.rs
EthereumMetadata.abi_mappings and SolanaMetadata.idl_mappings are
HashMap fields without serde(default), so JSON input that omits them
fails deserialization. Add serde(default) via codegen field_attribute
so callers can omit empty maps without errors.

Co-Authored-By: Claude <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 7 changed files in this pull request and generated 2 comments.

Comment thread src/parser/gateway/src/main.rs
Comment thread src/parser/gateway/src/main.rs Outdated
The doc comment said network_id but SolanaMetadata uses
serde(rename_all = "camelCase"), so the actual JSON field
name clients send is networkId.

Co-Authored-By: Claude <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 7 changed files in this pull request and generated no new comments.

@pepe-anchor pepe-anchor marked this pull request as ready for review May 8, 2026 13:52
…serialization

Covers the three behaviors changed in recent commits:
- error_response always sets EMPTY_SHA256 in both digest fields
- ChainMetadataInput tagged enum prevents Solana being misread as Ethereum
- serde(default) on abi_mappings/idl_mappings allows omitting empty maps

Co-Authored-By: Claude <noreply@anthropic.com>
Copy link
Copy Markdown
Collaborator

@r-n-o r-n-o left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not super familiar with the parser/gateway crate. Is that something you use internally to test visualsign? In a normal setting I don't think you should need it because Turnkey already runs an HTTP gateway (the Turnkey gateway powers the 2 paths for dev and prod, /visualsign-dev/api/v2/parse and /visualsign/api/v2/parse). If the bug is also present in the Turnkey gateway I'll have to make a change there.

So I believe this change will be a no-op from the point of view of the visualsign parser app? (and the dev+prod endpoints)

Regardless: I see you have new tests in main.rs so this is clearly fixing something 😅

@pepe-anchor
Copy link
Copy Markdown
Contributor Author

I'm not super familiar with the parser/gateway crate. Is that something you use internally to test visualsign? In a normal setting I don't think you should need it because Turnkey already runs an HTTP gateway (the Turnkey gateway powers the 2 paths for dev and prod, /visualsign-dev/api/v2/parse and /visualsign/api/v2/parse). If the bug is also present in the Turnkey gateway I'll have to make a change there.

So I believe this change will be a no-op from the point of view of the visualsign parser app? (and the dev+prod endpoints)

Regardless: I see you have new tests in main.rs so this is clearly fixing something 😅

I was testing this PR and noticed that we were ignoring the abiMappings. I think that we might also have to change the Turnkey gateway to start handling the abiMappings.

Copy link
Copy Markdown
Contributor

@prasanna-anchorage prasanna-anchorage left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving. The discriminated-union ChainMetadataInput wrapper is a clean fix for the serde(untagged) ambiguity that would silently deserialize a Solana-only payload (just networkId) as EthereumMetadata. Codegen narrowing from crate-wide SERDE_DERIVE to per-type is the right call given QOSParserRequest/Response embed health/google.rpc types without serde. Empty-SHA256 sentinel in error_response matches the spec. Test coverage hits all four key behaviors. Mixed snake-outer / camel-inner JSON shape is preserved for back-compat with explicit documentation.

r-n-o's clarifying question is resolved (Turnkey production gateway has the same bug — separate ticket on their side, not blocking this fix in the local-dev gateway).

@prasanna-anchorage prasanna-anchorage merged commit 76749be into main May 13, 2026
8 checks passed
@prasanna-anchorage prasanna-anchorage deleted the worktree-5016d101 branch May 13, 2026 04:58
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.

4 participants