1mod address_funds;
2mod contract;
3mod contract_group;
4mod document;
5mod drive_methods;
6pub(crate) mod finalize_task;
7mod group;
8mod identity;
9mod prefunded_specialized_balance;
10mod shielded;
11mod system;
12mod token;
13mod withdrawals;
14
15use crate::util::batch::GroveDbOpBatch;
16
17use crate::drive::Drive;
18use crate::error::Error;
19use crate::fees::op::LowLevelDriveOperation;
20use dpp::block::block_info::BlockInfo;
21use dpp::fee::Credits;
22
23pub use address_funds::AddressFundsOperationType;
24pub use contract::DataContractOperationType;
25pub use contract_group::ContractGroupOperationType;
26pub use document::DocumentOperation;
27pub use document::DocumentOperationType;
28pub use document::DocumentOperationsForContractDocumentType;
29pub use document::UpdateOperationInfo;
30pub use group::GroupOperationType;
31pub use identity::IdentityOperationType;
32pub use prefunded_specialized_balance::PrefundedSpecializedBalanceOperationType;
33pub use shielded::ShieldedPoolOperationType;
34pub use system::SystemOperationType;
35pub use token::TokenOperationType;
36pub use withdrawals::WithdrawalOperationType;
37
38use grovedb::{EstimatedLayerInformation, TransactionArg};
39
40use crate::fees::op::LowLevelDriveOperation::GroveOperation;
41
42use dpp::version::PlatformVersion;
43use grovedb::batch::{KeyInfoPath, QualifiedGroveDbOp};
44
45use crate::error::drive::DriveError;
46use crate::util::batch::drive_op_batch::finalize_task::{
47 DriveOperationFinalizationTasks, DriveOperationFinalizeTask,
48};
49
50use std::collections::{BTreeMap, HashMap};
51
52pub trait DriveLowLevelOperationConverter {
54 fn into_low_level_drive_operations(
56 self,
57 drive: &Drive,
58 estimated_costs_only_with_layer_info: &mut Option<
59 HashMap<KeyInfoPath, EstimatedLayerInformation>,
60 >,
61 block_info: &BlockInfo,
62 transaction: TransactionArg,
63 platform_version: &PlatformVersion,
64 ) -> Result<Vec<LowLevelDriveOperation>, Error>;
65}
66
67pub struct DriveOperationContext {
70 #[allow(dead_code)]
71 #[deprecated(note = "This function is marked as unused.")]
72 #[allow(deprecated)]
73 identity_balance_changes: BTreeMap<[u8; 32], i64>,
74}
75
76#[allow(clippy::large_enum_variant)]
78#[derive(Clone, Debug)]
79pub enum DriveOperation<'a> {
80 DataContractOperation(DataContractOperationType<'a>),
82 DocumentOperation(DocumentOperationType<'a>),
84 TokenOperation(TokenOperationType),
86 WithdrawalOperation(WithdrawalOperationType),
88 IdentityOperation(IdentityOperationType),
90 PrefundedSpecializedBalanceOperation(PrefundedSpecializedBalanceOperationType),
92 SystemOperation(SystemOperationType),
94 GroupOperation(GroupOperationType),
96 ContractGroupOperation(ContractGroupOperationType),
98 AddressFundsOperation(AddressFundsOperationType),
100 ShieldedPoolOperation(ShieldedPoolOperationType),
102 GroveDBOperation(QualifiedGroveDbOp),
104 GroveDBOpBatch(GroveDbOpBatch),
106 FinalizeOperation(DriveOperationFinalizeTask),
108}
109
110impl DriveLowLevelOperationConverter for DriveOperation<'_> {
111 fn into_low_level_drive_operations(
112 self,
113 drive: &Drive,
114 estimated_costs_only_with_layer_info: &mut Option<
115 HashMap<KeyInfoPath, EstimatedLayerInformation>,
116 >,
117 block_info: &BlockInfo,
118 transaction: TransactionArg,
119 platform_version: &PlatformVersion,
120 ) -> Result<Vec<LowLevelDriveOperation>, Error> {
121 match self {
122 DriveOperation::DataContractOperation(contract_operation_type) => {
123 contract_operation_type.into_low_level_drive_operations(
124 drive,
125 estimated_costs_only_with_layer_info,
126 block_info,
127 transaction,
128 platform_version,
129 )
130 }
131 DriveOperation::DocumentOperation(document_operation_type) => document_operation_type
132 .into_low_level_drive_operations(
133 drive,
134 estimated_costs_only_with_layer_info,
135 block_info,
136 transaction,
137 platform_version,
138 ),
139 DriveOperation::WithdrawalOperation(withdrawal_operation_type) => {
140 withdrawal_operation_type.into_low_level_drive_operations(
141 drive,
142 estimated_costs_only_with_layer_info,
143 block_info,
144 transaction,
145 platform_version,
146 )
147 }
148 DriveOperation::IdentityOperation(identity_operation_type) => identity_operation_type
149 .into_low_level_drive_operations(
150 drive,
151 estimated_costs_only_with_layer_info,
152 block_info,
153 transaction,
154 platform_version,
155 ),
156 DriveOperation::PrefundedSpecializedBalanceOperation(
157 prefunded_balance_operation_type,
158 ) => prefunded_balance_operation_type.into_low_level_drive_operations(
159 drive,
160 estimated_costs_only_with_layer_info,
161 block_info,
162 transaction,
163 platform_version,
164 ),
165 DriveOperation::SystemOperation(system_operation_type) => system_operation_type
166 .into_low_level_drive_operations(
167 drive,
168 estimated_costs_only_with_layer_info,
169 block_info,
170 transaction,
171 platform_version,
172 ),
173 DriveOperation::ShieldedPoolOperation(shielded_pool_operation_type) => {
174 shielded_pool_operation_type.into_low_level_drive_operations(
175 drive,
176 estimated_costs_only_with_layer_info,
177 block_info,
178 transaction,
179 platform_version,
180 )
181 }
182 DriveOperation::GroveDBOperation(op) => Ok(vec![GroveOperation(op)]),
183 DriveOperation::GroveDBOpBatch(operations) => Ok(operations
184 .operations
185 .into_iter()
186 .map(GroveOperation)
187 .collect()),
188 DriveOperation::TokenOperation(token_operation_type) => token_operation_type
189 .into_low_level_drive_operations(
190 drive,
191 estimated_costs_only_with_layer_info,
192 block_info,
193 transaction,
194 platform_version,
195 ),
196 DriveOperation::GroupOperation(group_operation_type) => group_operation_type
197 .into_low_level_drive_operations(
198 drive,
199 estimated_costs_only_with_layer_info,
200 block_info,
201 transaction,
202 platform_version,
203 ),
204 DriveOperation::ContractGroupOperation(contract_group_operation_type) => {
205 contract_group_operation_type.into_low_level_drive_operations(
206 drive,
207 estimated_costs_only_with_layer_info,
208 block_info,
209 transaction,
210 platform_version,
211 )
212 }
213 DriveOperation::AddressFundsOperation(address_funds_operation_type) => {
214 address_funds_operation_type.into_low_level_drive_operations(
215 drive,
216 estimated_costs_only_with_layer_info,
217 block_info,
218 transaction,
219 platform_version,
220 )
221 }
222 DriveOperation::FinalizeOperation(_) => Ok(vec![]),
223 }
224 }
225}
226
227impl DriveOperation<'_> {
228 pub(crate) fn into_low_level_drive_operations_after_ttl_drain(
230 self,
231 drive: &Drive,
232 estimated_costs_only_with_layer_info: &mut Option<
233 HashMap<KeyInfoPath, EstimatedLayerInformation>,
234 >,
235 block_info: &BlockInfo,
236 transaction: TransactionArg,
237 platform_version: &PlatformVersion,
238 ) -> Result<Vec<LowLevelDriveOperation>, Error> {
239 match self {
240 Self::DocumentOperation(operation) => operation
241 .into_low_level_drive_operations_after_ttl_drain(
242 drive,
243 estimated_costs_only_with_layer_info,
244 block_info,
245 transaction,
246 platform_version,
247 ),
248 operation => operation.into_low_level_drive_operations(
249 drive,
250 estimated_costs_only_with_layer_info,
251 block_info,
252 transaction,
253 platform_version,
254 ),
255 }
256 }
257}
258
259impl Drive {
260 pub(crate) fn prepare_drive_operations_time_range_ttl(
263 &self,
264 operations: &[DriveOperation],
265 block_info: &BlockInfo,
266 transaction: TransactionArg,
267 platform_version: &PlatformVersion,
268 ) -> Result<(), Error> {
269 for operation in operations {
270 if let DriveOperation::DocumentOperation(document) = operation {
271 document.prepare_time_range_ttl(self, block_info, transaction, platform_version)?;
272 }
273 }
274 Ok(())
275 }
276}
277
278impl DriveOperationFinalizationTasks for DriveOperation<'_> {
279 fn finalization_tasks(
280 &self,
281 platform_version: &PlatformVersion,
282 ) -> Result<Option<Vec<DriveOperationFinalizeTask>>, Error> {
283 match platform_version
284 .drive
285 .methods
286 .state_transitions
287 .operations
288 .finalization_tasks
289 {
290 0 => self.finalization_tasks_v0(platform_version),
291 version => Err(Error::Drive(DriveError::UnknownVersionMismatch {
292 method: "DriveOperation.finalization_tasks".to_string(),
293 known_versions: vec![0],
294 received: version,
295 })),
296 }
297 }
298}
299
300impl DriveOperation<'_> {
301 fn finalization_tasks_v0(
302 &self,
303 platform_version: &PlatformVersion,
304 ) -> Result<Option<Vec<DriveOperationFinalizeTask>>, Error> {
305 match self {
306 DriveOperation::DataContractOperation(o) => o.finalization_tasks(platform_version),
307 DriveOperation::FinalizeOperation(task) => Ok(Some(vec![task.clone()])),
308 _ => Ok(None),
309 }
310 }
311
312 pub fn credit_mints(operations: &[DriveOperation]) -> Credits {
317 operations
318 .iter()
319 .filter_map(|operation| match operation {
320 DriveOperation::SystemOperation(SystemOperationType::AddToSystemCredits {
321 amount,
322 }) => Some(*amount),
323 _ => None,
324 })
325 .fold(0u64, |total, amount| total.saturating_add(amount))
326 }
327}
328
329#[cfg(feature = "server")]
330#[cfg(test)]
331mod tests {
332 use grovedb::Element;
333 use std::borrow::Cow;
334 use std::option::Option::None;
335
336 use super::*;
337
338 use crate::util::test_helpers::setup_contract;
339 use dpp::block::block_info::BlockInfo;
340 use dpp::data_contract::accessors::v0::DataContractV0Getters;
341 use dpp::data_contract::DataContract;
342 use dpp::serialization::PlatformSerializableWithPlatformVersion;
343 use dpp::tests::json_document::{json_document_to_contract, json_document_to_document};
344 use dpp::util::cbor_serializer;
345 use rand::Rng;
346 use serde_json::json;
347
348 use crate::util::batch::drive_op_batch::document::DocumentOperation::{
349 AddOperation, UpdateOperation,
350 };
351 use crate::util::batch::drive_op_batch::document::DocumentOperationType::MultipleDocumentOperationsForSameContractDocumentType;
352 use crate::util::batch::drive_op_batch::document::{
353 DocumentOperationsForContractDocumentType, UpdateOperationInfo,
354 };
355 use crate::util::batch::DataContractOperationType::ApplyContract;
356 use crate::util::batch::DocumentOperationType::AddDocument;
357 use crate::util::batch::DriveOperation::{DataContractOperation, DocumentOperation};
358
359 use crate::drive::contract::paths::contract_root_path;
360 use crate::drive::Drive;
361 use crate::util::object_size_info::DocumentInfo::DocumentRefInfo;
362 use crate::util::object_size_info::{DataContractInfo, DocumentTypeInfo, OwnedDocumentInfo};
363 use crate::util::storage_flags::StorageFlags;
364 use crate::util::test_helpers::setup::setup_drive_with_initial_state_structure;
365
366 #[test]
367 fn test_add_dashpay_documents() {
368 let drive: Drive = setup_drive_with_initial_state_structure(None);
369 let platform_version = PlatformVersion::latest();
370
371 let mut drive_operations = vec![];
372 let db_transaction = drive.grove.start_transaction();
373
374 let contract = json_document_to_contract(
375 "tests/supporting_files/contract/dashpay/dashpay-contract-all-mutable.json",
376 false,
377 platform_version,
378 )
379 .expect("expected to get contract");
380
381 let _document_type = contract
382 .document_type_for_name("contactRequest")
383 .expect("expected to get document type");
384
385 drive_operations.push(DataContractOperation(ApplyContract {
386 contract: Cow::Borrowed(&contract),
387 storage_flags: None,
388 }));
389
390 let random_owner_id = rand::thread_rng().gen::<[u8; 32]>();
391
392 let document_type = contract
393 .document_type_for_name("contactRequest")
394 .expect("expected to get document type");
395
396 let dashpay_cr_document = json_document_to_document(
397 "tests/supporting_files/contract/dashpay/contact-request0.json",
398 Some(random_owner_id.into()),
399 document_type,
400 platform_version,
401 )
402 .expect("expected to get document");
403
404 drive_operations.push(DocumentOperation(AddDocument {
405 owned_document_info: OwnedDocumentInfo {
406 document_info: DocumentRefInfo((
407 &dashpay_cr_document,
408 StorageFlags::optional_default_as_cow(),
409 )),
410 owner_id: None,
411 },
412 contract_info: DataContractInfo::BorrowedDataContract(&contract),
413 document_type_info: DocumentTypeInfo::DocumentTypeRef(document_type),
414 override_document: false,
415 }));
416
417 drive
418 .apply_drive_operations(
419 drive_operations,
420 true,
421 &BlockInfo::default(),
422 Some(&db_transaction),
423 platform_version,
424 None,
425 )
426 .expect("expected to insert contract and document");
427
428 let element = drive
429 .grove
430 .get(
431 &contract_root_path(&contract.id().to_buffer()),
432 &[0],
433 Some(&db_transaction),
434 &platform_version.drive.grove_version,
435 )
436 .unwrap()
437 .expect("expected to get contract back");
438
439 assert_eq!(
440 element,
441 Element::Item(
442 contract
443 .serialize_to_bytes_with_platform_version(platform_version)
444 .expect("expected to serialize contract"),
445 None
446 )
447 );
448
449 let query_value = json!({
450 "where": [
451 ],
452 "limit": 100,
453 "orderBy": [
454 ["$ownerId", "asc"],
455 ]
456 });
457 let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
458 .expect("expected to serialize to cbor");
459
460 let (docs, _, _) = drive
461 .query_documents_cbor_from_contract(
462 &contract,
463 document_type,
464 where_cbor.as_slice(),
465 None,
466 Some(&db_transaction),
467 Some(platform_version.protocol_version),
468 )
469 .expect("expected to query");
470 assert_eq!(docs.len(), 1);
471 }
472
473 #[test]
474 fn test_add_multiple_dashpay_documents_individually_should_succeed() {
475 let drive = setup_drive_with_initial_state_structure(None);
476
477 let platform_version = PlatformVersion::latest();
478
479 let mut drive_operations = vec![];
480 let db_transaction = drive.grove.start_transaction();
481
482 let contract = json_document_to_contract(
483 "tests/supporting_files/contract/dashpay/dashpay-contract-all-mutable.json",
484 false,
485 platform_version,
486 )
487 .expect("expected to get contract");
488
489 let document_type = contract
490 .document_type_for_name("contactRequest")
491 .expect("expected to get document type");
492
493 drive_operations.push(DataContractOperation(ApplyContract {
494 contract: Cow::Borrowed(&contract),
495 storage_flags: None,
496 }));
497 let random_owner_id = rand::thread_rng().gen::<[u8; 32]>();
498
499 let dashpay_cr_document = json_document_to_document(
500 "tests/supporting_files/contract/dashpay/contact-request0.json",
501 Some(random_owner_id.into()),
502 document_type,
503 platform_version,
504 )
505 .expect("expected to get contract");
506
507 drive_operations.push(DocumentOperation(AddDocument {
508 owned_document_info: OwnedDocumentInfo {
509 document_info: DocumentRefInfo((&dashpay_cr_document, None)),
510 owner_id: None,
511 },
512 contract_info: DataContractInfo::BorrowedDataContract(&contract),
513 document_type_info: DocumentTypeInfo::DocumentTypeNameAsStr("contactRequest"),
514 override_document: false,
515 }));
516
517 let random_owner_id = rand::thread_rng().gen::<[u8; 32]>();
518
519 let dashpay_cr_1_document = json_document_to_document(
520 "tests/supporting_files/contract/dashpay/contact-request1.json",
521 Some(random_owner_id.into()),
522 document_type,
523 platform_version,
524 )
525 .expect("expected to get contract");
526
527 drive_operations.push(DocumentOperation(AddDocument {
528 owned_document_info: OwnedDocumentInfo {
529 document_info: DocumentRefInfo((&dashpay_cr_1_document, None)),
530 owner_id: None,
531 },
532 contract_info: DataContractInfo::BorrowedDataContract(&contract),
533 document_type_info: DocumentTypeInfo::DocumentTypeNameAsStr("contactRequest"),
534 override_document: false,
535 }));
536
537 drive
538 .apply_drive_operations(
539 drive_operations,
540 true,
541 &BlockInfo::default(),
542 Some(&db_transaction),
543 platform_version,
544 None,
545 )
546 .expect("expected to be able to insert documents");
547
548 let query_value = json!({
549 "where": [
550 ],
551 "limit": 100,
552 "orderBy": [
553 ["$ownerId", "asc"],
554 ]
555 });
556 let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
557 .expect("expected to serialize to cbor");
558
559 let (docs, _, _) = drive
560 .query_documents_cbor_from_contract(
561 &contract,
562 document_type,
563 where_cbor.as_slice(),
564 None,
565 Some(&db_transaction),
566 Some(platform_version.protocol_version),
567 )
568 .expect("expected to query");
569 assert_eq!(docs.len(), 2);
570 }
571
572 #[test]
573 fn test_add_multiple_dashpay_documents() {
574 let drive: Drive = setup_drive_with_initial_state_structure(None);
575
576 let platform_version = PlatformVersion::latest();
577
578 let mut drive_operations = vec![];
579 let db_transaction = drive.grove.start_transaction();
580
581 let contract = json_document_to_contract(
582 "tests/supporting_files/contract/dashpay/dashpay-contract-all-mutable.json",
583 false,
584 platform_version,
585 )
586 .expect("expected to get contract");
587
588 let document_type = contract
589 .document_type_for_name("contactRequest")
590 .expect("expected to get document type");
591
592 drive_operations.push(DataContractOperation(ApplyContract {
593 contract: Cow::Borrowed(&contract),
594 storage_flags: None,
595 }));
596
597 let random_owner_id = rand::thread_rng().gen::<[u8; 32]>();
598
599 let document0 = json_document_to_document(
600 "tests/supporting_files/contract/dashpay/contact-request0.json",
601 Some(random_owner_id.into()),
602 document_type,
603 platform_version,
604 )
605 .expect("expected to get document 0");
606
607 let document1 = json_document_to_document(
608 "tests/supporting_files/contract/dashpay/contact-request1.json",
609 Some(random_owner_id.into()),
610 document_type,
611 platform_version,
612 )
613 .expect("expected to get document 1");
614
615 let operations = vec![
616 AddOperation {
617 owned_document_info: OwnedDocumentInfo {
618 document_info: DocumentRefInfo((
619 &document0,
620 StorageFlags::optional_default_as_cow(),
621 )),
622 owner_id: Some(random_owner_id),
623 },
624 override_document: false,
625 },
626 AddOperation {
627 owned_document_info: OwnedDocumentInfo {
628 document_info: DocumentRefInfo((
629 &document1,
630 StorageFlags::optional_default_as_cow(),
631 )),
632 owner_id: Some(random_owner_id),
633 },
634 override_document: false,
635 },
636 ];
637
638 drive_operations.push(DocumentOperation(
639 MultipleDocumentOperationsForSameContractDocumentType {
640 document_operations: DocumentOperationsForContractDocumentType {
641 operations,
642 contract: &contract,
643 document_type,
644 },
645 },
646 ));
647
648 drive
649 .apply_drive_operations(
650 drive_operations,
651 true,
652 &BlockInfo::default(),
653 Some(&db_transaction),
654 platform_version,
655 None,
656 )
657 .expect("expected to be able to insert documents");
658
659 let element = drive
660 .grove
661 .get(
662 &contract_root_path(&contract.id().to_buffer()),
663 &[0],
664 Some(&db_transaction),
665 &platform_version.drive.grove_version,
666 )
667 .unwrap()
668 .expect("expected to get contract back");
669
670 assert_eq!(
671 element,
672 Element::Item(
673 contract
674 .serialize_to_bytes_with_platform_version(platform_version)
675 .expect("expected to serialize contract"),
676 None
677 )
678 );
679
680 let query_value = json!({
681 "where": [
682 ],
683 "limit": 100,
684 "orderBy": [
685 ["$ownerId", "asc"],
686 ]
687 });
688 let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
689 .expect("expected to serialize to cbor");
690
691 let (docs, _, _) = drive
692 .query_documents_cbor_from_contract(
693 &contract,
694 document_type,
695 where_cbor.as_slice(),
696 None,
697 Some(&db_transaction),
698 Some(platform_version.protocol_version),
699 )
700 .expect("expected to query");
701 assert_eq!(docs.len(), 2);
702 }
703
704 #[test]
705 fn test_add_multiple_family_documents() {
706 let drive: Drive = setup_drive_with_initial_state_structure(None);
707
708 let platform_version = PlatformVersion::latest();
709
710 let mut drive_operations = vec![];
711 let db_transaction = drive.grove.start_transaction();
712
713 let contract = setup_contract(
714 &drive,
715 "tests/supporting_files/contract/family/family-contract.json",
716 None,
717 None,
718 None::<fn(&mut DataContract)>,
719 Some(&db_transaction),
720 None,
721 );
722
723 let document_type = contract
724 .document_type_for_name("person")
725 .expect("expected to get document type");
726
727 let random_owner_id0 = rand::thread_rng().gen::<[u8; 32]>();
728
729 let person_document0 = json_document_to_document(
730 "tests/supporting_files/contract/family/person0.json",
731 Some(random_owner_id0.into()),
732 document_type,
733 platform_version,
734 )
735 .expect("expected to get document");
736
737 let random_owner_id1 = rand::thread_rng().gen::<[u8; 32]>();
738
739 let person_document1 = json_document_to_document(
740 "tests/supporting_files/contract/family/person3.json",
741 Some(random_owner_id1.into()),
742 document_type,
743 platform_version,
744 )
745 .expect("expected to get document");
746
747 let mut operations = vec![];
748
749 operations.push(AddOperation {
750 owned_document_info: OwnedDocumentInfo {
751 document_info: DocumentRefInfo((
752 &person_document0,
753 StorageFlags::optional_default_as_cow(),
754 )),
755 owner_id: Some(random_owner_id0),
756 },
757 override_document: false,
758 });
759
760 let random_owner_id1 = rand::thread_rng().gen::<[u8; 32]>();
761
762 operations.push(AddOperation {
763 owned_document_info: OwnedDocumentInfo {
764 document_info: DocumentRefInfo((
765 &person_document1,
766 StorageFlags::optional_default_as_cow(),
767 )),
768 owner_id: Some(random_owner_id1),
769 },
770 override_document: false,
771 });
772
773 drive_operations.push(DocumentOperation(
774 MultipleDocumentOperationsForSameContractDocumentType {
775 document_operations: DocumentOperationsForContractDocumentType {
776 operations,
777 contract: &contract,
778 document_type,
779 },
780 },
781 ));
782
783 drive
784 .apply_drive_operations(
785 drive_operations,
786 true,
787 &BlockInfo::default(),
788 Some(&db_transaction),
789 platform_version,
790 None,
791 )
792 .expect("expected to be able to insert documents");
793
794 let query_value = json!({
795 "where": [
796 ],
797 "limit": 100,
798 "orderBy": [
799 ["$ownerId", "asc"],
800 ]
801 });
802 let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
803 .expect("expected to serialize to cbor");
804
805 let (docs, _, _) = drive
806 .query_documents_cbor_from_contract(
807 &contract,
808 document_type,
809 where_cbor.as_slice(),
810 None,
811 Some(&db_transaction),
812 Some(platform_version.protocol_version),
813 )
814 .expect("expected to query");
815 assert_eq!(docs.len(), 2);
816 }
817
818 #[test]
819 fn test_update_multiple_family_documents() {
820 let drive: Drive = setup_drive_with_initial_state_structure(None);
821
822 let platform_version = PlatformVersion::latest();
823
824 let mut drive_operations = vec![];
825 let db_transaction = drive.grove.start_transaction();
826
827 let contract = setup_contract(
828 &drive,
829 "tests/supporting_files/contract/family/family-contract-only-age-index.json",
830 None,
831 None,
832 None::<fn(&mut DataContract)>,
833 Some(&db_transaction),
834 None,
835 );
836
837 let document_type = contract
838 .document_type_for_name("person")
839 .expect("expected to get document type");
840
841 let random_owner_id0 = rand::thread_rng().gen::<[u8; 32]>();
842
843 let person_document0 = json_document_to_document(
844 "tests/supporting_files/contract/family/person0.json",
845 Some(random_owner_id0.into()),
846 document_type,
847 platform_version,
848 )
849 .expect("expected to get document");
850
851 let random_owner_id1 = rand::thread_rng().gen::<[u8; 32]>();
852
853 let person_document1 = json_document_to_document(
854 "tests/supporting_files/contract/family/person3.json",
855 Some(random_owner_id1.into()),
856 document_type,
857 platform_version,
858 )
859 .expect("expected to get document");
860
861 let operations = vec![
862 AddOperation {
863 owned_document_info: OwnedDocumentInfo {
864 document_info: DocumentRefInfo((
865 &person_document0,
866 StorageFlags::optional_default_as_cow(),
867 )),
868 owner_id: Some(random_owner_id0),
869 },
870 override_document: false,
871 },
872 AddOperation {
873 owned_document_info: OwnedDocumentInfo {
874 document_info: DocumentRefInfo((
875 &person_document1,
876 StorageFlags::optional_default_as_cow(),
877 )),
878 owner_id: Some(random_owner_id1),
879 },
880 override_document: false,
881 },
882 ];
883
884 drive_operations.push(DocumentOperation(
885 MultipleDocumentOperationsForSameContractDocumentType {
886 document_operations: DocumentOperationsForContractDocumentType {
887 operations,
888 contract: &contract,
889 document_type,
890 },
891 },
892 ));
893
894 drive
895 .apply_drive_operations(
896 drive_operations,
897 true,
898 &BlockInfo::default(),
899 Some(&db_transaction),
900 platform_version,
901 None,
902 )
903 .expect("expected to be able to insert documents");
904
905 drive_operations = vec![];
908
909 let random_owner_id0 = rand::thread_rng().gen::<[u8; 32]>();
910
911 let person_document0 = json_document_to_document(
912 "tests/supporting_files/contract/family/person0-older.json",
913 Some(random_owner_id0.into()),
914 document_type,
915 platform_version,
916 )
917 .expect("expected to get document");
918
919 let random_owner_id1 = rand::thread_rng().gen::<[u8; 32]>();
920
921 let person_document1 = json_document_to_document(
922 "tests/supporting_files/contract/family/person3-older.json",
923 Some(random_owner_id1.into()),
924 document_type,
925 platform_version,
926 )
927 .expect("expected to get document");
928
929 let operations = vec![
930 UpdateOperation(UpdateOperationInfo {
931 document: &person_document0,
932 serialized_document: None,
933 owner_id: Some(random_owner_id0),
934 storage_flags: None,
935 }),
936 UpdateOperation(UpdateOperationInfo {
937 document: &person_document1,
938 serialized_document: None,
939 owner_id: Some(random_owner_id1),
940 storage_flags: None,
941 }),
942 ];
943
944 drive_operations.push(DocumentOperation(
945 MultipleDocumentOperationsForSameContractDocumentType {
946 document_operations: DocumentOperationsForContractDocumentType {
947 operations,
948 contract: &contract,
949 document_type,
950 },
951 },
952 ));
953
954 drive
955 .apply_drive_operations(
956 drive_operations,
957 true,
958 &BlockInfo::default(),
959 Some(&db_transaction),
960 platform_version,
961 None,
962 )
963 .expect("expected to be able to update documents");
964
965 let query_value = json!({
966 "where": [
967 ],
968 "limit": 100,
969 "orderBy": [
970 ["age", "asc"],
971 ]
972 });
973 let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
974 .expect("expected to serialize to cbor");
975
976 let (docs, _, _) = drive
977 .query_documents_cbor_from_contract(
978 &contract,
979 document_type,
980 where_cbor.as_slice(),
981 None,
982 Some(&db_transaction),
983 Some(platform_version.protocol_version),
984 )
985 .expect("expected to query");
986 assert_eq!(docs.len(), 2);
987
988 let query_value = json!({
989 "where": [
990 ["age", "==", 35]
991 ],
992 "limit": 100,
993 "orderBy": [
994 ["age", "asc"],
995 ]
996 });
997 let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
998 .expect("expected to serialize to cbor");
999
1000 let (docs, _, _) = drive
1001 .query_documents_cbor_from_contract(
1002 &contract,
1003 document_type,
1004 where_cbor.as_slice(),
1005 None,
1006 Some(&db_transaction),
1007 Some(platform_version.protocol_version),
1008 )
1009 .expect("expected to query");
1010 assert_eq!(docs.len(), 0);
1011
1012 let query_value = json!({
1013 "where": [
1014 ["age", "==", 36]
1015 ],
1016 "limit": 100,
1017 "orderBy": [
1018 ["age", "asc"],
1019 ]
1020 });
1021 let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
1022 .expect("expected to serialize to cbor");
1023
1024 let (docs, _, _) = drive
1025 .query_documents_cbor_from_contract(
1026 &contract,
1027 document_type,
1028 where_cbor.as_slice(),
1029 None,
1030 Some(&db_transaction),
1031 Some(platform_version.protocol_version),
1032 )
1033 .expect("expected to query");
1034 assert_eq!(docs.len(), 2);
1035 }
1036
1037 #[test]
1038 fn test_update_multiple_family_documents_with_index_being_removed_and_added() {
1039 let drive: Drive = setup_drive_with_initial_state_structure(None);
1040
1041 let platform_version = PlatformVersion::latest();
1042
1043 let db_transaction = drive.grove.start_transaction();
1044
1045 let contract = setup_contract(
1046 &drive,
1047 "tests/supporting_files/contract/family/family-contract-only-age-index.json",
1048 None,
1049 None,
1050 None::<fn(&mut DataContract)>,
1051 Some(&db_transaction),
1052 None,
1053 );
1054
1055 let document_type = contract
1056 .document_type_for_name("person")
1057 .expect("expected to get document type");
1058
1059 let random_owner_id0 = rand::thread_rng().gen::<[u8; 32]>();
1060
1061 let person_document0 = json_document_to_document(
1062 "tests/supporting_files/contract/family/person0.json",
1063 Some(random_owner_id0.into()),
1064 document_type,
1065 platform_version,
1066 )
1067 .expect("expected to get document");
1068
1069 let random_owner_id1 = rand::thread_rng().gen::<[u8; 32]>();
1070
1071 let person_document1 = json_document_to_document(
1072 "tests/supporting_files/contract/family/person3-older.json",
1073 Some(random_owner_id1.into()),
1074 document_type,
1075 platform_version,
1076 )
1077 .expect("expected to get document");
1078
1079 let operations = vec![
1080 AddOperation {
1081 owned_document_info: OwnedDocumentInfo {
1082 document_info: DocumentRefInfo((
1083 &person_document0,
1084 StorageFlags::optional_default_as_cow(),
1085 )),
1086 owner_id: Some(random_owner_id0),
1087 },
1088 override_document: false,
1089 },
1090 AddOperation {
1091 owned_document_info: OwnedDocumentInfo {
1092 document_info: DocumentRefInfo((
1093 &person_document1,
1094 StorageFlags::optional_default_as_cow(),
1095 )),
1096 owner_id: Some(random_owner_id1),
1097 },
1098 override_document: false,
1099 },
1100 ];
1101 let drive_operations = vec![DocumentOperation(
1102 MultipleDocumentOperationsForSameContractDocumentType {
1103 document_operations: DocumentOperationsForContractDocumentType {
1104 operations,
1105 contract: &contract,
1106 document_type,
1107 },
1108 },
1109 )];
1110
1111 drive
1112 .apply_drive_operations(
1113 drive_operations,
1114 true,
1115 &BlockInfo::default(),
1116 Some(&db_transaction),
1117 platform_version,
1118 None,
1119 )
1120 .expect("expected to be able to insert documents");
1121
1122 let person_document0 = json_document_to_document(
1125 "tests/supporting_files/contract/family/person0-older.json",
1126 Some(random_owner_id0.into()),
1127 document_type,
1128 platform_version,
1129 )
1130 .expect("expected to get document");
1131
1132 let person_document1 = json_document_to_document(
1133 "tests/supporting_files/contract/family/person3.json",
1134 Some(random_owner_id1.into()),
1135 document_type,
1136 platform_version,
1137 )
1138 .expect("expected to get document");
1139
1140 let operations = vec![
1141 UpdateOperation(UpdateOperationInfo {
1142 document: &person_document0,
1143 serialized_document: None,
1144 owner_id: Some(random_owner_id0),
1145 storage_flags: None,
1146 }),
1147 UpdateOperation(UpdateOperationInfo {
1148 document: &person_document1,
1149 serialized_document: None,
1150 owner_id: Some(random_owner_id1),
1151 storage_flags: None,
1152 }),
1153 ];
1154
1155 let drive_operations = vec![DocumentOperation(
1156 MultipleDocumentOperationsForSameContractDocumentType {
1157 document_operations: DocumentOperationsForContractDocumentType {
1158 operations,
1159 contract: &contract,
1160 document_type,
1161 },
1162 },
1163 )];
1164
1165 drive
1166 .apply_drive_operations(
1167 drive_operations,
1168 true,
1169 &BlockInfo::default(),
1170 Some(&db_transaction),
1171 platform_version,
1172 None,
1173 )
1174 .expect("expected to be able to update documents");
1175
1176 let query_value = json!({
1177 "where": [
1178 ["age", ">=", 5]
1179 ],
1180 "limit": 100,
1181 "orderBy": [
1182 ["age", "asc"],
1183 ]
1184 });
1185 let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
1186 .expect("expected to serialize to cbor");
1187
1188 let (docs, _, _) = drive
1189 .query_documents_cbor_from_contract(
1190 &contract,
1191 document_type,
1192 where_cbor.as_slice(),
1193 None,
1194 Some(&db_transaction),
1195 Some(platform_version.protocol_version),
1196 )
1197 .expect("expected to query");
1198 assert_eq!(docs.len(), 2);
1199
1200 let query_value = json!({
1201 "where": [
1202 ["age", "==", 35]
1203 ],
1204 "limit": 100,
1205 "orderBy": [
1206 ["age", "asc"],
1207 ]
1208 });
1209 let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
1210 .expect("expected to serialize to cbor");
1211
1212 let (docs, _, _) = drive
1213 .query_documents_cbor_from_contract(
1214 &contract,
1215 document_type,
1216 where_cbor.as_slice(),
1217 None,
1218 Some(&db_transaction),
1219 Some(platform_version.protocol_version),
1220 )
1221 .expect("expected to query");
1222 assert_eq!(docs.len(), 1);
1223
1224 let query_value = json!({
1225 "where": [
1226 ["age", "==", 36]
1227 ],
1228 "limit": 100,
1229 "orderBy": [
1230 ["age", "asc"],
1231 ]
1232 });
1233 let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
1234 .expect("expected to serialize to cbor");
1235
1236 let (docs, _, _) = drive
1237 .query_documents_cbor_from_contract(
1238 &contract,
1239 document_type,
1240 where_cbor.as_slice(),
1241 None,
1242 Some(&db_transaction),
1243 Some(platform_version.protocol_version),
1244 )
1245 .expect("expected to query");
1246 assert_eq!(docs.len(), 1);
1247 }
1248}