diff --git a/Cargo.lock b/Cargo.lock index 59e590d8db..b9fa7bdbbf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6919,6 +6919,7 @@ dependencies = [ name = "katana-provider" version = "0.7.0-alpha.2" dependencies = [ + "alloy-primitives", "anyhow", "auto_impl", "futures", diff --git a/crates/katana/storage/provider/Cargo.toml b/crates/katana/storage/provider/Cargo.toml index 8d644db79e..b9c0379152 100644 --- a/crates/katana/storage/provider/Cargo.toml +++ b/crates/katana/storage/provider/Cargo.toml @@ -21,12 +21,17 @@ futures = { workspace = true, optional = true } starknet = { workspace = true, optional = true } tokio = { workspace = true, optional = true } +alloy-primitives = { workspace = true, optional = true } +serde_json = { workspace = true, optional = true } + [features] default = [ "fork", "in-memory" ] fork = [ "dep:futures", "dep:starknet", "dep:tokio", "in-memory" ] in-memory = [ ] +test-utils = [ "dep:alloy-primitives", "dep:serde_json" ] [dev-dependencies] +alloy-primitives.workspace = true katana-core.workspace = true katana-runner.workspace = true lazy_static.workspace = true diff --git a/crates/katana/storage/provider/src/lib.rs b/crates/katana/storage/provider/src/lib.rs index 667ff1b0e9..5b247c70da 100644 --- a/crates/katana/storage/provider/src/lib.rs +++ b/crates/katana/storage/provider/src/lib.rs @@ -23,6 +23,9 @@ pub mod error; pub mod providers; pub mod traits; +#[cfg(any(test, feature = "test-utils"))] +pub mod test_utils; + use crate::traits::block::{BlockHashProvider, BlockNumberProvider, BlockProvider, HeaderProvider}; use crate::traits::state::{StateFactoryProvider, StateProvider}; use crate::traits::state_update::StateUpdateProvider; diff --git a/crates/katana/storage/provider/src/test_utils.rs b/crates/katana/storage/provider/src/test_utils.rs new file mode 100644 index 0000000000..151ad7a560 --- /dev/null +++ b/crates/katana/storage/provider/src/test_utils.rs @@ -0,0 +1,76 @@ +use std::sync::Arc; + +use alloy_primitives::U256; +use katana_db::mdbx::{test_utils, DbEnvKind}; +use katana_primitives::block::{BlockHash, FinalityStatus}; +use katana_primitives::class::CompiledClass; +use katana_primitives::contract::ContractAddress; +use katana_primitives::genesis::allocation::{ + DevGenesisAccount, GenesisAccountAlloc, GenesisAllocation, +}; +use katana_primitives::genesis::{Genesis, GenesisClass}; +use katana_primitives::utils::class::parse_compiled_class_v1; +use starknet::macros::felt; + +use crate::providers::db::DbProvider; +use crate::providers::in_memory::InMemoryProvider; +use crate::traits::block::BlockWriter; + +/// Creates an in-memory provider with initial states loaded for testing. +pub fn test_in_memory_provider() -> InMemoryProvider { + let provider = InMemoryProvider::new(); + initialize_test_provider(&provider); + provider +} + +/// Creates a persistent storage provider with initial states loaded for testin. +pub fn test_db_provider() -> DbProvider { + let provider = DbProvider::new(test_utils::create_test_db(DbEnvKind::RW)); + initialize_test_provider(&provider); + provider +} + +/// Initializes the provider with a genesis block and states. +fn initialize_test_provider(provider: &P) { + let genesis = create_genesis_for_testing(); + + let hash = BlockHash::ZERO; + let status = FinalityStatus::AcceptedOnL2; + let block = genesis.block().seal_with_hash_and_status(hash, status); + let states = genesis.state_updates(); + + provider + .insert_block_with_states_and_receipts(block, states, Vec::new(), Vec::new()) + .expect("Failed to initialize test provider with genesis block and states."); +} + +/// Creates a genesis config specifically for testing purposes. +/// This includes: +/// - An account with simple `__execute__` function, deployed at address `0x1`. +pub fn create_genesis_for_testing() -> Genesis { + let class_hash = felt!("0x111"); + let address = ContractAddress::from(felt!("0x1")); + + // TODO: we should have a genesis builder that can do all of this for us. + let class = { + let json = include_str!("../test-data/simple_account.sierra.json"); + let json = serde_json::from_str(json).unwrap(); + let sierra = parse_compiled_class_v1(json).unwrap(); + + GenesisClass { + sierra: None, + compiled_class_hash: class_hash, + casm: Arc::new(CompiledClass::Class(sierra)), + } + }; + + // setup test account + let (_, account) = DevGenesisAccount::new_with_balance(felt!("0x1"), class_hash, U256::MAX); + let account = GenesisAllocation::Account(GenesisAccountAlloc::DevAccount(account)); + + let mut genesis = Genesis::default(); + // insert test account class and contract + genesis.classes.insert(class_hash, class); + genesis.extend_allocations([(address, account)]); + genesis +} diff --git a/crates/katana/storage/provider/test-data/simple_account.sierra.json b/crates/katana/storage/provider/test-data/simple_account.sierra.json new file mode 120000 index 0000000000..e85326c2b0 --- /dev/null +++ b/crates/katana/storage/provider/test-data/simple_account.sierra.json @@ -0,0 +1 @@ +../../../contracts/compiled/account_with_dummy_validate.sierra.json \ No newline at end of file