Skip to content

Commit 7501306

Browse files
committed
starknet_committer: add index layout leaves
1 parent eb93872 commit 7501306

File tree

6 files changed

+213
-1
lines changed

6 files changed

+213
-1
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: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
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+
macro_rules! impl_has_static_prefix_for_index_layouts {
51+
($($ty:ty),* $(,)?) => {
52+
$(
53+
impl HasStaticPrefix for $ty {
54+
type KeyContext = TrieType;
55+
fn get_static_prefix(key_context: &Self::KeyContext) -> DbKeyPrefix {
56+
key_context.db_prefix()
57+
}
58+
}
59+
)*
60+
};
61+
}
62+
63+
impl_has_static_prefix_for_index_layouts! {
64+
IndexLayoutContractState,
65+
IndexLayoutCompiledClassHash,
66+
IndexLayoutStarknetStorageValue,
67+
}
68+
69+
macro_rules! impl_leaf_for_wrappers {
70+
($($wrapper:ty => $inner:ty),+ $(,)?) => {
71+
$(
72+
impl Leaf for $wrapper {
73+
type Input = <$inner as Leaf>::Input;
74+
type Output = <$inner as Leaf>::Output;
75+
76+
fn is_empty(&self) -> bool {
77+
// assumes `pub struct Wrapper(pub Inner);`
78+
self.0.is_empty()
79+
}
80+
81+
async fn create(
82+
input: Self::Input,
83+
) -> LeafResult<(Self, Self::Output)> {
84+
let (created_leaf, output) = <$inner as Leaf>::create(input).await?;
85+
Ok((Self(created_leaf), output))
86+
}
87+
}
88+
)+
89+
};
90+
}
91+
92+
impl_leaf_for_wrappers!(
93+
IndexLayoutContractState => ContractState,
94+
IndexLayoutStarknetStorageValue => StarknetStorageValue,
95+
IndexLayoutCompiledClassHash => CompiledClassHash,
96+
);
97+
98+
impl DBObject for IndexLayoutContractState {
99+
type DeserializeContext = EmptyDeserializationContext;
100+
fn serialize(&self) -> Result<DbValue, SerializationError> {
101+
serialize_felts(vec![self.0.class_hash.0, self.0.storage_root_hash.0, self.0.nonce.0])
102+
}
103+
104+
fn deserialize(
105+
value: &DbValue,
106+
_deserialize_context: &Self::DeserializeContext,
107+
) -> Result<Self, DeserializationError> {
108+
let mut cursor: &[u8] = &value.0;
109+
let class_hash = deserialize_felt(&mut cursor, || {
110+
DeserializationError::FeltDeserializationError(value.clone())
111+
})?;
112+
let storage_root_hash = deserialize_felt(&mut cursor, || {
113+
DeserializationError::FeltDeserializationError(value.clone())
114+
})?;
115+
let nonce = deserialize_felt(&mut cursor, || {
116+
DeserializationError::FeltDeserializationError(value.clone())
117+
})?;
118+
Ok(Self(ContractState {
119+
class_hash: ClassHash(class_hash),
120+
storage_root_hash: HashOutput(storage_root_hash),
121+
nonce: Nonce(nonce),
122+
}))
123+
}
124+
}
125+
126+
impl DBObject for IndexLayoutCompiledClassHash {
127+
type DeserializeContext = EmptyDeserializationContext;
128+
129+
fn serialize(&self) -> Result<DbValue, SerializationError> {
130+
serialize_felts(vec![self.0.0])
131+
}
132+
133+
fn deserialize(
134+
value: &DbValue,
135+
_deserialize_context: &Self::DeserializeContext,
136+
) -> Result<Self, DeserializationError> {
137+
Ok(Self(CompiledClassHash(deserialize_felt(&mut &value.0[..], || {
138+
DeserializationError::FeltDeserializationError(value.clone())
139+
})?)))
140+
}
141+
}
142+
143+
impl DBObject for IndexLayoutStarknetStorageValue {
144+
type DeserializeContext = EmptyDeserializationContext;
145+
146+
fn serialize(&self) -> Result<DbValue, SerializationError> {
147+
serialize_felts(vec![self.0.0])
148+
}
149+
150+
fn deserialize(
151+
value: &DbValue,
152+
_deserialize_context: &Self::DeserializeContext,
153+
) -> Result<Self, DeserializationError> {
154+
Ok(Self(StarknetStorageValue(deserialize_felt(&mut &value.0[..], || {
155+
DeserializationError::FeltDeserializationError(value.clone())
156+
})?)))
157+
}
158+
}
159+
160+
fn deserialize_felt(
161+
cursor: &mut &[u8],
162+
mk_err: impl FnOnce() -> DeserializationError,
163+
) -> Result<Felt, DeserializationError> {
164+
Felt::deserialize(cursor).ok_or_else(mk_err)
165+
}
166+
167+
fn serialize_felts(felts: Vec<Felt>) -> Result<DbValue, SerializationError> {
168+
let mut buffer = Vec::new();
169+
for felt in felts {
170+
felt.serialize(&mut buffer)?;
171+
}
172+
Ok(DbValue(buffer))
173+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
use rstest::rstest;
2+
use starknet_api::core::{ClassHash, Nonce};
3+
use starknet_api::hash::HashOutput;
4+
use starknet_patricia::patricia_merkle_tree::node_data::leaf::Leaf;
5+
use starknet_patricia_storage::db_object::EmptyDeserializationContext;
6+
use starknet_types_core::felt::Felt;
7+
8+
use crate::block_committer::input::StarknetStorageValue;
9+
use crate::db::index_db::leaves::{
10+
IndexLayoutCompiledClassHash,
11+
IndexLayoutContractState,
12+
IndexLayoutStarknetStorageValue,
13+
};
14+
use crate::patricia_merkle_tree::leaf::leaf_impl::ContractState;
15+
use crate::patricia_merkle_tree::types::CompiledClassHash;
16+
17+
#[rstest]
18+
#[case::index_layout_contract_state(IndexLayoutContractState(ContractState {
19+
class_hash: ClassHash(Felt::from(1)),
20+
storage_root_hash: HashOutput(Felt::from(2)),
21+
nonce: Nonce(Felt::from(3)),}
22+
))]
23+
#[case::index_layout_compiled_class_hash(IndexLayoutCompiledClassHash(CompiledClassHash(
24+
Felt::from(1)
25+
)))]
26+
#[case::index_layout_starknet_storage_value(IndexLayoutStarknetStorageValue(
27+
StarknetStorageValue(Felt::from(1))
28+
))]
29+
fn test_index_layout_leaf_serde<L: Leaf>(#[case] leaf: L) {
30+
let serialized = leaf.serialize().unwrap();
31+
let deserialized = L::deserialize(&serialized, &EmptyDeserializationContext).unwrap();
32+
assert_eq!(leaf, deserialized);
33+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
pub mod leaves;
2+
#[cfg(test)]
3+
pub mod leaves_test;

0 commit comments

Comments
 (0)