Skip to content

Commit 2a89a72

Browse files
committed
wip
1 parent 4c6b127 commit 2a89a72

File tree

5 files changed

+99
-106
lines changed

5 files changed

+99
-106
lines changed

crates/grpc/tests/starknet.rs

Lines changed: 46 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,3 @@
1-
//! Integration tests for the Starknet gRPC server.
2-
//!
3-
//! All tests share a single TestNode instance that is created and migrated
4-
//! once. Each test creates its own gRPC and JSON-RPC clients to the shared
5-
//! node, then compares results from both endpoints.
6-
//!
7-
//! Requirements:
8-
//! - `git`, `asdf`, `scarb`, and `sozo` must be installed and properly configured
9-
//! - Run with `cargo nextest run -p katana-grpc --features grpc`
10-
11-
use std::net::SocketAddr;
12-
use std::sync::OnceLock;
13-
141
use katana_grpc::proto::{
152
BlockHashAndNumberRequest, BlockNumberRequest, BlockTag, ChainIdRequest, GetBlockRequest,
163
GetClassAtRequest, GetClassHashAtRequest, GetEventsRequest, GetNonceRequest,
@@ -25,65 +12,25 @@ use starknet::providers::jsonrpc::HttpTransport;
2512
use starknet::providers::{JsonRpcClient, Provider, Url};
2613
use tonic::Request;
2714

28-
/// Shared test context initialized once for all tests.
29-
struct TestContext {
30-
/// Keeps the tokio runtime (and thus the node) alive for the test suite.
31-
_runtime: tokio::runtime::Runtime,
32-
grpc_addr: SocketAddr,
33-
rpc_addr: SocketAddr,
34-
genesis_address: Felt,
35-
chain_id: Felt,
36-
}
37-
38-
static TEST_CTX: OnceLock<TestContext> = OnceLock::new();
39-
40-
fn test_context() -> &'static TestContext {
41-
TEST_CTX.get_or_init(|| {
42-
// Spawn initialization on a separate thread to avoid "cannot start a
43-
// runtime from within a runtime" when called from #[tokio::test].
44-
std::thread::spawn(|| {
45-
let runtime = tokio::runtime::Builder::new_multi_thread().enable_all().build().unwrap();
46-
47-
let (grpc_addr, rpc_addr, genesis_address, chain_id) = runtime.block_on(async {
48-
let node = TestNode::new().await;
49-
node.migrate_spawn_and_move().await.expect("migration failed");
50-
51-
let grpc_addr = *node.grpc_addr().expect("grpc not enabled");
52-
let rpc_addr = *node.rpc_addr();
53-
let (address, _) = node
54-
.backend()
55-
.chain_spec
56-
.genesis()
57-
.accounts()
58-
.next()
59-
.expect("must have genesis account");
60-
let genesis_address: Felt = (*address).into();
61-
let chain_id = node.backend().chain_spec.id().id();
62-
63-
// Leak the node so the servers stay alive for the entire test suite.
64-
std::mem::forget(node);
65-
66-
(grpc_addr, rpc_addr, genesis_address, chain_id)
67-
});
68-
69-
TestContext { _runtime: runtime, grpc_addr, rpc_addr, genesis_address, chain_id }
70-
})
71-
.join()
72-
.expect("test context initialization thread panicked")
73-
})
74-
}
15+
async fn setup() -> (TestNode, GrpcClient, JsonRpcClient<HttpTransport>) {
16+
let node = TestNode::new_with_spawn_and_move_db().await;
7517

76-
async fn setup() -> (GrpcClient, JsonRpcClient<HttpTransport>) {
77-
let ctx = test_context();
78-
79-
let grpc = GrpcClient::connect(format!("http://{}", ctx.grpc_addr))
18+
let grpc_addr = *node.grpc_addr().expect("grpc not enabled");
19+
let grpc = GrpcClient::connect(format!("http://{grpc_addr}"))
8020
.await
8121
.expect("failed to connect to gRPC server");
8222

83-
let url = Url::parse(&format!("http://{}", ctx.rpc_addr)).expect("failed to parse url");
23+
let rpc_addr = *node.rpc_addr();
24+
let url = Url::parse(&format!("http://{rpc_addr}")).expect("failed to parse url");
8425
let rpc = JsonRpcClient::new(HttpTransport::new(url));
8526

86-
(grpc, rpc)
27+
(node, grpc, rpc)
28+
}
29+
30+
fn genesis_address(node: &TestNode) -> Felt {
31+
let (address, _) =
32+
node.backend().chain_spec.genesis().accounts().next().expect("must have genesis account");
33+
(*address).into()
8734
}
8835

8936
fn felt_to_proto(felt: Felt) -> katana_grpc::proto::Felt {
@@ -108,8 +55,9 @@ fn grpc_block_id_latest() -> Option<katana_grpc::proto::BlockId> {
10855

10956
#[tokio::test]
11057
async fn test_chain_id() {
111-
let (mut grpc, rpc) = setup().await;
112-
let ctx = test_context();
58+
let (node, mut grpc, rpc) = setup().await;
59+
60+
let chain_id = node.backend().chain_spec.id().id();
11361

11462
let rpc_chain_id = rpc.chain_id().await.expect("rpc chain_id failed");
11563

@@ -120,13 +68,13 @@ async fn test_chain_id() {
12068
.into_inner()
12169
.chain_id;
12270

123-
assert_eq!(rpc_chain_id, ctx.chain_id);
124-
assert_eq!(grpc_chain_id, format!("{:#x}", ctx.chain_id));
71+
assert_eq!(rpc_chain_id, chain_id);
72+
assert_eq!(grpc_chain_id, format!("{:#x}", chain_id));
12573
}
12674

12775
#[tokio::test]
12876
async fn test_block_number() {
129-
let (mut grpc, rpc) = setup().await;
77+
let (_node, mut grpc, rpc) = setup().await;
13078

13179
let rpc_block_number = rpc.block_number().await.expect("rpc block_number failed");
13280

@@ -143,7 +91,7 @@ async fn test_block_number() {
14391

14492
#[tokio::test]
14593
async fn test_block_hash_and_number() {
146-
let (mut grpc, rpc) = setup().await;
94+
let (_node, mut grpc, rpc) = setup().await;
14795

14896
let rpc_result = rpc.block_hash_and_number().await.expect("rpc block_hash_and_number failed");
14997

@@ -160,7 +108,7 @@ async fn test_block_hash_and_number() {
160108

161109
#[tokio::test]
162110
async fn test_get_block_with_txs() {
163-
let (mut grpc, rpc) = setup().await;
111+
let (_node, mut grpc, rpc) = setup().await;
164112

165113
let rpc_block = rpc.get_block_with_txs(BlockId::Number(0)).await.expect("rpc failed");
166114

@@ -191,7 +139,7 @@ async fn test_get_block_with_txs() {
191139

192140
#[tokio::test]
193141
async fn test_get_block_with_tx_hashes() {
194-
let (mut grpc, rpc) = setup().await;
142+
let (_node, mut grpc, rpc) = setup().await;
195143

196144
let rpc_block = rpc.get_block_with_tx_hashes(BlockId::Number(0)).await.expect("rpc failed");
197145

@@ -230,7 +178,7 @@ async fn test_get_block_with_tx_hashes() {
230178

231179
#[tokio::test]
232180
async fn test_get_block_with_txs_latest() {
233-
let (mut grpc, rpc) = setup().await;
181+
let (_node, mut grpc, rpc) = setup().await;
234182

235183
let rpc_block =
236184
rpc.get_block_with_txs(BlockId::Tag(StarknetBlockTag::Latest)).await.expect("rpc failed");
@@ -258,18 +206,18 @@ async fn test_get_block_with_txs_latest() {
258206

259207
#[tokio::test]
260208
async fn test_get_class_at() {
261-
let (mut grpc, rpc) = setup().await;
262-
let ctx = test_context();
209+
let (node, mut grpc, rpc) = setup().await;
210+
let address = genesis_address(&node);
263211

264212
let rpc_class = rpc
265-
.get_class_at(BlockId::Tag(StarknetBlockTag::Latest), ctx.genesis_address)
213+
.get_class_at(BlockId::Tag(StarknetBlockTag::Latest), address)
266214
.await
267215
.expect("rpc get_class_at failed");
268216

269217
let grpc_result = grpc
270218
.get_class_at(Request::new(GetClassAtRequest {
271219
block_id: grpc_block_id_latest(),
272-
contract_address: Some(felt_to_proto(ctx.genesis_address)),
220+
contract_address: Some(felt_to_proto(address)),
273221
}))
274222
.await
275223
.expect("grpc get_class_at failed")
@@ -291,18 +239,18 @@ async fn test_get_class_at() {
291239

292240
#[tokio::test]
293241
async fn test_get_class_hash_at() {
294-
let (mut grpc, rpc) = setup().await;
295-
let ctx = test_context();
242+
let (node, mut grpc, rpc) = setup().await;
243+
let address = genesis_address(&node);
296244

297245
let rpc_class_hash = rpc
298-
.get_class_hash_at(BlockId::Tag(StarknetBlockTag::Latest), ctx.genesis_address)
246+
.get_class_hash_at(BlockId::Tag(StarknetBlockTag::Latest), address)
299247
.await
300248
.expect("rpc get_class_hash_at failed");
301249

302250
let grpc_result = grpc
303251
.get_class_hash_at(Request::new(GetClassHashAtRequest {
304252
block_id: grpc_block_id_latest(),
305-
contract_address: Some(felt_to_proto(ctx.genesis_address)),
253+
contract_address: Some(felt_to_proto(address)),
306254
}))
307255
.await
308256
.expect("grpc get_class_hash_at failed")
@@ -314,18 +262,18 @@ async fn test_get_class_hash_at() {
314262

315263
#[tokio::test]
316264
async fn test_get_storage_at() {
317-
let (mut grpc, rpc) = setup().await;
318-
let ctx = test_context();
265+
let (node, mut grpc, rpc) = setup().await;
266+
let address = genesis_address(&node);
319267

320268
let rpc_value = rpc
321-
.get_storage_at(ctx.genesis_address, Felt::ZERO, BlockId::Tag(StarknetBlockTag::Latest))
269+
.get_storage_at(address, Felt::ZERO, BlockId::Tag(StarknetBlockTag::Latest))
322270
.await
323271
.expect("rpc get_storage_at failed");
324272

325273
let grpc_result = grpc
326274
.get_storage_at(Request::new(GetStorageAtRequest {
327275
block_id: grpc_block_id_latest(),
328-
contract_address: Some(felt_to_proto(ctx.genesis_address)),
276+
contract_address: Some(felt_to_proto(address)),
329277
key: Some(felt_to_proto(Felt::ZERO)),
330278
}))
331279
.await
@@ -338,18 +286,18 @@ async fn test_get_storage_at() {
338286

339287
#[tokio::test]
340288
async fn test_get_nonce() {
341-
let (mut grpc, rpc) = setup().await;
342-
let ctx = test_context();
289+
let (node, mut grpc, rpc) = setup().await;
290+
let address = genesis_address(&node);
343291

344292
let rpc_nonce = rpc
345-
.get_nonce(BlockId::Tag(StarknetBlockTag::Latest), ctx.genesis_address)
293+
.get_nonce(BlockId::Tag(StarknetBlockTag::Latest), address)
346294
.await
347295
.expect("rpc get_nonce failed");
348296

349297
let grpc_result = grpc
350298
.get_nonce(Request::new(GetNonceRequest {
351299
block_id: grpc_block_id_latest(),
352-
contract_address: Some(felt_to_proto(ctx.genesis_address)),
300+
contract_address: Some(felt_to_proto(address)),
353301
}))
354302
.await
355303
.expect("grpc get_nonce failed")
@@ -362,7 +310,7 @@ async fn test_get_nonce() {
362310

363311
#[tokio::test]
364312
async fn test_spec_version() {
365-
let (mut grpc, rpc) = setup().await;
313+
let (_node, mut grpc, rpc) = setup().await;
366314

367315
let rpc_version = rpc.spec_version().await.expect("rpc spec_version failed");
368316

@@ -378,7 +326,7 @@ async fn test_spec_version() {
378326

379327
#[tokio::test]
380328
async fn test_syncing() {
381-
let (mut grpc, rpc) = setup().await;
329+
let (_node, mut grpc, rpc) = setup().await;
382330

383331
let rpc_syncing = rpc.syncing().await.expect("rpc syncing failed");
384332

@@ -403,7 +351,7 @@ async fn test_syncing() {
403351

404352
#[tokio::test]
405353
async fn test_get_block_transaction_count() {
406-
let (mut grpc, rpc) = setup().await;
354+
let (_node, mut grpc, rpc) = setup().await;
407355

408356
let rpc_count = rpc
409357
.get_block_transaction_count(BlockId::Number(0))
@@ -424,7 +372,7 @@ async fn test_get_block_transaction_count() {
424372

425373
#[tokio::test]
426374
async fn test_get_state_update() {
427-
let (mut grpc, rpc) = setup().await;
375+
let (_node, mut grpc, rpc) = setup().await;
428376

429377
let rpc_state =
430378
rpc.get_state_update(BlockId::Number(0)).await.expect("rpc get_state_update failed");
@@ -461,7 +409,7 @@ async fn test_get_state_update() {
461409

462410
#[tokio::test]
463411
async fn test_get_events() {
464-
let (mut grpc, rpc) = setup().await;
412+
let (_node, mut grpc, rpc) = setup().await;
465413

466414
let rpc_events = rpc
467415
.get_events(
@@ -512,7 +460,7 @@ async fn test_get_events() {
512460

513461
#[tokio::test]
514462
async fn test_get_transaction_by_hash() {
515-
let (mut grpc, rpc) = setup().await;
463+
let (_node, mut grpc, rpc) = setup().await;
516464

517465
// Get a transaction hash from block 1
518466
let rpc_block =
@@ -548,7 +496,7 @@ async fn test_get_transaction_by_hash() {
548496

549497
#[tokio::test]
550498
async fn test_get_transaction_receipt() {
551-
let (mut grpc, rpc) = setup().await;
499+
let (_node, mut grpc, rpc) = setup().await;
552500

553501
// Get a transaction hash from block 1
554502
let rpc_block =

crates/storage/db/src/lib.rs

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,42 @@ impl Db {
100100
let dir = tempfile::Builder::new().disable_cleanup(true).tempdir()?;
101101
let path = dir.path();
102102

103+
let version = if is_database_empty(path) {
104+
fs::create_dir_all(&path).with_context(|| {
105+
format!("Creating database directory at path {}", path.display())
106+
})?;
107+
108+
create_db_version_file(&path, CURRENT_DB_VERSION).with_context(|| {
109+
format!("Inserting database version file at path {}", path.display())
110+
})?
111+
} else {
112+
match get_db_version(&path) {
113+
Ok(version) if version != CURRENT_DB_VERSION => {
114+
if !is_block_compatible_version(&version) {
115+
return Err(anyhow!(DatabaseVersionError::MismatchVersion {
116+
expected: CURRENT_DB_VERSION,
117+
found: version
118+
}));
119+
}
120+
debug!(target: "db", "Using database version {version} with block compatibility mode");
121+
version
122+
}
123+
124+
Ok(version) => version,
125+
126+
Err(DatabaseVersionError::FileNotFound) => {
127+
create_db_version_file(&path, CURRENT_DB_VERSION).with_context(|| {
128+
format!(
129+
"No database version file found. Inserting version file at path {}",
130+
path.display()
131+
)
132+
})?
133+
}
134+
135+
Err(err) => return Err(anyhow!(err)),
136+
}
137+
};
138+
103139
let env = mdbx::DbEnvBuilder::new()
104140
.max_size(GIGABYTE * 10) // 10gb
105141
.growth_step((GIGABYTE / 2) as isize) // 512mb
@@ -108,7 +144,7 @@ impl Db {
108144

109145
env.create_default_tables()?;
110146

111-
Ok(Self { env, version: CURRENT_DB_VERSION })
147+
Ok(Self { env, version })
112148
}
113149

114150
/// Opens an existing database at the given `path` with [`SyncMode::UtterlyNoSync`] for

0 commit comments

Comments
 (0)