Skip to content

Commit 17c75e3

Browse files
committed
starknet_committer,starknet_patricia: add deserialization context
1 parent f515f75 commit 17c75e3

File tree

7 files changed

+76
-53
lines changed

7 files changed

+76
-53
lines changed

crates/starknet_committer/src/db/facts_db/traversal.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::collections::HashMap;
22

33
use starknet_api::hash::HashOutput;
44
use starknet_patricia::patricia_merkle_tree::filled_tree::node::FilledNode;
5+
use starknet_patricia::patricia_merkle_tree::filled_tree::node_serde::NodeContext;
56
use starknet_patricia::patricia_merkle_tree::node_data::inner_node::{
67
NodeData,
78
Preimage,
@@ -10,7 +11,7 @@ use starknet_patricia::patricia_merkle_tree::node_data::inner_node::{
1011
use starknet_patricia::patricia_merkle_tree::node_data::leaf::Leaf;
1112
use starknet_patricia::patricia_merkle_tree::traversal::{SubTreeTrait, TraversalResult};
1213
use starknet_patricia::patricia_merkle_tree::types::{NodeIndex, SortedLeafIndices};
13-
use starknet_patricia_storage::db_object::HasStaticPrefix;
14+
use starknet_patricia_storage::db_object::{DBObject, HasStaticPrefix};
1415
use starknet_patricia_storage::errors::StorageError;
1516
use starknet_patricia_storage::storage_trait::{create_db_key, DbKey, Storage};
1617

@@ -40,7 +41,10 @@ pub async fn calculate_subtrees_roots<'a, L: Leaf>(
4041
let db_vals = storage.mget(&db_keys.iter().collect::<Vec<&DbKey>>()).await?;
4142
for ((subtree, optional_val), db_key) in subtrees.iter().zip(db_vals.iter()).zip(db_keys) {
4243
let Some(val) = optional_val else { Err(StorageError::MissingKey(db_key))? };
43-
subtrees_roots.push(FilledNode::deserialize(subtree.root_hash, val, subtree.is_leaf())?)
44+
subtrees_roots.push(FilledNode::deserialize(
45+
val,
46+
&NodeContext { is_leaf: subtree.is_leaf(), node_hash: subtree.root_hash },
47+
)?)
4448
}
4549
Ok(subtrees_roots)
4650
}

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

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use serde_json::Value;
44
use starknet_api::core::{ClassHash, Nonce};
55
use starknet_api::hash::HashOutput;
66
use starknet_patricia::patricia_merkle_tree::types::SubTreeHeight;
7-
use starknet_patricia_storage::db_object::{DBObject, Deserializable};
7+
use starknet_patricia_storage::db_object::DBObject;
88
use starknet_patricia_storage::errors::DeserializationError;
99
use starknet_patricia_storage::storage_trait::{DbKeyPrefix, DbValue};
1010
use starknet_types_core::felt::Felt;
@@ -31,21 +31,46 @@ impl From<CommitterLeafPrefix> for DbKeyPrefix {
3131
}
3232

3333
impl DBObject for StarknetStorageValue {
34+
type DeserializeContext = ();
35+
3436
/// Serializes the value into a 32-byte vector.
3537
fn serialize(&self) -> DbValue {
3638
DbValue(self.0.to_bytes_be().to_vec())
3739
}
40+
41+
fn deserialize(
42+
value: &DbValue,
43+
_deserialize_context: &Self::DeserializeContext,
44+
) -> Result<Self, DeserializationError> {
45+
Ok(Self(Felt::from_bytes_be_slice(&value.0)))
46+
}
3847
}
3948

4049
impl DBObject for CompiledClassHash {
50+
type DeserializeContext = ();
51+
4152
/// Creates a json string describing the leaf and casts it into a byte vector.
4253
fn serialize(&self) -> DbValue {
4354
let json_string = format!(r#"{{"compiled_class_hash": "{}"}}"#, self.0.to_hex_string());
4455
DbValue(json_string.into_bytes())
4556
}
57+
58+
fn deserialize(
59+
value: &DbValue,
60+
_deserialize_context: &Self::DeserializeContext,
61+
) -> Result<Self, DeserializationError> {
62+
let json_str = std::str::from_utf8(&value.0)?;
63+
let map: HashMap<String, String> = serde_json::from_str(json_str)?;
64+
let hash_as_hex = map
65+
.get("compiled_class_hash")
66+
.ok_or(DeserializationError::NonExistingKey("compiled_class_hash".to_string()))?;
67+
Ok(Self::from_hex(hash_as_hex)?)
68+
}
4669
}
4770

4871
impl DBObject for ContractState {
72+
type DeserializeContext = ();
73+
4974
/// Creates a json string describing the leaf and casts it into a byte vector.
5075
fn serialize(&self) -> DbValue {
5176
let json_string = format!(
@@ -57,27 +82,11 @@ impl DBObject for ContractState {
5782
);
5883
DbValue(json_string.into_bytes())
5984
}
60-
}
61-
62-
impl Deserializable for StarknetStorageValue {
63-
fn deserialize(value: &DbValue) -> Result<Self, DeserializationError> {
64-
Ok(Self(Felt::from_bytes_be_slice(&value.0)))
65-
}
66-
}
67-
68-
impl Deserializable for CompiledClassHash {
69-
fn deserialize(value: &DbValue) -> Result<Self, DeserializationError> {
70-
let json_str = std::str::from_utf8(&value.0)?;
71-
let map: HashMap<String, String> = serde_json::from_str(json_str)?;
72-
let hash_as_hex = map
73-
.get("compiled_class_hash")
74-
.ok_or(DeserializationError::NonExistingKey("compiled_class_hash".to_string()))?;
75-
Ok(Self::from_hex(hash_as_hex)?)
76-
}
77-
}
7885

79-
impl Deserializable for ContractState {
80-
fn deserialize(value: &DbValue) -> Result<Self, DeserializationError> {
86+
fn deserialize(
87+
value: &DbValue,
88+
_deserialize_context: &Self::DeserializeContext,
89+
) -> Result<Self, DeserializationError> {
8190
let json_str = std::str::from_utf8(&value.0)?;
8291
let deserialized_map: Value = serde_json::from_str(json_str)?;
8392
let get_leaf_key = |map: &Value, key: &str| {

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use starknet_api::core::{ClassHash, Nonce};
55
use starknet_api::felt;
66
use starknet_api::hash::HashOutput;
77
use starknet_patricia::patricia_merkle_tree::node_data::leaf::Leaf;
8-
use starknet_patricia_storage::db_object::Deserializable;
8+
use starknet_patricia_storage::db_object::DBObject;
99
use starknet_patricia_storage::storage_trait::DbValue;
1010
use starknet_types_core::felt::Felt;
1111

@@ -32,7 +32,7 @@ use crate::patricia_merkle_tree::types::CompiledClassHash;
3232
]
3333
fn test_leaf_serde<L: Leaf + Eq + Debug>(#[case] leaf: L) {
3434
let serialized = leaf.serialize();
35-
let deserialized = L::deserialize(&serialized).unwrap();
35+
let deserialized = L::deserialize(&serialized, &()).unwrap();
3636
assert_eq!(deserialized, leaf);
3737
}
3838

@@ -60,7 +60,7 @@ fn test_deserialize_contract_state_without_nonce() {
6060
.to_vec(),
6161
);
6262

63-
let contract_state = ContractState::deserialize(&serialized).unwrap();
63+
let contract_state = ContractState::deserialize(&serialized, &()).unwrap();
6464

6565
// Validate the fields (nonce should be the default "0")
6666
assert_eq!(contract_state.nonce, Nonce(Felt::ZERO));

crates/starknet_patricia/src/patricia_merkle_tree/external_test_utils.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use ethnum::U256;
44
use num_bigint::{BigUint, RandBigInt};
55
use rand::Rng;
66
use starknet_api::hash::HashOutput;
7-
use starknet_patricia_storage::db_object::{DBObject, Deserializable, HasStaticPrefix};
7+
use starknet_patricia_storage::db_object::{DBObject, HasStaticPrefix};
88
use starknet_patricia_storage::errors::DeserializationError;
99
use starknet_patricia_storage::storage_trait::{create_db_key, DbKey, DbKeyPrefix, DbValue};
1010
use starknet_types_core::felt::Felt;
@@ -32,13 +32,16 @@ impl HasStaticPrefix for MockLeaf {
3232
}
3333

3434
impl DBObject for MockLeaf {
35+
type DeserializeContext = ();
36+
3537
fn serialize(&self) -> DbValue {
3638
DbValue(self.0.to_bytes_be().to_vec())
3739
}
38-
}
3940

40-
impl Deserializable for MockLeaf {
41-
fn deserialize(value: &DbValue) -> Result<Self, DeserializationError> {
41+
fn deserialize(
42+
value: &DbValue,
43+
_deserialize_context: &Self::DeserializeContext,
44+
) -> Result<Self, DeserializationError> {
4245
Ok(Self(Felt::from_bytes_be_slice(&value.0)))
4346
}
4447
}

crates/starknet_patricia/src/patricia_merkle_tree/filled_tree/node_serde.rs

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -51,17 +51,22 @@ impl<L: Leaf> FilledNode<L> {
5151

5252
impl<L: Leaf> HasDynamicPrefix for FilledNode<L> {
5353
type KeyContext = <L as HasStaticPrefix>::KeyContext;
54-
55-
fn get_prefix(&self, key_context: &Self::KeyContext) -> DbKeyPrefix {
54+
fn get_prefix(&self, _key_context: &Self::KeyContext) -> DbKeyPrefix {
5655
match &self.data {
5756
NodeData::Binary(_) | NodeData::Edge(_) => PatriciaPrefix::InnerNode,
58-
NodeData::Leaf(_) => PatriciaPrefix::Leaf(L::get_static_prefix(key_context)),
57+
NodeData::Leaf(_) => PatriciaPrefix::Leaf(L::get_static_prefix(_key_context)),
5958
}
6059
.into()
6160
}
6261
}
6362

63+
pub struct NodeContext {
64+
pub is_leaf: bool,
65+
pub node_hash: HashOutput,
66+
}
67+
6468
impl<L: Leaf> DBObject for FilledNode<L> {
69+
type DeserializeContext = NodeContext;
6570
/// This method serializes the filled node into a byte vector, where:
6671
/// - For binary nodes: Concatenates left and right hashes.
6772
/// - For edge nodes: Concatenates bottom hash, path, and path length.
@@ -93,22 +98,21 @@ impl<L: Leaf> DBObject for FilledNode<L> {
9398
NodeData::Leaf(leaf_data) => leaf_data.serialize(),
9499
}
95100
}
96-
}
97101

98-
impl<L: Leaf> FilledNode<L> {
99-
/// Deserializes filled nodes.
100-
pub fn deserialize(
101-
node_hash: HashOutput,
102+
fn deserialize(
102103
value: &DbValue,
103-
is_leaf: bool,
104+
deserialize_context: &Self::DeserializeContext,
104105
) -> Result<Self, DeserializationError> {
105-
if is_leaf {
106-
return Ok(Self { hash: node_hash, data: NodeData::Leaf(L::deserialize(value)?) });
106+
if deserialize_context.is_leaf {
107+
return Ok(Self {
108+
hash: deserialize_context.node_hash,
109+
data: NodeData::Leaf(L::deserialize(value, &())?),
110+
});
107111
}
108112

109113
if value.0.len() == BINARY_BYTES {
110114
Ok(Self {
111-
hash: node_hash,
115+
hash: deserialize_context.node_hash,
112116
data: NodeData::Binary(BinaryData {
113117
left_hash: HashOutput(Felt::from_bytes_be_slice(
114118
&value.0[..SERIALIZE_HASH_BYTES],
@@ -128,7 +132,7 @@ impl<L: Leaf> FilledNode<L> {
128132
BINARY_BYTES
129133
);
130134
Ok(Self {
131-
hash: node_hash,
135+
hash: deserialize_context.node_hash,
132136
data: NodeData::Edge(EdgeData {
133137
bottom_hash: HashOutput(Felt::from_bytes_be_slice(
134138
&value.0[..SERIALIZE_HASH_BYTES],

crates/starknet_patricia/src/patricia_merkle_tree/node_data/leaf.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::collections::HashMap;
22
use std::fmt::Debug;
33
use std::future::Future;
44

5-
use starknet_patricia_storage::db_object::{DBObject, Deserializable, HasStaticPrefix};
5+
use starknet_patricia_storage::db_object::{DBObject, HasStaticPrefix};
66
use starknet_types_core::felt::Felt;
77

88
use crate::patricia_merkle_tree::node_data::errors::{LeafError, LeafResult};
@@ -11,7 +11,7 @@ use crate::patricia_merkle_tree::original_skeleton_tree::tree::OriginalSkeletonT
1111
use crate::patricia_merkle_tree::types::NodeIndex;
1212

1313
pub trait Leaf:
14-
Clone + Sync + Send + HasStaticPrefix + DBObject + Deserializable + Default + Debug + Eq
14+
Clone + Sync + Send + HasStaticPrefix + DBObject<DeserializeContext = ()> + Default + Debug + Eq
1515
{
1616
// TODO(Amos, 1/1/2025): When default values for associated types are stable - use them, and
1717
// add a default implementation for `create`.

crates/starknet_patricia_storage/src/db_object.rs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,20 @@ impl<T: HasStaticPrefix> HasDynamicPrefix for T {
2828
}
2929
}
3030

31-
pub trait DBObject: HasDynamicPrefix {
32-
/// Serializes the given value.
31+
pub trait DBObject: Sized + HasDynamicPrefix {
32+
/// Extra data needed to deserialize the object. For example, facts layout nodes need the node
33+
/// hash and an indication of whether or not it's a leaf node (index layout nodes only need the
34+
/// latter).
35+
type DeserializeContext;
36+
3337
fn serialize(&self) -> DbValue;
3438

35-
/// Returns a `DbKey` from a prefix and a suffix.
39+
fn deserialize(
40+
value: &DbValue,
41+
deserialize_context: &Self::DeserializeContext,
42+
) -> Result<Self, DeserializationError>;
43+
3644
fn get_db_key(&self, key_context: &Self::KeyContext, suffix: &[u8]) -> DbKey {
3745
create_db_key(self.get_prefix(key_context), suffix)
3846
}
3947
}
40-
41-
pub trait Deserializable: Sized {
42-
/// Deserializes the given value.
43-
fn deserialize(value: &DbValue) -> Result<Self, DeserializationError>;
44-
}

0 commit comments

Comments
 (0)