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_event::DocumentEvent;
15use dpp::document::Document;
16use dpp::prelude::{Identifier, IdentityNonce};
17
18use dpp::system_data_contracts::withdrawals_contract::v1::document_types::withdrawal;
19
20use crate::drive::votes::resolved::vote_polls::contested_document_resource_vote_poll::ContestedDocumentResourceVotePollWithContractInfo;
21use dpp::platform_value::Value;
22use dpp::version::PlatformVersion;
23use dpp::voting::vote_info_storage::contested_document_vote_poll_stored_info::ContestedDocumentVotePollStoredInfo;
24use dpp::ProtocolError;
25use grovedb::batch::KeyInfoPath;
26use grovedb::{EstimatedLayerInformation, TransactionArg};
27use std::borrow::Cow;
28use std::collections::{BTreeMap, HashMap};
29
30#[derive(Clone, Debug)]
32#[allow(clippy::large_enum_variant)]
33pub enum DocumentOperation<'a> {
34 AddOperation {
36 owned_document_info: OwnedDocumentInfo<'a>,
38 override_document: bool,
40 },
41 UpdateOperation(UpdateOperationInfo<'a>),
43}
44
45#[derive(Clone, Debug)]
47pub struct DocumentOperationsForContractDocumentType<'a> {
48 pub operations: Vec<DocumentOperation<'a>>,
50 pub contract: &'a DataContract,
52 pub document_type: DocumentTypeRef<'a>,
54}
55
56#[derive(Clone, Debug)]
58#[allow(clippy::large_enum_variant)]
59pub enum DocumentOperationType<'a> {
60 AddDocument {
62 owned_document_info: OwnedDocumentInfo<'a>,
64 contract_info: DataContractInfo<'a>,
66 document_type_info: DocumentTypeInfo<'a>,
68 override_document: bool,
70 },
71 AddContestedDocument {
75 owned_document_info: OwnedDocumentInfo<'a>,
77 contested_document_resource_vote_poll: ContestedDocumentResourceVotePollWithContractInfo,
79 contract_info: DataContractInfo<'a>,
81 document_type_info: DocumentTypeInfo<'a>,
83 insert_without_check: bool,
85 also_insert_vote_poll_stored_info: Option<ContestedDocumentVotePollStoredInfo>,
87 },
88 UpdateDocument {
90 owned_document_info: OwnedDocumentInfo<'a>,
92 contract_info: DataContractInfo<'a>,
94 document_type_info: DocumentTypeInfo<'a>,
96 },
97 DeleteDocument {
99 document_id: Identifier,
101 contract_info: DataContractInfo<'a>,
103 document_type_info: DocumentTypeInfo<'a>,
105 },
106 DeleteIndexOnlyDocument {
111 document_id: Identifier,
113 owner_id: Identifier,
115 data: BTreeMap<String, Value>,
117 contract_info: DataContractInfo<'a>,
119 document_type_info: DocumentTypeInfo<'a>,
121 },
122 AddWithdrawalDocument {
124 owned_document_info: OwnedDocumentInfo<'a>,
126 },
127 MultipleDocumentOperationsForSameContractDocumentType {
129 document_operations: DocumentOperationsForContractDocumentType<'a>,
131 },
132 DocumentHistory {
136 source_data_contract_id: Identifier,
138 source_document_type_name: String,
140 source_document_id: Identifier,
142 owner_id: Identifier,
144 nonce: IdentityNonce,
146 event: DocumentEvent,
148 },
149}
150
151impl DriveLowLevelOperationConverter for DocumentOperationType<'_> {
152 fn into_low_level_drive_operations(
153 self,
154 drive: &Drive,
155 estimated_costs_only_with_layer_info: &mut Option<
156 HashMap<KeyInfoPath, EstimatedLayerInformation>,
157 >,
158 block_info: &BlockInfo,
159 transaction: TransactionArg,
160 platform_version: &PlatformVersion,
161 ) -> Result<Vec<LowLevelDriveOperation>, Error> {
162 match self {
163 DocumentOperationType::AddDocument {
164 owned_document_info,
165 contract_info,
166 document_type_info,
167 override_document,
168 } => {
169 let mut drive_operations: Vec<LowLevelDriveOperation> = vec![];
170 let contract_resolved_info = contract_info.resolve(
171 drive,
172 block_info,
173 transaction,
174 &mut drive_operations,
175 platform_version,
176 )?;
177 let contract = contract_resolved_info.as_ref();
178 let document_type = document_type_info.resolve(contract)?;
179
180 let document_and_contract_info = DocumentAndContractInfo {
181 owned_document_info,
182 contract,
183 document_type,
184 };
185 let mut operations = drive.add_document_for_contract_operations(
186 document_and_contract_info,
187 override_document,
188 block_info,
189 &mut None,
190 estimated_costs_only_with_layer_info,
191 transaction,
192 platform_version,
193 )?;
194 drive_operations.append(&mut operations);
195 Ok(drive_operations)
196 }
197 DocumentOperationType::AddContestedDocument {
198 owned_document_info,
199 contested_document_resource_vote_poll,
200 contract_info,
201 document_type_info,
202 insert_without_check,
203 also_insert_vote_poll_stored_info,
204 } => {
205 let mut drive_operations: Vec<LowLevelDriveOperation> = vec![];
206 let contract_resolved_info = contract_info.resolve(
207 drive,
208 block_info,
209 transaction,
210 &mut drive_operations,
211 platform_version,
212 )?;
213 let contract = contract_resolved_info.as_ref();
214 let document_type = document_type_info.resolve(contract)?;
215
216 let document_and_contract_info = DocumentAndContractInfo {
217 owned_document_info,
218 contract,
219 document_type,
220 };
221 let mut operations = drive.add_contested_document_for_contract_operations(
222 document_and_contract_info,
223 contested_document_resource_vote_poll,
224 insert_without_check,
225 block_info,
226 also_insert_vote_poll_stored_info,
227 &mut None,
228 estimated_costs_only_with_layer_info,
229 transaction,
230 platform_version,
231 )?;
232 drive_operations.append(&mut operations);
233 Ok(drive_operations)
234 }
235 DocumentOperationType::AddWithdrawalDocument {
236 owned_document_info,
237 } => {
238 let contract = drive
239 .cache
240 .system_data_contracts
241 .load_withdrawals(platform_version)?;
242
243 let document_type = contract
244 .document_type_for_name(withdrawal::NAME)
245 .map_err(ProtocolError::DataContractError)?;
246
247 let document_and_contract_info = DocumentAndContractInfo {
248 owned_document_info,
249 contract: &contract,
250 document_type,
251 };
252 drive.add_document_for_contract_operations(
253 document_and_contract_info,
254 false,
255 block_info,
256 &mut None,
257 estimated_costs_only_with_layer_info,
258 transaction,
259 platform_version,
260 )
261 }
262 DocumentOperationType::UpdateDocument {
263 owned_document_info,
264 contract_info,
265 document_type_info,
266 } => {
267 let mut drive_operations = vec![];
268 let contract_resolved_info = contract_info.resolve(
269 drive,
270 block_info,
271 transaction,
272 &mut drive_operations,
273 platform_version,
274 )?;
275 let contract = contract_resolved_info.as_ref();
276 let document_type = document_type_info.resolve(contract)?;
277
278 let document_and_contract_info = DocumentAndContractInfo {
279 owned_document_info,
280 contract,
281 document_type,
282 };
283 let mut operations = drive.update_document_for_contract_operations(
284 document_and_contract_info,
285 block_info,
286 &mut None,
287 estimated_costs_only_with_layer_info,
288 transaction,
289 platform_version,
290 )?;
291 drive_operations.append(&mut operations);
292 Ok(drive_operations)
293 }
294 DocumentOperationType::DocumentHistory {
295 source_data_contract_id,
296 source_document_type_name,
297 source_document_id,
298 owner_id,
299 nonce,
300 event,
301 } => {
302 let batch_operations = drive.add_document_history_operations(
303 source_data_contract_id,
304 source_document_type_name.as_str(),
305 source_document_id,
306 owner_id,
307 nonce,
308 event,
309 block_info,
310 estimated_costs_only_with_layer_info,
311 transaction,
312 platform_version,
313 )?;
314 Ok(batch_operations)
315 }
316 DocumentOperationType::DeleteDocument {
317 document_id,
318 contract_info,
319 document_type_info,
320 } => {
321 let mut drive_operations: Vec<LowLevelDriveOperation> = vec![];
322 let contract_resolved_info = contract_info.resolve(
323 drive,
324 block_info,
325 transaction,
326 &mut drive_operations,
327 platform_version,
328 )?;
329 let contract = contract_resolved_info.as_ref();
330 let document_type = document_type_info.resolve(contract)?;
331
332 drive.delete_document_for_contract_operations(
333 document_id,
334 contract,
335 document_type,
336 None,
337 estimated_costs_only_with_layer_info,
338 transaction,
339 platform_version,
340 )
341 }
342 DocumentOperationType::DeleteIndexOnlyDocument {
343 document_id,
344 owner_id,
345 data,
346 contract_info,
347 document_type_info,
348 } => {
349 let mut drive_operations: Vec<LowLevelDriveOperation> = vec![];
350 let contract_resolved_info = contract_info.resolve(
351 drive,
352 block_info,
353 transaction,
354 &mut drive_operations,
355 platform_version,
356 )?;
357 let contract = contract_resolved_info.as_ref();
358 let document_type = document_type_info.resolve(contract)?;
359
360 let document = Drive::index_only_document_from_values(document_id, owner_id, data)?;
362
363 drive.delete_index_only_document_for_contract_operations(
364 document,
365 contract,
366 document_type,
367 None,
368 estimated_costs_only_with_layer_info,
369 transaction,
370 platform_version,
371 )
372 }
373 DocumentOperationType::MultipleDocumentOperationsForSameContractDocumentType {
374 document_operations,
375 } => {
376 let DocumentOperationsForContractDocumentType {
377 operations,
378 contract,
379 document_type,
380 } = document_operations;
381
382 let mut drive_operations = vec![];
383 for document_operation in operations {
384 match document_operation {
385 DocumentOperation::AddOperation {
386 owned_document_info,
387 override_document,
388 } => {
389 let document_and_contract_info = DocumentAndContractInfo {
390 owned_document_info,
391 contract,
392 document_type,
393 };
394 let mut operations = drive.add_document_for_contract_operations(
395 document_and_contract_info,
396 override_document,
397 block_info,
398 &mut Some(&mut drive_operations),
399 estimated_costs_only_with_layer_info,
400 transaction,
401 platform_version,
402 )?;
403 drive_operations.append(&mut operations);
404 }
405 DocumentOperation::UpdateOperation(update_operation) => {
406 let UpdateOperationInfo {
407 document,
408 serialized_document,
409 owner_id,
410 storage_flags,
411 } = update_operation;
412
413 let document_info =
414 if let Some(serialized_document) = serialized_document {
415 DocumentRefAndSerialization((
416 document,
417 serialized_document,
418 storage_flags,
419 ))
420 } else {
421 DocumentRefInfo((document, storage_flags))
422 };
423 let document_and_contract_info = DocumentAndContractInfo {
424 owned_document_info: OwnedDocumentInfo {
425 document_info,
426 owner_id,
427 },
428 contract,
429 document_type,
430 };
431 let mut operations = drive.update_document_for_contract_operations(
432 document_and_contract_info,
433 block_info,
434 &mut Some(&mut drive_operations),
435 estimated_costs_only_with_layer_info,
436 transaction,
437 platform_version,
438 )?;
439 drive_operations.append(&mut operations);
440 }
441 }
442 }
443 Ok(drive_operations)
444 }
445 }
446 }
447}
448
449#[derive(Clone, Debug)]
451pub struct UpdateOperationInfo<'a> {
452 pub document: &'a Document,
454 pub serialized_document: Option<&'a [u8]>,
456 pub owner_id: Option<[u8; 32]>,
458 pub storage_flags: Option<Cow<'a, StorageFlags>>,
460}