Skip to content

Commit f5ba56f

Browse files
committed
starknet_committer: add index layout leaves
1 parent 0371ece commit f5ba56f

File tree

7 files changed

+235
-2
lines changed

7 files changed

+235
-2
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/starknet_committer/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,15 @@ rand_distr.workspace = true
2020
rstest.workspace = true
2121
serde = { workspace = true, features = ["derive"] }
2222
serde_json.workspace = true
23-
starknet-types-core = { workspace = true, features = ["hash"] }
23+
starknet-types-core = { workspace = true, features = ["papyrus-serialization","hash"] }
2424
starknet_api.workspace = true
2525
starknet_patricia.workspace = true
2626
starknet_patricia_storage.workspace = true
2727
strum.workspace = true
2828
thiserror.workspace = true
2929
tokio = { workspace = true, features = ["rt"] }
3030
tracing.workspace = true
31+
derive_more.workspace = true
3132

3233
[dev-dependencies]
3334
starknet_api = { workspace = true, features = ["testing"] }

crates/starknet_committer/src/db.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ mod db_layout;
33
pub mod external_test_utils;
44
pub mod facts_db;
55
pub mod forest_trait;
6+
pub mod index_db;
Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
use starknet_api::core::{ClassHash, ContractAddress, Nonce};
2+
use starknet_api::hash::HashOutput;
3+
use starknet_patricia::patricia_merkle_tree::node_data::errors::LeafResult;
4+
use starknet_patricia::patricia_merkle_tree::node_data::leaf::Leaf;
5+
use starknet_patricia_storage::db_object::{
6+
DBObject,
7+
EmptyDeserializationContext,
8+
HasStaticPrefix,
9+
};
10+
use starknet_patricia_storage::errors::{DeserializationError, SerializationError};
11+
use starknet_patricia_storage::storage_trait::{DbKeyPrefix, DbValue};
12+
use starknet_types_core::felt::Felt;
13+
14+
use crate::block_committer::input::StarknetStorageValue;
15+
use crate::patricia_merkle_tree::leaf::leaf_impl::ContractState;
16+
use crate::patricia_merkle_tree::types::CompiledClassHash;
17+
18+
// Wrap the leaves types so that we can implement the [DBObject] trait differently in index
19+
// layout.
20+
#[derive(Clone, Debug, Default, Eq, PartialEq, derive_more::AsRef, derive_more::From)]
21+
pub struct IndexLayoutContractState(pub ContractState);
22+
23+
#[derive(Clone, Debug, Default, Eq, PartialEq, derive_more::AsRef, derive_more::From)]
24+
pub struct IndexLayoutCompiledClassHash(pub CompiledClassHash);
25+
26+
#[derive(Clone, Debug, Default, Eq, PartialEq, derive_more::From)]
27+
pub struct IndexLayoutStarknetStorageValue(pub StarknetStorageValue);
28+
29+
// TODO(Ariel): Delete this enum and use `CommitmentType` instead.
30+
#[derive(Debug, PartialEq)]
31+
pub enum TrieType {
32+
ContractsTrie,
33+
ClassesTrie,
34+
StorageTrie(ContractAddress),
35+
}
36+
37+
impl TrieType {
38+
fn db_prefix(&self) -> DbKeyPrefix {
39+
match self {
40+
TrieType::ContractsTrie => DbKeyPrefix::new(b"CONTRACTS_TREE_PREFIX".into()),
41+
TrieType::ClassesTrie => DbKeyPrefix::new(b"CLASSES_TREE_PREFIX".into()),
42+
TrieType::StorageTrie(contract_address) => {
43+
let prefix = contract_address.to_bytes_be().to_vec();
44+
DbKeyPrefix::new(prefix.into())
45+
}
46+
}
47+
}
48+
}
49+
50+
// TODO(Ariel): Remove this macro when HasStaticPrefix is a local trait. Replace with a blanket
51+
// impl for any type that implements some dummy IndexLayoutStaticPrefix trait.
52+
macro_rules! impl_has_static_prefix_for_index_layouts {
53+
($($ty:ty),* $(,)?) => {
54+
$(
55+
impl HasStaticPrefix for $ty {
56+
type KeyContext = TrieType;
57+
fn get_static_prefix(key_context: &Self::KeyContext) -> DbKeyPrefix {
58+
key_context.db_prefix()
59+
}
60+
}
61+
)*
62+
};
63+
}
64+
65+
impl_has_static_prefix_for_index_layouts! {
66+
IndexLayoutContractState,
67+
IndexLayoutCompiledClassHash,
68+
IndexLayoutStarknetStorageValue,
69+
}
70+
71+
macro_rules! impl_leaf_for_wrappers {
72+
($($wrapper:ty => $inner:ty),+ $(,)?) => {
73+
$(
74+
impl Leaf for $wrapper {
75+
type Input = <$inner as Leaf>::Input;
76+
type Output = <$inner as Leaf>::Output;
77+
78+
fn is_empty(&self) -> bool {
79+
// assumes `pub struct Wrapper(pub Inner);`
80+
self.0.is_empty()
81+
}
82+
83+
async fn create(
84+
input: Self::Input,
85+
) -> LeafResult<(Self, Self::Output)> {
86+
let (created_leaf, output) = <$inner as Leaf>::create(input).await?;
87+
Ok((Self(created_leaf), output))
88+
}
89+
}
90+
)+
91+
};
92+
}
93+
94+
impl_leaf_for_wrappers!(
95+
IndexLayoutContractState => ContractState,
96+
IndexLayoutStarknetStorageValue => StarknetStorageValue,
97+
IndexLayoutCompiledClassHash => CompiledClassHash,
98+
);
99+
100+
impl DBObject for IndexLayoutContractState {
101+
type DeserializeContext = EmptyDeserializationContext;
102+
fn serialize(&self) -> Result<DbValue, SerializationError> {
103+
serialize_felts(vec![self.0.class_hash.0, self.0.storage_root_hash.0, self.0.nonce.0])
104+
}
105+
106+
fn deserialize(
107+
value: &DbValue,
108+
_deserialize_context: &Self::DeserializeContext,
109+
) -> Result<Self, DeserializationError> {
110+
let mut cursor: &[u8] = &value.0;
111+
let class_hash = deserialize_felt(&mut cursor, value)?;
112+
let storage_root_hash = deserialize_felt(&mut cursor, value)?;
113+
let nonce = deserialize_felt(&mut cursor, value)?;
114+
Ok(IndexLayoutContractState(ContractState {
115+
class_hash: ClassHash(class_hash),
116+
storage_root_hash: HashOutput(storage_root_hash),
117+
nonce: Nonce(nonce),
118+
}))
119+
}
120+
}
121+
122+
impl DBObject for IndexLayoutCompiledClassHash {
123+
type DeserializeContext = EmptyDeserializationContext;
124+
fn serialize(&self) -> Result<DbValue, SerializationError> {
125+
serialize_felts(vec![self.0.0])
126+
}
127+
fn deserialize(
128+
value: &DbValue,
129+
_deserialize_context: &Self::DeserializeContext,
130+
) -> Result<Self, DeserializationError> {
131+
Ok(IndexLayoutCompiledClassHash(CompiledClassHash(deserialize_felt(
132+
&mut &value.0[..],
133+
value,
134+
)?)))
135+
}
136+
}
137+
138+
impl DBObject for IndexLayoutStarknetStorageValue {
139+
type DeserializeContext = EmptyDeserializationContext;
140+
fn serialize(&self) -> Result<DbValue, SerializationError> {
141+
serialize_felts(vec![self.0.0])
142+
}
143+
fn deserialize(
144+
value: &DbValue,
145+
_deserialize_context: &Self::DeserializeContext,
146+
) -> Result<Self, DeserializationError> {
147+
Ok(IndexLayoutStarknetStorageValue(StarknetStorageValue(deserialize_felt(
148+
&mut &value.0[..],
149+
value,
150+
)?)))
151+
}
152+
}
153+
154+
fn deserialize_felt(cursor: &mut &[u8], value: &DbValue) -> Result<Felt, DeserializationError> {
155+
Felt::deserialize(cursor).ok_or(DeserializationError::FeltDeserializationError(value.clone()))
156+
}
157+
158+
fn serialize_felts(felts: Vec<Felt>) -> Result<DbValue, SerializationError> {
159+
let mut buffer = Vec::new();
160+
for felt in felts {
161+
felt.serialize(&mut buffer)?;
162+
}
163+
Ok(DbValue(buffer))
164+
}
165+
166+
#[cfg(test)]
167+
mod leaves_serde_tests {
168+
use starknet_api::core::{ClassHash, Nonce};
169+
use starknet_api::hash::HashOutput;
170+
use starknet_patricia_storage::db_object::{DBObject, EmptyDeserializationContext};
171+
use starknet_types_core::felt::Felt;
172+
173+
use crate::block_committer::input::StarknetStorageValue;
174+
use crate::db::index_db::leaves::{
175+
IndexLayoutCompiledClassHash,
176+
IndexLayoutContractState,
177+
IndexLayoutStarknetStorageValue,
178+
};
179+
use crate::patricia_merkle_tree::leaf::leaf_impl::ContractState;
180+
use crate::patricia_merkle_tree::types::CompiledClassHash;
181+
182+
#[test]
183+
fn test_index_layout_contract_state_serde() {
184+
let contract_state = ContractState {
185+
class_hash: ClassHash(Felt::from(1)),
186+
storage_root_hash: HashOutput(Felt::from(2)),
187+
nonce: Nonce(Felt::from(3)),
188+
};
189+
let index_layout_contract_state = IndexLayoutContractState(contract_state);
190+
let serialized = index_layout_contract_state.serialize().unwrap();
191+
let deserialized =
192+
IndexLayoutContractState::deserialize(&serialized, &EmptyDeserializationContext)
193+
.unwrap();
194+
assert_eq!(index_layout_contract_state, deserialized);
195+
}
196+
197+
#[test]
198+
fn test_index_layout_compiled_class_hash_serde() {
199+
let compiled_class_hash = CompiledClassHash(Felt::from(1));
200+
let index_layout_compiled_class_hash = IndexLayoutCompiledClassHash(compiled_class_hash);
201+
let serialized = index_layout_compiled_class_hash.serialize().unwrap();
202+
let deserialized =
203+
IndexLayoutCompiledClassHash::deserialize(&serialized, &EmptyDeserializationContext)
204+
.unwrap();
205+
assert_eq!(index_layout_compiled_class_hash, deserialized);
206+
}
207+
208+
#[test]
209+
fn test_index_layout_starknet_storage_value_serde() {
210+
let starknet_storage_value = StarknetStorageValue(Felt::from(1));
211+
let index_layout_starknet_storage_value =
212+
IndexLayoutStarknetStorageValue(starknet_storage_value);
213+
let serialized = index_layout_starknet_storage_value.serialize().unwrap();
214+
let deserialized =
215+
IndexLayoutStarknetStorageValue::deserialize(&serialized, &EmptyDeserializationContext)
216+
.unwrap();
217+
assert_eq!(index_layout_starknet_storage_value, deserialized);
218+
}
219+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub mod leaves;

crates/starknet_committer/src/patricia_merkle_tree/leaf/leaf_impl.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,11 @@ pub struct ContractState {
2020
pub storage_root_hash: HashOutput,
2121
pub class_hash: ClassHash,
2222
}
23-
23+
impl AsRef<ContractState> for ContractState {
24+
fn as_ref(&self) -> &ContractState {
25+
self
26+
}
27+
}
2428
impl HasStaticPrefix for StarknetStorageValue {
2529
type KeyContext = EmptyKeyContext;
2630
fn get_static_prefix(_key_context: &Self::KeyContext) -> DbKeyPrefix {

crates/starknet_committer/src/patricia_merkle_tree/types.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ pub fn class_hash_into_node_index(class_hash: &ClassHash) -> NodeIndex {
2323
#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
2424
pub struct CompiledClassHash(pub Felt);
2525

26+
impl AsRef<CompiledClassHash> for CompiledClassHash {
27+
fn as_ref(&self) -> &CompiledClassHash {
28+
self
29+
}
30+
}
31+
2632
impl_from_hex_for_felt_wrapper!(CompiledClassHash);
2733

2834
pub type StorageTrie = FilledTreeImpl<StarknetStorageValue>;

0 commit comments

Comments
 (0)