Skip to content

Commit

Permalink
chore: add deserialization types and basic casting implementation. ne…
Browse files Browse the repository at this point in the history
…ed to add some tests
  • Loading branch information
nimrod-starkware committed Apr 11, 2024
1 parent 6af2975 commit f5e1bbe
Show file tree
Hide file tree
Showing 12 changed files with 308 additions and 3 deletions.
23 changes: 23 additions & 0 deletions Cargo.lock

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

3 changes: 3 additions & 0 deletions Cargo.toml
Expand Up @@ -16,6 +16,9 @@ license-file = "LICENSE"
clap = { version = "4.5.4", features = ["cargo", "derive"] }
derive_more = "0.99.17"
pretty_assertions = "1.2.1"
serde = { version = "1.0.197", features = ["derive"] }
serde_json = "1.0"
thiserror = "1.0.24"
rstest = "0.17.0"
starknet-types-core = { version = "0.0.11", features = ["hash"] }

Expand Down
5 changes: 4 additions & 1 deletion crates/committer/Cargo.toml
Expand Up @@ -14,5 +14,8 @@ pretty_assertions.workspace = true
rstest.workspace = true

[dependencies]
derive_more.workspace = true
serde.workspace = true
serde_json.workspace = true
starknet-types-core.workspace = true
thiserror.workspace = true
derive_more.workspace = true
4 changes: 4 additions & 0 deletions crates/committer/src/deserialization.rs
@@ -0,0 +1,4 @@
pub mod cast;
pub mod errors;
pub mod read;
pub mod types;
123 changes: 123 additions & 0 deletions crates/committer/src/deserialization/cast.rs
@@ -0,0 +1,123 @@
use crate::deserialization::errors::DeserializationError;
use crate::deserialization::types::{ContractAddress, ContractState};
use crate::deserialization::types::{
Input, RawInput, StarknetStorageKey, StarknetStorageValue, StateDiff,
};
use crate::hash::types::HashOutput;
use crate::patricia_merkle_tree::filled_node::{ClassHash, CompiledClassHash, Nonce};
use crate::patricia_merkle_tree::types::TreeHeight;
use crate::storage::storage_trait::{StorageKey, StorageValue};
use crate::types::Felt;

use std::collections::HashMap;

impl TryFrom<RawInput> for Input {
type Error = DeserializationError;
fn try_from(raw_input: RawInput) -> Result<Self, Self::Error> {
let mut storage = HashMap::new();
for entry in raw_input.storage {
add_unique(
&mut storage,
"storage",
StorageKey(entry.key),
StorageValue(entry.value),
)?;
}

let mut address_to_class_hash = HashMap::new();
for entry in raw_input.state_diff.address_to_class_hash {
add_unique(
&mut address_to_class_hash,
"address to class hash",
ContractAddress(Felt::from_bytes_be_slice(&entry.key)),
ClassHash(Felt::from_bytes_be_slice(&entry.value)),
)?;
}

let mut address_to_nonce = HashMap::new();
for entry in raw_input.state_diff.address_to_nonce {
add_unique(
&mut address_to_nonce,
"address to nonce",
ContractAddress(Felt::from_bytes_be_slice(&entry.key)),
Nonce(Felt::from_bytes_be_slice(&entry.value)),
)?;
}

let mut class_hash_to_compiled_class_hash = HashMap::new();
for entry in raw_input.state_diff.class_hash_to_compiled_class_hash {
add_unique(
&mut class_hash_to_compiled_class_hash,
"class hash to compiled class hash",
ClassHash(Felt::from_bytes_be_slice(&entry.key)),
CompiledClassHash(Felt::from_bytes_be_slice(&entry.value)),
)?;
}

let mut current_contract_state_leaves = HashMap::new();
for entry in raw_input.state_diff.current_contract_state_leaves {
add_unique(
&mut current_contract_state_leaves,
"current contract state leaves",
ContractAddress(Felt::from_bytes_be_slice(&entry.address)),
ContractState {
nonce: Nonce(Felt::from_bytes_be_slice(&entry.nonce)),
class_hash: ClassHash(Felt::from_bytes_be_slice(&entry.class_hash)),
storage_root_hash: HashOutput(Felt::from_bytes_be_slice(
&entry.storage_root_hash,
)),
},
)?;
}

let mut storage_updates = HashMap::new();
for outer_entry in raw_input.state_diff.storage_updates {
let inner_map = outer_entry
.storage_updates
.iter()
.map(|inner_entry| {
(
StarknetStorageKey(Felt::from_bytes_be_slice(&inner_entry.key)),
StarknetStorageValue(Felt::from_bytes_be_slice(&inner_entry.value)),
)
})
.collect();
add_unique(
&mut storage_updates,
"starknet storage updates",
ContractAddress(Felt::from_bytes_be_slice(&outer_entry.address)),
inner_map,
)?;
}

Ok(Input {
storage,
state_diff: StateDiff {
address_to_class_hash,
address_to_nonce,
class_hash_to_compiled_class_hash,
current_contract_state_leaves,
storage_updates,
},
tree_height: TreeHeight(raw_input.tree_height),
})
}
}

fn add_unique<K, V>(
map: &mut HashMap<K, V>,
map_name: &str,
key: K,
value: V,
) -> Result<(), DeserializationError>
where
K: std::cmp::Eq + std::hash::Hash + std::fmt::Debug,
{
if map.contains_key(&key) {
return Err(DeserializationError::KeyDuplicate(format!(
"{map_name}: {key:?}"
)));
}
map.insert(key, value);
Ok(())
}
18 changes: 18 additions & 0 deletions crates/committer/src/deserialization/errors.rs
@@ -0,0 +1,18 @@
use std::fmt::Debug;

use thiserror::Error;

#[allow(dead_code)]
#[derive(Debug, Error)]
pub(crate) enum DeserializationError {
#[error("There is a key duplicate at {0} mapping.")]
KeyDuplicate(String),
#[error("Couldn't read and parse the given input JSON.")]
ParsingError,
}

impl From<serde_json::Error> for DeserializationError {
fn from(_: serde_json::Error) -> Self {
DeserializationError::ParsingError
}
}
17 changes: 17 additions & 0 deletions crates/committer/src/deserialization/read.rs
@@ -0,0 +1,17 @@
use crate::deserialization::types::Input;
use crate::deserialization::types::RawInput;

use crate::deserialization::errors::DeserializationError;
#[allow(dead_code)]
type DeserializationResult<T> = Result<T, DeserializationError>;
#[allow(dead_code)]
pub(crate) fn parse_input(input: String) -> DeserializationResult<Input> {
let raw_input: RawInput = serde_json::from_str(&input)?;
raw_input.try_into()
}

#[cfg(test)]
#[allow(dead_code)]
fn test_input_parsing() {
todo!()
}
105 changes: 105 additions & 0 deletions crates/committer/src/deserialization/types.rs
@@ -0,0 +1,105 @@
use crate::hash::types::HashOutput;
use crate::patricia_merkle_tree::filled_node::{ClassHash, CompiledClassHash, Nonce};
use crate::patricia_merkle_tree::types::TreeHeight;
use crate::storage::storage_trait::{StorageKey, StorageValue};
use crate::types::Felt;
use serde::Deserialize;
use std::collections::HashMap;

type RawFelt = [u8; 32];
#[derive(PartialEq, Eq, Hash, Debug)]
// TODO(Nimrod, 1/6/2024): Swap to starknet-types-core types once implemented.
pub(crate) struct ContractAddress(pub Felt);
#[derive(PartialEq, Eq, Hash)]
// TODO(Nimrod, 1/6/2024): Swap to starknet-types-core types once implemented.
pub(crate) struct StarknetStorageKey(pub Felt);
#[allow(dead_code)]
pub(crate) struct StarknetStorageValue(pub Felt);

#[derive(Deserialize, Debug)]
#[allow(dead_code)]
/// Input to the committer.
pub(crate) struct RawInput {
/// Storage. Will be casted to HashMap<vec<u8>, Vec<u8>> to simulate DB access.
pub storage: Vec<RawStorageEntry>,
/// All relevant information for the state diff commitment.
pub state_diff: RawStateDiff,
/// The height of the patricia tree.
// TODO(Nimrod,20/4/2024): Strong assumption - all trees have same height. How can I get
// rid of it?
pub tree_height: u8,
}

#[allow(dead_code)]
pub(crate) struct Input {
pub storage: HashMap<StorageKey, StorageValue>,
pub state_diff: StateDiff,
pub tree_height: TreeHeight,
}

#[derive(Deserialize, Debug)]
#[allow(dead_code)]
/// Fact storage entry.
pub(crate) struct RawStorageEntry {
pub key: Vec<u8>,
pub value: Vec<u8>,
}

#[derive(Deserialize, Debug)]
#[allow(dead_code)]
pub(crate) struct RawFeltMapEntry {
pub key: RawFelt,
pub value: RawFelt,
}

#[derive(Deserialize, Debug)]
#[allow(dead_code)]
/// Represents storage updates. Later will be casted to HashMap<Felt, HashMap<Felt,Felt>> entry.
pub(crate) struct RawStorageUpdates {
pub address: RawFelt,
pub storage_updates: Vec<RawFeltMapEntry>,
}

#[derive(Deserialize, Debug)]
#[allow(dead_code)]
/// Represents current state leaf at the contract state tree. Later will be casted to
/// HashMap<Felt, (nonce, class_hash, storage_root_hash)> entry.
pub(crate) struct RawContractStateLeaf {
pub address: RawFelt,
pub nonce: RawFelt,
pub storage_root_hash: RawFelt,
pub class_hash: RawFelt,
}

#[derive(Deserialize, Debug)]
#[allow(dead_code)]
/// Represents state diff.
pub(crate) struct RawStateDiff {
/// Will be casted to HashMap<Felt,Felt>.
pub address_to_class_hash: Vec<RawFeltMapEntry>,
/// Will be casted to HashMap<Felt,Felt>.
pub address_to_nonce: Vec<RawFeltMapEntry>,
/// Will be casted to HashMap<Felt,Felt>.
pub class_hash_to_compiled_class_hash: Vec<RawFeltMapEntry>,
/// Will be casted to HashMap<Felt,HashMap<Felt,Felt>>.
pub storage_updates: Vec<RawStorageUpdates>,
/// Will be casted to HashMap<Felt,ContractState>.
pub current_contract_state_leaves: Vec<RawContractStateLeaf>,
}

#[allow(dead_code)]
pub(crate) struct StateDiff {
pub address_to_class_hash: HashMap<ContractAddress, ClassHash>,
pub address_to_nonce: HashMap<ContractAddress, Nonce>,
pub class_hash_to_compiled_class_hash: HashMap<ClassHash, CompiledClassHash>,
pub current_contract_state_leaves: HashMap<ContractAddress, ContractState>,
pub storage_updates:
HashMap<ContractAddress, HashMap<StarknetStorageKey, StarknetStorageValue>>,
}

#[allow(dead_code)]
pub(crate) struct ContractState {
pub nonce: Nonce,
pub class_hash: ClassHash,
pub storage_root_hash: HashOutput,
}
1 change: 1 addition & 0 deletions crates/committer/src/lib.rs
@@ -1,3 +1,4 @@
pub mod deserialization;
pub mod hash;
pub mod patricia_merkle_tree;
pub mod storage;
Expand Down
4 changes: 4 additions & 0 deletions crates/committer/src/patricia_merkle_tree/filled_node.rs
Expand Up @@ -2,10 +2,14 @@ use crate::patricia_merkle_tree::types::{EdgeData, LeafDataTrait};
use crate::{hash::types::HashOutput, types::Felt};
// TODO(Nimrod, 1/6/2024): Swap to starknet-types-core types once implemented.
#[allow(dead_code)]
#[derive(Eq, PartialEq, Hash, Debug)]
pub(crate) struct ClassHash(pub Felt);
#[allow(dead_code)]
pub(crate) struct Nonce(pub Felt);

#[allow(dead_code)]
pub(crate) struct CompiledClassHash(pub Felt);

#[allow(dead_code)]
/// A node in a Patricia-Merkle tree which was modified during an update.
pub(crate) struct FilledNode<L: LeafDataTrait> {
Expand Down
5 changes: 3 additions & 2 deletions crates/committer/src/storage/storage_trait.rs
Expand Up @@ -2,10 +2,11 @@ use crate::storage::errors::StorageError;
use std::collections::HashMap;

#[allow(dead_code)]
pub(crate) struct StorageKey(Vec<u8>);
#[derive(PartialEq, Eq, Hash, Debug)]
pub(crate) struct StorageKey(pub Vec<u8>);

#[allow(dead_code)]
pub(crate) struct StorageValue(Vec<u8>);
pub(crate) struct StorageValue(pub Vec<u8>);

pub(crate) trait Storage {
/// Returns value from storage, if it exists.
Expand Down
3 changes: 3 additions & 0 deletions crates/committer/src/types.rs
Expand Up @@ -32,6 +32,9 @@ impl std::ops::Mul for Felt {
#[allow(dead_code)]
impl Felt {
pub const ZERO: Felt = Felt(StarknetTypesFelt::ZERO);
pub(crate) fn from_bytes_be_slice(bytes: &[u8]) -> Self {
Self(StarknetTypesFelt::from_bytes_be_slice(bytes))
}
pub const ONE: Felt = Felt(StarknetTypesFelt::ONE);
pub const TWO: Felt = Felt(StarknetTypesFelt::TWO);

Expand Down

0 comments on commit f5e1bbe

Please sign in to comment.