Skip to content

feat(rpc): expose protocol config over the gRPC APIs - #2596

Merged
kkovaacs merged 28 commits into
nextfrom
krisztian/grpc-protocol-config
Sep 14, 2026
Merged

feat(rpc): expose protocol config over the gRPC APIs#2596
kkovaacs merged 28 commits into
nextfrom
krisztian/grpc-protocol-config

Conversation

@kkovaacs

@kkovaacs kkovaacs commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Add protocol configs to GetBlockHeaderByNumber, SyncChainMmr, and public/validator block subscriptions.
  • Verify config commitments and propagate configs through signing, replication, and recovery.
  • Use verified RPC configs in NTX execution, the network monitor, and benchmarks; remove --fee-faucet-id options.

Changelog

[[entry]]
scope       = "rpc"
impact      = "breaking"
description = "Expose protocol configurations through gRPC and use verified configs across synchronization, recovery, NTX execution, monitoring."

Stack created with GitHub Stacks CLIGive Feedback 💬

@kkovaacs
kkovaacs added this pull request to stack #2581 September 9, 2026 10:09

@Mirko-von-Leipzig Mirko-von-Leipzig left a comment

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.

Only a partial review

Comment thread bin/network-monitor/src/deploy/mod.rs
Comment thread bin/network-monitor/src/remote_prover.rs Outdated
Comment thread proto/proto/rpc.proto Outdated
Comment thread proto/proto/rpc.proto Outdated
Comment thread proto/proto/rpc.proto Outdated
Comment thread proto/proto/internal/validator.proto Outdated
Comment thread bin/validator/src/db/migrations/001_initial.sql
Comment thread bin/validator/src/db/queries/protocol_config/mod.rs Outdated
Comment thread bin/validator/src/db/queries/protocol_config/mod.rs Outdated
Comment thread crates/store/src/db/models/queries/protocol_configs.rs Outdated
@kkovaacs
kkovaacs force-pushed the krisztian/grpc-protocol-config branch from 3a0711e to e532549 Compare September 10, 2026 08:58
@kkovaacs
kkovaacs force-pushed the krisztian/grpc-protocol-config branch 2 times, most recently from 1eb94a1 to d19628c Compare September 10, 2026 09:21
@kkovaacs
kkovaacs force-pushed the krisztian/grpc-protocol-config branch from d19628c to ddab236 Compare September 10, 2026 09:54
@kkovaacs
kkovaacs force-pushed the krisztian/grpc-protocol-config branch from ddab236 to 4bdd1b5 Compare September 10, 2026 12:18
Comment thread crates/rpc/src/server/api/sync_chain_mmr.rs Outdated
Comment on lines +71 to +77
let (start, _) = view
.get_block_header(Some(current_client_block_height), false)
.await
.map_err(super::get_block_header_error_to_status)?;
let start =
start.ok_or_else(|| Status::internal("starting block header is missing"))?;
start.protocol_config_commitment() != block_header.protocol_config_commitment()

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.

We could optimise this if we also store the block at which a protocol config changes with the protocol config data?

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.

How would that help us? I mean, that'd still mean that you'd need to make a DB query that checks is there were changes in the (start, tip) range?

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.

Yes but you wouldn't have to fetch and decode the entire header and calculate the commitment.

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.

Oh, it's not actually calculating anything (the protocol config commitment is a field in the header). You have to decode that though, but that should be fairly cheap?

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 think this just seemed easier to do just this range search:

super::load_protocol_config(&view, current_client_block_height..=block_header.range).await

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 suggested adding a block number tracking here as well; but that means changing PK to composite (or to block number).

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.

If if not strictly required, I think it would be useful to have the block number in this table - would allow us to easily inspect all protocol configurations as they evolve over time. I'm assuming that adding this field is very easy - if not, then we can come back to it later.

Comment thread crates/store/src/state/writer/worker.rs Outdated
Comment on lines +212 to +227
let commitment = header.protocol_config_commitment();
if let Some(config) = protocol_config.as_ref() {
let calculated = config.to_commitment();
if calculated != commitment {
return Err(crate::errors::DatabaseError::ProtocolConfigCommitmentMismatch {
expected: commitment,
calculated,
}
.into());
}
}
let stored = self.db.select_protocol_config_by_commitment(commitment).await?;
if stored.is_none() && protocol_config.is_none() {
return Err(crate::errors::DatabaseError::ProtocolConfigNotFound(commitment).into());
}
let new_protocol_config = if stored.is_none() { protocol_config } else { None };

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.

Took me a while to understand why this looked more complicated, but I think its because we avoid re-storing a config if we already have it. e.g. A, B then A again, the last A doesn't get stored.

I don't think that's really worth optimising for, we can just insert or ignore, or if we go with my suggestion to also add the block number, then we have to insert regardless.

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'd like to avoid adding the block number unless there's a really good reason to do so, so we should maybe just do an "insert or ignore" here?

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.

One downside is that if we just "insert or ignore" then we don't actually ensure that the commitment in the block header that's being applied is present (is either already in the DB or being added just now).

Comment thread bin/ntx-builder/src/chain_state.rs
@kkovaacs
kkovaacs force-pushed the krisztian/grpc-protocol-config branch from 3851287 to fc34817 Compare September 11, 2026 08:52
@kkovaacs
kkovaacs force-pushed the krisztian/grpc-protocol-config branch 2 times, most recently from b302641 to fc34817 Compare September 11, 2026 10:45
@kkovaacs
kkovaacs force-pushed the krisztian/grpc-protocol-config branch from fc34817 to fe71f00 Compare September 11, 2026 11:13
@kkovaacs
kkovaacs force-pushed the krisztian/grpc-protocol-config branch from fe71f00 to ea9a8e9 Compare September 11, 2026 11:29
@kkovaacs
kkovaacs force-pushed the krisztian/grpc-protocol-config branch from ea9a8e9 to d42a4d5 Compare September 11, 2026 11:35
Base automatically changed from krisztian/store-protocol-config to next September 11, 2026 11:42
@kkovaacs
kkovaacs force-pushed the krisztian/grpc-protocol-config branch from d42a4d5 to c8806dd Compare September 11, 2026 11:43
kkovaacs and others added 2 commits September 11, 2026 13:43
Co-authored-by: Mirko <48352201+Mirko-von-Leipzig@users.noreply.github.com>
Comment thread bin/validator/src/db/queries/protocol_config/mod.rs Outdated
@kkovaacs
kkovaacs force-pushed the krisztian/grpc-protocol-config branch from c8806dd to 090ceb0 Compare September 11, 2026 12:51

@bobbinth bobbinth left a comment

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.

Looks good! Thank you! This is not an exhaustive review - I largely skipped big parts of the NTX builder and the monitor changes, and focused primarily on the non-test code. I left some comments inline - the main one is about using BlockProofRequest message for validators - but maybe I just misunderstood something there.

Comment thread bin/validator/src/db/mod.rs Outdated
Comment thread bin/validator/src/db/mod.rs Outdated
Comment thread bin/validator/src/db/mod.rs Outdated
Comment on lines 92 to 105
pub async fn sign_block(
&self,
proposed_block: &ProposedBlock,
block_inputs: &BlockInputs,
protocol_config: &ProtocolConfig,
) -> Result<Vec<SignBlockResponse>, ValidatorError> {
let message = proto::block_proving::BlockProofRequest {
protocol_config: Some(protocol_config.into()),
batches: proposed_block.batches().as_slice().iter().map(Into::into).collect(),
block_inputs: Some(block_inputs.into()),
timestamp: proposed_block.timestamp(),
next_validator_config: Some(proposed_block.next_validator_config().into()),
next_protocol_config: proposed_block.next_protocol_config().map(Into::into),
};

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.

Not from this PR, but why are we sending BlockProofRequest to the validators? Is it just for convenience because BlockProofRequest message and the message we want to send to the validator have the same "shape"? If so, I'd consider still using two different messages because maybe they'll evolve in different was in the future (could be done in a different PR).

Comment thread proto/proto/types/block_proving.proto Outdated
Comment on lines +55 to +57
// The active configuration for signing. May be omitted if the validator already stores it.
// Proving-only callers may omit this field.
optional protocol_config.ProtocolConfig protocol_config = 6;

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.

Probably related to the above comment: I didn't fully understand the purpose of this field - is this something like:

  • When BlockProofRequest is sent to a prover, we don't need this field.
  • When BlockProofRequest is sent to a validator and the validator already has the config, we don't need it.
  • When BlockProofRequest is sent to a validator, and if the validator doesn't already have this config, we do need it.

I guess the question is: how do we know if the validator has or doesn't have the config?

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.

The block producer always includes the active configuration, so it does not need to know what each validator stores. Omission is supported for callers that know the validator already has it; an omitted unknown configuration returns InvalidArgument. Proving requests omit the field.

I'll create a follow-up PR that creates a validator-specifig SignBlockRequest for the validator API.

Comment thread crates/store/src/state/writer/mod.rs
Comment thread crates/rpc/src/server/api.rs Outdated
Comment thread crates/proto/src/domain/protocol_config.rs Outdated
@kkovaacs
kkovaacs merged commit 8147108 into next Sep 14, 2026
32 checks passed
@kkovaacs
kkovaacs deleted the krisztian/grpc-protocol-config branch September 14, 2026 09:36
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