starknet_transaction_prover: add OpenRPC spec and spec validation#12879
starknet_transaction_prover: add OpenRPC spec and spec validation#12879avi-starkware merged 1 commit intomain-v0.14.2from
Conversation
02086f9 to
857c8f8
Compare
857c8f8 to
5af226f
Compare
35c6087 to
657f805
Compare
|
How about verifying that This validates the result schema. Code quote: prove_transaction_result_matches_schema() |
|
To @AvivYossef-starkware's suggestion, this PR potentially replaces |
AvivYossef-starkware
left a comment
There was a problem hiding this comment.
@AvivYossef-starkware reviewed 4 files and all commit messages, and made 8 comments.
Reviewable status: 4 of 5 files reviewed, 6 unresolved discussions (waiting on avi-starkware, noaov1, and Yoni-Starkware).
a discussion (no related file):
Previously, avivg-starkware wrote…
To @AvivYossef-starkware's suggestion, this PR potentially replaces
MockProvingRpc.
I added a comment below of a test I think is needed. If this case is addressed, I'll revert #12909.
@avi-starkware, plz try to make it more readable and add comments
crates/starknet_os_runner/resources/proving_api_openrpc.json line 1 at r3 (raw file):
{
How did you create this file?
crates/starknet_os_runner/src/server.rs line 8 at r3 (raw file):
#[cfg(test)] #[path = "server/rpc_spec_test.rs"]
?
Code quote:
[path = "server/rpc_spec_test.rs"]crates/starknet_os_runner/src/server/rpc_spec_test.rs line 27 at r3 (raw file):
fn load_spec() -> Value { serde_json::from_str(OPENRPC_SPEC).expect("OpenRPC spec must be valid JSON") }
Why don't you use you load_respurce_file method?
Code quote:
/// Embedded OpenRPC specification document.
const OPENRPC_SPEC: &str = include_str!("../../resources/proving_api_openrpc.json");
fn load_spec() -> Value {
serde_json::from_str(OPENRPC_SPEC).expect("OpenRPC spec must be valid JSON")
}crates/starknet_os_runner/src/server/rpc_spec_test.rs line 27 at r3 (raw file):
fn load_spec() -> Value { serde_json::from_str(OPENRPC_SPEC).expect("OpenRPC spec must be valid JSON") }
use LaztLock to load it on
Code quote:
fn load_spec() -> Value {
serde_json::from_str(OPENRPC_SPEC).expect("OpenRPC spec must be valid JSON")
}crates/starknet_os_runner/src/server/rpc_spec_test.rs line 78 at r3 (raw file):
obj.insert("required".to_string(), required.into()); } }
lets make it more readable
consider something like
( just make the test
struct SpecError {
code: i32,
message: String,
expects_data: bool,
}
impl SpecError {
fn from_spec(value: &Value) -> Self {
Self {
code: value["code"].as_i64().unwrap() as i32,
message: value["message"].as_str().unwrap().to_string(),
expects_data: value.get("data").is_some(),
}
}
fn assert_matches(&self, error: &ErrorObjectOwned) {
assert_eq!(error.code(), self.code);
assert_eq!(error.message(), self.message);
assert_eq!(error.data().is_some(), self.expects_data);
}
}
#[rstest]
#[case("BLOCK_NOT_FOUND", error::block_not_found())]
#[case("ACCOUNT_VALIDATION_FAILED", error::validation_failure("test".to_string()))]
#[case("UNSUPPORTED_TX_VERSION", error::unsupported_tx_version("v99".to_string()))]
#[case("SERVICE_BUSY", error::service_busy(2))]
fn error_responses_match_spec(
#[case] spec_key: &str,
#[case] actual: ErrorObjectOwned,
) {
let spec = load_spec();
SpecError::from_spec(&spec["components"]["errors"][spec_key])
.assert_matches(&actual);
}
Code quote:
/// Transforms spec error definitions into JSON Schemas that can validate error responses.
///
/// Adapted from `apollo_rpc::test_utils::fix_errors`.
fn fix_errors(spec: &mut Value) {
let Some(errors) = spec
.as_object_mut()
.and_then(|obj| obj.get_mut("components"))
.and_then(|components| components.as_object_mut())
.and_then(|components| components.get_mut("errors"))
.and_then(|errors| errors.as_object_mut())
else {
return;
};
for value in errors.values_mut() {
let obj = value.as_object_mut().unwrap();
let Some(code) = obj.get("code").cloned() else {
continue;
};
let Some(message) = obj.get("message").cloned() else {
continue;
};
let has_data = obj.contains_key("data");
obj.clear();
let mut properties = serde_json::Map::from_iter([
(
"code".to_string(),
serde_json::Map::from_iter([
("type".to_string(), "integer".into()),
("enum".to_string(), vec![code].into()),
])
.into(),
),
(
"message".to_string(),
serde_json::Map::from_iter([
("type".to_string(), "string".into()),
("enum".to_string(), vec![message].into()),
])
.into(),
),
]);
let mut required: Vec<Value> = vec!["code".into(), "message".into()];
if has_data {
properties.insert("data".to_string(), serde_json::Map::from_iter([]).into());
required.push("data".into());
}
obj.insert("properties".to_string(), properties.into());
obj.insert("required".to_string(), required.into());
}
}crates/starknet_os_runner/src/server/rpc_spec_test.rs line 269 at r3 (raw file):
{}\nErrors: {:?}", serde_json::to_string_pretty(&serialized).unwrap(), tx_schema.validate(&serialized).err().map(|e| e.collect::<Vec<_>>()),
Share something like it with all the tests
fn assert_matches_schema(schema: &JSONSchema, value: &Value, label: &str) {
assert!(
schema.is_valid(value),
"{label} does not match spec schema.\nSerialized: {}\nErrors: {:?}",
serde_json::to_string_pretty(value).unwrap(),
schema.validate(value).err().map(|e| e.collect::<Vec<_>>()),
);
}
Code quote:
assert!(
tx_schema.is_valid(&serialized),
"Serialized RpcTransaction does not match RPC_TRANSACTION schema.\nSerialized: \
{}\nErrors: {:?}",
serde_json::to_string_pretty(&serialized).unwrap(),
tx_schema.validate(&serialized).err().map(|e| e.collect::<Vec<_>>()),crates/starknet_os_runner/src/server/rpc_spec_test.rs line 292 at r3 (raw file):
block_id_schema.validate(&serialized).err().map(|e| e.collect::<Vec<_>>()), ); }
Suggestion:
#[rstest]
#[case("hash", BlockId::Hash(BlockHash(felt!("0x123"))))]
#[case("number", BlockId::Number(BlockNumber(42)))]
#[case("latest", BlockId::Latest)]
fn serialized_block_id_matches_schema(#[case] label: &str, #[case] block_id: BlockId) {
let schema = compile_component_schema("BLOCK_ID");
assert_matches_schema(&schema, &serde_json::to_value(block_id).unwrap(), label);
}163b684 to
c87dff8
Compare
avi-starkware
left a comment
There was a problem hiding this comment.
@avi-starkware made 5 comments.
Reviewable status: 1 of 5 files reviewed, 6 unresolved discussions (waiting on avivg-starkware, AvivYossef-starkware, noaov1, and Yoni-Starkware).
crates/starknet_os_runner/src/server/rpc_spec_test.rs line 27 at r3 (raw file):
Previously, AvivYossef-starkware wrote…
Why don't you use you load_respurce_file method?
I used read_json_file instead.
crates/starknet_os_runner/src/server/rpc_spec_test.rs line 27 at r3 (raw file):
Previously, AvivYossef-starkware wrote…
use LaztLock to load it on
Done.
crates/starknet_os_runner/src/server/rpc_spec_test.rs line 78 at r3 (raw file):
Previously, AvivYossef-starkware wrote…
lets make it more readable
consider something like
( just make the teststruct SpecError { code: i32, message: String, expects_data: bool, } impl SpecError { fn from_spec(value: &Value) -> Self { Self { code: value["code"].as_i64().unwrap() as i32, message: value["message"].as_str().unwrap().to_string(), expects_data: value.get("data").is_some(), } } fn assert_matches(&self, error: &ErrorObjectOwned) { assert_eq!(error.code(), self.code); assert_eq!(error.message(), self.message); assert_eq!(error.data().is_some(), self.expects_data); } } #[rstest] #[case("BLOCK_NOT_FOUND", error::block_not_found())] #[case("ACCOUNT_VALIDATION_FAILED", error::validation_failure("test".to_string()))] #[case("UNSUPPORTED_TX_VERSION", error::unsupported_tx_version("v99".to_string()))] #[case("SERVICE_BUSY", error::service_busy(2))] fn error_responses_match_spec( #[case] spec_key: &str, #[case] actual: ErrorObjectOwned, ) { let spec = load_spec(); SpecError::from_spec(&spec["components"]["errors"][spec_key]) .assert_matches(&actual); }
Done.
crates/starknet_os_runner/src/server/rpc_spec_test.rs line 175 at r3 (raw file):
Previously, avivg-starkware wrote…
How about verifying that
prove_transactionmatches thestarknet_proveTransactionspecs definition (i.e., that the params match)?This validates the result schema.
and I see there are tests validating the params types (' BlockIdandRpcTransaction`) independently .
Done.
I added a test that actually tries to send a request (with stucture based on the to the JSON-RPC module and makes sure it doesn't get an `invalid params
crates/starknet_os_runner/src/server/rpc_spec_test.rs line 292 at r3 (raw file):
block_id_schema.validate(&serialized).err().map(|e| e.collect::<Vec<_>>()), ); }
Done.
avi-starkware
left a comment
There was a problem hiding this comment.
@avi-starkware made 1 comment.
Reviewable status: 1 of 5 files reviewed, 6 unresolved discussions (waiting on avivg-starkware, AvivYossef-starkware, noaov1, and Yoni-Starkware).
crates/starknet_os_runner/src/server/rpc_spec_test.rs line 269 at r3 (raw file):
Previously, AvivYossef-starkware wrote…
Share something like it with all the tests
fn assert_matches_schema(schema: &JSONSchema, value: &Value, label: &str) { assert!( schema.is_valid(value), "{label} does not match spec schema.\nSerialized: {}\nErrors: {:?}", serde_json::to_string_pretty(value).unwrap(), schema.validate(value).err().map(|e| e.collect::<Vec<_>>()), ); }
Done.
c87dff8 to
24a1976
Compare
AvivYossef-starkware
left a comment
There was a problem hiding this comment.
@AvivYossef-starkware reviewed 4 files and all commit messages, made 5 comments, and resolved 5 discussions.
Reviewable status: all files reviewed, 5 unresolved discussions (waiting on avi-starkware, avivg-starkware, noaov1, and Yoni-Starkware).
crates/starknet_os_runner/src/server/rpc_spec_test.rs line 76 at r4 (raw file):
let rpc_impl = ProvingRpcServerImpl::new(RpcVirtualSnosProver::new(&config), 2); rpc_impl.into_rpc() }
And better to be a fixture
Suggestion:
fn rpc_module() -> RpcModule<ProvingRpcServerImpl> {
let config =
ProverConfig { rpc_node_url: "http://localhost:1".to_string(), ..Default::default() };
let rpc_impl = ProvingRpcServerImpl::new(RpcVirtualSnosProver::new(&config), 2);
rpc_impl.into_rpc()
}crates/starknet_os_runner/src/server/rpc_spec_test.rs line 177 at r4 (raw file):
assert_ne!( code, -32602,
plz define it as a const and document it
(Maybe you can import it from JSON-RPCSE? )
Code quote:
-32602crates/starknet_os_runner/src/server/rpc_spec_test.rs line 202 at r4 (raw file):
( PROVE_TRANSACTION_METHOD, serde_json::to_value(sample_prove_transaction_result()).unwrap(),
It won't catch an issue if someone changes the return type of starknet_prove_transaction ( but it may be unlikely? )
Code quote:
serde_json::to_value(sample_prove_transaction_result()).unwrap()crates/starknet_os_runner/src/server/rpc_spec_test.rs line 223 at r4 (raw file):
fn error_responses_match_spec(#[case] spec_key: &str, #[case] actual: ErrorObjectOwned) { SpecError::from_spec(&SPEC["components"]["errors"][spec_key]).assert_matches(&actual); }
What if we add more errors?
Code quote:
#[rstest]
#[case("BLOCK_NOT_FOUND", error::block_not_found())]
#[case("ACCOUNT_VALIDATION_FAILED", error::validation_failure("test".to_string()))]
#[case("UNSUPPORTED_TX_VERSION", error::unsupported_tx_version("v99".to_string()))]
#[case("SERVICE_BUSY", error::service_busy(2))]
fn error_responses_match_spec(#[case] spec_key: &str, #[case] actual: ErrorObjectOwned) {
SpecError::from_spec(&SPEC["components"]["errors"][spec_key]).assert_matches(&actual);
}crates/starknet_os_runner/src/server/rpc_spec_test.rs line 231 at r4 (raw file):
fn serialized_block_id_matches_schema(#[case] label: &str, #[case] block_id: BlockId) { let schema = compile_schema_for_ref(&SPEC, &format!("components/schemas/BLOCK_ID")); assert_matches_schema(&schema, &serde_json::to_value(block_id).unwrap(), label);
Why do you specifically test BlockId?
Code quote:
#[rstest]
#[case("hash", BlockId::Hash(BlockHash(felt!("0x123"))))]
#[case("number", BlockId::Number(BlockNumber(42)))]
#[case("latest", BlockId::Latest)]
fn serialized_block_id_matches_schema(#[case] label: &str, #[case] block_id: BlockId) {
let schema = compile_schema_for_ref(&SPEC, &format!("components/schemas/BLOCK_ID"));
assert_matches_schema(&schema, &serde_json::to_value(block_id).unwrap(), label);
avivg-starkware
left a comment
There was a problem hiding this comment.
@avivg-starkware made 1 comment.
Reviewable status: all files reviewed, 6 unresolved discussions (waiting on avi-starkware, noaov1, and Yoni-Starkware).
crates/starknet_os_runner/src/server/rpc_spec_test.rs line 185 at r5 (raw file):
} } }
The test mixes object construction with the test logic, making it hard to tell what's being tested. I'd suggest extracting a build_method_test_cases helper that creates and validates the test data, so the test body is just as follows.
Also, we currently only test named params ("params": {…}). We should test positional params ("params": […]) too.
I sketched out the helpers below as a general direction.
Suggestion (i):
/// Validates that the spec's parameter definitions match the actual RPC implementation.
///
/// For each method, sends both a named-param and a positional-param JSON-RPC request and asserts
/// no "invalid params" error.
#[tokio::test]
async fn spec_request_params_match_rpc_module() {
let module = build_test_rpc_module();
let test_cases = build_method_test_cases(&module);
for (method_name, method_index, sample_values) in &test_cases {
assert_rpc_accepts_spec_param_names(&module, method_name, *method_index, sample_values)
.await;
assert_rpc_accepts_spec_param_indices(&module, method_name, sample_values).await;
}
}Code snippet (ii):
/// Builds test cases with resolved spec data for each RPC method.
/// Also asserts that the test cases cover every method in the spec and module (completeness guard).
fn build_method_test_cases(
module: &RpcModule<ProvingRpcServerImpl>,
) -> Vec<(&'static str, usize, Vec<Value>)> {
let sample_values: Vec<(&str, Vec<Value>)> = vec![
(SPEC_VERSION_METHOD, vec![]),
(
PROVE_TRANSACTION_METHOD,
vec![
serde_json::to_value(BlockId::Latest).unwrap(),
serde_json::to_value(rpc_invoke_tx(invoke_tx_args!())).unwrap(),
],
),
];
// Completeness guard: test cases must cover all spec and module methods.
let methods = SPEC["methods"].as_array().unwrap();
let tested: HashSet<&str> = sample_values.iter().map(|(name, _)| *name).collect();
let spec_methods: HashSet<&str> = methods.iter().map(|m| m["name"].as_str().unwrap()).collect();
let module_methods: HashSet<&str> = module.method_names().collect();
assert_eq!(tested, spec_methods, "Test cases don't cover all spec methods");
assert_eq!(tested, module_methods, "Test cases don't cover all module methods");
// Resolve spec method index and validate sample values against spec schemas.
sample_values
.into_iter()
.map(|(name, values)| {
let method_index =
methods.iter().position(|m| m["name"].as_str().unwrap() == name).unwrap();
let spec_params = methods[method_index]["params"].as_array().unwrap();
assert_eq!(
spec_params.len(),
values.len(),
"Sample value count for {name} doesn't match spec param count"
);
for (param_index, (spec_param, sample_value)) in
spec_params.iter().zip(&values).enumerate()
{
let param_name = spec_param["name"].as_str().unwrap();
let schema = compile_schema_for_ref(
&SPEC,
&format!("methods/{method_index}/params/{param_index}/schema"),
);
assert_matches_schema(
&schema,
sample_value,
&format!("Parameter '{param_name}' of {name}"),
);
}
(name, method_index, values)
})
.collect()
}
/// Sends a JSON-RPC request and asserts the module does not reject it with -32602 ("invalid
/// params"). `params_str` is the raw JSON fragment for the `"params"` field (may be empty).
async fn assert_rpc_does_not_reject_params(
module: &RpcModule<ProvingRpcServerImpl>,
method_name: &str,
params_str: &str,
) {
let req = format!(r#"{{"jsonrpc":"2.0","id":"1","method":"{method_name}"{params_str}}}"#);
let (resp, _) = module.raw_json_request(&req, 1).await.unwrap();
let json_resp: Value = serde_json::from_str(resp.get()).unwrap();
if let Some(error) = json_resp.get("error") {
let code = error["code"].as_i64().unwrap();
assert_ne!(
code,
-32602,
"Method {method_name}: RPC module rejected request with 'invalid params', meaning the \
spec's parameter names or types don't match the implementation.\nRequest: \
{req}\nError: {}",
serde_json::to_string_pretty(error).unwrap(),
);
}
}
/// Sends a named-param JSON-RPC request (e.g. `"params": {"block_id": ...}`) and asserts
/// the module accepts it.
async fn assert_rpc_accepts_spec_param_names(
module: &RpcModule<ProvingRpcServerImpl>,
method_name: &str,
method_index: usize,
sample_values: &[Value],
) {
let spec_params = SPEC["methods"][method_index]["params"].as_array().unwrap();
let params_obj: serde_json::Map<String, Value> = spec_params
.iter()
.zip(sample_values)
.map(|(spec_param, value)| {
(spec_param["name"].as_str().unwrap().to_string(), value.clone())
})
.collect();
let params_str = if params_obj.is_empty() {
String::new()
} else {
format!(r#", "params": {}"#, serde_json::to_string(¶ms_obj).unwrap())
};
assert_rpc_does_not_reject_params(module, method_name, ¶ms_str).await;
}
/// Sends a positional-param JSON-RPC request (e.g. `"params": [...]`) and asserts the module
/// accepts it.
async fn assert_rpc_accepts_spec_param_indices(
module: &RpcModule<ProvingRpcServerImpl>,
method_name: &str,
sample_values: &[Value],
) {
let params_str = if sample_values.is_empty() {
String::new()
} else {
format!(r#", "params": {}"#, serde_json::to_string(&sample_values).unwrap())
};
assert_rpc_does_not_reject_params(module, method_name, ¶ms_str).await;
}24a1976 to
003d2aa
Compare
avi-starkware
left a comment
There was a problem hiding this comment.
@avi-starkware made 6 comments.
Reviewable status: 1 of 6 files reviewed, 7 unresolved discussions (waiting on avivg-starkware, AvivYossef-starkware, noaov1, and Yoni-Starkware).
crates/starknet_os_runner/src/server.rs line 8 at r3 (raw file):
Previously, AvivYossef-starkware wrote…
?
Removed
crates/starknet_os_runner/src/server/rpc_spec_test.rs line 76 at r4 (raw file):
Previously, AvivYossef-starkware wrote…
And better to be a fixture
Done.
crates/starknet_os_runner/src/server/rpc_spec_test.rs line 177 at r4 (raw file):
Previously, AvivYossef-starkware wrote…
plz define it as a const and document it
(Maybe you can import it from JSON-RPCSE? )
Done.
crates/starknet_os_runner/src/server/rpc_spec_test.rs line 223 at r4 (raw file):
Previously, AvivYossef-starkware wrote…
What if we add more errors?
I added a check that goes over all errors in the spec.
To make sure we go over all errors that exits we will have to make them into an enum, which is a bigger change better to move to do in a separate PR.
crates/starknet_os_runner/src/server/rpc_spec_test.rs line 231 at r4 (raw file):
Previously, AvivYossef-starkware wrote…
Why do you specifically test BlockId?
I just thought it would be easy to cover all three cases for this schema, but it is probably overkill...
Removed.
crates/starknet_os_runner/src/server/rpc_spec_test.rs line 185 at r5 (raw file):
Previously, avivg-starkware wrote…
The test mixes object construction with the test logic, making it hard to tell what's being tested. I'd suggest extracting a
build_method_test_caseshelper that creates and validates the test data, so the test body is just as follows.Also, we currently only test named params ("params": {…}). We should test positional params ("params": […]) too.
I sketched out the helpers below as a general direction.
Done.
AvivYossef-starkware
left a comment
There was a problem hiding this comment.
@AvivYossef-starkware reviewed 5 files and all commit messages, made 4 comments, and resolved 3 discussions.
Reviewable status: all files reviewed, 6 unresolved discussions (waiting on avi-starkware, avivg-starkware, noaov1, and Yoni-Starkware).
crates/starknet_os_runner/src/server/rpc_spec_test.rs line 223 at r4 (raw file):
Previously, avi-starkware (Avi Cohen) wrote…
I added a check that goes over all errors in the spec.
To make sure we go over all errors that exits we will have to make them into an enum, which is a bigger change better to move to do in a separate PR.
Can you add TODO?
crates/starknet_os_runner/src/server/rpc_spec_test.rs line 96 at r6 (raw file):
module: &RpcModule<ProvingRpcServerImpl>, ) -> Vec<(&'static str, usize, Vec<Value>)> { let sample_values: Vec<(&str, Vec<Value>)> = vec![
consider defining a struct
Code quote:
(&str, Vec<Value>)crates/starknet_os_runner/src/server/rpc_spec_test.rs line 141 at r6 (raw file):
); } (name, method_index, values)
Define a struct
Code quote:
(name, method_index, values)crates/starknet_os_runner/src/server/rpc_spec_test.rs line 183 at r6 (raw file):
.iter() .zip(sample_values) .map(|(spec_param, value)| {
Suggestion:
sample_valuea1d844f to
7d6de3e
Compare
7d6de3e to
94bd95d
Compare
8c34eab to
03f8343
Compare
avivg-starkware
left a comment
There was a problem hiding this comment.
@avivg-starkware made 1 comment and resolved 2 discussions.
Reviewable status: 3 of 6 files reviewed, 1 unresolved discussion (waiting on avi-starkware, AvivYossef-starkware, noaov1, and Yoni-Starkware).
crates/starknet_os_runner/src/server/rpc_spec_test.rs line 202 at r4 (raw file):
Previously, AvivYossef-starkware wrote…
It won't catch an issue if someone changes the return type of
starknet_prove_transaction( but it may be unlikely? )
Why unlikely?
I think testing the response is needed; in the SDK, we will test the response object against the specs. If the response object in the specs does not match the RPC, then the SDK's test will be irrelevant.
bc1795d to
32803ba
Compare
|
Previously, avivg-starkware wrote…
I changed it to use a mock rpc to make sure the response types match the spec |
Code reviewNo issues found. Checked for bugs and CLAUDE.md compliance. 🤖 Generated with Claude Code |
32803ba to
68a7893
Compare
avivg-starkware
left a comment
There was a problem hiding this comment.
@avivg-starkware partially reviewed 6 files and all commit messages, made 7 comments, and resolved 1 discussion.
Reviewable status: 6 of 9 files reviewed, 6 unresolved discussions (waiting on avi-starkware, AvivYossef-starkware, noaov1, and Yoni-Starkware).
crates/starknet_transaction_prover/src/server/rpc_spec_test.rs line 32 at r15 (raw file):
ProverConfig { rpc_node_url: "http://localhost:1".to_string(), ..Default::default() }; let rpc_impl = ProvingRpcServerImpl::new(RpcVirtualSnosProver::new(&config), 2); rpc_impl.into_rpc()
Suggestion (i):
let config =
ProverConfig { rpc_node_url: DUMMY_RPC_NODE_URL.to_string(), ..Default::default() };
let rpc_impl = ProvingRpcServerImpl::new(
RpcVirtualSnosProver::new(&config),
TEST_MAX_CONCURRENT_REQUESTS,
);Code snippet (ii):
/// Dummy URL for test fixture.
const DUMMY_RPC_NODE_URL: &str = "http://localhost:1";
/// Max concurrent requests for the test fixture.
const TEST_MAX_CONCURRENT_REQUESTS: usize = 2;crates/starknet_transaction_prover/src/server/rpc_spec_test.rs line 77 at r15 (raw file):
code: i32::try_from(value["code"].as_i64().unwrap()).unwrap(), message: value["message"].as_str().unwrap().to_string(), expects_data: value.get("data").is_some(),
Do we not care what IS the data? just that it is there?
Code quote:
expects_data: value.get("data").is_some(),crates/starknet_transaction_prover/src/server/rpc_spec_test.rs line 153 at r15 (raw file):
let req = format!(r#"{{"jsonrpc":"2.0","id":"1","method":"{method_name}"{params_str}}}"#); let (resp, _) = module.raw_json_request(&req, 1).await.unwrap();
I think this is more readable (the funcs are used below as well )
Suggestion (i):
let req = format_rpc_request(method_name, params_str);
let (resp, _) = module.raw_json_request(&req, RPC_RESPONSE_BUFFER_SIZE).await.unwrap();Code snippet (ii):
/// Builds a positional-param JSON fragment (e.g. `,"params":[...]`).
/// Returns an empty string when `sample_values` is empty.
fn format_params(sample_values: &[Value]) -> String {
if sample_values.is_empty() {
String::new()
} else {
format!(r#","params":{}"#, serde_json::to_string(sample_values).unwrap())
}
}
/// Builds a JSON-RPC request string.
fn format_rpc_request(method_name: &str, params_fragment: &str) -> String {
format!(r#"{{"jsonrpc":"2.0","id":"1","method":"{method_name}"{params_fragment}}}"#)
}crates/starknet_transaction_prover/src/server/rpc_spec_test.rs line 205 at r15 (raw file):
format!(r#", "params": {}"#, serde_json::to_string(&sample_values).unwrap()) }; assert_rpc_does_not_reject_params(module, method_name, ¶ms_str).await;
I find this more readable
Suggestion:
assert_rpc_does_not_reject_params(
module,
method_name,
&format_params(sample_values),
)
.await;crates/starknet_transaction_prover/src/server/rpc_spec_test.rs line 236 at r15 (raw file):
let request = format!(r#"{{"jsonrpc":"2.0","id":"1","method":"{method_name}"{params_str}}}"#); let (resp, _) = mock_rpc_module.raw_json_request(&request, 1).await.unwrap();
Suggestion:
let request =
format_rpc_request(method_name, &format_params(sample_params));
let (resp, _) =
mock_rpc_module.raw_json_request(&request, RPC_RESPONSE_BUFFER_SIZE).await.unwrap();crates/starknet_transaction_prover/src/server/rpc_spec_test.rs line 262 at r15 (raw file):
); let (response, _) = rpc_module.raw_json_request(&request, 1).await.unwrap();
Suggestion:
let sample_values = vec![
serde_json::to_value(BlockId::Pending).unwrap(),
serde_json::to_value(rpc_invoke_tx(invoke_tx_args!())).unwrap(),
];
let request = format_rpc_request(
PROVE_TRANSACTION_METHOD,
&format_params(&sample_values),
);
let (response, _) =
rpc_module.raw_json_request(&request, RPC_RESPONSE_BUFFER_SIZE).await.unwrap()62d5ab7 to
0e99bb9
Compare
avi-starkware
left a comment
There was a problem hiding this comment.
@avi-starkware made 6 comments and resolved 5 discussions.
Reviewable status: 4 of 9 files reviewed, 1 unresolved discussion (waiting on avivg-starkware, AvivYossef-starkware, noaov1, and Yoni-Starkware).
crates/starknet_transaction_prover/src/server/rpc_spec_test.rs line 77 at r15 (raw file):
Previously, avivg-starkware wrote…
Do we not care what IS the data? just that it is there?
The spec only defines data as a string type (content varies at runtime), so presence-checking is the right level for spec conformance
crates/starknet_transaction_prover/src/server/rpc_spec_test.rs line 153 at r15 (raw file):
Previously, avivg-starkware wrote…
I think this is more readable (the funcs are used below as well )
Done.
crates/starknet_transaction_prover/src/server/rpc_spec_test.rs line 205 at r15 (raw file):
Previously, avivg-starkware wrote…
I find this more readable
Done.
crates/starknet_transaction_prover/src/server/rpc_spec_test.rs line 32 at r15 (raw file):
ProverConfig { rpc_node_url: "http://localhost:1".to_string(), ..Default::default() }; let rpc_impl = ProvingRpcServerImpl::new(RpcVirtualSnosProver::new(&config), 2); rpc_impl.into_rpc()
Done.
crates/starknet_transaction_prover/src/server/rpc_spec_test.rs line 236 at r15 (raw file):
let request = format!(r#"{{"jsonrpc":"2.0","id":"1","method":"{method_name}"{params_str}}}"#); let (resp, _) = mock_rpc_module.raw_json_request(&request, 1).await.unwrap();
Done.
crates/starknet_transaction_prover/src/server/rpc_spec_test.rs line 262 at r15 (raw file):
); let (response, _) = rpc_module.raw_json_request(&request, 1).await.unwrap();
Done.
avivg-starkware
left a comment
There was a problem hiding this comment.
@avivg-starkware partially reviewed 1 file and resolved 1 discussion.
Reviewable status: 5 of 9 files reviewed, all discussions resolved (waiting on AvivYossef-starkware, noaov1, and Yoni-Starkware).
134af25 to
f6c4b85
Compare
avi-starkware
left a comment
There was a problem hiding this comment.
@avi-starkware partially reviewed 9 files and all commit messages.
Reviewable status:complete! all files reviewed, all discussions resolved (waiting on noaov1 and Yoni-Starkware).
f6c4b85 to
278b168
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
278b168 to
f0eb540
Compare
avi-starkware
left a comment
There was a problem hiding this comment.
@avi-starkware partially reviewed 2 files and all commit messages.
Reviewable status:complete! all files reviewed, all discussions resolved (waiting on noaov1 and Yoni-Starkware).
Note
Low Risk
Primarily adds documentation artifacts and test-only schema validation; production server behavior is unchanged aside from stricter CI coverage that could surface mismatches.
Overview
Adds a formal OpenRPC document (
resources/proving_api_openrpc.json) describing thestarknet_specVersionandstarknet_proveTransactionmethods, their schemas, and standardized error definitions.Introduces a test-only spec validation suite (
server/rpc_spec_test.rs) usingjsonschemato assert request param compatibility (named + positional), response shapes from the mock RPC, and that error codes/messages inserver/errors.rsmatch the spec (with a completeness guard).Written by Cursor Bugbot for commit f0eb540. This will update automatically on new commits. Configure here.