Skip to content

Commit 4402c0e

Browse files
committed
starknet_committer: add index layout nodes
1 parent 01c2851 commit 4402c0e

File tree

3 files changed

+203
-13
lines changed

3 files changed

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

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)