radix_substate_store_interface/
db_key_mapper.rs

1use crate::interface::*;
2use radix_common::prelude::*;
3use radix_rust::copy_u8_array;
4
5/// A mapper between the business ReNode / Partition / Substate IDs and database keys.
6pub trait DatabaseKeyMapper: 'static {
7    /// Converts the given Node ID and Partition number to the database partition's key.
8    fn to_db_partition_key(node_id: &NodeId, partition_num: PartitionNumber) -> DbPartitionKey {
9        DbPartitionKey {
10            node_key: Self::to_db_node_key(node_id),
11            partition_num: Self::to_db_partition_num(partition_num),
12        }
13    }
14
15    /// Converts database partition's key back to ReNode ID and Partition number.
16    fn from_db_partition_key(partition_key: &DbPartitionKey) -> (NodeId, PartitionNumber) {
17        (
18            Self::from_db_node_key(&partition_key.node_key),
19            Self::from_db_partition_num(partition_key.partition_num),
20        )
21    }
22
23    /// Converts the given Node ID to the database Node key.
24    fn to_db_node_key(node_id: &NodeId) -> DbNodeKey;
25
26    /// Converts the database Node key back to ReNode ID.
27    fn from_db_node_key(db_node_key: &DbNodeKey) -> NodeId;
28
29    /// Converts the given Partition number to the database Partition number.
30    fn to_db_partition_num(partition_num: PartitionNumber) -> DbPartitionNum;
31
32    /// Converts the database Partition number back to a Partition number.
33    fn from_db_partition_num(db_partition_num: DbPartitionNum) -> PartitionNumber;
34
35    /// Converts the given [`SubstateKey`] to the database's sort key.
36    /// This is a convenience method, which simply unwraps the [`SubstateKey`] and maps any specific
37    /// type found inside (see `*_to_db_sort_key()` family).
38    fn to_db_sort_key(key: &SubstateKey) -> DbSortKey {
39        match key {
40            SubstateKey::Field(fields_key) => Self::field_to_db_sort_key(fields_key),
41            SubstateKey::Map(map_key) => Self::map_to_db_sort_key(map_key),
42            SubstateKey::Sorted(sorted_key) => Self::sorted_to_db_sort_key(sorted_key),
43        }
44    }
45
46    /// Converts the given [`SubstateKeyRef`] to the database's sort key.
47    /// This is a convenience method, which simply unwraps the [`SubstateKeyRef`] and maps any specific
48    /// type found inside (see `*_to_db_sort_key()` family).
49    fn to_db_sort_key_from_ref(key: SubstateKeyRef) -> DbSortKey {
50        match key {
51            SubstateKeyRef::Field(fields_key) => Self::field_to_db_sort_key(fields_key),
52            SubstateKeyRef::Map(map_key) => Self::map_to_db_sort_key(map_key),
53            SubstateKeyRef::Sorted(sorted_key) => Self::sorted_to_db_sort_key(sorted_key),
54        }
55    }
56
57    /// Converts the given database's sort key to a [`SubstateKey`].
58    /// This is a convenience method, which simply wraps the type-specific result of an appropriate
59    /// `*_from_db_sort_key()` method into a [`SubstateKey`].
60    ///
61    /// ## Examples
62    /// ```ignore
63    /// Mapper::from_db_sort_key::<FieldKey>(&db_sort_key);
64    /// Mapper::from_db_sort_key::<MapKey>(&db_sort_key);
65    /// Mapper::from_db_sort_key::<SortedKey>(&db_sort_key);
66    /// ```
67    fn from_db_sort_key<K: SubstateKeyContent>(db_sort_key: &DbSortKey) -> SubstateKey {
68        K::from_db_key::<Self>(db_sort_key).into_typed_key()
69    }
70
71    /// ## Examples
72    /// ```ignore
73    /// Mapper::from_db_sort_key_to_inner::<FieldKey>(&db_sort_key);
74    /// Mapper::from_db_sort_key_to_inner::<MapKey>(&db_sort_key);
75    /// Mapper::from_db_sort_key_to_inner::<SortedKey>(&db_sort_key);
76    /// ```
77    fn from_db_sort_key_to_inner<K: SubstateKeyContent>(db_sort_key: &DbSortKey) -> K {
78        K::from_db_key::<Self>(db_sort_key)
79    }
80
81    // Type-specific methods for mapping the `SubstateKey` inner data to/from `DbSortKey`:
82
83    fn field_to_db_sort_key(field_key: &FieldKey) -> DbSortKey;
84    fn field_from_db_sort_key(db_sort_key: &DbSortKey) -> FieldKey;
85
86    fn map_to_db_sort_key(map_key: &MapKey) -> DbSortKey;
87    fn map_from_db_sort_key(db_sort_key: &DbSortKey) -> MapKey;
88
89    fn sorted_to_db_sort_key(sorted_key: &SortedKey) -> DbSortKey;
90    fn sorted_from_db_sort_key(db_sort_key: &DbSortKey) -> SortedKey;
91}
92
93/// A [`DatabaseKeyMapper`] tailored for databases which cannot tolerate long common prefixes
94/// among keys (for performance reasons). In other words, it spreads the keys "evenly" (i.e.
95/// pseudo-randomly) across the key space. For context: our use-case for this is the Jellyfish
96/// Merkle Tree.
97///
98/// This implementation is the actual, protocol-enforced one, to be used in public Radix networks.
99///
100/// This implementation achieves the prefix-spreading by adding a hash prefix (shortened hash for
101/// performance reasons, but still hard to crack) to:
102/// - the ReNode part of DB Partition key
103/// - the Map key and Sorted key flavors of SubstateKey
104pub struct SpreadPrefixKeyMapper;
105
106impl DatabaseKeyMapper for SpreadPrefixKeyMapper {
107    fn to_db_node_key(node_id: &NodeId) -> DbNodeKey {
108        SpreadPrefixKeyMapper::to_hash_prefixed(node_id.as_bytes())
109    }
110
111    fn from_db_node_key(db_node_key: &DbNodeKey) -> NodeId {
112        NodeId(copy_u8_array(SpreadPrefixKeyMapper::from_hash_prefixed(
113            db_node_key,
114        )))
115    }
116
117    fn to_db_partition_num(partition_num: PartitionNumber) -> DbPartitionNum {
118        partition_num.0
119    }
120
121    fn from_db_partition_num(db_partition_num: DbPartitionNum) -> PartitionNumber {
122        PartitionNumber(db_partition_num)
123    }
124
125    fn field_to_db_sort_key(fields_key: &FieldKey) -> DbSortKey {
126        DbSortKey(vec![*fields_key])
127    }
128
129    fn field_from_db_sort_key(db_sort_key: &DbSortKey) -> FieldKey {
130        db_sort_key.0[0]
131    }
132
133    fn map_to_db_sort_key(map_key: &MapKey) -> DbSortKey {
134        DbSortKey(SpreadPrefixKeyMapper::to_hash_prefixed(map_key))
135    }
136
137    fn map_from_db_sort_key(db_sort_key: &DbSortKey) -> MapKey {
138        SpreadPrefixKeyMapper::from_hash_prefixed(&db_sort_key.0).to_vec()
139    }
140
141    fn sorted_to_db_sort_key(sorted_key: &SortedKey) -> DbSortKey {
142        DbSortKey(
143            [
144                sorted_key.0.as_slice(),
145                &SpreadPrefixKeyMapper::to_hash_prefixed(&sorted_key.1),
146            ]
147            .concat(),
148        )
149    }
150
151    fn sorted_from_db_sort_key(db_sort_key: &DbSortKey) -> SortedKey {
152        (
153            copy_u8_array(&db_sort_key.0[..2]),
154            SpreadPrefixKeyMapper::from_hash_prefixed(&db_sort_key.0[2..]).to_vec(),
155        )
156    }
157}
158
159impl SpreadPrefixKeyMapper {
160    /// A number of leading bytes populated with a hash of the sort key (for spreading purposes).
161    /// This number should be:
162    /// - high enough to avoid being cracked (for crafting arbitrarily long key prefixes);
163    /// - low enough to avoid inflating database key sizes.
164    ///
165    /// Note: hashing will not be applied to [`FieldKey`] (which is a single byte, and hence does
166    /// not create the risk of long common prefixes).
167    const HASHED_PREFIX_LENGTH: usize = 20;
168
169    /// Returns the given bytes prefixed by their known-length hash (see [`Self::HASHED_PREFIX_LENGTH`]).
170    fn to_hash_prefixed(plain_bytes: &[u8]) -> Vec<u8> {
171        let hashed_prefix = &hash(plain_bytes).0[..Self::HASHED_PREFIX_LENGTH];
172        [hashed_prefix, plain_bytes].concat()
173    }
174
175    /// Returns the given slice without its known-length hash prefix (see [`HASHED_PREFIX_LENGTH`]).
176    fn from_hash_prefixed(prefixed_bytes: &[u8]) -> &[u8] {
177        &prefixed_bytes[Self::HASHED_PREFIX_LENGTH..]
178    }
179}
180
181// Internal-only trait enabling the concrete `DatabaseKeyMapper` implementations to drive their
182// logic by `SubstateKey`'s inner data type.
183
184pub trait SubstateKeyContent: Sized + 'static {
185    fn from_db_key<M: DatabaseKeyMapper + ?Sized>(db_sort_key: &DbSortKey) -> Self;
186    fn into_typed_key(self) -> SubstateKey;
187}
188
189impl SubstateKeyContent for MapKey {
190    fn from_db_key<M: DatabaseKeyMapper + ?Sized>(db_sort_key: &DbSortKey) -> Self {
191        M::map_from_db_sort_key(db_sort_key)
192    }
193
194    fn into_typed_key(self) -> SubstateKey {
195        SubstateKey::Map(self)
196    }
197}
198
199impl SubstateKeyContent for FieldKey {
200    fn from_db_key<M: DatabaseKeyMapper + ?Sized>(db_sort_key: &DbSortKey) -> Self {
201        M::field_from_db_sort_key(db_sort_key)
202    }
203
204    fn into_typed_key(self) -> SubstateKey {
205        SubstateKey::Field(self)
206    }
207}
208
209impl SubstateKeyContent for SortedKey {
210    fn from_db_key<M: DatabaseKeyMapper + ?Sized>(db_sort_key: &DbSortKey) -> Self {
211        M::sorted_from_db_sort_key(db_sort_key)
212    }
213
214    fn into_typed_key(self) -> SubstateKey {
215        SubstateKey::Sorted(self)
216    }
217}