radix_substate_store_interface/
interface.rs

1use crate::db_key_mapper::*;
2use radix_common::prelude::*;
3
4pub type DbNodeKey = Vec<u8>;
5
6pub type DbPartitionNum = u8;
7
8/// A database-level key of an entire partition.
9/// Seen from the higher-level API: it represents a pair (RE Node ID, Module ID).
10/// Seen from the lower-level implementation: it is used as a key in the upper-layer tree of our
11/// two-layered JMT.
12#[derive(Debug, Clone, Hash, PartialEq, Eq, Ord, PartialOrd, Sbor)]
13pub struct DbPartitionKey {
14    pub node_key: DbNodeKey,
15    pub partition_num: DbPartitionNum,
16}
17
18/// A database-level key of a substate within a known partition.
19/// Seen from the higher-level API: it represents a local Substate Key.
20/// Seen from the lower-level implementation: it is used as a key in the Substate-Tier JMT.
21#[derive(Debug, Clone, Hash, PartialEq, Eq, Ord, PartialOrd, Sbor)]
22pub struct DbSortKey(pub Vec<u8>);
23
24/// A fully-specified key of a substate (i.e. specifying its partition and sort key).
25pub type DbSubstateKey = (DbPartitionKey, DbSortKey);
26
27/// A key-value entry of a substate within a known partition.
28pub type PartitionEntry = (DbSortKey, DbSubstateValue);
29
30pub trait CreateDatabaseUpdates {
31    type DatabaseUpdates;
32
33    /// Uses the default [`DatabaseKeyMapper`], [`SpreadPrefixKeyMapper`], to express self using database-level key encoding.
34    fn create_database_updates(&self) -> Self::DatabaseUpdates {
35        self.create_database_updates_with_mapper::<SpreadPrefixKeyMapper>()
36    }
37
38    /// Uses the given [`DatabaseKeyMapper`] to express self using database-level key encoding.
39    fn create_database_updates_with_mapper<M: DatabaseKeyMapper>(&self) -> Self::DatabaseUpdates;
40}
41
42/// A canonical description of all database updates to be applied.
43/// Note: this struct can be migrated to an enum if we ever have a need for database-wide batch
44/// changes (see [`PartitionDatabaseUpdates`] enum).
45#[derive(Debug, Clone, PartialEq, Eq, Sbor, Default)]
46pub struct DatabaseUpdates {
47    /// Node-level updates.
48    pub node_updates: IndexMap<DbNodeKey, NodeDatabaseUpdates>,
49}
50
51impl DatabaseUpdates {
52    pub fn node_ids(&self) -> impl Iterator<Item = NodeId> + '_ {
53        self.node_updates
54            .keys()
55            .map(|key| SpreadPrefixKeyMapper::from_db_node_key(key))
56    }
57}
58
59impl CreateDatabaseUpdates for StateUpdates {
60    type DatabaseUpdates = DatabaseUpdates;
61
62    fn create_database_updates_with_mapper<M: DatabaseKeyMapper>(&self) -> DatabaseUpdates {
63        DatabaseUpdates {
64            node_updates: self
65                .by_node
66                .iter()
67                .map(|(node_id, node_state_updates)| {
68                    (
69                        M::to_db_node_key(node_id),
70                        node_state_updates.create_database_updates_with_mapper::<M>(),
71                    )
72                })
73                .collect(),
74        }
75    }
76}
77
78/// A canonical description of specific Node's updates to be applied.
79/// Note: this struct can be migrated to an enum if we ever have a need for Node-wide batch changes
80/// (see [`PartitionDatabaseUpdates`] enum).
81#[derive(Debug, Clone, PartialEq, Eq, Sbor, Default)]
82pub struct NodeDatabaseUpdates {
83    /// Partition-level updates.
84    pub partition_updates: IndexMap<DbPartitionNum, PartitionDatabaseUpdates>,
85}
86
87impl CreateDatabaseUpdates for NodeStateUpdates {
88    type DatabaseUpdates = NodeDatabaseUpdates;
89
90    fn create_database_updates_with_mapper<M: DatabaseKeyMapper>(&self) -> NodeDatabaseUpdates {
91        match self {
92            NodeStateUpdates::Delta { by_partition } => NodeDatabaseUpdates {
93                partition_updates: by_partition
94                    .iter()
95                    .map(|(partition_num, partition_state_updates)| {
96                        (
97                            M::to_db_partition_num(*partition_num),
98                            partition_state_updates.create_database_updates_with_mapper::<M>(),
99                        )
100                    })
101                    .collect(),
102            },
103        }
104    }
105}
106
107/// A canonical description of specific Partition's updates to be applied.
108#[derive(Debug, Clone, PartialEq, Eq, Sbor)]
109pub enum PartitionDatabaseUpdates {
110    /// A delta change, touching just selected substates.
111    Delta {
112        substate_updates: IndexMap<DbSortKey, DatabaseUpdate>,
113    },
114
115    /// A reset, dropping all Substates of a partition and replacing them with a new set.
116    Reset {
117        new_substate_values: IndexMap<DbSortKey, DbSubstateValue>,
118    },
119}
120
121impl PartitionDatabaseUpdates {
122    /// Returns an effective change applied to the given Substate by this Partition update.
123    /// May return [`None`] only if the Substate was unaffected.
124    ///
125    /// This method is useful for index-updating logic which does not care about the nature of the
126    /// Partition update (i.e. delta vs reset).
127    pub fn get_substate_change(&self, sort_key: &DbSortKey) -> Option<DatabaseUpdateRef> {
128        match self {
129            Self::Delta { substate_updates } => {
130                substate_updates.get(sort_key).map(|update| match update {
131                    DatabaseUpdate::Set(value) => DatabaseUpdateRef::Set(value),
132                    DatabaseUpdate::Delete => DatabaseUpdateRef::Delete,
133                })
134            }
135            Self::Reset {
136                new_substate_values,
137            } => new_substate_values
138                .get(sort_key)
139                .map(|value| DatabaseUpdateRef::Set(value))
140                .or_else(|| Some(DatabaseUpdateRef::Delete)),
141        }
142    }
143}
144
145impl CreateDatabaseUpdates for PartitionStateUpdates {
146    type DatabaseUpdates = PartitionDatabaseUpdates;
147
148    fn create_database_updates_with_mapper<M: DatabaseKeyMapper>(
149        &self,
150    ) -> PartitionDatabaseUpdates {
151        match self {
152            PartitionStateUpdates::Delta { by_substate } => PartitionDatabaseUpdates::Delta {
153                substate_updates: by_substate
154                    .iter()
155                    .map(|(key, update)| (M::to_db_sort_key(key), update.clone()))
156                    .collect(),
157            },
158            PartitionStateUpdates::Batch(batch) => batch.create_database_updates_with_mapper::<M>(),
159        }
160    }
161}
162
163impl CreateDatabaseUpdates for BatchPartitionStateUpdate {
164    type DatabaseUpdates = PartitionDatabaseUpdates;
165
166    fn create_database_updates_with_mapper<M: DatabaseKeyMapper>(
167        &self,
168    ) -> PartitionDatabaseUpdates {
169        match self {
170            BatchPartitionStateUpdate::Reset {
171                new_substate_values,
172            } => PartitionDatabaseUpdates::Reset {
173                new_substate_values: new_substate_values
174                    .iter()
175                    .map(|(key, value)| (M::to_db_sort_key(key), value.clone()))
176                    .collect(),
177            },
178        }
179    }
180}
181
182impl Default for PartitionDatabaseUpdates {
183    fn default() -> Self {
184        Self::Delta {
185            substate_updates: index_map_new(),
186        }
187    }
188}
189
190impl DatabaseUpdates {
191    /// Constructs an instance from the given legacy representation (a map of maps), which is only
192    /// capable of specifying "deltas" (i.e. individual substate changes; no partition deletes).
193    ///
194    /// Note: This method is only meant for tests/demos - with regular Engine usage, the
195    /// [`DatabaseUpdates`] can be obtained directly from the receipt.
196    pub fn from_delta_maps(
197        maps: IndexMap<DbPartitionKey, IndexMap<DbSortKey, DatabaseUpdate>>,
198    ) -> DatabaseUpdates {
199        let mut database_updates = DatabaseUpdates::default();
200        for (
201            DbPartitionKey {
202                node_key,
203                partition_num,
204            },
205            substate_updates,
206        ) in maps
207        {
208            database_updates
209                .node_updates
210                .entry(node_key)
211                .or_default()
212                .partition_updates
213                .insert(
214                    partition_num,
215                    PartitionDatabaseUpdates::Delta { substate_updates },
216                );
217        }
218        database_updates
219    }
220}
221
222/// A read interface between Track and a database vendor.
223pub trait SubstateDatabase {
224    /// Reads a substate value by its db partition and db sort key, or [`Option::None`] if missing.
225    ///
226    /// ## Alternatives
227    ///
228    /// It's likely easier to use the [`get_substate`][SubstateDatabaseExtensions::get_substate] or
229    /// [`get_raw_substate`][SubstateDatabaseExtensions::get_raw_substate] methods instead, which
230    /// allow providing logical keys.
231    /// These methods should also exist on the database type as long as the
232    /// [`SubstateDatabaseExtensions`] trait is in scope.
233    fn get_raw_substate_by_db_key(
234        &self,
235        partition_key: &DbPartitionKey,
236        sort_key: &DbSortKey,
237    ) -> Option<DbSubstateValue>;
238
239    /// Iterates over all entries of the given partition (starting either from the beginning, or
240    /// from the given [`DbSortKey`]), in a lexicographical order (ascending) of the [`DbSortKey`]s.
241    /// Note: If the exact given starting key does not exist, the iteration starts with its
242    /// immediate successor.
243    ///
244    /// ## Alternatives
245    ///
246    /// There are lots of methods starting `list_` which allow iterating using more intuitive abstractions.
247    /// These methods are present as long as the [`SubstateDatabaseExtensions`] trait is in scope.
248    fn list_raw_values_from_db_key(
249        &self,
250        partition_key: &DbPartitionKey,
251        from_sort_key: Option<&DbSortKey>,
252    ) -> Box<dyn Iterator<Item = PartitionEntry> + '_>;
253}
254
255impl<T: SubstateDatabase + ?Sized> SubstateDatabaseExtensions for T {}
256
257/// These are a separate trait so that [`SubstateDatabase`] stays object-safe,
258/// and can be used as `dyn SubstateDatabase`.
259///
260/// Generic parameters aren't permitted on object-safe traits.
261pub trait SubstateDatabaseExtensions: SubstateDatabase {
262    /// Gets the raw bytes of the substate's value, if it exists.
263    ///
264    /// # Example
265    /// ```ignore
266    /// let is_bootstrapped = db.get_raw_substate(
267    ///     PACKAGE_PACKAGE,
268    ///     TYPE_INFO_FIELD_PARTITION,
269    ///     TypeInfoField::TypeInfo,
270    /// ).is_some();
271    /// ```
272    fn get_raw_substate<'a>(
273        &self,
274        node_id: impl AsRef<NodeId>,
275        partition_number: PartitionNumber,
276        substate_key: impl ResolvableSubstateKey<'a>,
277    ) -> Option<Vec<u8>> {
278        self.get_raw_substate_by_db_key(
279            &db_partition_key(node_id, partition_number),
280            &db_sort_key(substate_key),
281        )
282    }
283
284    /// Gets the substate's value, if it exists, and returns it decoded as `Some(V)`.
285    /// If it doesn't exist, `None` is returned.
286    ///
287    /// # Panics
288    /// This method panics if:
289    /// * There is an error decoding the value into the `V`.
290    ///
291    /// # Example use:
292    /// ```ignore
293    /// let type_info_substate = db.get_substate::<TypeInfoSubstate>(
294    ///     PACKAGE_PACKAGE,
295    ///     TYPE_INFO_FIELD_PARTITION,
296    ///     TypeInfoField::TypeInfo,
297    /// )?;
298    /// ```
299    fn get_substate<'a, V: ScryptoDecode>(
300        &self,
301        node_id: impl AsRef<NodeId>,
302        partition_number: PartitionNumber,
303        substate_key: impl ResolvableSubstateKey<'a>,
304    ) -> Option<V> {
305        let raw = self.get_raw_substate(node_id, partition_number, substate_key)?;
306        Some(decode_value(&raw))
307    }
308
309    /// Gets the value of a subsate which is expected to exist, returns it decoded as `V`.
310    ///
311    /// # Panics
312    /// This method panics if:
313    /// * The substate doesn't exist in the database.
314    /// * There is an error decoding the value into the `V`.
315    ///
316    /// # Example use:
317    /// ```ignore
318    /// let existing_type_info_substate: TypeInfoSubstate = db.get_existing_substate(
319    ///     PACKAGE_PACKAGE,
320    ///     TYPE_INFO_FIELD_PARTITION,
321    ///     TypeInfoField::TypeInfo,
322    /// )?;
323    /// ```
324    fn get_existing_substate<'a, V: ScryptoDecode>(
325        &self,
326        node_id: impl AsRef<NodeId>,
327        partition_number: PartitionNumber,
328        substate_key: impl ResolvableSubstateKey<'a>,
329    ) -> V {
330        let substate_value = self.get_substate(node_id, partition_number, substate_key);
331        substate_value.unwrap_or_else(|| {
332            panic!(
333                "Expected substate of type {} to already exist.",
334                core::any::type_name::<V>(),
335            )
336        })
337    }
338
339    // ------------------------------------------------------------------------------------
340    // LIST RAW
341    // ------------------------------------------------------------------------------------
342
343    /// Returns an iterator of the substates of a partition from an inclusive start cursor.
344    ///
345    /// The iterator returns raw keys and values.
346    ///
347    /// Pass `None::<SubstateKey>` as the cursor to iterate from the start of the partition.
348    #[inline]
349    fn list_raw_values<'a>(
350        &self,
351        node_id: impl AsRef<NodeId>,
352        partition_number: PartitionNumber,
353        from_substate_key_inclusive: impl ResolvableOptionalSubstateKey<'a>,
354    ) -> Box<dyn Iterator<Item = (DbSortKey, Vec<u8>)> + '_> {
355        self.list_raw_values_from_db_key(
356            &db_partition_key(node_id, partition_number),
357            optional_db_sort_key(from_substate_key_inclusive).as_ref(),
358        )
359    }
360
361    // ------------------------------------------------------------------------------------
362    // LIST KINDED PARTITIONS (OF A KNOWN BUT GENERIC KIND)
363    // ------------------------------------------------------------------------------------
364    // NOTE: There is not `list_kinded_entries` because mapping of the key requires knowing
365    // the specific kind of the substate key.
366    // ------------------------------------------------------------------------------------
367
368    /// Returns an iterator of the substates of a partition from an inclusive start cursor.
369    ///
370    /// The iterator returns `K` and the raw value for each substate.
371    /// The caller must specify `K` as [`FieldKey`], [`MapKey`] or [`SortedKey`].
372    ///
373    /// Pass `None::<SubstateKey>` as the cursor to iterate from the start of the partition.
374    fn list_kinded_raw_values<'a, K: SubstateKeyContent>(
375        &self,
376        node_id: impl AsRef<NodeId>,
377        partition_number: PartitionNumber,
378        from_substate_key_inclusive: impl ResolvableOptionalSubstateKey<'a>,
379    ) -> Box<dyn Iterator<Item = (K, Vec<u8>)> + '_> {
380        let iterable = self
381            .list_raw_values_from_db_key(
382                &db_partition_key(node_id, partition_number),
383                optional_db_sort_key(from_substate_key_inclusive).as_ref(),
384            )
385            .map(|(db_sort_key, raw_value)| {
386                (
387                    SpreadPrefixKeyMapper::from_db_sort_key_to_inner::<K>(&db_sort_key),
388                    raw_value,
389                )
390            });
391        Box::new(iterable)
392    }
393
394    /// Returns an iterator of the substates of a partition from an inclusive start cursor.
395    ///
396    /// The iterator returns `K` and `V` for each substate.
397    /// The caller must specify `K` as [`FieldKey`], [`MapKey`] or [`SortedKey`].
398    /// The value type `V` can be specified or inferred.
399    ///
400    /// Pass `None::<SubstateKey>` as the cursor to iterate from the start of the partition.
401    ///
402    /// # Panics
403    /// This method panics if:
404    /// * There is an error decoding the value bytes into `V`.
405    fn list_kinded_values<'a, K: SubstateKeyContent, V: ScryptoDecode>(
406        &self,
407        node_id: impl AsRef<NodeId>,
408        partition_number: PartitionNumber,
409        from_substate_key_inclusive: impl ResolvableOptionalSubstateKey<'a>,
410    ) -> Box<dyn Iterator<Item = (K, V)> + '_> {
411        let iterator = self
412            .list_raw_values(node_id, partition_number, from_substate_key_inclusive)
413            .map(|(db_sort_key, raw_value)| {
414                (
415                    SpreadPrefixKeyMapper::from_db_sort_key_to_inner::<K>(&db_sort_key),
416                    decode_value::<V>(&raw_value),
417                )
418            });
419        Box::new(iterator)
420    }
421
422    // ------------------------------------------------------------------------------------
423    // LIST FIELD PARTITIONS
424    // ------------------------------------------------------------------------------------
425
426    /// Returns an iterator of the substates of a field partition from an inclusive start cursor.
427    ///
428    /// The iterator returns the `FieldKey = u8` and the raw value for each substate.
429    ///
430    /// Pass `None::<SubstateKey>` as the cursor to iterate from the start of the partition.
431    fn list_field_raw_values<'a>(
432        &self,
433        node_id: impl AsRef<NodeId>,
434        partition_number: PartitionNumber,
435        from_substate_key_inclusive: impl ResolvableOptionalSubstateKey<'a>,
436    ) -> Box<dyn Iterator<Item = (FieldKey, Vec<u8>)> + '_> {
437        self.list_kinded_raw_values::<FieldKey>(
438            node_id,
439            partition_number,
440            from_substate_key_inclusive,
441        )
442    }
443
444    /// Returns an iterator of the substates of a field partition from an inclusive start cursor.
445    ///
446    /// The iterator returns the `FieldKey = u8` and the decoded value `V` for each substate.
447    /// The value type `V` can be specified or inferred.
448    ///
449    /// Pass `None::<SubstateKey>` as the cursor to iterate from the start of the partition.
450    ///
451    /// # Panics
452    /// This method panics if:
453    /// * There is an error decoding the value bytes into `V`.
454    fn list_field_values<'a, V: ScryptoDecode>(
455        &self,
456        node_id: impl AsRef<NodeId>,
457        partition_number: PartitionNumber,
458        from_substate_key_inclusive: impl ResolvableOptionalSubstateKey<'a>,
459    ) -> Box<dyn Iterator<Item = (FieldKey, V)> + '_> {
460        self.list_kinded_values::<FieldKey, V>(
461            node_id,
462            partition_number,
463            from_substate_key_inclusive,
464        )
465    }
466
467    /// Returns an iterator of the substates of a field partition from an inclusive start cursor.
468    ///
469    /// The iterator returns the decoded key type `K` and the decoded value `V` for each substate.
470    /// The key type `K` and value types `V` can be specified or inferred.
471    ///
472    /// Pass `None::<SubstateKey>` as the cursor to iterate from the start of the partition.
473    ///
474    /// # Panics
475    /// This method panics if:
476    /// * There is an error converting the field key byte into `K`.
477    /// * There is an error decoding the value bytes into `V`.
478    fn list_field_entries<'a, K: TryFrom<FieldKey>, V: ScryptoDecode>(
479        &self,
480        node_id: impl AsRef<NodeId>,
481        partition_number: PartitionNumber,
482        from_substate_key_inclusive: impl ResolvableOptionalSubstateKey<'a>,
483    ) -> Box<dyn Iterator<Item = (K, V)> + '_> {
484        let iterator = self
485            .list_raw_values(node_id, partition_number, from_substate_key_inclusive)
486            .map(|(db_sort_key, raw_value)| {
487                (
488                    K::try_from(SpreadPrefixKeyMapper::from_db_sort_key_to_inner::<FieldKey>(&db_sort_key))
489                        .unwrap_or_else(|_| panic!("The field key type should be able to be decoded from the substate's key")),
490                    decode_value::<V>(&raw_value),
491                )
492            });
493        Box::new(iterator)
494    }
495
496    // ------------------------------------------------------------------------------------
497    // LIST MAP PARTITIONS
498    // ------------------------------------------------------------------------------------
499
500    /// Returns an iterator of the substates of a map partition from an inclusive start cursor.
501    ///
502    /// The iterator returns the `MapKey = Vec<u8>` and the raw value for each substate.
503    ///
504    /// Pass `None::<SubstateKey>` as the cursor to iterate from the start of the partition.
505    fn list_map_raw_values<'a>(
506        &self,
507        node_id: impl AsRef<NodeId>,
508        partition_number: PartitionNumber,
509        from_substate_key_inclusive: impl ResolvableOptionalSubstateKey<'a>,
510    ) -> Box<dyn Iterator<Item = (MapKey, Vec<u8>)> + '_> {
511        self.list_kinded_raw_values::<MapKey>(
512            node_id,
513            partition_number,
514            from_substate_key_inclusive,
515        )
516    }
517
518    /// Returns an iterator of the substates of a map partition from an inclusive start cursor.
519    ///
520    /// The iterator returns the `MapKey = Vec<u8>` and the decoded value `V` for each substate.
521    /// The value type `V` can be specified or inferred.
522    ///
523    /// Pass `None::<SubstateKey>` as the cursor to iterate from the start of the partition.
524    ///
525    /// # Panics
526    /// This method panics if:
527    /// * There is an error decoding the value bytes into `V`.
528    fn list_map_values<'a, V: ScryptoDecode>(
529        &self,
530        node_id: impl AsRef<NodeId>,
531        partition_number: PartitionNumber,
532        from_substate_key_inclusive: impl ResolvableOptionalSubstateKey<'a>,
533    ) -> Box<dyn Iterator<Item = (MapKey, V)> + '_> {
534        self.list_kinded_values::<MapKey, V>(node_id, partition_number, from_substate_key_inclusive)
535    }
536
537    /// Returns an iterator of the substates of a map partition from an inclusive start cursor.
538    ///
539    /// The iterator returns the decoded key type `K` and the decoded value `V` for each substate.
540    /// The key type `K` and value types `V` can be specified or inferred.
541    ///
542    /// Pass `None::<SubstateKey>` as the cursor to iterate from the start of the partition.
543    ///
544    /// # Panics
545    /// This method panics if:
546    /// * There is an error decoding the field bytes into `K`.
547    /// * There is an error decoding the value bytes into `V`.
548    fn list_map_entries<'a, K: ScryptoDecode, V: ScryptoDecode>(
549        &self,
550        node_id: impl AsRef<NodeId>,
551        partition_number: PartitionNumber,
552        from_substate_key_inclusive: impl ResolvableOptionalSubstateKey<'a>,
553    ) -> Box<dyn Iterator<Item = (K, V)> + '_> {
554        let iterator = self
555            .list_map_raw_values(node_id, partition_number, from_substate_key_inclusive)
556            .map(|(raw_key, raw_value)| (decode_key::<K>(&raw_key), decode_value::<V>(&raw_value)));
557        Box::new(iterator)
558    }
559
560    // ------------------------------------------------------------------------------------
561    // LIST SORTED PARTITIONS
562    // ------------------------------------------------------------------------------------
563
564    /// Returns an iterator of the substates of a sorted partition from an inclusive start cursor.
565    ///
566    /// The iterator returns the `SortedKey = ([u8; 2], Vec<u8>)` and the raw value for each substate.
567    ///
568    /// Pass `None::<SubstateKey>` as the cursor to iterate from the start of the partition.
569    fn list_sorted_raw_values<'a>(
570        &self,
571        node_id: impl AsRef<NodeId>,
572        partition_number: PartitionNumber,
573        from_substate_key_inclusive: impl ResolvableOptionalSubstateKey<'a>,
574    ) -> Box<dyn Iterator<Item = (SortedKey, Vec<u8>)> + '_> {
575        self.list_kinded_raw_values::<SortedKey>(
576            node_id,
577            partition_number,
578            from_substate_key_inclusive,
579        )
580    }
581
582    /// Returns an iterator of the substates of a sorted partition from an inclusive start cursor.
583    ///
584    /// The iterator returns the `SortedKey = ([u8; 2], Vec<u8>)` and the decoded value `V`
585    /// for each substate. The value type `V` can be specified or inferred.
586    ///
587    /// Pass `None::<SubstateKey>` as the cursor to iterate from the start of the partition.
588    ///
589    /// # Panics
590    /// This method panics if:
591    /// * There is an error decoding the value bytes into `V`.
592    fn list_sorted_values<'a, V: ScryptoDecode>(
593        &self,
594        node_id: impl AsRef<NodeId>,
595        partition_number: PartitionNumber,
596        from_substate_key_inclusive: impl ResolvableOptionalSubstateKey<'a>,
597    ) -> Box<dyn Iterator<Item = (SortedKey, V)> + '_> {
598        self.list_kinded_values::<SortedKey, V>(
599            node_id,
600            partition_number,
601            from_substate_key_inclusive,
602        )
603    }
604}
605
606fn db_partition_key(
607    node_id: impl AsRef<NodeId>,
608    partition_number: PartitionNumber,
609) -> DbPartitionKey {
610    SpreadPrefixKeyMapper::to_db_partition_key(node_id.as_ref(), partition_number)
611}
612
613fn db_sort_key<'a>(substate_key: impl ResolvableSubstateKey<'a>) -> DbSortKey {
614    SpreadPrefixKeyMapper::to_db_sort_key_from_ref(substate_key.into_substate_key_or_ref().as_ref())
615}
616
617fn optional_db_sort_key<'a>(
618    optional_substate_key: impl ResolvableOptionalSubstateKey<'a>,
619) -> Option<DbSortKey> {
620    optional_substate_key
621        .into_optional_substate_key_or_ref()
622        .map(|key_or_ref| SpreadPrefixKeyMapper::to_db_sort_key_from_ref(key_or_ref.as_ref()))
623}
624
625fn decode_key<K: ScryptoDecode>(raw: &[u8]) -> K {
626    scrypto_decode::<K>(&raw).unwrap_or_else(|err| {
627        panic!(
628            "Expected key to be decodable as {}. Error: {:?}.",
629            core::any::type_name::<K>(),
630            err,
631        )
632    })
633}
634
635fn decode_value<V: ScryptoDecode>(raw: &[u8]) -> V {
636    scrypto_decode::<V>(&raw).unwrap_or_else(|err| {
637        panic!(
638            "Expected value to be decodable as {}. Error: {:?}.",
639            core::any::type_name::<V>(),
640            err,
641        )
642    })
643}
644
645/// A write interface between Track and a database vendor.
646pub trait CommittableSubstateDatabase {
647    /// Commits state changes to the database.
648    fn commit(&mut self, database_updates: &DatabaseUpdates);
649}
650
651impl<T: CommittableSubstateDatabase + ?Sized> CommittableSubstateDatabaseExtensions for T {}
652
653pub trait CommittableSubstateDatabaseExtensions: CommittableSubstateDatabase {
654    fn update_substate_raw<'a>(
655        &mut self,
656        node_id: impl AsRef<NodeId>,
657        partition_number: PartitionNumber,
658        substate_key: impl ResolvableSubstateKey<'a>,
659        value: Vec<u8>,
660    ) {
661        self.commit(&DatabaseUpdates::from_delta_maps(indexmap!(
662            SpreadPrefixKeyMapper::to_db_partition_key(
663                node_id.as_ref(),
664                partition_number,
665            ) => indexmap!(
666                SpreadPrefixKeyMapper::to_db_sort_key_from_ref(
667                    substate_key.into_substate_key_or_ref().as_ref(),
668                ) => DatabaseUpdate::Set(
669                    value
670                )
671            )
672        )))
673    }
674
675    fn delete_substate<'a>(
676        &mut self,
677        node_id: impl AsRef<NodeId>,
678        partition_number: PartitionNumber,
679        substate_key: impl ResolvableSubstateKey<'a>,
680    ) {
681        self.commit(&DatabaseUpdates::from_delta_maps(indexmap!(
682            SpreadPrefixKeyMapper::to_db_partition_key(
683                node_id.as_ref(),
684                partition_number,
685            ) => indexmap!(
686                SpreadPrefixKeyMapper::to_db_sort_key_from_ref(
687                    substate_key.into_substate_key_or_ref().as_ref(),
688                ) => DatabaseUpdate::Delete,
689            )
690        )))
691    }
692
693    fn update_substate<'a, E: ScryptoEncode>(
694        &mut self,
695        node_id: impl AsRef<NodeId>,
696        partition_number: PartitionNumber,
697        substate_key: impl ResolvableSubstateKey<'a>,
698        value: E,
699    ) {
700        let encoded_value = scrypto_encode(&value).unwrap_or_else(|err| {
701            panic!(
702                "Expected value to be encodable as {}. Error: {:?}.",
703                core::any::type_name::<E>(),
704                err,
705            )
706        });
707        self.update_substate_raw(node_id, partition_number, substate_key, encoded_value)
708    }
709}
710
711/// A partition listing interface between Track and a database vendor.
712pub trait ListableSubstateDatabase {
713    /// Iterates over all partition keys, in an arbitrary order.
714    ///
715    /// ## Alternatives
716    /// You likely want to use the [`read_partition_keys`][ListableSubstateDatabaseExtensions::read_partition_keys]
717    /// method instead, which returns an unmapped key. This is available if
718    /// the trait [`ListableSubstateDatabaseExtensions`] is in scope.
719    fn list_partition_keys(&self) -> Box<dyn Iterator<Item = DbPartitionKey> + '_>;
720}
721
722impl<T: ListableSubstateDatabase + ?Sized> ListableSubstateDatabaseExtensions for T {}
723
724/// These are a separate trait so that [`ListableSubstateDatabase`] stays object-safe,
725/// and can be used as `dyn ListableSubstateDatabase`.
726///
727/// Generic parameters aren't permitted on object-safe traits.
728pub trait ListableSubstateDatabaseExtensions: ListableSubstateDatabase {
729    fn read_partition_keys(&self) -> Box<dyn Iterator<Item = (NodeId, PartitionNumber)> + '_> {
730        let iterator = self
731            .list_partition_keys()
732            .map(|key| SpreadPrefixKeyMapper::from_db_partition_key(&key));
733        Box::new(iterator)
734    }
735}