Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions crates/starknet_committer/src/block_committer.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
pub mod commit;
#[cfg(test)]
pub mod commit_test;
pub mod errors;
pub mod input;
#[cfg(any(feature = "testing", test))]
Expand Down
180 changes: 180 additions & 0 deletions crates/starknet_committer/src/block_committer/commit_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
use std::collections::HashMap;
use std::sync::LazyLock;

use rand::rngs::SmallRng;
use rand::SeedableRng;
use rstest::rstest;
use rstest_reuse::{apply, template};
use starknet_api::core::{ClassHash, ContractAddress};
use starknet_api::hash::{HashOutput, StateRoots};
use starknet_patricia_storage::map_storage::MapStorage;
use starknet_types_core::felt::Felt;

use crate::block_committer::commit::{CommitBlockImpl, CommitBlockTrait};
use crate::block_committer::input::{
Input,
InputContext,
ReaderConfig,
StarknetStorageKey,
StarknetStorageValue,
StateDiff,
};
use crate::block_committer::state_diff_generator::generate_random_state_diff;
use crate::db::facts_db::db::FactsDb;
use crate::db::facts_db::types::FactsDbInitialRead;
use crate::db::forest_trait::{ForestReader, ForestWriter};
use crate::db::index_db::db::IndexDb;
use crate::patricia_merkle_tree::types::CompiledClassHash;

static FIRST_CONTRACT_ADDRESS: LazyLock<ContractAddress> =
LazyLock::new(|| ContractAddress::from(1_u128));
static SECOND_CONTRACT_ADDRESS: LazyLock<ContractAddress> =
LazyLock::new(|| ContractAddress::from(1_u128 << 100));

const EXPECTED_ROOTS_SIMPLE_CASE: StateRoots = StateRoots {
contracts_trie_root_hash: HashOutput(Felt::from_hex_unchecked(
"0x1dfab71737a9b4528835c11c3cef25d2587ef8afe5098d3b21f2ea77e944500",
)),
classes_trie_root_hash: HashOutput(Felt::from_hex_unchecked(
"0x7ae8007b033a1c032c6a791331f56a652833b0b25633587318276f4462c8c1c",
)),
};

const EXPECTED_ROOTS_RANDOM_CASE: StateRoots = StateRoots {
contracts_trie_root_hash: HashOutput(Felt::from_hex_unchecked(
"0x2877d3a2370c501255c8451f615f4f2aa900f6acf2f0cd36b735b1108a4a0e4",
)),
classes_trie_root_hash: HashOutput(Felt::from_hex_unchecked("0x0")),
};

const N_RANDOM_STATE_UPDATES: usize = 200;

#[template]
#[rstest]
#[case([get_first_state_diff(), get_second_state_diff()], EXPECTED_ROOTS_SIMPLE_CASE)]
#[case(get_random_state_diffs(), EXPECTED_ROOTS_RANDOM_CASE)]
fn state_diff_cases(#[case] state_diffs: [StateDiff; 2], #[case] expected_roots: StateRoots) {}

#[apply(state_diff_cases)]
#[tokio::test]
#[rstest]
async fn test_commit_two_consecutive_blocks_facts_layout(
#[case] state_diffs: [StateDiff; 2],
#[case] expected_roots: StateRoots,
) {
test_commit_two_consecutive_blocks::<FactsDbInitialRead, FactsDb<MapStorage>>(
|storage| FactsDb::new(storage),
FactsDbInitialRead::default(),
state_diffs,
expected_roots,
)
.await;
}

#[apply(state_diff_cases)]
#[tokio::test]
#[rstest]
async fn test_commit_two_consecutive_blocks_index_layout(
#[case] state_diffs: [StateDiff; 2],
#[case] expected_roots: StateRoots,
) {
test_commit_two_consecutive_blocks::<FactsDbInitialRead, IndexDb<MapStorage>>(
|storage| IndexDb::new(storage),
FactsDbInitialRead::default(),
state_diffs,
expected_roots,
)
.await;
}

async fn test_commit_two_consecutive_blocks<
ReaderInputContext: InputContext + Clone + Send,
Db: ForestReader<ReaderInputContext> + ForestWriter,
>(
db_generator: impl FnOnce(MapStorage) -> Db,
initial_read_context: ReaderInputContext,
state_diffs: [StateDiff; 2],
expected_roots: StateRoots,
) {
let [first_state_diff, second_state_diff] = state_diffs;

let storage = MapStorage::default();
let mut db = db_generator(storage);

let mut input = Input {
state_diff: first_state_diff,
initial_read_context: initial_read_context.clone(),
config: ReaderConfig::default(),
};
let filled_forest = CommitBlockImpl::commit_block(input, &mut db, None).await.unwrap();
db.write(&filled_forest).await.unwrap();

input = Input {
state_diff: second_state_diff,
initial_read_context,
config: ReaderConfig::default(),
};

let filled_forest = CommitBlockImpl::commit_block(input, &mut db, None).await.unwrap();
db.write(&filled_forest).await.unwrap();

assert_eq!(filled_forest.state_roots(), expected_roots);
}

fn get_first_state_diff() -> StateDiff {
let mut contract_class_changes = HashMap::new();
contract_class_changes.insert(*FIRST_CONTRACT_ADDRESS, ClassHash(Felt::ONE));
contract_class_changes.insert(*SECOND_CONTRACT_ADDRESS, ClassHash(Felt::TWO));

let mut individual_storage_changes = HashMap::new();
individual_storage_changes
.insert(StarknetStorageKey::from(1_u128), StarknetStorageValue(Felt::from(1_u128)));
individual_storage_changes
.insert(StarknetStorageKey::from(2_u128), StarknetStorageValue(Felt::from(2_u128)));

let mut storage_updates = HashMap::new();
storage_updates.insert(*FIRST_CONTRACT_ADDRESS, individual_storage_changes.clone());
storage_updates.insert(*SECOND_CONTRACT_ADDRESS, individual_storage_changes);

StateDiff {
address_to_class_hash: contract_class_changes,
address_to_nonce: HashMap::new(),
class_hash_to_compiled_class_hash: HashMap::new(),
storage_updates,
}
}

fn get_second_state_diff() -> StateDiff {
let mut contract_class_changes = HashMap::new();
contract_class_changes.insert(*FIRST_CONTRACT_ADDRESS, ClassHash(Felt::TWO));

let mut individual_storage_changes = HashMap::new();
individual_storage_changes
.insert(StarknetStorageKey::from(1_u128), StarknetStorageValue(Felt::from(2_u128)));
individual_storage_changes
.insert(StarknetStorageKey::from(2_u128), StarknetStorageValue(Felt::from(4_u128)));

let mut storage_updates = HashMap::new();
storage_updates.insert(*SECOND_CONTRACT_ADDRESS, individual_storage_changes);

let mut declarations = HashMap::new();
declarations.insert(ClassHash(Felt::THREE), CompiledClassHash(Felt::THREE));

StateDiff {
address_to_class_hash: contract_class_changes,
address_to_nonce: HashMap::new(),
class_hash_to_compiled_class_hash: declarations,
storage_updates,
}
}

fn get_random_state_diffs() -> [StateDiff; 2] {
// Use a constant seed for reproducibility.
let mut seed = 42_u64;
let mut rng = SmallRng::seed_from_u64(seed);
let first_state_diff = generate_random_state_diff(&mut rng, N_RANDOM_STATE_UPDATES, None);
seed += 1;
rng = SmallRng::seed_from_u64(seed);
let second_state_diff = generate_random_state_diff(&mut rng, N_RANDOM_STATE_UPDATES, None);
[first_state_diff, second_state_diff]
}
11 changes: 10 additions & 1 deletion crates/starknet_committer/src/db/facts_db/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,16 @@ impl<'a> SubTreeTrait<'a> for FactsSubTree<'a> {
}
}
/// Used for reading the roots in facts layout case.
#[derive(Debug, PartialEq)]
#[derive(Clone, Debug, PartialEq)]
pub struct FactsDbInitialRead(pub StateRoots);

impl Default for FactsDbInitialRead {
fn default() -> Self {
Self(StateRoots {
contracts_trie_root_hash: HashOutput::ROOT_OF_EMPTY_TREE,
classes_trie_root_hash: HashOutput::ROOT_OF_EMPTY_TREE,
})
}
}

impl InputContext for FactsDbInitialRead {}
Loading