drive/util/batch/drive_op_batch/
withdrawals.rs

1use std::collections::HashMap;
2
3use crate::drive::identity::withdrawals::paths::{
4    get_withdrawal_root_path_vec, get_withdrawal_transactions_broadcasted_path_vec,
5    get_withdrawal_transactions_queue_path_vec, get_withdrawal_transactions_sum_tree_path_vec,
6    WITHDRAWAL_TRANSACTIONS_NEXT_INDEX_KEY,
7};
8use crate::util::grove_operations::{
9    BatchDeleteApplyType, BatchInsertApplyType, BatchMoveApplyType,
10};
11use crate::util::object_size_info::PathKeyElementInfo;
12use crate::{drive::Drive, error::Error, fees::op::LowLevelDriveOperation};
13use dpp::block::block_info::BlockInfo;
14
15use super::DriveLowLevelOperationConverter;
16use crate::query::Query;
17use dpp::fee::{Credits, SignedCredits};
18use dpp::prelude::TimestampMillis;
19use dpp::version::PlatformVersion;
20use dpp::withdrawal::{WithdrawalTransactionIndex, WithdrawalTransactionIndexAndBytes};
21use grovedb::{batch::KeyInfoPath, EstimatedLayerInformation, MaybeTree, TransactionArg};
22use grovedb::{Element, PathQuery, SizedQuery};
23
24/// Operations for Withdrawals
25#[derive(Clone, Debug)]
26pub enum WithdrawalOperationType {
27    /// Update index counter
28    UpdateIndexCounter {
29        /// index counter value
30        index: WithdrawalTransactionIndex,
31    },
32    /// Insert Core Transaction into queue
33    InsertTransactions {
34        /// transaction id bytes
35        withdrawal_transactions: Vec<WithdrawalTransactionIndexAndBytes>,
36    },
37    /// Deletes the withdrawal transactions from the main queue and adds them to the broadcasted queue
38    MoveWithdrawalTransactionsToBroadcasted {
39        /// A vector of the indexes to be moved
40        indexes: Vec<WithdrawalTransactionIndex>,
41    },
42    /// Deletes the withdrawal transactions from the main queue and adds them to the broadcasted queue
43    MoveBroadcastedWithdrawalTransactionsBackToQueueForResigning {
44        /// A vector of the indexes to be moved
45        indexes: Vec<WithdrawalTransactionIndex>,
46    },
47    /// Deletes the withdrawal transactions from the broadcasted queue
48    DeleteCompletedBroadcastedWithdrawalTransactions {
49        /// A vector of the indexes to be deleted
50        indexes: Vec<WithdrawalTransactionIndex>,
51    },
52    /// Reserve an amount in the system for withdrawals, the reservation will expire at the date given
53    ReserveWithdrawalAmount {
54        /// amount to reserve
55        amount: Credits,
56        /// expiration date
57        expiration_after: TimestampMillis,
58    },
59}
60
61impl DriveLowLevelOperationConverter for WithdrawalOperationType {
62    fn into_low_level_drive_operations(
63        self,
64        drive: &Drive,
65        _estimated_costs_only_with_layer_info: &mut Option<
66            HashMap<KeyInfoPath, EstimatedLayerInformation>,
67        >,
68        block_info: &BlockInfo,
69        transaction: TransactionArg,
70        platform_version: &PlatformVersion,
71    ) -> Result<Vec<LowLevelDriveOperation>, Error> {
72        match self {
73            WithdrawalOperationType::UpdateIndexCounter { index } => {
74                let mut drive_operations = vec![];
75
76                let path = get_withdrawal_root_path_vec();
77
78                drive.batch_insert(
79                    PathKeyElementInfo::PathKeyRefElement::<'_, 1>((
80                        path,
81                        &WITHDRAWAL_TRANSACTIONS_NEXT_INDEX_KEY,
82                        Element::Item(index.to_be_bytes().to_vec(), None),
83                    )),
84                    &mut drive_operations,
85                    &platform_version.drive,
86                )?;
87
88                Ok(drive_operations)
89            }
90            WithdrawalOperationType::InsertTransactions {
91                withdrawal_transactions,
92            } => {
93                let mut drive_operations = vec![];
94
95                let path = get_withdrawal_transactions_queue_path_vec();
96
97                for (index, bytes) in withdrawal_transactions {
98                    drive.batch_insert(
99                        PathKeyElementInfo::PathKeyElement::<'_, 0>((
100                            path.clone(),
101                            index.to_be_bytes().to_vec(),
102                            Element::Item(bytes, None),
103                        )),
104                        &mut drive_operations,
105                        &platform_version.drive,
106                    )?;
107                }
108
109                Ok(drive_operations)
110            }
111            WithdrawalOperationType::ReserveWithdrawalAmount {
112                amount,
113                expiration_after,
114            } => {
115                let mut drive_operations = vec![];
116
117                let expiration_date = block_info.time_ms + expiration_after;
118
119                let sum_path = get_withdrawal_transactions_sum_tree_path_vec();
120
121                drive.batch_insert_sum_item_or_add_to_if_already_exists(
122                    PathKeyElementInfo::PathKeyElement::<'_, 0>((
123                        sum_path.clone(),
124                        expiration_date.to_be_bytes().to_vec(),
125                        Element::SumItem(amount as SignedCredits, None),
126                    )),
127                    BatchInsertApplyType::StatefulBatchInsert,
128                    transaction,
129                    &mut drive_operations,
130                    &platform_version.drive,
131                )?;
132
133                Ok(drive_operations)
134            }
135            WithdrawalOperationType::MoveWithdrawalTransactionsToBroadcasted { indexes } => {
136                let mut drive_operations = vec![];
137
138                if indexes.is_empty() {
139                    return Ok(drive_operations);
140                }
141
142                let original_path = get_withdrawal_transactions_queue_path_vec();
143                let new_path = get_withdrawal_transactions_broadcasted_path_vec();
144
145                let mut query = Query::new();
146
147                let len = indexes.len();
148
149                query.insert_keys(
150                    indexes
151                        .into_iter()
152                        .map(|index| index.to_be_bytes().to_vec())
153                        .collect(),
154                );
155
156                let path_query = PathQuery::new(
157                    original_path,
158                    SizedQuery::new(query, Some(len as u16), None),
159                );
160
161                drive.batch_move_items_in_path_query(
162                    &path_query,
163                    new_path,
164                    true,
165                    // we know that we are not deleting a subtree
166                    BatchMoveApplyType::StatefulBatchMove {
167                        is_known_to_be_subtree_with_sum: Some(MaybeTree::NotTree),
168                    },
169                    None,
170                    transaction,
171                    &mut drive_operations,
172                    &platform_version.drive,
173                )?;
174
175                Ok(drive_operations)
176            }
177            WithdrawalOperationType::MoveBroadcastedWithdrawalTransactionsBackToQueueForResigning { indexes } => {
178                let mut drive_operations = vec![];
179
180                if indexes.is_empty() {
181                    return Ok(drive_operations);
182                }
183
184                let original_path = get_withdrawal_transactions_broadcasted_path_vec();
185                let new_path = get_withdrawal_transactions_queue_path_vec();
186
187                let mut query = Query::new();
188
189                let len = indexes.len();
190
191                query.insert_keys(
192                    indexes
193                        .into_iter()
194                        .map(|index| index.to_be_bytes().to_vec())
195                        .collect(),
196                );
197
198                let path_query = PathQuery::new(
199                    original_path,
200                    SizedQuery::new(query, Some(len as u16), None),
201                );
202
203                drive.batch_move_items_in_path_query(
204                    &path_query,
205                    new_path,
206                    true,
207                    // we know that we are not deleting a subtree
208                    BatchMoveApplyType::StatefulBatchMove {
209                        is_known_to_be_subtree_with_sum: Some(MaybeTree::NotTree),
210                    },
211                    None,
212                    transaction,
213                    &mut drive_operations,
214                    &platform_version.drive,
215                )?;
216
217                Ok(drive_operations)
218            }
219            WithdrawalOperationType::DeleteCompletedBroadcastedWithdrawalTransactions { indexes } => {
220                let mut drive_operations = vec![];
221
222                if indexes.is_empty() {
223                    return Ok(drive_operations);
224                }
225
226                let path = get_withdrawal_transactions_broadcasted_path_vec();
227
228                let mut query = Query::new();
229
230                let len = indexes.len();
231
232                query.insert_keys(
233                    indexes
234                        .into_iter()
235                        .map(|index| index.to_be_bytes().to_vec())
236                        .collect(),
237                );
238
239                let path_query = PathQuery::new(
240                    path,
241                    SizedQuery::new(query, Some(len as u16), None),
242                );
243
244                drive.batch_delete_items_in_path_query(
245                    &path_query,
246                    true,
247                    // we know that we are not deleting a subtree
248                    BatchDeleteApplyType::StatefulBatchDelete {
249                        is_known_to_be_subtree_with_sum: Some(MaybeTree::NotTree),
250                    },
251                    transaction,
252                    &mut drive_operations,
253                    &platform_version.drive,
254                )?;
255
256                Ok(drive_operations)
257            }
258        }
259    }
260}