1use crate::drive::Drive;
2use crate::error::Error;
3use crate::fees::op::LowLevelDriveOperation;
4use crate::util::batch::drive_op_batch::DriveLowLevelOperationConverter;
5use crate::util::object_size_info::DocumentInfo::{DocumentRefAndSerialization, DocumentRefInfo};
6use crate::util::object_size_info::{
7 DataContractInfo, DocumentAndContractInfo, DocumentTypeInfo, OwnedDocumentInfo,
8};
9use crate::util::storage_flags::StorageFlags;
10use dpp::block::block_info::BlockInfo;
11use dpp::data_contract::accessors::v0::DataContractV0Getters;
12use dpp::data_contract::document_type::DocumentTypeRef;
13use dpp::data_contract::DataContract;
14use dpp::document::Document;
15use dpp::prelude::Identifier;
16
17use dpp::system_data_contracts::withdrawals_contract::v1::document_types::withdrawal;
18
19use crate::drive::votes::resolved::vote_polls::contested_document_resource_vote_poll::ContestedDocumentResourceVotePollWithContractInfo;
20use dpp::version::PlatformVersion;
21use dpp::voting::vote_info_storage::contested_document_vote_poll_stored_info::ContestedDocumentVotePollStoredInfo;
22use dpp::ProtocolError;
23use grovedb::batch::KeyInfoPath;
24use grovedb::{EstimatedLayerInformation, TransactionArg};
25use std::borrow::Cow;
26use std::collections::HashMap;
27
28#[derive(Clone, Debug)]
30#[allow(clippy::large_enum_variant)]
31pub enum DocumentOperation<'a> {
32 AddOperation {
34 owned_document_info: OwnedDocumentInfo<'a>,
36 override_document: bool,
38 },
39 UpdateOperation(UpdateOperationInfo<'a>),
41}
42
43#[derive(Clone, Debug)]
45pub struct DocumentOperationsForContractDocumentType<'a> {
46 pub operations: Vec<DocumentOperation<'a>>,
48 pub contract: &'a DataContract,
50 pub document_type: DocumentTypeRef<'a>,
52}
53
54#[derive(Clone, Debug)]
56#[allow(clippy::large_enum_variant)]
57pub enum DocumentOperationType<'a> {
58 AddDocument {
60 owned_document_info: OwnedDocumentInfo<'a>,
62 contract_info: DataContractInfo<'a>,
64 document_type_info: DocumentTypeInfo<'a>,
66 override_document: bool,
68 },
69 AddContestedDocument {
73 owned_document_info: OwnedDocumentInfo<'a>,
75 contested_document_resource_vote_poll: ContestedDocumentResourceVotePollWithContractInfo,
77 contract_info: DataContractInfo<'a>,
79 document_type_info: DocumentTypeInfo<'a>,
81 insert_without_check: bool,
83 also_insert_vote_poll_stored_info: Option<ContestedDocumentVotePollStoredInfo>,
85 },
86 UpdateDocument {
88 owned_document_info: OwnedDocumentInfo<'a>,
90 contract_info: DataContractInfo<'a>,
92 document_type_info: DocumentTypeInfo<'a>,
94 },
95 DeleteDocument {
97 document_id: Identifier,
99 contract_info: DataContractInfo<'a>,
101 document_type_info: DocumentTypeInfo<'a>,
103 },
104 AddWithdrawalDocument {
106 owned_document_info: OwnedDocumentInfo<'a>,
108 },
109 MultipleDocumentOperationsForSameContractDocumentType {
111 document_operations: DocumentOperationsForContractDocumentType<'a>,
113 },
114}
115
116impl DriveLowLevelOperationConverter for DocumentOperationType<'_> {
117 fn into_low_level_drive_operations(
118 self,
119 drive: &Drive,
120 estimated_costs_only_with_layer_info: &mut Option<
121 HashMap<KeyInfoPath, EstimatedLayerInformation>,
122 >,
123 block_info: &BlockInfo,
124 transaction: TransactionArg,
125 platform_version: &PlatformVersion,
126 ) -> Result<Vec<LowLevelDriveOperation>, Error> {
127 match self {
128 DocumentOperationType::AddDocument {
129 owned_document_info,
130 contract_info,
131 document_type_info,
132 override_document,
133 } => {
134 let mut drive_operations: Vec<LowLevelDriveOperation> = vec![];
135 let contract_resolved_info = contract_info.resolve(
136 drive,
137 block_info,
138 transaction,
139 &mut drive_operations,
140 platform_version,
141 )?;
142 let contract = contract_resolved_info.as_ref();
143 let document_type = document_type_info.resolve(contract)?;
144
145 let document_and_contract_info = DocumentAndContractInfo {
146 owned_document_info,
147 contract,
148 document_type,
149 };
150 let mut operations = drive.add_document_for_contract_operations(
151 document_and_contract_info,
152 override_document,
153 block_info,
154 &mut None,
155 estimated_costs_only_with_layer_info,
156 transaction,
157 platform_version,
158 )?;
159 drive_operations.append(&mut operations);
160 Ok(drive_operations)
161 }
162 DocumentOperationType::AddContestedDocument {
163 owned_document_info,
164 contested_document_resource_vote_poll,
165 contract_info,
166 document_type_info,
167 insert_without_check,
168 also_insert_vote_poll_stored_info,
169 } => {
170 let mut drive_operations: Vec<LowLevelDriveOperation> = vec![];
171 let contract_resolved_info = contract_info.resolve(
172 drive,
173 block_info,
174 transaction,
175 &mut drive_operations,
176 platform_version,
177 )?;
178 let contract = contract_resolved_info.as_ref();
179 let document_type = document_type_info.resolve(contract)?;
180
181 let document_and_contract_info = DocumentAndContractInfo {
182 owned_document_info,
183 contract,
184 document_type,
185 };
186 let mut operations = drive.add_contested_document_for_contract_operations(
187 document_and_contract_info,
188 contested_document_resource_vote_poll,
189 insert_without_check,
190 block_info,
191 also_insert_vote_poll_stored_info,
192 &mut None,
193 estimated_costs_only_with_layer_info,
194 transaction,
195 platform_version,
196 )?;
197 drive_operations.append(&mut operations);
198 Ok(drive_operations)
199 }
200 DocumentOperationType::AddWithdrawalDocument {
201 owned_document_info,
202 } => {
203 let contract = drive.cache.system_data_contracts.load_withdrawals();
204
205 let document_type = contract
206 .document_type_for_name(withdrawal::NAME)
207 .map_err(ProtocolError::DataContractError)?;
208
209 let document_and_contract_info = DocumentAndContractInfo {
210 owned_document_info,
211 contract: &contract,
212 document_type,
213 };
214 drive.add_document_for_contract_operations(
215 document_and_contract_info,
216 false,
217 block_info,
218 &mut None,
219 estimated_costs_only_with_layer_info,
220 transaction,
221 platform_version,
222 )
223 }
224 DocumentOperationType::UpdateDocument {
225 owned_document_info,
226 contract_info,
227 document_type_info,
228 } => {
229 let mut drive_operations = vec![];
230 let contract_resolved_info = contract_info.resolve(
231 drive,
232 block_info,
233 transaction,
234 &mut drive_operations,
235 platform_version,
236 )?;
237 let contract = contract_resolved_info.as_ref();
238 let document_type = document_type_info.resolve(contract)?;
239
240 let document_and_contract_info = DocumentAndContractInfo {
241 owned_document_info,
242 contract,
243 document_type,
244 };
245 let mut operations = drive.update_document_for_contract_operations(
246 document_and_contract_info,
247 block_info,
248 &mut None,
249 estimated_costs_only_with_layer_info,
250 transaction,
251 platform_version,
252 )?;
253 drive_operations.append(&mut operations);
254 Ok(drive_operations)
255 }
256 DocumentOperationType::DeleteDocument {
257 document_id,
258 contract_info,
259 document_type_info,
260 } => {
261 let mut drive_operations: Vec<LowLevelDriveOperation> = vec![];
262 let contract_resolved_info = contract_info.resolve(
263 drive,
264 block_info,
265 transaction,
266 &mut drive_operations,
267 platform_version,
268 )?;
269 let contract = contract_resolved_info.as_ref();
270 let document_type = document_type_info.resolve(contract)?;
271
272 drive.delete_document_for_contract_operations(
273 document_id,
274 contract,
275 document_type,
276 None,
277 estimated_costs_only_with_layer_info,
278 transaction,
279 platform_version,
280 )
281 }
282 DocumentOperationType::MultipleDocumentOperationsForSameContractDocumentType {
283 document_operations,
284 } => {
285 let DocumentOperationsForContractDocumentType {
286 operations,
287 contract,
288 document_type,
289 } = document_operations;
290
291 let mut drive_operations = vec![];
292 for document_operation in operations {
293 match document_operation {
294 DocumentOperation::AddOperation {
295 owned_document_info,
296 override_document,
297 } => {
298 let document_and_contract_info = DocumentAndContractInfo {
299 owned_document_info,
300 contract,
301 document_type,
302 };
303 let mut operations = drive.add_document_for_contract_operations(
304 document_and_contract_info,
305 override_document,
306 block_info,
307 &mut Some(&mut drive_operations),
308 estimated_costs_only_with_layer_info,
309 transaction,
310 platform_version,
311 )?;
312 drive_operations.append(&mut operations);
313 }
314 DocumentOperation::UpdateOperation(update_operation) => {
315 let UpdateOperationInfo {
316 document,
317 serialized_document,
318 owner_id,
319 storage_flags,
320 } = update_operation;
321
322 let document_info =
323 if let Some(serialized_document) = serialized_document {
324 DocumentRefAndSerialization((
325 document,
326 serialized_document,
327 storage_flags,
328 ))
329 } else {
330 DocumentRefInfo((document, storage_flags))
331 };
332 let document_and_contract_info = DocumentAndContractInfo {
333 owned_document_info: OwnedDocumentInfo {
334 document_info,
335 owner_id,
336 },
337 contract,
338 document_type,
339 };
340 let mut operations = drive.update_document_for_contract_operations(
341 document_and_contract_info,
342 block_info,
343 &mut Some(&mut drive_operations),
344 estimated_costs_only_with_layer_info,
345 transaction,
346 platform_version,
347 )?;
348 drive_operations.append(&mut operations);
349 }
350 }
351 }
352 Ok(drive_operations)
353 }
354 }
355 }
356}
357
358#[derive(Clone, Debug)]
360pub struct UpdateOperationInfo<'a> {
361 pub document: &'a Document,
363 pub serialized_document: Option<&'a [u8]>,
365 pub owner_id: Option<[u8; 32]>,
367 pub storage_flags: Option<Cow<'a, StorageFlags>>,
369}