starknet_devnet_types/
patricia_key.rs

1use serde::{Deserialize, Deserializer, Serialize};
2use starknet_api::core::PATRICIA_KEY_UPPER_BOUND;
3use starknet_rs_core::types::Felt;
4
5use crate::error::{DevnetResult, Error};
6use crate::serde_helpers::hex_string::{
7    deserialize_to_prefixed_patricia_key, serialize_patricia_key_to_prefixed_hex,
8};
9
10#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
11pub struct PatriciaKey(pub(crate) Felt);
12
13pub(crate) const PATRICIA_KEY_ZERO: PatriciaKey = PatriciaKey(Felt::ZERO);
14
15impl PatriciaKey {
16    pub fn new(felt: Felt) -> DevnetResult<Self> {
17        if Felt::from_hex_unchecked(PATRICIA_KEY_UPPER_BOUND) < felt {
18            return Err(Error::StarknetApiError(starknet_api::StarknetApiError::OutOfRange {
19                string: format!("[0x0, {PATRICIA_KEY_UPPER_BOUND})"),
20            }));
21        }
22        Ok(Self(felt))
23    }
24
25    /// Constructs without range checks.
26    /// Safety: `felt` must be in [0x0, PATRICIA_KEY_UPPER_BOUND).
27    pub(crate) fn new_unchecked(felt: Felt) -> Self {
28        debug_assert!(
29            Felt::from_hex_unchecked(PATRICIA_KEY_UPPER_BOUND) >= felt,
30            "PatriciaKey out of range"
31        );
32        Self(felt)
33    }
34
35    pub fn to_felt(&self) -> Felt {
36        self.0
37    }
38}
39
40impl Serialize for PatriciaKey {
41    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
42    where
43        S: serde::Serializer,
44    {
45        serialize_patricia_key_to_prefixed_hex(self, serializer)
46    }
47}
48
49impl<'de> Deserialize<'de> for PatriciaKey {
50    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
51    where
52        D: Deserializer<'de>,
53    {
54        deserialize_to_prefixed_patricia_key(deserializer)
55    }
56}
57
58impl From<starknet_api::core::PatriciaKey> for PatriciaKey {
59    fn from(value: starknet_api::core::PatriciaKey) -> Self {
60        Self(*value.key())
61    }
62}
63
64impl From<PatriciaKey> for starknet_api::core::PatriciaKey {
65    fn from(value: PatriciaKey) -> Self {
66        Self::from_hex_unchecked(&value.0.to_hex_string())
67    }
68}
69
70impl TryFrom<Felt> for PatriciaKey {
71    type Error = Error;
72
73    fn try_from(value: Felt) -> Result<Self, Self::Error> {
74        Self::new(value)
75    }
76}
77
78impl From<PatriciaKey> for starknet_api::state::StorageKey {
79    fn from(value: PatriciaKey) -> Self {
80        Self(value.into())
81    }
82}
83
84pub type StorageKey = PatriciaKey;
85
86#[cfg(test)]
87mod tests {
88    use super::PatriciaKey;
89    use crate::felt::felt_from_prefixed_hex;
90
91    #[test]
92    fn creation_of_patricia_key_should_be_successful() {
93        assert!(
94            PatriciaKey::new(
95                felt_from_prefixed_hex(
96                    "0x7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
97                )
98                .unwrap()
99            )
100            .is_ok()
101        );
102    }
103
104    #[test]
105    fn patricia_key_with_too_large_felt_should_return_error() {
106        let result = PatriciaKey::new(
107            felt_from_prefixed_hex(
108                "0x800000000000000000000000000000000000000000000000000000000000001",
109            )
110            .unwrap(),
111        );
112        assert!(result.is_err());
113    }
114}