Skip to content

Commit 6d1b723

Browse files
committed
starknet_committer: add index layout nodes
1 parent 3eb0ec5 commit 6d1b723

File tree

3 files changed

+210
-13
lines changed

3 files changed

+210
-13
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
pub mod leaves;
2+
pub mod types;
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
use ethnum::U256;
2+
use starknet_api::hash::HashOutput;
3+
use starknet_patricia::patricia_merkle_tree::filled_tree::node::FilledNode;
4+
use starknet_patricia::patricia_merkle_tree::node_data::inner_node::{
5+
BinaryData,
6+
EdgeData,
7+
EdgePath,
8+
EdgePathLength,
9+
NodeData,
10+
PathToBottom,
11+
};
12+
use starknet_patricia::patricia_merkle_tree::node_data::leaf::Leaf;
13+
use starknet_patricia::patricia_merkle_tree::traversal::{SubTreeTrait, UnmodifiedChildTraversal};
14+
use starknet_patricia::patricia_merkle_tree::types::{NodeIndex, SortedLeafIndices};
15+
use starknet_patricia::patricia_merkle_tree::updated_skeleton_tree::hash_function::TreeHashFunction;
16+
use starknet_patricia_storage::db_object::{
17+
DBObject,
18+
EmptyDeserializationContext,
19+
HasStaticPrefix,
20+
};
21+
use starknet_patricia_storage::errors::DeserializationError;
22+
use starknet_patricia_storage::storage_trait::{DbKeyPrefix, DbValue};
23+
use starknet_types_core::felt::Felt;
24+
25+
use crate::hash_function::hash::TreeHashFunctionImpl;
26+
27+
pub(crate) const INDEX_LAYOUT_BINARY_BYTES: usize = 32;
28+
pub(crate) const SERIALIZE_HASH_BYTES: usize = 32;
29+
30+
// TODO(Ariel): Remove this wrapper once DBObject is a local trait.
31+
pub struct IndexFilledNode<L: Leaf>(pub FilledNode<L, ()>);
32+
33+
pub struct IndexNodeContext {
34+
pub is_leaf: bool,
35+
}
36+
37+
impl<L: Leaf> HasStaticPrefix for IndexFilledNode<L> {
38+
type KeyContext = <L as HasStaticPrefix>::KeyContext;
39+
fn get_static_prefix(key_context: &Self::KeyContext) -> DbKeyPrefix {
40+
L::get_static_prefix(key_context)
41+
}
42+
}
43+
44+
impl<L> DBObject for IndexFilledNode<L>
45+
where
46+
L: Leaf,
47+
TreeHashFunctionImpl: TreeHashFunction<L>,
48+
{
49+
type DeserializeContext = IndexNodeContext;
50+
fn serialize(&self) -> DbValue {
51+
match &self.0.data {
52+
NodeData::Binary(_) => DbValue(self.0.hash.0.to_bytes_be().to_vec()),
53+
NodeData::Edge(edge_data) => {
54+
let mut raw_bytes = self.0.hash.0.to_bytes_be().to_vec();
55+
let bit_len: u8 = edge_data.path_to_bottom.length.into();
56+
let byte_len: usize = (bit_len.saturating_add(7) / 8).into();
57+
raw_bytes.push(bit_len);
58+
raw_bytes
59+
.extend(edge_data.path_to_bottom.path.0.to_le_bytes()[..byte_len].to_vec());
60+
DbValue(raw_bytes)
61+
}
62+
NodeData::Leaf(leaf) => leaf.serialize(),
63+
}
64+
}
65+
fn deserialize(
66+
value: &DbValue,
67+
deserialize_context: &Self::DeserializeContext,
68+
) -> Result<Self, DeserializationError> {
69+
if deserialize_context.is_leaf {
70+
let leaf = L::deserialize(value, &EmptyDeserializationContext)?;
71+
let hash = TreeHashFunctionImpl::compute_leaf_hash(&leaf);
72+
Ok(IndexFilledNode(FilledNode { hash, data: NodeData::Leaf(leaf) }))
73+
} else if value.0.len() == INDEX_LAYOUT_BINARY_BYTES {
74+
Ok(IndexFilledNode(FilledNode {
75+
hash: HashOutput(Felt::from_bytes_be_slice(&value.0)),
76+
data: NodeData::Binary(BinaryData::<()> { left_data: (), right_data: () }),
77+
}))
78+
} else {
79+
let node_hash = HashOutput(Felt::from_bytes_be_slice(&value.0[..SERIALIZE_HASH_BYTES]));
80+
let value = &value.0[SERIALIZE_HASH_BYTES..];
81+
let bit_len = value[0];
82+
let byte_len = (bit_len.saturating_add(7) / 8).into();
83+
let path = U256::from_le_bytes(
84+
value[1..byte_len].try_into().expect("Slice with incorrect length."),
85+
);
86+
Ok(IndexFilledNode(FilledNode {
87+
hash: node_hash,
88+
data: NodeData::Edge(EdgeData::<()> {
89+
bottom_data: (),
90+
path_to_bottom: PathToBottom::new(
91+
EdgePath(path),
92+
EdgePathLength::new(bit_len)
93+
.map_err(|error| DeserializationError::ValueError(Box::new(error)))?,
94+
)
95+
.map_err(|error| DeserializationError::ValueError(Box::new(error)))?,
96+
}),
97+
}))
98+
}
99+
}
100+
}
101+
102+
pub struct IndexLayoutSubTree<'a> {
103+
pub sorted_leaf_indices: SortedLeafIndices<'a>,
104+
pub root_index: NodeIndex,
105+
}
106+
107+
impl<'a> SubTreeTrait<'a> for IndexLayoutSubTree<'a> {
108+
type NodeData = ();
109+
type NodeDeserializeContext = IndexNodeContext;
110+
111+
fn create(
112+
sorted_leaf_indices: SortedLeafIndices<'a>,
113+
root_index: NodeIndex,
114+
_child_data: Self::NodeData,
115+
) -> Self {
116+
Self { sorted_leaf_indices, root_index }
117+
}
118+
119+
fn get_root_index(&self) -> NodeIndex {
120+
self.root_index
121+
}
122+
123+
fn get_sorted_leaf_indices(&self) -> &SortedLeafIndices<'a> {
124+
&self.sorted_leaf_indices
125+
}
126+
127+
fn should_traverse_unmodified_child(_data: Self::NodeData) -> UnmodifiedChildTraversal {
128+
UnmodifiedChildTraversal::Traverse
129+
}
130+
131+
fn get_root_context(&self) -> Self::NodeDeserializeContext {
132+
Self::NodeDeserializeContext { is_leaf: self.is_leaf() }
133+
}
134+
135+
fn get_root_prefix<L: Leaf>(
136+
&self,
137+
_key_context: &<L as HasStaticPrefix>::KeyContext,
138+
) -> DbKeyPrefix {
139+
L::get_static_prefix(_key_context)
140+
}
141+
142+
fn get_root_suffix(&self) -> Vec<u8> {
143+
self.root_index.0.to_be_bytes().to_vec()
144+
}
145+
}

crates/starknet_committer/src/hash_function/hash.rs

Lines changed: 64 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::convert::AsRef;
2+
13
use starknet_api::hash::HashOutput;
24
use starknet_patricia::patricia_merkle_tree::node_data::inner_node::NodeData;
35
use starknet_patricia::patricia_merkle_tree::updated_skeleton_tree::hash_function::{
@@ -8,9 +10,13 @@ use starknet_types_core::felt::Felt;
810
use starknet_types_core::hash::{Pedersen, Poseidon, StarkHash};
911

1012
use crate::block_committer::input::StarknetStorageValue;
13+
use crate::db::index_db::leaves::{
14+
IndexLayoutCompiledClassHash,
15+
IndexLayoutContractState,
16+
IndexLayoutStarknetStorageValue,
17+
};
1118
use crate::patricia_merkle_tree::leaf::leaf_impl::ContractState;
1219
use crate::patricia_merkle_tree::types::CompiledClassHash;
13-
1420
/// Implementation of HashFunction for Pedersen hash function.
1521
pub struct PedersenHashFunction;
1622
impl HashFunction for PedersenHashFunction {
@@ -43,35 +49,69 @@ impl TreeHashFunctionImpl {
4349
/// <https://docs.starknet.io/documentation/architecture_and_concepts/Network_Architecture/starknet-state/#trie_construction>
4450
impl TreeHashFunction<ContractState> for TreeHashFunctionImpl {
4551
fn compute_leaf_hash(contract_state: &ContractState) -> HashOutput {
46-
HashOutput(Pedersen::hash(
47-
&Pedersen::hash(
48-
&Pedersen::hash(&contract_state.class_hash.0, &contract_state.storage_root_hash.0),
49-
&contract_state.nonce.0,
50-
),
51-
&Self::CONTRACT_STATE_HASH_VERSION,
52-
))
52+
compute_contract_state_leaf_hash(contract_state)
5353
}
5454
fn compute_node_hash(node_data: &NodeData<ContractState, HashOutput>) -> HashOutput {
5555
Self::compute_node_hash_with_inner_hash_function::<PedersenHashFunction>(node_data)
5656
}
5757
}
5858

59+
impl TreeHashFunction<IndexLayoutContractState> for TreeHashFunctionImpl {
60+
fn compute_leaf_hash(contract_state: &IndexLayoutContractState) -> HashOutput {
61+
compute_contract_state_leaf_hash(contract_state)
62+
}
63+
fn compute_node_hash(node_data: &NodeData<IndexLayoutContractState, HashOutput>) -> HashOutput {
64+
Self::compute_node_hash_with_inner_hash_function::<PedersenHashFunction>(node_data)
65+
}
66+
}
67+
68+
fn compute_contract_state_leaf_hash<L: AsRef<ContractState>>(
69+
contract_state_leaf: &L,
70+
) -> HashOutput {
71+
let contract_state: &ContractState = contract_state_leaf.as_ref();
72+
HashOutput(Pedersen::hash(
73+
&Pedersen::hash(
74+
&Pedersen::hash(&contract_state.class_hash.0, &contract_state.storage_root_hash.0),
75+
&contract_state.nonce.0,
76+
),
77+
&TreeHashFunctionImpl::CONTRACT_STATE_HASH_VERSION,
78+
))
79+
}
80+
5981
/// Implementation of TreeHashFunction for the classes trie.
6082
/// The implementation is based on the following reference:
6183
/// <https://docs.starknet.io/documentation/architecture_and_concepts/Network_Architecture/starknet-state/#trie_construction>
6284
impl TreeHashFunction<CompiledClassHash> for TreeHashFunctionImpl {
6385
fn compute_leaf_hash(compiled_class_hash: &CompiledClassHash) -> HashOutput {
64-
let contract_class_leaf_version: Felt = Felt::from_hex(Self::CONTRACT_CLASS_LEAF_V0)
65-
.expect(
66-
"could not parse hex string corresponding to b'CONTRACT_CLASS_LEAF_V0' to Felt",
67-
);
68-
HashOutput(Poseidon::hash(&contract_class_leaf_version, &compiled_class_hash.0))
86+
compute_compiled_class_leaf_hash(compiled_class_hash)
6987
}
7088
fn compute_node_hash(node_data: &NodeData<CompiledClassHash, HashOutput>) -> HashOutput {
7189
Self::compute_node_hash_with_inner_hash_function::<PoseidonHashFunction>(node_data)
7290
}
7391
}
7492

93+
impl TreeHashFunction<IndexLayoutCompiledClassHash> for TreeHashFunctionImpl {
94+
fn compute_leaf_hash(compiled_class_hash: &IndexLayoutCompiledClassHash) -> HashOutput {
95+
compute_compiled_class_leaf_hash(compiled_class_hash)
96+
}
97+
fn compute_node_hash(
98+
node_data: &NodeData<IndexLayoutCompiledClassHash, HashOutput>,
99+
) -> HashOutput {
100+
Self::compute_node_hash_with_inner_hash_function::<PoseidonHashFunction>(node_data)
101+
}
102+
}
103+
104+
fn compute_compiled_class_leaf_hash<L: AsRef<CompiledClassHash>>(
105+
compiled_class_hash_leaf: &L,
106+
) -> HashOutput {
107+
let compiled_class_hash: &CompiledClassHash = compiled_class_hash_leaf.as_ref();
108+
let contract_class_leaf_version: Felt = Felt::from_hex(
109+
TreeHashFunctionImpl::CONTRACT_CLASS_LEAF_V0,
110+
)
111+
.expect("could not parse hex string corresponding to b'CONTRACT_CLASS_LEAF_V0' to Felt");
112+
HashOutput(Poseidon::hash(&contract_class_leaf_version, &compiled_class_hash.0))
113+
}
114+
75115
/// Implementation of TreeHashFunction for the storage trie.
76116
/// The implementation is based on the following reference:
77117
/// <https://docs.starknet.io/documentation/architecture_and_concepts/Network_Architecture/starknet-state/#trie_construction>
@@ -84,6 +124,17 @@ impl TreeHashFunction<StarknetStorageValue> for TreeHashFunctionImpl {
84124
}
85125
}
86126

127+
impl TreeHashFunction<IndexLayoutStarknetStorageValue> for TreeHashFunctionImpl {
128+
fn compute_leaf_hash(storage_value: &IndexLayoutStarknetStorageValue) -> HashOutput {
129+
HashOutput(storage_value.0.0)
130+
}
131+
fn compute_node_hash(
132+
node_data: &NodeData<IndexLayoutStarknetStorageValue, HashOutput>,
133+
) -> HashOutput {
134+
Self::compute_node_hash_with_inner_hash_function::<PedersenHashFunction>(node_data)
135+
}
136+
}
137+
87138
/// Combined trait for all specific implementations.
88139
pub(crate) trait ForestHashFunction:
89140
TreeHashFunction<ContractState>

0 commit comments

Comments
 (0)