From 0135dcb2e05ec0261937c0e72ea7242b1c04c7d1 Mon Sep 17 00:00:00 2001 From: apoorvsadana <95699312+apoorvsadana@users.noreply.github.com> Date: Tue, 8 Oct 2024 01:51:33 +0530 Subject: [PATCH 1/4] handle batched requests in middleware --- Cargo.lock | 107 ++++++++++++---------- crates/node/src/service/rpc/middleware.rs | 28 ++++-- crates/tests/src/lib.rs | 2 + crates/tests/src/rpc/read.rs | 82 +++++++++++++++++ 4 files changed, 161 insertions(+), 58 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 373270b30..3a517ceda 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5377,7 +5377,7 @@ dependencies = [ "serde", "serde_json", "serde_yaml", - "starknet-core", + "starknet-core 0.11.0", "starknet-providers", "starknet_api", "thiserror", @@ -5428,7 +5428,7 @@ dependencies = [ "rayon", "rstest 0.18.2", "serde", - "starknet-core", + "starknet-core 0.11.0", "starknet-types-core", "starknet_api", "tempfile", @@ -5457,7 +5457,7 @@ dependencies = [ "rocksdb", "rstest 0.18.2", "serde", - "starknet-core", + "starknet-core 0.11.0", "starknet-types-core", "starknet_api", "tempfile", @@ -5492,7 +5492,7 @@ dependencies = [ "rand", "rstest 0.18.2", "serde_json", - "starknet-core", + "starknet-core 0.11.0", "starknet-signers", "starknet-types-core", "starknet_api", @@ -5513,7 +5513,7 @@ dependencies = [ "rstest 0.18.2", "serde_json", "starknet", - "starknet-core", + "starknet-core 0.11.0", "starknet-providers", "tempfile", "tokio", @@ -5570,7 +5570,7 @@ dependencies = [ "mp-class", "mp-convert", "rstest 0.18.2", - "starknet-core", + "starknet-core 0.11.0", "starknet-types-core", "starknet_api", "thiserror", @@ -5596,7 +5596,7 @@ dependencies = [ "rstest 0.18.2", "serde", "serde_json", - "starknet-core", + "starknet-core 0.11.0", "starknet-types-core", "thiserror", "tokio", @@ -5628,7 +5628,7 @@ dependencies = [ "proptest", "proptest-derive", "rstest 0.18.2", - "starknet-core", + "starknet-core 0.11.0", "starknet-types-core", "starknet_api", "thiserror", @@ -5673,7 +5673,7 @@ dependencies = [ "paste", "rstest 0.18.2", "serde_json", - "starknet-core", + "starknet-core 0.11.0", "starknet-providers", "starknet-types-core", "starknet_api", @@ -5708,7 +5708,7 @@ dependencies = [ "reqwest 0.12.5", "rstest 0.18.2", "serde_json", - "starknet-core", + "starknet-core 0.11.0", "starknet-providers", "starknet-types-core", "starknet_api", @@ -5819,7 +5819,7 @@ dependencies = [ "mp-transactions", "primitive-types", "serde", - "starknet-core", + "starknet-core 0.11.0", "starknet-types-core", "thiserror", ] @@ -5866,7 +5866,7 @@ dependencies = [ "serde", "serde_json", "sha3", - "starknet-core", + "starknet-core 0.11.0", "starknet-providers", "starknet-types-core", "thiserror", @@ -5881,7 +5881,7 @@ dependencies = [ "primitive-types", "serde", "serde_with 3.9.0", - "starknet-core", + "starknet-core 0.11.0", "starknet-types-core", "starknet_api", "thiserror", @@ -5903,7 +5903,7 @@ dependencies = [ "serde", "serde_json", "serde_with 3.9.0", - "starknet-core", + "starknet-core 0.11.0", "starknet-types-core", ] @@ -5918,7 +5918,7 @@ dependencies = [ "mp-convert", "rstest 0.18.2", "serde", - "starknet-core", + "starknet-core 0.11.0", "starknet-providers", "starknet-types-core", "starknet_api", @@ -5931,7 +5931,7 @@ dependencies = [ "bincode 1.3.3", "mp-convert", "serde", - "starknet-core", + "starknet-core 0.11.0", "starknet-providers", "starknet-types-core", "thiserror", @@ -5954,7 +5954,7 @@ dependencies = [ "num-bigint", "serde", "serde_with 3.9.0", - "starknet-core", + "starknet-core 0.11.0", "starknet-providers", "starknet-types-core", "starknet_api", @@ -7929,8 +7929,8 @@ checksum = "1e633a772f59214c296d5037c95c36b72792c9360323818da2b625c7b4ec4b49" dependencies = [ "starknet-accounts", "starknet-contract", - "starknet-core", - "starknet-crypto 0.7.1", + "starknet-core 0.11.0", + "starknet-crypto 0.7.2", "starknet-macros", "starknet-providers", "starknet-signers", @@ -7944,8 +7944,8 @@ checksum = "eee8a6b588a22c7e79f5d8d4e33413387db63a8beb98be8610138541794cc0a5" dependencies = [ "async-trait", "auto_impl", - "starknet-core", - "starknet-crypto 0.7.1", + "starknet-core 0.11.0", + "starknet-crypto 0.7.2", "starknet-providers", "starknet-signers", "thiserror", @@ -7961,7 +7961,7 @@ dependencies = [ "serde_json", "serde_with 2.3.3", "starknet-accounts", - "starknet-core", + "starknet-core 0.11.0", "starknet-providers", "thiserror", ] @@ -7984,6 +7984,25 @@ dependencies = [ "starknet-types-core", ] +[[package]] +name = "starknet-core" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2538240cbe6663c673fe77465f294da707080f39678dd7066761554899e46100" +dependencies = [ + "base64 0.21.7", + "crypto-bigint", + "flate2", + "hex", + "serde", + "serde_json", + "serde_json_pythonic", + "serde_with 3.9.0", + "sha3", + "starknet-crypto 0.7.2", + "starknet-types-core", +] + [[package]] name = "starknet-crypto" version = "0.5.2" @@ -8037,17 +8056,17 @@ dependencies = [ "num-traits 0.2.19", "rfc6979", "sha2", - "starknet-crypto-codegen 0.4.0 (git+https://github.com/kasarlabs/starknet-rs.git?branch=fork)", - "starknet-curve 0.5.0 (git+https://github.com/kasarlabs/starknet-rs.git?branch=fork)", + "starknet-crypto-codegen 0.4.0", + "starknet-curve 0.5.0", "starknet-types-core", "zeroize", ] [[package]] name = "starknet-crypto" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff2a821ad8d98c6c3e4d0e5097f3fe6e2ed120ada9d32be87cd1330c7923a2f0" +checksum = "60a5064173a8e8d2675e67744fd07f310de44573924b6b7af225a6bdd8102913" dependencies = [ "crypto-bigint", "hex", @@ -8057,8 +8076,7 @@ dependencies = [ "num-traits 0.2.19", "rfc6979", "sha2", - "starknet-crypto-codegen 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "starknet-curve 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "starknet-curve 0.5.1", "starknet-types-core", "zeroize", ] @@ -8074,23 +8092,12 @@ dependencies = [ "syn 2.0.66", ] -[[package]] -name = "starknet-crypto-codegen" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e179dedc3fa6da064e56811d3e05d446aa2f7459e4eb0e3e49378a337235437" -dependencies = [ - "starknet-curve 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "starknet-types-core", - "syn 2.0.66", -] - [[package]] name = "starknet-crypto-codegen" version = "0.4.0" source = "git+https://github.com/kasarlabs/starknet-rs.git?branch=fork#1a0428e28e31e02cee1f4ddb80476d23eac77dc1" dependencies = [ - "starknet-curve 0.5.0 (git+https://github.com/kasarlabs/starknet-rs.git?branch=fork)", + "starknet-curve 0.5.0", "starknet-types-core", "syn 2.0.66", ] @@ -8116,16 +8123,16 @@ dependencies = [ [[package]] name = "starknet-curve" version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56935b306dcf0b8f14bb2a1257164b8478bb8be4801dfae0923f5b266d1b457c" +source = "git+https://github.com/kasarlabs/starknet-rs.git?branch=fork#1a0428e28e31e02cee1f4ddb80476d23eac77dc1" dependencies = [ "starknet-types-core", ] [[package]] name = "starknet-curve" -version = "0.5.0" -source = "git+https://github.com/kasarlabs/starknet-rs.git?branch=fork#1a0428e28e31e02cee1f4ddb80476d23eac77dc1" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcde6bd74269b8161948190ace6cf069ef20ac6e79cd2ba09b320efa7500b6de" dependencies = [ "starknet-types-core", ] @@ -8144,11 +8151,11 @@ dependencies = [ [[package]] name = "starknet-macros" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4fe4f8d615329410578cbedcdbaa4a36c7f28f68c3f3ac56006cfbdaeaa2b41" +checksum = "8986a940af916fc0a034f4e42c6ba76d94f1e97216d75447693dfd7aefaf3ef2" dependencies = [ - "starknet-core", + "starknet-core 0.12.0", "syn 2.0.66", ] @@ -8167,7 +8174,7 @@ dependencies = [ "serde", "serde_json", "serde_with 2.3.3", - "starknet-core", + "starknet-core 0.11.0", "thiserror", "url", ] @@ -8184,8 +8191,8 @@ dependencies = [ "eth-keystore", "getrandom", "rand", - "starknet-core", - "starknet-crypto 0.7.1", + "starknet-core 0.11.0", + "starknet-crypto 0.7.2", "thiserror", ] diff --git a/crates/node/src/service/rpc/middleware.rs b/crates/node/src/service/rpc/middleware.rs index 3c072eddc..695fa9325 100644 --- a/crates/node/src/service/rpc/middleware.rs +++ b/crates/node/src/service/rpc/middleware.rs @@ -267,18 +267,30 @@ async fn add_rpc_version_to_method(req: &mut hyper::Request) -> Result<(), let version = RpcVersion::from_request_path(&path)?; let whole_body = hyper::body::to_bytes(req.body_mut()).await?; - let mut json: Value = serde_json::from_slice(&whole_body)?; + let json: Value = serde_json::from_slice(&whole_body)?; - if let Some(method) = json.get_mut("method").as_deref().and_then(Value::as_str) { - let new_method = format!("starknet_{}_{}", version.name(), method.strip_prefix("starknet_").unwrap_or(method)); - - json["method"] = Value::String(new_method); + // in case of batched requests, the request is an array of JSON-RPC requests + let mut batched_request = false; + let mut items = if let Value::Array(items) = json { + batched_request = true; + items } else { - return Err(VersionMiddlewareError::InvalidRequestFormat); + vec![json] + }; + + for item in items.iter_mut() { + if let Some(method) = item.get_mut("method").as_deref().and_then(Value::as_str) { + let new_method = + format!("starknet_{}_{}", version.name(), method.strip_prefix("starknet_").unwrap_or(method)); + + item["method"] = Value::String(new_method); + } else { + return Err(VersionMiddlewareError::InvalidRequestFormat); + } } - let new_body = Body::from(serde_json::to_vec(&json)?); - *req.body_mut() = new_body; + let response = if batched_request { serde_json::to_vec(&items)? } else { serde_json::to_vec(&items[0])? }; + *req.body_mut() = Body::from(response); Ok(()) } diff --git a/crates/tests/src/lib.rs b/crates/tests/src/lib.rs index 0e63776c6..cfd962e98 100644 --- a/crates/tests/src/lib.rs +++ b/crates/tests/src/lib.rs @@ -78,6 +78,8 @@ impl MadaraCmd { || async { match rpc.block_hash_and_number().await { Ok(got) => { + println!("got block_n {}", got.block_number); + println!("expected block_n {}", block_n); if got.block_number < block_n { bail!("got block_n {}, expected {block_n}", got.block_number); } diff --git a/crates/tests/src/rpc/read.rs b/crates/tests/src/rpc/read.rs index 6c1c6d9b7..fd3aa667b 100644 --- a/crates/tests/src/rpc/read.rs +++ b/crates/tests/src/rpc/read.rs @@ -140,6 +140,88 @@ mod test_rpc_read_calls { assert_eq!(result, 1); } + /// Fetches the latest block hash and number. + /// + /// Example curl command: + /// + /// ```bash + /// curl --location 'https://free-rpc.nethermind.io/sepolia-juno/' \ + /// --header 'Content-Type: application/json' \ + /// --data '[ + /// { + /// "jsonrpc": "2.0", + /// "method": "starknet_blockHashAndNumber", + /// "params": {}, + /// "id": 0 + /// }, + /// { + /// "jsonrpc": "2.0", + /// "method": "starknet_getBlockTransactionCount", + /// "params": { + /// "block_id": { + /// "block_number": 2 + /// } + /// }, + /// "id": 1 + /// } + /// ]' + /// ``` + #[rstest] + #[tokio::test] + async fn test_batched_requests_work() { + let madara = get_shared_state().await; + + // use reqwest to send a batch request to the madara rpc. + // TODO: use a jsonrpc client instead of reqwest when we move + // to starknet-providers 0.12.0 + let client = reqwest::Client::new(); + let res = client + .post(madara.rpc_url.clone()) + .json(&[ + serde_json::json!({ + "jsonrpc": "2.0", + "method": "starknet_blockHashAndNumber", + "params": {}, + "id": 0 + }), + serde_json::json!({ + "jsonrpc": "2.0", + "method": "starknet_getBlockTransactionCount", + "params": { + "block_id": { + "block_number": 2 + } + }, + "id": 1 + }), + ]) + .send() + .await + .unwrap(); + + let result = res.json::().await.unwrap(); + + assert_eq!( + result[0], + serde_json::json!({ + "jsonrpc": "2.0", + "result": { + "block_hash": "0x4177d1ba942a4ab94f86a476c06f0f9e02363ad410cdf177c54064788c9bcb5", + "block_number": 19 + }, + "id": 0 + }) + ); + assert_eq!( + result[1], + serde_json::json!({ + "jsonrpc": "2.0", + "result": 1, + "id": 1 + }) + ); + } + /// Fetches a block with its transactions and receipts. /// /// Example curl command: From 200368265b9773f2a68268d74246dc40442d6a3b Mon Sep 17 00:00:00 2001 From: apoorvsadana <95699312+apoorvsadana@users.noreply.github.com> Date: Tue, 8 Oct 2024 01:52:03 +0530 Subject: [PATCH 2/4] fix changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1fd72fe15..090e8ad62 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Next release +- fix(rpc): handle batched requests in middleware - fix(sync): pending block retrying mechanism - fix:(tests): Add testing feature to mc-db dev dependency (#294) - feat: new crate gateway client & server From 94008b61464b1622a867b5388018850766dd1fae Mon Sep 17 00:00:00 2001 From: apoorvsadana <95699312+apoorvsadana@users.noreply.github.com> Date: Tue, 8 Oct 2024 01:53:24 +0530 Subject: [PATCH 3/4] remove println --- crates/tests/src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/crates/tests/src/lib.rs b/crates/tests/src/lib.rs index cfd962e98..0e63776c6 100644 --- a/crates/tests/src/lib.rs +++ b/crates/tests/src/lib.rs @@ -78,8 +78,6 @@ impl MadaraCmd { || async { match rpc.block_hash_and_number().await { Ok(got) => { - println!("got block_n {}", got.block_number); - println!("expected block_n {}", block_n); if got.block_number < block_n { bail!("got block_n {}, expected {block_n}", got.block_number); } From e7f014896fc8a223f2237ed7b4bf57eea60c89fa Mon Sep 17 00:00:00 2001 From: apoorvsadana <95699312+apoorvsadana@users.noreply.github.com> Date: Tue, 8 Oct 2024 20:33:01 +0530 Subject: [PATCH 4/4] broken rpcs should return with correct id --- crates/node/src/service/rpc/middleware.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/crates/node/src/service/rpc/middleware.rs b/crates/node/src/service/rpc/middleware.rs index 695fa9325..68e8fc876 100644 --- a/crates/node/src/service/rpc/middleware.rs +++ b/crates/node/src/service/rpc/middleware.rs @@ -170,8 +170,6 @@ enum VersionMiddlewareError { BodyReadError(#[from] hyper::Error), #[error("Failed to parse JSON: {0}")] JsonParseError(#[from] serde_json::Error), - #[error("Invalid request format")] - InvalidRequestFormat, #[error("Invalid URL format")] InvalidUrlFormat, #[error("Invalid version specified")] @@ -248,7 +246,7 @@ where let body = json!({ "jsonrpc": "2.0", "error": error, - "id": 0 + "id": null }) .to_string(); @@ -284,9 +282,8 @@ async fn add_rpc_version_to_method(req: &mut hyper::Request) -> Result<(), format!("starknet_{}_{}", version.name(), method.strip_prefix("starknet_").unwrap_or(method)); item["method"] = Value::String(new_method); - } else { - return Err(VersionMiddlewareError::InvalidRequestFormat); } + // we don't need to throw an error here, the request will be rejected later if the method is not supported } let response = if batched_request { serde_json::to_vec(&items)? } else { serde_json::to_vec(&items[0])? };