Skip to main content

drive/util/grove_operations/
mod.rs

1//! Grove Operations.
2//!
3//! Defines and implements in Drive functions pertinent to groveDB operations.
4//!
5
6/// Grove insert operation
7pub mod grove_insert;
8
9/// Grove insert operation into an empty tree
10pub mod grove_insert_empty_tree;
11
12/// Grove insert operation, but only if it doesn't already exist
13pub mod grove_insert_if_not_exists;
14
15/// Grove delete operation
16pub mod grove_delete;
17
18/// Fetch raw grove data
19pub mod grove_get_raw;
20
21/// Fetch raw grove data and match that is item
22pub mod grove_get_raw_item;
23
24/// Fetch raw grove data if it exists
25pub mod grove_get_raw_optional;
26
27/// Fetch u64 value from encoded variable vector in raw grove data
28pub mod grove_get_raw_value_u64_from_encoded_var_vec;
29
30/// Grove get operation
31pub mod grove_get;
32
33/// Serialized results from grove path query
34pub mod grove_get_path_query_serialized_results;
35
36/// Grove path query operation
37pub mod grove_get_path_query;
38
39/// Grove path query operation with optional return value
40pub mod grove_get_path_query_with_optional;
41
42/// Fetch raw data from grove path query with optional return value
43pub mod grove_get_raw_path_query_with_optional;
44
45/// Fetch raw data from grove path query
46pub mod grove_get_raw_path_query;
47
48/// Proved path query in grove
49pub mod grove_get_proved_path_query;
50
51/// V1 proved path query in grove (supports BulkAppendTree/CommitmentTree)
52pub mod grove_get_proved_path_query_v1;
53
54/// Get total count from a CommitmentTree
55pub mod grove_commitment_tree_count;
56
57/// Proved branch chunk query in grove
58pub mod grove_get_proved_branch_chunk_query;
59
60/// Proved trunk chunk query in grove
61pub mod grove_get_proved_trunk_chunk_query;
62
63/// Get total value from sum tree in grove
64pub mod grove_get_sum_tree_total_value;
65
66/// Check if raw data exists in grove
67pub mod grove_has_raw;
68
69/// Batch insert operation into empty tree
70pub mod batch_insert_empty_tree;
71
72/// Batch insert operation into empty sum tree
73pub mod batch_insert_empty_sum_tree;
74
75/// Batch insert operation into empty count tree (O(1) total count)
76pub mod batch_insert_empty_count_tree;
77
78/// Batch insert operation into empty count-sum tree (O(1) totals for both
79/// count and sum, no per-node aggregation). Used when a document type
80/// opts into BOTH `documentsCountable` and `documentsSummable` without
81/// any range-* flags.
82pub mod batch_insert_empty_count_sum_tree;
83
84/// Batch insert operation into empty provable count tree (range-countable)
85pub mod batch_insert_empty_provable_count_tree;
86
87/// Batch insert operation into empty provable sum tree (range-summable).
88/// Mirrors [`batch_insert_empty_provable_count_tree`] for the sum surface
89/// — commits per-node aggregated sums to every internal merk node so
90/// range queries land on an O(log n) `AggregateSumOnRange` proof.
91pub mod batch_insert_empty_provable_sum_tree;
92
93/// Batch insert operation into empty provable count-sum tree (combined
94/// count+sum surface). Used when an index opts into both `rangeCountable`
95/// and `rangeSummable` — a single tree carries both metrics per-node.
96/// Lights up once grovedb PR 670 ships `Element::ProvableCountSumTree`
97/// as a callable element variant.
98pub mod batch_insert_empty_provable_count_sum_tree;
99
100/// Batch insert operation into empty provable-count + provable-sum tree
101/// (PCPS, the fully-provable combined surface). Used when an index opts
102/// into BOTH `rangeCountable: true` AND `rangeSummable: true` —
103/// per-node counts AND per-node sums are committed to every internal
104/// merk node so range queries can answer
105/// `AggregateCountOnRange`/`AggregateSumOnRange` (and the combined
106/// variant once grovedb PR 670 ships) over the same tree.
107pub mod batch_insert_empty_provable_count_provable_sum_tree;
108
109/// Batch insert operation into an empty provable count-**indexed** tree
110/// (PCIT, grovedb PR 657). Same primary node shape as
111/// [`batch_insert_empty_provable_count_tree`], plus one ordered secondary
112/// Merk keyed by each child's aggregate count — the storage primitive behind
113/// `rankedCountable`.
114pub mod batch_insert_empty_provable_count_indexed_tree;
115
116/// Batch insert operation into an empty provable sum-**indexed** tree
117/// (PSIT, grovedb PR 657). Sum-axis mirror of
118/// [`batch_insert_empty_provable_count_indexed_tree`] — the storage primitive
119/// behind `rankedSummable` on a sum-only range layout.
120pub mod batch_insert_empty_provable_sum_indexed_tree;
121
122/// Batch insert operation into an empty provable-count + provable-sum
123/// **indexed** tree (PCPSIT, grovedb PR 657). Primary mirrors
124/// [`batch_insert_empty_provable_count_provable_sum_tree`]; the element
125/// carries a canonical TLV of 1..=3 ordered secondaries (Count / Sum / Avg).
126/// This is the arm every ranked index takes whose range layout is PCPS.
127pub mod batch_insert_empty_provable_count_provable_sum_indexed_tree;
128
129/// Batch insert operation into empty tree, but only if it doesn't already exist
130pub mod batch_insert_empty_tree_if_not_exists;
131
132/// Batch insert operation into empty tree, but only if it doesn't exist and check existing operations
133pub mod batch_insert_empty_tree_if_not_exists_check_existing_operations;
134
135/// Batch insert operation
136pub mod batch_insert;
137
138/// Batch replace operation
139pub mod batch_replace;
140
141/// Batch insert operation, but only if it doesn't already exist
142pub mod batch_insert_if_not_exists;
143
144/// Batch insert operation, but only if the value has changed
145pub mod batch_insert_if_changed_value;
146
147/// Batch delete operation
148pub mod batch_delete;
149
150/// Batch remove raw data operation
151pub mod batch_remove_raw;
152
153/// Batch delete operation up the tree while it's empty
154pub mod batch_delete_up_tree_while_empty;
155
156/// The pending grove operations GroveDB reads while it builds a delete
157pub(crate) mod pending_grove_operations;
158
159/// Batch refresh reference operation
160pub mod batch_refresh_reference;
161
162/// Apply grove operation
163pub mod grove_apply_operation;
164
165/// Apply batch grove operation
166pub mod grove_apply_batch;
167
168/// Apply batch grove operation with additional costs
169pub mod grove_apply_batch_with_add_costs;
170
171/// Apply partial batch grove operation
172pub mod grove_apply_partial_batch;
173
174/// Apply partial batch grove operation with additional costs
175pub mod grove_apply_partial_batch_with_add_costs;
176
177/// Get cost of grove batch operations
178pub mod grove_batch_operations_costs;
179
180/// Clear a subtree in grovedb
181pub mod grove_clear;
182
183/// Provides functionality to delete items in a path based on a query.
184pub mod batch_delete_items_in_path_query;
185
186/// Inserts an element if it does not exist and returns the existing element if it does.
187pub mod batch_insert_if_not_exists_return_existing_element;
188
189/// Inserts a sum item or adds to it if it already exists.
190pub mod batch_insert_sum_item_or_add_to_if_already_exists;
191
192/// Retrieves serialized or sum results from a path query in GroveDB.
193mod grove_get_path_query_serialized_or_sum_results;
194
195/// Executes a proved path query in GroveDB with an optional conditional query.
196pub mod grove_get_proved_path_query_with_conditional;
197
198/// Inserts an element if it does not exist and returns the existing element if it does in GroveDB.
199pub mod grove_insert_if_not_exists_return_existing_element;
200
201/// Batch inserts sum item if not already existing
202pub mod batch_insert_sum_item_if_not_exists;
203/// Moved items that are found in a path query to a new path.
204pub mod batch_move_items_in_path_query;
205
206/// Batch inserts item with sum item if not already existing
207pub mod batch_insert_item_with_sum_item_if_not_exists;
208/// Keeps the item, but inserts or adds to the sum item if it already exists
209pub mod batch_keep_item_insert_sum_item_or_add_to_if_already_exists;
210mod batch_move;
211/// Get the total value from a big sum tree
212pub mod grove_get_big_sum_tree_total_value;
213/// Get total value from sum tree in grove if it exists
214pub mod grove_get_optional_sum_tree_total_value;
215/// Fetch raw grove data if it exists, None otherwise
216pub mod grove_get_raw_optional_item;
217
218use grovedb_costs::CostContext;
219
220use grovedb::{EstimatedLayerInformation, MaybeTree, TreeType};
221
222use crate::error::Error;
223use crate::fees::op::LowLevelDriveOperation;
224use crate::fees::op::LowLevelDriveOperation::CalculatedCostOperation;
225
226use grovedb::Error as GroveError;
227
228use intmap::IntMap;
229
230/// Pushes an operation's `OperationCost` to `drive_operations` given its `CostContext`
231/// and returns the operation's return value.
232pub(crate) fn push_drive_operation_result<T>(
233    cost_context: CostContext<Result<T, GroveError>>,
234    drive_operations: &mut Vec<LowLevelDriveOperation>,
235) -> Result<T, Error> {
236    let CostContext { value, cost } = cost_context;
237    if !cost.is_nothing() {
238        drive_operations.push(CalculatedCostOperation(cost));
239    }
240    value.map_err(Error::from)
241}
242
243/// Pushes an operation's `OperationCost` to `drive_operations` given its `CostContext`
244/// if `drive_operations` is given. Returns the operation's return value.
245fn push_drive_operation_result_optional<T>(
246    cost_context: CostContext<Result<T, GroveError>>,
247    drive_operations: Option<&mut Vec<LowLevelDriveOperation>>,
248) -> Result<T, Error> {
249    let CostContext { value, cost } = cost_context;
250    if let Some(drive_operations) = drive_operations {
251        drive_operations.push(CalculatedCostOperation(cost));
252    }
253    value.map_err(Error::from)
254}
255/// Is subtree?
256pub type IsSubTree = bool;
257/// Is sum subtree?
258pub type IsSumSubTree = bool;
259/// Is sum tree?
260pub type IsSumTree = bool;
261
262/// Batch delete apply type
263#[derive(Debug, Copy, Clone)]
264pub enum BatchDeleteApplyType {
265    /// Stateless batch delete
266    StatelessBatchDelete {
267        /// Are we deleting in a sum tree
268        in_tree_type: TreeType,
269        /// What is the estimated key size
270        estimated_key_size: u32,
271        /// What is the estimated value size
272        estimated_value_size: u32,
273    },
274    /// Stateful batch delete
275    StatefulBatchDelete {
276        /// Are we known to be in a subtree and does this subtree have sums
277        is_known_to_be_subtree_with_sum: Option<MaybeTree>,
278    },
279}
280
281/// Batch move apply type
282#[derive(Debug, Copy, Clone)]
283pub enum BatchMoveApplyType {
284    /// Stateless batch move
285    StatelessBatchMove {
286        /// What type of tree are we in for the move
287        in_tree_type: TreeType,
288        /// Are we moving a trees?
289        tree_type: Option<TreeType>,
290        /// What is the estimated key size
291        estimated_key_size: u32,
292        /// What is the estimated value size
293        estimated_value_size: u32,
294        /// The flags length
295        flags_len: FlagsLen,
296    },
297    /// Stateful batch move
298    StatefulBatchMove {
299        /// Are we known to be in a subtree and does this subtree have sums
300        is_known_to_be_subtree_with_sum: Option<MaybeTree>,
301    },
302}
303
304#[derive(Clone)]
305/// Batch delete up tree apply type
306pub enum BatchDeleteUpTreeApplyType {
307    /// Stateless batch delete
308    StatelessBatchDelete {
309        /// The estimated layer info
310        estimated_layer_info: IntMap<u16, EstimatedLayerInformation>,
311    },
312    /// Stateful batch delete
313    StatefulBatchDelete {
314        /// Are we known to be in a subtree and does this subtree have sums
315        is_known_to_be_subtree_with_sum: Option<MaybeTree>,
316    },
317}
318
319/// batch insert tree apply type
320#[derive(Clone, Copy)]
321/// Batch insert tree apply type
322pub enum BatchInsertTreeApplyType {
323    /// Stateless batch insert tree
324    StatelessBatchInsertTree {
325        /// Does this tree use sums?
326        in_tree_type: TreeType,
327        /// Are we inserting in a sum tree
328        tree_type: TreeType,
329        /// The flags length
330        flags_len: FlagsLen,
331    },
332    /// Stateful batch insert tree
333    StatefulBatchInsertTree,
334}
335
336/// Represents the types for batch insert operations in a tree structure.
337impl BatchInsertTreeApplyType {
338    /// Converts the current `BatchInsertTreeApplyType` into a corresponding `DirectQueryType`.
339    ///
340    /// # Returns
341    ///
342    /// - A variant of `DirectQueryType::StatelessDirectQuery` if the current type is `BatchInsertTreeApplyType::StatelessBatchInsertTree`.
343    /// - `DirectQueryType::StatefulDirectQuery` if the current type is `BatchInsertTreeApplyType::StatefulBatchInsertTree`.
344    /// ```
345    pub(crate) fn to_direct_query_type(self) -> DirectQueryType {
346        match self {
347            BatchInsertTreeApplyType::StatelessBatchInsertTree {
348                in_tree_type,
349                tree_type,
350                flags_len,
351            } => DirectQueryType::StatelessDirectQuery {
352                in_tree_type,
353                query_target: QueryTarget::QueryTargetTree(flags_len, tree_type),
354            },
355            BatchInsertTreeApplyType::StatefulBatchInsertTree => {
356                DirectQueryType::StatefulDirectQuery
357            }
358        }
359    }
360}
361
362/// Batch insert apply type
363#[derive(Clone, Copy)]
364pub enum BatchInsertApplyType {
365    /// Stateless batch insert
366    StatelessBatchInsert {
367        /// Does this tree use sums?
368        in_tree_type: TreeType,
369        /// the type of Target (Tree or Value)
370        target: QueryTarget,
371    },
372    /// Stateful batch insert
373    StatefulBatchInsert,
374}
375
376impl BatchInsertApplyType {
377    /// Converts the current `BatchInsertApplyType` into a corresponding `DirectQueryType`.
378    ///
379    /// # Returns
380    ///
381    /// - A variant of `DirectQueryType::StatelessDirectQuery` if the current type is `BatchInsertApplyType::StatelessBatchInsert`.
382    /// - `DirectQueryType::StatefulDirectQuery` if the current type is `BatchInsertApplyType::StatefulBatchInsert`.
383    /// ```
384    // TODO: Not using
385    #[allow(dead_code)]
386    #[allow(clippy::wrong_self_convention)]
387    pub(crate) fn to_direct_query_type(&self) -> DirectQueryType {
388        match self {
389            BatchInsertApplyType::StatelessBatchInsert {
390                in_tree_type: in_tree_using_sums,
391                target,
392            } => DirectQueryType::StatelessDirectQuery {
393                in_tree_type: *in_tree_using_sums,
394                query_target: *target,
395            },
396            BatchInsertApplyType::StatefulBatchInsert => DirectQueryType::StatefulDirectQuery,
397        }
398    }
399}
400
401/// Flags length
402pub type FlagsLen = u32;
403
404/// query target
405#[derive(Clone, Copy)]
406/// Query target
407pub enum QueryTarget {
408    /// tree
409    QueryTargetTree(FlagsLen, TreeType),
410    /// value
411    QueryTargetValue(u32),
412}
413
414impl QueryTarget {
415    /// Length
416    pub(crate) fn len(&self) -> u32 {
417        match self {
418            QueryTarget::QueryTargetTree(flags_len, tree_type) => {
419                *flags_len + tree_type.inner_node_type().cost() + 3
420            }
421            QueryTarget::QueryTargetValue(len) => *len,
422        }
423    }
424}
425
426/// direct query type
427#[derive(Clone, Copy)]
428/// Direct query type
429pub enum DirectQueryType {
430    /// Stateless direct query
431    StatelessDirectQuery {
432        /// Does this tree use sums?
433        in_tree_type: TreeType,
434        /// the type of Target (Tree or Value)
435        query_target: QueryTarget,
436    },
437    /// Stateful direct query
438    StatefulDirectQuery,
439}
440
441impl From<DirectQueryType> for QueryType {
442    fn from(value: DirectQueryType) -> Self {
443        match value {
444            DirectQueryType::StatelessDirectQuery {
445                in_tree_type,
446                query_target,
447            } => QueryType::StatelessQuery {
448                in_tree_type,
449                query_target,
450                estimated_reference_sizes: vec![],
451            },
452            DirectQueryType::StatefulDirectQuery => QueryType::StatefulQuery,
453        }
454    }
455}
456
457impl DirectQueryType {
458    /// Converts the current `DirectQueryType` into a corresponding `QueryType`
459    /// while associating it with the given reference sizes.
460    ///
461    /// # Parameters
462    ///
463    /// * `reference_sizes`: A vector of `u32` values representing the reference sizes
464    ///   associated with the query.
465    ///
466    /// # Returns
467    ///
468    /// - A variant of `QueryType::StatelessQuery` with the provided reference sizes if
469    ///   the current type is `DirectQueryType::StatelessDirectQuery`.
470    /// - `QueryType::StatefulQuery` if the current type is `DirectQueryType::StatefulDirectQuery`.
471    ///
472    /// # Example
473    ///
474    /// ```ignore
475    /// let direct_query = DirectQueryType::StatelessDirectQuery {
476    ///     in_tree_using_sums: true,
477    ///     query_target: SomeTarget, // Replace with an actual target instance.
478    /// };
479    ///
480    /// let ref_sizes = vec![100, 200, 300];
481    /// let query_type = direct_query.add_reference_sizes(ref_sizes);
482    /// ```
483    #[allow(dead_code)]
484    #[deprecated(note = "This function is marked as unused.")]
485    #[allow(deprecated)]
486    pub(crate) fn add_reference_sizes(self, reference_sizes: Vec<u32>) -> QueryType {
487        match self {
488            DirectQueryType::StatelessDirectQuery {
489                in_tree_type: in_tree_using_sums,
490                query_target,
491            } => QueryType::StatelessQuery {
492                in_tree_type: in_tree_using_sums,
493                query_target,
494                estimated_reference_sizes: reference_sizes,
495            },
496            DirectQueryType::StatefulDirectQuery => QueryType::StatefulQuery,
497        }
498    }
499}
500
501/// Query type
502#[derive(Clone)]
503pub enum QueryType {
504    /// Stateless query
505    StatelessQuery {
506        /// Does this tree use sums?
507        in_tree_type: TreeType,
508        /// the type of Target (Tree or Value)
509        query_target: QueryTarget,
510        /// The estimated sizes of references
511        estimated_reference_sizes: Vec<u32>,
512    },
513    /// Stateful query
514    StatefulQuery,
515}
516
517impl From<BatchDeleteApplyType> for QueryType {
518    fn from(value: BatchDeleteApplyType) -> Self {
519        match value {
520            BatchDeleteApplyType::StatelessBatchDelete {
521                in_tree_type: is_sum_tree,
522                estimated_value_size,
523                ..
524            } => QueryType::StatelessQuery {
525                in_tree_type: is_sum_tree,
526                query_target: QueryTarget::QueryTargetValue(estimated_value_size),
527                estimated_reference_sizes: vec![],
528            },
529            BatchDeleteApplyType::StatefulBatchDelete { .. } => QueryType::StatefulQuery,
530        }
531    }
532}
533
534impl From<&BatchDeleteApplyType> for QueryType {
535    fn from(value: &BatchDeleteApplyType) -> Self {
536        match value {
537            BatchDeleteApplyType::StatelessBatchDelete {
538                in_tree_type: is_sum_tree,
539                estimated_value_size,
540                ..
541            } => QueryType::StatelessQuery {
542                in_tree_type: *is_sum_tree,
543                query_target: QueryTarget::QueryTargetValue(*estimated_value_size),
544                estimated_reference_sizes: vec![],
545            },
546            BatchDeleteApplyType::StatefulBatchDelete { .. } => QueryType::StatefulQuery,
547        }
548    }
549}
550
551impl From<BatchDeleteApplyType> for DirectQueryType {
552    fn from(value: BatchDeleteApplyType) -> Self {
553        match value {
554            BatchDeleteApplyType::StatelessBatchDelete {
555                in_tree_type: is_sum_tree,
556                estimated_value_size,
557                ..
558            } => DirectQueryType::StatelessDirectQuery {
559                in_tree_type: is_sum_tree,
560                query_target: QueryTarget::QueryTargetValue(estimated_value_size),
561            },
562            BatchDeleteApplyType::StatefulBatchDelete { .. } => {
563                DirectQueryType::StatefulDirectQuery
564            }
565        }
566    }
567}
568
569impl From<&BatchDeleteApplyType> for DirectQueryType {
570    fn from(value: &BatchDeleteApplyType) -> Self {
571        match value {
572            BatchDeleteApplyType::StatelessBatchDelete {
573                in_tree_type: is_sum_tree,
574                estimated_value_size,
575                ..
576            } => DirectQueryType::StatelessDirectQuery {
577                in_tree_type: *is_sum_tree,
578                query_target: QueryTarget::QueryTargetValue(*estimated_value_size),
579            },
580            BatchDeleteApplyType::StatefulBatchDelete { .. } => {
581                DirectQueryType::StatefulDirectQuery
582            }
583        }
584    }
585}
586
587/// Specifies which GroveDB instance to use for a query
588#[derive(Debug, Clone, Copy, PartialEq, Eq)]
589pub enum GroveDBToUse {
590    /// Use the current (main) GroveDB
591    Current,
592    /// Use the latest checkpoint
593    LatestCheckpoint,
594    /// Use a specific checkpoint at the given block height
595    Checkpoint(u64),
596}