Skip to content

feat(rpc): network verification via commitment header#1084

Merged
Mirko-von-Leipzig merged 21 commits intonextfrom
mirko/rpc-verify-network
Jul 24, 2025
Merged

feat(rpc): network verification via commitment header#1084
Mirko-von-Leipzig merged 21 commits intonextfrom
mirko/rpc-verify-network

Conversation

@Mirko-von-Leipzig
Copy link
Copy Markdown
Collaborator

@Mirko-von-Leipzig Mirko-von-Leipzig commented Jul 14, 2025

This PR adds support for verifying the network identity for RPC clients.

This PR also changes the existing format for the version checking:

# Original
application/vnd.miden+grpc.x.y.z

# New
application/vnd.miden; version=x.y.z; genesis=0xABC

The now obsolete format gets rejected now which I think is okay. The new format still allows for an optional +grpc suffix.

The original version checking behavior is retained, though we may want to consider switching to Caret instead of Exact but that's separate from this addition.

This PR also improves the correctness of the accept header verification by:

  • accepting wildcards */* and application/* media-types
  • rejecting zero-weighted media-types q=0

Similar to the RPC version check added in #844, we now check the network the client thinks its on. The client can now set the genesis block's commitment in the miden-network header, and the RPC service will reject the request if there is a mismatch.

This does add an additional header, and maybe instead we should add it to the accept header? I'm just unsure what this format should look like; and we probably want to do additional parsing instead.

Closes #1066.

@Mirko-von-Leipzig Mirko-von-Leipzig force-pushed the mirko/rpc-verify-network branch 3 times, most recently from 37be2c3 to 55a9e6a Compare July 14, 2025 11:07
@Mirko-von-Leipzig Mirko-von-Leipzig force-pushed the mirko/rpc-verify-network branch from 55a9e6a to 61fb917 Compare July 14, 2025 11:11
@Mirko-von-Leipzig Mirko-von-Leipzig force-pushed the mirko/rpc-verify-network branch from ce9ba13 to b1324ec Compare July 14, 2025 11:54
Comment thread crates/rpc/src/server/accept.rs
Comment thread crates/rpc/src/server/accept.rs Outdated
};
assert_eq!(AcceptHeaderValue::try_from(input), Ok(expected));
let uut = HeaderVerificationLayer::for_tests();
uut.verify(&headers).unwrap_err();
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Could we test the exact error variants coming out? Given you have created the error enums now.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

We can; but I'm not sure that adds any specific value?

For example, in the case where both mismatch, which error should it be? Could be either..

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

For example, in the case where both mismatch, which error should it be? Could be either..

It would be well defined which error would be returned if both mismatched. Checking the error proves our logic is working precisely as expected. We could erroneously return invalid semver variant for an input with a correct semver for example. Unless I'm missing something.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I had a crack at adding the expected error variants into the cases but I think its blocked on variants like

    VersionParsing(#[source] semver::Error, String),

Because semver::Error and its constructors etc are not public so we can't recreate them for the tests.

Comment thread crates/rpc/src/server/api.rs
Comment thread crates/rpc/src/server/api.rs
Comment thread crates/rpc/src/server/accept.rs Outdated
Copy link
Copy Markdown
Contributor

@bobbinth bobbinth left a comment

Choose a reason for hiding this comment

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

Thank you! Looks good! Not a review but I did leave a couple of questions/comments inline.

This does add an additional header, and maybe instead we should add it to the accept header? I'm just unsure what this format should look like; and we probably want to do additional parsing instead.

I haven't thought about it too much, but it does feel like maybe handling everything through the accept header is a bit more "natural" - i.e., we have a single header which tells us if the request should be accepted or rejected.

On the other hand, this probably complicates parsing a bit and makes it more difficult to handle partial scenarios (e.g., missing version info but present genesis commitment or vise-versa). But it is also not clear if we should care about partial scenarios - and in that case, maybe channeling everything through the accept header is a better option.

Comment thread crates/rpc/src/server/mod.rs
Comment thread crates/rpc/src/server/mod.rs
Comment thread crates/rpc/src/server/accept.rs
@Mirko-von-Leipzig Mirko-von-Leipzig force-pushed the mirko/rpc-verify-network branch 2 times, most recently from 7325d95 to 1a25c73 Compare July 18, 2025 13:36
@Mirko-von-Leipzig Mirko-von-Leipzig marked this pull request as draft July 18, 2025 16:51
@Mirko-von-Leipzig
Copy link
Copy Markdown
Collaborator Author

I'm most of the way there, but I'm converting to draft until its done properly to spare you looking at it for no reason.

As a short summary of my intentions:

  • Client can now specify any version(s) using the semver::VersionReq format. This is the same as Rust's Cargo.toml rules. I think this is a great idea because
    • Clients can fully specify without the server ever having to recompile e.g. if we accidentally do a semver faux pax the client's can just adjust there headers to be more specific.
    • Once/if we ever support multiple RPC versions this will be naturally supported already. We just need to adjust the logic so the server does more proper content type selection.
  • Genesis support is added.

@Mirko-von-Leipzig Mirko-von-Leipzig force-pushed the mirko/rpc-verify-network branch from 1a25c73 to bee1a0f Compare July 21, 2025 13:07
@Mirko-von-Leipzig Mirko-von-Leipzig force-pushed the mirko/rpc-verify-network branch from 86f569a to bbe039e Compare July 23, 2025 13:40
@Mirko-von-Leipzig
Copy link
Copy Markdown
Collaborator Author

I've refactored this to use an external crate and revert the version requirements to what they were before. I've also updated the description to match the current reality.

If you could re-review please :)

@Mirko-von-Leipzig Mirko-von-Leipzig marked this pull request as ready for review July 23, 2025 13:46
@Mirko-von-Leipzig Mirko-von-Leipzig force-pushed the mirko/rpc-verify-network branch from bbe039e to e654322 Compare July 23, 2025 13:48
Comment on lines +65 to +73
let supported_versions = VersionReq {
comparators: vec![Comparator {
op: semver::Op::Exact,
major: rpc_version.major,
minor: rpc_version.minor.into(),
patch: None,
pre: semver::Prerelease::default(),
}],
};
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I'm a bit on the fence about this; but I've left the current behavior as is.

The issue is that its a bit back-to-front. The client should be indicating which versions they're compatible with. For example, their RPC version might be patch compatible with our server's but they may require a new feature or addition that we introduced.

Its easy to do by swapping the client and server types around. The downside is that client's need to think a bit more about what they want.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think this is fine for now, but I would create an issue to revisit this in the future because in principle I agree: the client should be specifying the version that it is compatible with and if the node is within this specifications, the request should be accepted.

Comment thread crates/rpc/src/server/accept.rs
Comment thread crates/rpc/src/server/accept.rs
Comment thread crates/rpc/src/server/accept.rs
Comment thread crates/rpc/src/server/accept.rs
@Mirko-von-Leipzig Mirko-von-Leipzig force-pushed the mirko/rpc-verify-network branch from e654322 to 61aca21 Compare July 23, 2025 16:00
Copy link
Copy Markdown
Contributor

@bobbinth bobbinth left a comment

Choose a reason for hiding this comment

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

Looks good! Thank you! I left a couple of small comments inline.

Comment thread CHANGELOG.md Outdated
Comment thread crates/rpc/src/server/accept.rs
@Mirko-von-Leipzig Mirko-von-Leipzig force-pushed the mirko/rpc-verify-network branch from 5157d20 to cf11dfd Compare July 24, 2025 08:44
Copy link
Copy Markdown
Contributor

@bobbinth bobbinth left a comment

Choose a reason for hiding this comment

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

All looks good! Thank you!

@Mirko-von-Leipzig Mirko-von-Leipzig merged commit 7dcbf64 into next Jul 24, 2025
8 checks passed
@Mirko-von-Leipzig Mirko-von-Leipzig deleted the mirko/rpc-verify-network branch July 24, 2025 16:31
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.

gRPC genesis check

6 participants