Skip to content

Commit

Permalink
test(gateway): test RpcStateReader (#449)
Browse files Browse the repository at this point in the history
  • Loading branch information
yair-starkware authored Jul 14, 2024
1 parent b1804bb commit 26074b1
Show file tree
Hide file tree
Showing 6 changed files with 240 additions and 5 deletions.
26 changes: 26 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ hyper = { version = "0.14", features = ["client", "server", "http1", "http2", "t
indexmap = "2.1.0"
itertools = "0.13.0"
lazy_static = "1.4.0"
mockito = "1.4.0"
num-traits = "0.2"
num-bigint = { version = "0.4.5", default-features = false }
# TODO(YaelD, 28/5/2024): The special Papyrus version is needed in order to be aligned with the
Expand Down
1 change: 1 addition & 0 deletions crates/gateway/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ validator.workspace = true

[dev-dependencies]
assert_matches.workspace = true
mockito.workspace = true
num-bigint.workspace = true
pretty_assertions.workspace = true
rstest.workspace = true
Expand Down
2 changes: 2 additions & 0 deletions crates/gateway/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ pub mod errors;
pub mod gateway;
mod rpc_objects;
mod rpc_state_reader;
#[cfg(test)]
mod rpc_state_reader_test;
mod state_reader;
#[cfg(test)]
mod state_reader_test_utils;
Expand Down
10 changes: 5 additions & 5 deletions crates/gateway/src/rpc_objects.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,13 @@ pub struct GetBlockWithTxHashesParams {
pub block_id: BlockId,
}

#[derive(Debug, Deserialize, Serialize)]
#[derive(Debug, Default, Deserialize, Serialize)]
pub struct ResourcePrice {
pub price_in_wei: GasPrice,
pub price_in_fri: GasPrice,
}

#[derive(Debug, Deserialize, Serialize)]
#[derive(Debug, Default, Deserialize, Serialize)]
pub struct BlockHeader {
pub block_hash: BlockHash,
pub parent_hash: BlockHash,
Expand Down Expand Up @@ -107,20 +107,20 @@ pub enum RpcResponse {
Error(RpcErrorResponse),
}

#[derive(Serialize, Deserialize, Debug)]
#[derive(Serialize, Deserialize, Debug, Default)]
pub struct RpcSuccessResponse {
pub jsonrpc: Option<String>,
pub result: Value,
pub id: u32,
}

#[derive(Serialize, Deserialize, Debug)]
#[derive(Serialize, Deserialize, Debug, Default)]
pub struct RpcErrorResponse {
pub jsonrpc: Option<String>,
pub error: RpcSpecError,
}

#[derive(Serialize, Deserialize, Debug)]
#[derive(Serialize, Deserialize, Debug, Default)]
pub struct RpcSpecError {
pub code: u16,
pub message: String,
Expand Down
205 changes: 205 additions & 0 deletions crates/gateway/src/rpc_state_reader_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
use blockifier::execution::contract_class::ContractClass;
use blockifier::state::state_api::StateReader;
use cairo_lang_starknet_classes::casm_contract_class::CasmContractClass;
use papyrus_rpc::CompiledContractClass;
use serde::Serialize;
use serde_json::json;
use starknet_api::block::{BlockNumber, GasPrice};
use starknet_api::core::{ClassHash, ContractAddress, Nonce, PatriciaKey};
use starknet_api::{class_hash, contract_address, felt, patricia_key};

use crate::config::RpcStateReaderConfig;
use crate::rpc_objects::{
BlockHeader, BlockId, GetBlockWithTxHashesParams, GetClassHashAtParams,
GetCompiledContractClassParams, GetNonceParams, GetStorageAtParams, ResourcePrice, RpcResponse,
RpcSuccessResponse,
};
use crate::rpc_state_reader::RpcStateReader;
use crate::state_reader::MempoolStateReader;

async fn run_rpc_server() -> mockito::ServerGuard {
mockito::Server::new_async().await
}

fn mock_rpc_interaction(
server: &mut mockito::ServerGuard,
json_rpc_version: &str,
method: &str,
params: impl Serialize,
expected_response: &RpcResponse,
) -> mockito::Mock {
let request_body = json!({
"jsonrpc": json_rpc_version,
"id": 0,
"method": method,
"params": json!(params),
});
server
.mock("POST", "/")
.match_header("Content-Type", "application/json")
.match_body(mockito::Matcher::Json(request_body))
.with_status(201)
.with_body(serde_json::to_string(expected_response).unwrap())
.create()
}

#[tokio::test]
async fn test_get_block_info() {
let mut server = run_rpc_server().await;
let config = RpcStateReaderConfig { url: server.url(), ..Default::default() };

let expected_result = BlockNumber(100);

let mock = mock_rpc_interaction(
&mut server,
&config.json_rpc_version,
"starknet_getBlockWithTxHashes",
GetBlockWithTxHashesParams { block_id: BlockId::Latest },
&RpcResponse::Success(RpcSuccessResponse {
result: serde_json::to_value(BlockHeader {
block_number: expected_result,
// GasPrice must be non-zero.
l1_gas_price: ResourcePrice {
price_in_wei: GasPrice(1),
price_in_fri: GasPrice(1),
},
l1_data_gas_price: ResourcePrice {
price_in_wei: GasPrice(1),
price_in_fri: GasPrice(1),
},
..Default::default()
})
.unwrap(),
..Default::default()
}),
);

let client = RpcStateReader::from_latest(&config);
let result =
tokio::task::spawn_blocking(move || client.get_block_info()).await.unwrap().unwrap();
// TODO(yair): Add partial_eq for BlockInfo and assert_eq the whole BlockInfo.
assert_eq!(result.block_number, expected_result);
mock.assert_async().await;
}

#[tokio::test]
async fn test_get_storage_at() {
let mut server = run_rpc_server().await;
let config = RpcStateReaderConfig { url: server.url(), ..Default::default() };

let expected_result = felt!("0x999");

let mock = mock_rpc_interaction(
&mut server,
&config.json_rpc_version,
"starknet_getStorageAt",
GetStorageAtParams {
block_id: BlockId::Latest,
contract_address: contract_address!("0x1"),
key: starknet_api::state::StorageKey::from(0u32),
},
&RpcResponse::Success(RpcSuccessResponse {
result: serde_json::to_value(expected_result).unwrap(),
..Default::default()
}),
);

let client = RpcStateReader::from_latest(&config);
let result = tokio::task::spawn_blocking(move || {
client.get_storage_at(contract_address!("0x1"), starknet_api::state::StorageKey::from(0u32))
})
.await
.unwrap()
.unwrap();
assert_eq!(result, expected_result);
mock.assert_async().await;
}

#[tokio::test]
async fn test_get_nonce_at() {
let mut server = run_rpc_server().await;
let config = RpcStateReaderConfig { url: server.url(), ..Default::default() };

let expected_result = Nonce(felt!("0x999"));

let mock = mock_rpc_interaction(
&mut server,
&config.json_rpc_version,
"starknet_getNonce",
GetNonceParams { block_id: BlockId::Latest, contract_address: contract_address!("0x1") },
&RpcResponse::Success(RpcSuccessResponse {
result: serde_json::to_value(expected_result).unwrap(),
..Default::default()
}),
);

let client = RpcStateReader::from_latest(&config);
let result = tokio::task::spawn_blocking(move || client.get_nonce_at(contract_address!("0x1")))
.await
.unwrap()
.unwrap();
assert_eq!(result, expected_result);
mock.assert_async().await;
}

#[tokio::test]
async fn test_get_compiled_contract_class() {
let mut server = run_rpc_server().await;
let config = RpcStateReaderConfig { url: server.url(), ..Default::default() };

let expected_result = CasmContractClass::default();

let mock = mock_rpc_interaction(
&mut server,
&config.json_rpc_version,
"starknet_getCompiledContractClass",
GetCompiledContractClassParams {
block_id: BlockId::Latest,
class_hash: class_hash!("0x1"),
},
&RpcResponse::Success(RpcSuccessResponse {
result: serde_json::to_value(CompiledContractClass::V1(expected_result)).unwrap(),
..Default::default()
}),
);

let client = RpcStateReader::from_latest(&config);
let result =
tokio::task::spawn_blocking(move || client.get_compiled_contract_class(class_hash!("0x1")))
.await
.unwrap()
.unwrap();
assert_eq!(result, ContractClass::V1(CasmContractClass::default().try_into().unwrap()));
mock.assert_async().await;
}

#[tokio::test]
async fn test_get_class_hash_at() {
let mut server = run_rpc_server().await;
let config = RpcStateReaderConfig { url: server.url(), ..Default::default() };

let expected_result = class_hash!("0x999");

let mock = mock_rpc_interaction(
&mut server,
&config.json_rpc_version,
"starknet_getClassHashAt",
GetClassHashAtParams {
block_id: BlockId::Latest,
contract_address: contract_address!("0x1"),
},
&RpcResponse::Success(RpcSuccessResponse {
result: serde_json::to_value(expected_result).unwrap(),
..Default::default()
}),
);

let client = RpcStateReader::from_latest(&config);
let result =
tokio::task::spawn_blocking(move || client.get_class_hash_at(contract_address!("0x1")))
.await
.unwrap()
.unwrap();
assert_eq!(result, expected_result);
mock.assert_async().await;
}

0 comments on commit 26074b1

Please sign in to comment.