Skip to content

Commit 72c8dbf

Browse files
committed
starknet_committer: add index layout leaves
1 parent 4b39ed1 commit 72c8dbf

File tree

8 files changed

+239
-7
lines changed

8 files changed

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

crates/starknet_patricia_storage/src/storage_trait.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -172,15 +172,15 @@ impl Storage for NullStorage {
172172
}
173173

174174
#[derive(Debug)]
175-
pub struct DbKeyPrefix(&'static [u8]);
175+
pub struct DbKeyPrefix(Vec<u8>);
176176

177177
impl DbKeyPrefix {
178-
pub fn new(prefix: &'static [u8]) -> Self {
179-
Self(prefix)
178+
pub fn new(prefix: &[u8]) -> Self {
179+
Self(prefix.to_vec())
180180
}
181181

182-
pub fn to_bytes(&self) -> &'static [u8] {
183-
self.0
182+
pub fn to_bytes(&self) -> &[u8] {
183+
self.0.as_slice()
184184
}
185185
}
186186

0 commit comments

Comments
 (0)