1use crate::error::drive::DriveError;
2use crate::error::fee::FeeError;
3use crate::error::Error;
4use crate::util::object_size_info::DriveKeyInfo::{Key, KeySize};
5use crate::util::object_size_info::KeyValueInfo::{KeyRefRequest, KeyValueMaxSize};
6use crate::util::object_size_info::{DriveKeyInfo, KeyValueInfo};
7use crate::util::storage_flags::StorageFlags;
8use crate::util::type_constants::{
9 DEFAULT_HASH_SIZE_U16, DEFAULT_HASH_SIZE_U8, U32_SIZE_U16, U32_SIZE_U8, U64_SIZE_U16,
10 U64_SIZE_U8,
11};
12use dpp::data_contract::document_type::accessors::DocumentTypeV0Getters;
13use dpp::data_contract::document_type::methods::DocumentTypeBasicMethods;
14use dpp::data_contract::document_type::{DocumentTypeRef, IndexLevel};
15use dpp::document::document_methods::DocumentMethodsV0;
16use dpp::document::{Document, DocumentV0Getters};
17use dpp::version::PlatformVersion;
18use grovedb::batch::key_info::KeyInfo;
19use std::borrow::Cow;
20
21#[derive(Clone, Debug)]
23pub enum DocumentInfo<'a> {
24 DocumentOwnedInfo((Document, Option<Cow<'a, StorageFlags>>)),
26 DocumentRefInfo((&'a Document, Option<Cow<'a, StorageFlags>>)),
28 DocumentRefAndSerialization((&'a Document, &'a [u8], Option<Cow<'a, StorageFlags>>)),
30 DocumentAndSerialization((Document, Vec<u8>, Option<Cow<'a, StorageFlags>>)),
32 DocumentEstimatedAverageSize(u32),
34}
35
36pub trait DocumentInfoV0Methods {
38 fn is_document_and_serialization(&self) -> bool;
40 fn is_document_size(&self) -> bool;
42 fn get_borrowed_document(&self) -> Option<&Document>;
44 fn id_key_value_info(&self) -> KeyValueInfo<'_>;
46 fn get_estimated_size_for_document_type(
48 &self,
49 key_path: &str,
50 document_type: DocumentTypeRef,
51 platform_version: &PlatformVersion,
52 ) -> Result<u16, Error>;
53 fn get_raw_for_document_type(
55 &self,
56 key_path: &str,
57 document_type: DocumentTypeRef,
58 owner_id: Option<[u8; 32]>,
59 size_info_with_base_event: Option<(&IndexLevel, [u8; 32])>,
60 platform_version: &PlatformVersion,
61 ) -> Result<Option<DriveKeyInfo<'_>>, Error>;
62 fn get_borrowed_document_and_storage_flags(&self)
64 -> Option<(&Document, Option<&StorageFlags>)>;
65 fn get_storage_flags_ref(&self) -> Option<&StorageFlags>;
67 fn get_document_id_as_slice(&self) -> Option<&[u8]>;
69}
70
71impl DocumentInfoV0Methods for DocumentInfo<'_> {
72 fn is_document_and_serialization(&self) -> bool {
74 matches!(self, DocumentInfo::DocumentRefAndSerialization(..))
75 }
76
77 fn is_document_size(&self) -> bool {
79 matches!(self, DocumentInfo::DocumentEstimatedAverageSize(_))
80 }
81
82 fn get_borrowed_document(&self) -> Option<&Document> {
84 match self {
85 DocumentInfo::DocumentRefAndSerialization((document, _, _))
86 | DocumentInfo::DocumentRefInfo((document, _)) => Some(document),
87 DocumentInfo::DocumentOwnedInfo((document, _))
88 | DocumentInfo::DocumentAndSerialization((document, _, _)) => Some(document),
89 DocumentInfo::DocumentEstimatedAverageSize(_) => None,
90 }
91 }
92
93 fn id_key_value_info(&self) -> KeyValueInfo<'_> {
95 match self {
96 DocumentInfo::DocumentRefAndSerialization((document, _, _))
97 | DocumentInfo::DocumentRefInfo((document, _)) => {
98 KeyRefRequest(document.id_ref().as_slice())
99 }
100 DocumentInfo::DocumentOwnedInfo((document, _))
101 | DocumentInfo::DocumentAndSerialization((document, _, _)) => {
102 KeyRefRequest(document.id_ref().as_slice())
103 }
104 DocumentInfo::DocumentEstimatedAverageSize(document_max_size) => {
105 KeyValueMaxSize((32, *document_max_size))
106 }
107 }
108 }
109
110 fn get_estimated_size_for_document_type(
112 &self,
113 key_path: &str,
114 document_type: DocumentTypeRef,
115 platform_version: &PlatformVersion,
116 ) -> Result<u16, Error> {
117 match key_path {
118 "$ownerId" | "$id" | "$creatorId" => Ok(DEFAULT_HASH_SIZE_U16),
119 "$createdAt" | "$updatedAt" | "$transferredAt" => Ok(U64_SIZE_U16),
120 "$createdAtBlockHeight" | "$updatedAtBlockHeight" | "$transferredAtBlockHeight" => {
121 Ok(U64_SIZE_U16)
122 }
123 "$createdAtCoreBlockHeight"
124 | "$updatedAtCoreBlockHeight"
125 | "$transferredAtCoreBlockHeight" => Ok(U32_SIZE_U16),
126 key_path => {
127 let property = document_type.flattened_properties().get(key_path).ok_or({
128 Error::Fee(FeeError::DocumentTypeFieldNotFoundForEstimation(format!(
129 "incorrect key path [{}] for document type for estimated sizes",
130 key_path
131 )))
132 })?;
133 let estimated_size = property
134 .property_type
135 .middle_byte_size_ceil(platform_version)?
136 .ok_or({
137 Error::Drive(DriveError::CorruptedCodeExecution(
138 "document type must have a max size",
139 ))
140 })?;
141 Ok(estimated_size)
142 }
143 }
144 }
145
146 fn get_raw_for_document_type(
148 &self,
149 key_path: &str,
150 document_type: DocumentTypeRef,
151 owner_id: Option<[u8; 32]>,
152 size_info_with_base_event: Option<(&IndexLevel, [u8; 32])>,
153 platform_version: &PlatformVersion,
154 ) -> Result<Option<DriveKeyInfo<'_>>, Error> {
155 match self {
156 DocumentInfo::DocumentRefAndSerialization((document, _, _))
157 | DocumentInfo::DocumentRefInfo((document, _)) => {
158 let raw_value = document.get_raw_for_document_type(
159 key_path,
160 document_type,
161 owner_id,
162 platform_version,
163 )?;
164 match raw_value {
165 None => Ok(None),
166 Some(value) => Ok(Some(Key(value))),
167 }
168 }
169 DocumentInfo::DocumentOwnedInfo((document, _))
170 | DocumentInfo::DocumentAndSerialization((document, _, _)) => {
171 let raw_value = document.get_raw_for_document_type(
172 key_path,
173 document_type,
174 owner_id,
175 platform_version,
176 )?;
177 match raw_value {
178 None => Ok(None),
179 Some(value) => Ok(Some(Key(value))),
180 }
181 }
182 DocumentInfo::DocumentEstimatedAverageSize(_) => {
183 let (index_level, base_event) = size_info_with_base_event.ok_or(Error::Drive(
184 DriveError::CorruptedCodeExecution("size_info_with_base_event None but needed"),
185 ))?;
186 match key_path {
187 "$ownerId" | "$id" | "$creatorId" => Ok(Some(KeySize(KeyInfo::MaxKeySize {
188 unique_id: document_type
189 .unique_id_for_document_field(index_level, base_event)
190 .to_vec(),
191 max_size: DEFAULT_HASH_SIZE_U8,
192 }))),
193 "$createdAt" | "$updatedAt" | "$transferredAt" => {
194 Ok(Some(KeySize(KeyInfo::MaxKeySize {
195 unique_id: document_type
196 .unique_id_for_document_field(index_level, base_event)
197 .to_vec(),
198 max_size: U64_SIZE_U8,
199 })))
200 }
201 "$createdAtBlockHeight"
202 | "$updatedAtBlockHeight"
203 | "$transferredAtBlockHeight" => Ok(Some(KeySize(KeyInfo::MaxKeySize {
204 unique_id: document_type
205 .unique_id_for_document_field(index_level, base_event)
206 .to_vec(),
207 max_size: U64_SIZE_U8,
208 }))),
209 "$createdAtCoreBlockHeight"
210 | "$updatedAtCoreBlockHeight"
211 | "$transferredAtCoreBlockHeight" => Ok(Some(KeySize(KeyInfo::MaxKeySize {
212 unique_id: document_type
213 .unique_id_for_document_field(index_level, base_event)
214 .to_vec(),
215 max_size: U32_SIZE_U8,
216 }))),
217 key_path => {
218 let property =
219 document_type.flattened_properties().get(key_path).ok_or({
220 Error::Fee(FeeError::DocumentTypeFieldNotFoundForEstimation(
221 format!("incorrect key path [{}] for document type for get_raw_for_document_type", key_path)
222 ))
223 })?;
224
225 let estimated_middle_size = property
226 .property_type
227 .middle_byte_size_ceil(platform_version)?
228 .ok_or({
229 Error::Drive(DriveError::CorruptedCodeExecution(
230 "document type must have a max size",
231 ))
232 })?;
233 if estimated_middle_size > u8::MAX as u16 {
234 return Err(Error::Drive(DriveError::CorruptedCodeExecution(
236 "estimated middle size is too big for a key",
237 )));
238 }
239 Ok(Some(KeySize(KeyInfo::MaxKeySize {
240 unique_id: document_type
241 .unique_id_for_document_field(index_level, base_event)
242 .to_vec(),
243 max_size: estimated_middle_size as u8,
244 })))
245 }
246 }
247 }
248 }
249 }
250
251 fn get_borrowed_document_and_storage_flags(
253 &self,
254 ) -> Option<(&Document, Option<&StorageFlags>)> {
255 match self {
256 DocumentInfo::DocumentRefAndSerialization((document, _, storage_flags))
257 | DocumentInfo::DocumentRefInfo((document, storage_flags)) => {
258 Some((document, storage_flags.as_ref().map(|flags| flags.as_ref())))
259 }
260 DocumentInfo::DocumentOwnedInfo((document, storage_flags))
261 | DocumentInfo::DocumentAndSerialization((document, _, storage_flags)) => {
262 Some((document, storage_flags.as_ref().map(|flags| flags.as_ref())))
263 }
264 DocumentInfo::DocumentEstimatedAverageSize(_) => None,
265 }
266 }
267
268 fn get_storage_flags_ref(&self) -> Option<&StorageFlags> {
270 match self {
271 DocumentInfo::DocumentRefAndSerialization((_, _, storage_flags))
272 | DocumentInfo::DocumentRefInfo((_, storage_flags))
273 | DocumentInfo::DocumentOwnedInfo((_, storage_flags))
274 | DocumentInfo::DocumentAndSerialization((_, _, storage_flags)) => {
275 storage_flags.as_ref().map(|flags| flags.as_ref())
276 }
277 DocumentInfo::DocumentEstimatedAverageSize(_) => {
278 StorageFlags::optional_default_as_ref()
279 }
280 }
281 }
282
283 fn get_document_id_as_slice(&self) -> Option<&[u8]> {
285 match self {
286 DocumentInfo::DocumentRefAndSerialization((document, _, _))
287 | DocumentInfo::DocumentRefInfo((document, _)) => Some(document.id_ref().as_slice()),
288 DocumentInfo::DocumentOwnedInfo((document, _))
289 | DocumentInfo::DocumentAndSerialization((document, _, _)) => {
290 Some(document.id_ref().as_slice())
291 }
292 DocumentInfo::DocumentEstimatedAverageSize(_) => None,
293 }
294 }
295}
296
297#[cfg(test)]
298mod tests {
299 use super::*;
300 use dpp::document::DocumentV0;
301 use dpp::prelude::Identifier;
302 use std::collections::BTreeMap;
303
304 fn make_document(id_bytes: [u8; 32]) -> Document {
306 Document::V0(DocumentV0 {
307 contract_version: None,
308 id: Identifier::new(id_bytes),
309 owner_id: Identifier::new([0xAA; 32]),
310 properties: BTreeMap::new(),
311 revision: Some(1),
312 created_at: None,
313 updated_at: None,
314 transferred_at: None,
315 created_at_block_height: None,
316 updated_at_block_height: None,
317 transferred_at_block_height: None,
318 created_at_core_block_height: None,
319 updated_at_core_block_height: None,
320 transferred_at_core_block_height: None,
321 creator_id: None,
322 })
323 }
324
325 #[test]
330 fn test_is_document_and_serialization_true_for_ref_and_serialization() {
331 let doc = make_document([1; 32]);
332 let serialized = vec![1, 2, 3];
333 let info = DocumentInfo::DocumentRefAndSerialization((&doc, &serialized, None));
334 assert!(info.is_document_and_serialization());
335 }
336
337 #[test]
338 fn test_is_document_and_serialization_false_for_owned_info() {
339 let doc = make_document([2; 32]);
340 let info = DocumentInfo::DocumentOwnedInfo((doc, None));
341 assert!(!info.is_document_and_serialization());
342 }
343
344 #[test]
345 fn test_is_document_and_serialization_false_for_ref_info() {
346 let doc = make_document([3; 32]);
347 let info = DocumentInfo::DocumentRefInfo((&doc, None));
348 assert!(!info.is_document_and_serialization());
349 }
350
351 #[test]
352 fn test_is_document_and_serialization_false_for_estimated_size() {
353 let info = DocumentInfo::DocumentEstimatedAverageSize(100);
354 assert!(!info.is_document_and_serialization());
355 }
356
357 #[test]
358 fn test_is_document_and_serialization_false_for_document_and_serialization() {
359 let doc = make_document([4; 32]);
360 let info = DocumentInfo::DocumentAndSerialization((doc, vec![9, 8, 7], None));
361 assert!(!info.is_document_and_serialization());
362 }
363
364 #[test]
369 fn test_is_document_size_true_for_estimated() {
370 let info = DocumentInfo::DocumentEstimatedAverageSize(256);
371 assert!(info.is_document_size());
372 }
373
374 #[test]
375 fn test_is_document_size_false_for_owned_info() {
376 let doc = make_document([5; 32]);
377 let info = DocumentInfo::DocumentOwnedInfo((doc, None));
378 assert!(!info.is_document_size());
379 }
380
381 #[test]
382 fn test_is_document_size_false_for_ref_info() {
383 let doc = make_document([6; 32]);
384 let info = DocumentInfo::DocumentRefInfo((&doc, None));
385 assert!(!info.is_document_size());
386 }
387
388 #[test]
393 fn test_get_borrowed_document_from_ref_info() {
394 let doc = make_document([10; 32]);
395 let info = DocumentInfo::DocumentRefInfo((&doc, None));
396 let borrowed = info.get_borrowed_document();
397 assert!(borrowed.is_some());
398 assert_eq!(borrowed.unwrap().id_ref().as_slice(), &[10u8; 32]);
399 }
400
401 #[test]
402 fn test_get_borrowed_document_from_ref_and_serialization() {
403 let doc = make_document([11; 32]);
404 let ser = vec![0u8; 5];
405 let info = DocumentInfo::DocumentRefAndSerialization((&doc, &ser, None));
406 let borrowed = info.get_borrowed_document();
407 assert!(borrowed.is_some());
408 assert_eq!(borrowed.unwrap().id_ref().as_slice(), &[11u8; 32]);
409 }
410
411 #[test]
412 fn test_get_borrowed_document_from_owned_info() {
413 let doc = make_document([12; 32]);
414 let info = DocumentInfo::DocumentOwnedInfo((doc, None));
415 let borrowed = info.get_borrowed_document();
416 assert!(borrowed.is_some());
417 assert_eq!(borrowed.unwrap().id_ref().as_slice(), &[12u8; 32]);
418 }
419
420 #[test]
421 fn test_get_borrowed_document_from_document_and_serialization() {
422 let doc = make_document([13; 32]);
423 let info = DocumentInfo::DocumentAndSerialization((doc, vec![1, 2], None));
424 let borrowed = info.get_borrowed_document();
425 assert!(borrowed.is_some());
426 assert_eq!(borrowed.unwrap().id_ref().as_slice(), &[13u8; 32]);
427 }
428
429 #[test]
430 fn test_get_borrowed_document_none_for_estimated() {
431 let info = DocumentInfo::DocumentEstimatedAverageSize(500);
432 assert!(info.get_borrowed_document().is_none());
433 }
434
435 #[test]
440 fn test_id_key_value_info_ref_info_returns_key_ref_request() {
441 let doc = make_document([20; 32]);
442 let info = DocumentInfo::DocumentRefInfo((&doc, None));
443 match info.id_key_value_info() {
444 KeyRefRequest(key) => {
445 assert_eq!(key, &[20u8; 32]);
446 }
447 _ => panic!("expected KeyRefRequest"),
448 }
449 }
450
451 #[test]
452 fn test_id_key_value_info_owned_info_returns_key_ref_request() {
453 let doc = make_document([21; 32]);
454 let info = DocumentInfo::DocumentOwnedInfo((doc, None));
455 match info.id_key_value_info() {
456 KeyRefRequest(key) => {
457 assert_eq!(key, &[21u8; 32]);
458 }
459 _ => panic!("expected KeyRefRequest"),
460 }
461 }
462
463 #[test]
464 fn test_id_key_value_info_estimated_returns_key_value_max_size() {
465 let info = DocumentInfo::DocumentEstimatedAverageSize(999);
466 match info.id_key_value_info() {
467 KeyValueMaxSize((key_size, doc_size)) => {
468 assert_eq!(key_size, 32);
469 assert_eq!(doc_size, 999);
470 }
471 _ => panic!("expected KeyValueMaxSize"),
472 }
473 }
474
475 #[test]
476 fn test_id_key_value_info_ref_and_serialization_returns_key_ref_request() {
477 let doc = make_document([22; 32]);
478 let ser = vec![0u8; 3];
479 let info = DocumentInfo::DocumentRefAndSerialization((&doc, &ser, None));
480 match info.id_key_value_info() {
481 KeyRefRequest(key) => {
482 assert_eq!(key, &[22u8; 32]);
483 }
484 _ => panic!("expected KeyRefRequest"),
485 }
486 }
487
488 #[test]
489 fn test_id_key_value_info_document_and_serialization_returns_key_ref_request() {
490 let doc = make_document([23; 32]);
491 let info = DocumentInfo::DocumentAndSerialization((doc, vec![5, 6, 7], None));
492 match info.id_key_value_info() {
493 KeyRefRequest(key) => {
494 assert_eq!(key, &[23u8; 32]);
495 }
496 _ => panic!("expected KeyRefRequest"),
497 }
498 }
499
500 #[test]
505 fn test_estimated_size_for_owner_id() {
506 let info = DocumentInfo::DocumentEstimatedAverageSize(100);
507 assert_eq!(DEFAULT_HASH_SIZE_U16, 32);
523 assert_eq!(U64_SIZE_U16, 8);
524 assert_eq!(U32_SIZE_U16, 4);
525 drop(info);
528 }
529
530 #[test]
535 fn test_get_borrowed_document_and_storage_flags_from_ref_info_no_flags() {
536 let doc = make_document([30; 32]);
537 let info = DocumentInfo::DocumentRefInfo((&doc, None));
538 let result = info.get_borrowed_document_and_storage_flags();
539 assert!(result.is_some());
540 let (d, flags) = result.unwrap();
541 assert_eq!(d.id_ref().as_slice(), &[30u8; 32]);
542 assert!(flags.is_none());
543 }
544
545 #[test]
546 fn test_get_borrowed_document_and_storage_flags_from_owned_info_no_flags() {
547 let doc = make_document([31; 32]);
548 let info = DocumentInfo::DocumentOwnedInfo((doc, None));
549 let result = info.get_borrowed_document_and_storage_flags();
550 assert!(result.is_some());
551 let (d, flags) = result.unwrap();
552 assert_eq!(d.id_ref().as_slice(), &[31u8; 32]);
553 assert!(flags.is_none());
554 }
555
556 #[test]
557 fn test_get_borrowed_document_and_storage_flags_none_for_estimated() {
558 let info = DocumentInfo::DocumentEstimatedAverageSize(200);
559 assert!(info.get_borrowed_document_and_storage_flags().is_none());
560 }
561
562 #[test]
563 fn test_get_borrowed_document_and_storage_flags_ref_and_serialization() {
564 let doc = make_document([32; 32]);
565 let ser = vec![7u8; 4];
566 let info = DocumentInfo::DocumentRefAndSerialization((&doc, &ser, None));
567 let result = info.get_borrowed_document_and_storage_flags();
568 assert!(result.is_some());
569 let (d, flags) = result.unwrap();
570 assert_eq!(d.id_ref().as_slice(), &[32u8; 32]);
571 assert!(flags.is_none());
572 }
573
574 #[test]
575 fn test_get_borrowed_document_and_storage_flags_document_and_serialization() {
576 let doc = make_document([33; 32]);
577 let info = DocumentInfo::DocumentAndSerialization((doc, vec![10, 20], None));
578 let result = info.get_borrowed_document_and_storage_flags();
579 assert!(result.is_some());
580 let (d, flags) = result.unwrap();
581 assert_eq!(d.id_ref().as_slice(), &[33u8; 32]);
582 assert!(flags.is_none());
583 }
584
585 #[test]
590 fn test_get_storage_flags_ref_none_without_flags() {
591 let doc = make_document([40; 32]);
592 let info = DocumentInfo::DocumentRefInfo((&doc, None));
593 assert!(info.get_storage_flags_ref().is_none());
594 }
595
596 #[test]
597 fn test_get_storage_flags_ref_none_for_owned_without_flags() {
598 let doc = make_document([41; 32]);
599 let info = DocumentInfo::DocumentOwnedInfo((doc, None));
600 assert!(info.get_storage_flags_ref().is_none());
601 }
602
603 #[test]
608 fn test_get_document_id_as_slice_from_ref_info() {
609 let doc = make_document([50; 32]);
610 let info = DocumentInfo::DocumentRefInfo((&doc, None));
611 assert_eq!(info.get_document_id_as_slice(), Some([50u8; 32].as_slice()));
612 }
613
614 #[test]
615 fn test_get_document_id_as_slice_from_owned_info() {
616 let doc = make_document([51; 32]);
617 let info = DocumentInfo::DocumentOwnedInfo((doc, None));
618 assert_eq!(info.get_document_id_as_slice(), Some([51u8; 32].as_slice()));
619 }
620
621 #[test]
622 fn test_get_document_id_as_slice_from_ref_and_serialization() {
623 let doc = make_document([52; 32]);
624 let ser = vec![0u8; 2];
625 let info = DocumentInfo::DocumentRefAndSerialization((&doc, &ser, None));
626 assert_eq!(info.get_document_id_as_slice(), Some([52u8; 32].as_slice()));
627 }
628
629 #[test]
630 fn test_get_document_id_as_slice_from_document_and_serialization() {
631 let doc = make_document([53; 32]);
632 let info = DocumentInfo::DocumentAndSerialization((doc, vec![3, 4], None));
633 assert_eq!(info.get_document_id_as_slice(), Some([53u8; 32].as_slice()));
634 }
635
636 #[test]
637 fn test_get_document_id_as_slice_none_for_estimated() {
638 let info = DocumentInfo::DocumentEstimatedAverageSize(100);
639 assert!(info.get_document_id_as_slice().is_none());
640 }
641
642 #[test]
647 fn test_estimated_average_size_clone_preserves_value() {
648 let info = DocumentInfo::DocumentEstimatedAverageSize(42);
649 let cloned = info.clone();
650 match cloned {
651 DocumentInfo::DocumentEstimatedAverageSize(v) => assert_eq!(v, 42),
652 _ => panic!("clone should preserve variant"),
653 }
654 }
655}