1use borsh::{BorshDeserialize, BorshSerialize};
26
27use super::hash_comparison::TreeLeafData;
28
29pub const DEFAULT_SUBTREE_MAX_DEPTH: usize = 5;
37
38pub const MAX_SUBTREE_DEPTH: usize = 64;
43
44pub const MAX_SUBTREES_PER_REQUEST: usize = 100;
49
50pub const MAX_ENTITIES_PER_SUBTREE: usize = 10_000;
55
56pub const MAX_TOTAL_ENTITIES: usize = 100_000;
63
64pub const DEEP_TREE_THRESHOLD: usize = 3;
72
73pub const MAX_DIVERGENCE_RATIO: f64 = 0.20;
77
78pub const MAX_CLUSTERED_SUBTREES: usize = 5;
82
83#[derive(Clone, Debug, PartialEq, BorshSerialize, BorshDeserialize)]
97pub struct SubtreePrefetchRequest {
98 pub subtree_roots: Vec<[u8; 32]>,
103
104 max_depth: Option<usize>,
111}
112
113impl SubtreePrefetchRequest {
114 #[must_use]
116 pub fn new(subtree_roots: Vec<[u8; 32]>) -> Self {
117 Self {
118 subtree_roots,
119 max_depth: Some(DEFAULT_SUBTREE_MAX_DEPTH),
120 }
121 }
122
123 #[must_use]
127 pub fn with_depth(subtree_roots: Vec<[u8; 32]>, max_depth: usize) -> Self {
128 Self {
129 subtree_roots,
130 max_depth: Some(max_depth.min(MAX_SUBTREE_DEPTH)),
132 }
133 }
134
135 #[must_use]
140 pub fn unlimited_depth(subtree_roots: Vec<[u8; 32]>) -> Self {
141 Self {
142 subtree_roots,
143 max_depth: None,
144 }
145 }
146
147 #[must_use]
156 pub fn depth(&self) -> usize {
157 self.max_depth
158 .map(|d| d.min(MAX_SUBTREE_DEPTH))
159 .unwrap_or(MAX_SUBTREE_DEPTH)
160 }
161
162 #[must_use]
167 pub fn is_unlimited(&self) -> bool {
168 self.max_depth.is_none()
169 }
170
171 #[must_use]
173 pub fn subtree_count(&self) -> usize {
174 self.subtree_roots.len()
175 }
176
177 #[must_use]
179 pub fn is_empty(&self) -> bool {
180 self.subtree_roots.is_empty()
181 }
182
183 #[must_use]
190 pub fn is_valid(&self) -> bool {
191 if self.subtree_roots.len() > MAX_SUBTREES_PER_REQUEST {
193 return false;
194 }
195
196 if let Some(depth) = self.max_depth {
198 if depth > MAX_SUBTREE_DEPTH {
199 return false;
200 }
201 }
202
203 true
204 }
205}
206
207#[derive(Clone, Debug, PartialEq, BorshSerialize, BorshDeserialize)]
209pub struct SubtreePrefetchResponse {
210 pub subtrees: Vec<SubtreeData>,
215
216 pub not_found: Vec<[u8; 32]>,
221}
222
223impl SubtreePrefetchResponse {
224 #[must_use]
226 pub fn new(subtrees: Vec<SubtreeData>, not_found: Vec<[u8; 32]>) -> Self {
227 Self {
228 subtrees,
229 not_found,
230 }
231 }
232
233 #[must_use]
235 pub fn complete(subtrees: Vec<SubtreeData>) -> Self {
236 Self {
237 subtrees,
238 not_found: vec![],
239 }
240 }
241
242 #[must_use]
244 pub fn not_found(roots: Vec<[u8; 32]>) -> Self {
245 Self {
246 subtrees: vec![],
247 not_found: roots,
248 }
249 }
250
251 #[must_use]
253 pub fn is_complete(&self) -> bool {
254 self.not_found.is_empty()
255 }
256
257 #[must_use]
259 pub fn is_empty(&self) -> bool {
260 self.subtrees.is_empty() && self.not_found.is_empty()
261 }
262
263 #[must_use]
267 pub fn total_entity_count(&self) -> usize {
268 self.subtrees
269 .iter()
270 .fold(0usize, |acc, s| acc.saturating_add(s.entity_count()))
271 }
272
273 #[must_use]
275 pub fn subtree_count(&self) -> usize {
276 self.subtrees.len()
277 }
278
279 #[must_use]
285 pub fn is_valid(&self) -> bool {
286 if self.subtrees.len() > MAX_SUBTREES_PER_REQUEST {
288 return false;
289 }
290 if self.not_found.len() > MAX_SUBTREES_PER_REQUEST {
291 return false;
292 }
293
294 if self.total_entity_count() > MAX_TOTAL_ENTITIES {
296 return false;
297 }
298
299 self.subtrees.iter().all(SubtreeData::is_valid)
301 }
302}
303
304#[derive(Clone, Debug, PartialEq, BorshSerialize, BorshDeserialize)]
312pub struct SubtreeData {
313 pub root_id: [u8; 32],
315
316 pub root_hash: [u8; 32],
318
319 pub entities: Vec<TreeLeafData>,
325
326 pub depth: usize,
328
329 pub truncated: bool,
331}
332
333impl SubtreeData {
334 #[must_use]
336 pub fn new(
337 root_id: [u8; 32],
338 root_hash: [u8; 32],
339 entities: Vec<TreeLeafData>,
340 depth: usize,
341 ) -> Self {
342 Self {
343 root_id,
344 root_hash,
345 entities,
346 depth,
347 truncated: false,
348 }
349 }
350
351 #[must_use]
353 pub fn truncated(
354 root_id: [u8; 32],
355 root_hash: [u8; 32],
356 entities: Vec<TreeLeafData>,
357 depth: usize,
358 ) -> Self {
359 Self {
360 root_id,
361 root_hash,
362 entities,
363 depth,
364 truncated: true,
365 }
366 }
367
368 #[must_use]
370 pub fn entity_count(&self) -> usize {
371 self.entities.len()
372 }
373
374 #[must_use]
376 pub fn is_empty(&self) -> bool {
377 self.entities.is_empty()
378 }
379
380 #[must_use]
382 pub fn is_truncated(&self) -> bool {
383 self.truncated
384 }
385
386 #[must_use]
392 pub fn is_valid(&self) -> bool {
393 if self.entities.len() > MAX_ENTITIES_PER_SUBTREE {
395 return false;
396 }
397
398 if self.depth > MAX_SUBTREE_DEPTH {
400 return false;
401 }
402
403 self.entities.iter().all(TreeLeafData::is_valid)
405 }
406}
407
408#[must_use]
419pub fn should_use_subtree_prefetch(
420 tree_depth: usize,
421 divergence_ratio: f64,
422 estimated_differing_subtrees: usize,
423) -> bool {
424 let deep_tree = tree_depth > DEEP_TREE_THRESHOLD;
430 let moderate_divergence = divergence_ratio < MAX_DIVERGENCE_RATIO;
431 let clustered_changes = estimated_differing_subtrees <= MAX_CLUSTERED_SUBTREES;
432
433 deep_tree && moderate_divergence && clustered_changes
434}
435
436#[cfg(test)]
441mod tests {
442 use super::*;
443 use crate::sync::hash_comparison::{CrdtType, LeafMetadata, MAX_LEAF_VALUE_SIZE};
444
445 fn make_leaf(key: u8, value: Vec<u8>) -> TreeLeafData {
450 let metadata = LeafMetadata::new(CrdtType::lww_register("test"), 100, [key; 32]);
451 TreeLeafData::new([key; 32], value, metadata)
452 }
453
454 fn make_subtree(root_id: u8, entities: Vec<TreeLeafData>, depth: usize) -> SubtreeData {
455 SubtreeData::new([root_id; 32], [root_id + 100; 32], entities, depth)
456 }
457
458 #[test]
463 fn test_subtree_prefetch_request_new() {
464 let roots = vec![[1u8; 32], [2u8; 32]];
465 let request = SubtreePrefetchRequest::new(roots.clone());
466
467 assert_eq!(request.subtree_roots, roots);
468 assert_eq!(request.depth(), DEFAULT_SUBTREE_MAX_DEPTH);
469 assert!(!request.is_unlimited());
470 assert_eq!(request.subtree_count(), 2);
471 assert!(!request.is_empty());
472 assert!(request.is_valid());
473 }
474
475 #[test]
476 fn test_subtree_prefetch_request_empty() {
477 let request = SubtreePrefetchRequest::new(vec![]);
478
479 assert!(request.is_empty());
480 assert_eq!(request.subtree_count(), 0);
481 assert!(request.is_valid());
482 }
483
484 #[test]
485 fn test_subtree_prefetch_request_with_depth() {
486 let roots = vec![[1u8; 32]];
487 let request = SubtreePrefetchRequest::with_depth(roots, 10);
488
489 assert_eq!(request.depth(), 10);
490 assert!(!request.is_unlimited());
491 assert!(request.is_valid());
492 }
493
494 #[test]
495 fn test_subtree_prefetch_request_with_zero_depth() {
496 let roots = vec![[1u8; 32]];
497 let request = SubtreePrefetchRequest::with_depth(roots, 0);
498
499 assert_eq!(request.depth(), 0);
500 assert!(!request.is_unlimited());
501 assert!(request.is_valid());
502 }
503
504 #[test]
505 fn test_subtree_prefetch_request_depth_clamping() {
506 let request = SubtreePrefetchRequest::with_depth(vec![[1u8; 32]], MAX_SUBTREE_DEPTH);
508 assert_eq!(request.depth(), MAX_SUBTREE_DEPTH);
509 assert!(request.is_valid());
510
511 let excessive =
513 SubtreePrefetchRequest::with_depth(vec![[1u8; 32]], MAX_SUBTREE_DEPTH + 100);
514 assert_eq!(excessive.depth(), MAX_SUBTREE_DEPTH);
515 assert!(excessive.is_valid());
516 }
517
518 #[test]
519 fn test_subtree_prefetch_request_depth_accessor_always_bounded() {
520 let request = SubtreePrefetchRequest::new(vec![[1u8; 32]]);
522 assert_eq!(request.depth(), DEFAULT_SUBTREE_MAX_DEPTH);
523
524 let unlimited = SubtreePrefetchRequest::unlimited_depth(vec![[1u8; 32]]);
526 assert_eq!(unlimited.depth(), MAX_SUBTREE_DEPTH);
527 assert!(unlimited.is_unlimited());
528 }
529
530 #[test]
531 fn test_subtree_prefetch_request_unlimited() {
532 let roots = vec![[1u8; 32]];
533 let request = SubtreePrefetchRequest::unlimited_depth(roots);
534
535 assert!(request.is_unlimited());
536 assert_eq!(request.depth(), MAX_SUBTREE_DEPTH);
538 assert!(request.is_valid());
539 }
540
541 #[test]
542 fn test_subtree_prefetch_request_roundtrip() {
543 let request = SubtreePrefetchRequest::with_depth(vec![[1u8; 32], [2u8; 32]], 7);
544
545 let encoded = borsh::to_vec(&request).expect("serialize");
546 let decoded: SubtreePrefetchRequest = borsh::from_slice(&encoded).expect("deserialize");
547
548 assert_eq!(request, decoded);
549 }
550
551 #[test]
552 fn test_subtree_prefetch_request_validation() {
553 let roots: Vec<[u8; 32]> = (0..MAX_SUBTREES_PER_REQUEST)
555 .map(|i| [i as u8; 32])
556 .collect();
557 let at_limit = SubtreePrefetchRequest::new(roots);
558 assert!(at_limit.is_valid());
559
560 let roots: Vec<[u8; 32]> = (0..=MAX_SUBTREES_PER_REQUEST)
562 .map(|i| [i as u8; 32])
563 .collect();
564 let over_limit = SubtreePrefetchRequest::new(roots);
565 assert!(!over_limit.is_valid());
566 }
567
568 #[test]
573 fn test_subtree_data_new() {
574 let leaf = make_leaf(1, vec![1, 2, 3]);
575 let subtree = SubtreeData::new([10; 32], [11; 32], vec![leaf], 3);
576
577 assert_eq!(subtree.root_id, [10; 32]);
578 assert_eq!(subtree.root_hash, [11; 32]);
579 assert_eq!(subtree.entity_count(), 1);
580 assert_eq!(subtree.depth, 3);
581 assert!(!subtree.is_truncated());
582 assert!(!subtree.is_empty());
583 assert!(subtree.is_valid());
584 }
585
586 #[test]
587 fn test_subtree_data_truncated() {
588 let leaf = make_leaf(2, vec![4, 5, 6]);
589 let subtree = SubtreeData::truncated([20; 32], [21; 32], vec![leaf], 5);
590
591 assert!(subtree.is_truncated());
592 assert_eq!(subtree.depth, 5);
593 assert!(subtree.is_valid());
594 }
595
596 #[test]
597 fn test_subtree_data_empty() {
598 let subtree = SubtreeData::new([30; 32], [31; 32], vec![], 1);
599
600 assert!(subtree.is_empty());
601 assert_eq!(subtree.entity_count(), 0);
602 assert!(subtree.is_valid());
603 }
604
605 #[test]
606 fn test_subtree_data_zero_depth() {
607 let leaf = make_leaf(1, vec![1, 2, 3]);
608 let subtree = SubtreeData::new([10; 32], [11; 32], vec![leaf], 0);
609
610 assert_eq!(subtree.depth, 0);
611 assert!(subtree.is_valid());
612 }
613
614 #[test]
615 fn test_subtree_data_multiple_entities() {
616 let leaves = vec![
617 make_leaf(1, vec![1, 2, 3]),
618 make_leaf(2, vec![4, 5, 6]),
619 make_leaf(3, vec![7, 8, 9]),
620 ];
621 let subtree = SubtreeData::new([10; 32], [11; 32], leaves, 3);
622
623 assert_eq!(subtree.entity_count(), 3);
624 assert!(!subtree.is_empty());
625 assert!(subtree.is_valid());
626 }
627
628 #[test]
629 fn test_subtree_data_roundtrip() {
630 let leaf = make_leaf(3, vec![7, 8, 9]);
631 let subtree = SubtreeData::truncated([40; 32], [41; 32], vec![leaf], 4);
632
633 let encoded = borsh::to_vec(&subtree).expect("serialize");
634 let decoded: SubtreeData = borsh::from_slice(&encoded).expect("deserialize");
635
636 assert_eq!(subtree, decoded);
637 }
638
639 #[test]
640 fn test_subtree_data_validation() {
641 let valid_leaf = make_leaf(1, vec![1, 2, 3]);
643 let valid = SubtreeData::new([1; 32], [2; 32], vec![valid_leaf], 2);
644 assert!(valid.is_valid());
645
646 let metadata = LeafMetadata::new(CrdtType::lww_register("test"), 100, [1; 32]);
648 let invalid_leaf = TreeLeafData::new([1; 32], vec![0u8; MAX_LEAF_VALUE_SIZE + 1], metadata);
649 let invalid = SubtreeData::new([1; 32], [2; 32], vec![invalid_leaf], 2);
650 assert!(!invalid.is_valid());
651 }
652
653 #[test]
658 fn test_subtree_prefetch_response_complete() {
659 let leaf = make_leaf(1, vec![1, 2, 3]);
660 let subtree = make_subtree(10, vec![leaf], 2);
661
662 let response = SubtreePrefetchResponse::complete(vec![subtree]);
663
664 assert!(response.is_complete());
665 assert!(!response.is_empty());
666 assert_eq!(response.subtree_count(), 1);
667 assert_eq!(response.total_entity_count(), 1);
668 assert!(response.is_valid());
669 }
670
671 #[test]
672 fn test_subtree_prefetch_response_not_found() {
673 let response = SubtreePrefetchResponse::not_found(vec![[1u8; 32], [2u8; 32]]);
674
675 assert!(!response.is_complete());
676 assert!(!response.is_empty());
677 assert_eq!(response.subtree_count(), 0);
678 assert_eq!(response.not_found.len(), 2);
679 assert!(response.is_valid());
680 }
681
682 #[test]
683 fn test_subtree_prefetch_response_empty() {
684 let response = SubtreePrefetchResponse::new(vec![], vec![]);
685
686 assert!(response.is_complete());
687 assert!(response.is_empty());
688 assert_eq!(response.subtree_count(), 0);
689 assert_eq!(response.total_entity_count(), 0);
690 assert!(response.is_valid());
691 }
692
693 #[test]
694 fn test_subtree_prefetch_response_partial() {
695 let leaf1 = make_leaf(1, vec![1, 2]);
696 let leaf2 = make_leaf(2, vec![3, 4]);
697
698 let subtree1 = make_subtree(10, vec![leaf1], 2);
699 let subtree2 = make_subtree(20, vec![leaf2], 3);
700
701 let response = SubtreePrefetchResponse::new(
702 vec![subtree1, subtree2],
703 vec![[30u8; 32]], );
705
706 assert!(!response.is_complete());
707 assert!(!response.is_empty());
708 assert_eq!(response.subtree_count(), 2);
709 assert_eq!(response.total_entity_count(), 2);
710 assert!(response.is_valid());
711 }
712
713 #[test]
714 fn test_subtree_prefetch_response_with_empty_subtrees() {
715 let leaf = make_leaf(1, vec![1, 2, 3]);
717 let populated = make_subtree(10, vec![leaf], 2);
718 let empty = make_subtree(20, vec![], 1);
719
720 let response = SubtreePrefetchResponse::complete(vec![populated, empty]);
721
722 assert!(response.is_complete());
723 assert_eq!(response.subtree_count(), 2);
724 assert_eq!(response.total_entity_count(), 1); assert!(response.is_valid());
726 }
727
728 #[test]
729 fn test_subtree_prefetch_response_total_entity_count_multiple() {
730 let subtree1 = make_subtree(1, vec![make_leaf(1, vec![1]), make_leaf(2, vec![2])], 2);
731 let subtree2 = make_subtree(
732 2,
733 vec![
734 make_leaf(3, vec![3]),
735 make_leaf(4, vec![4]),
736 make_leaf(5, vec![5]),
737 ],
738 3,
739 );
740 let subtree3 = make_subtree(3, vec![], 1); let response = SubtreePrefetchResponse::complete(vec![subtree1, subtree2, subtree3]);
743
744 assert_eq!(response.subtree_count(), 3);
745 assert_eq!(response.total_entity_count(), 5); }
747
748 #[test]
749 fn test_subtree_prefetch_response_roundtrip() {
750 let leaf = make_leaf(4, vec![10, 11, 12]);
751 let subtree = make_subtree(50, vec![leaf], 2);
752
753 let response = SubtreePrefetchResponse::new(vec![subtree], vec![[60u8; 32]]);
754
755 let encoded = borsh::to_vec(&response).expect("serialize");
756 let decoded: SubtreePrefetchResponse = borsh::from_slice(&encoded).expect("deserialize");
757
758 assert_eq!(response, decoded);
759 }
760
761 #[test]
762 fn test_subtree_prefetch_response_validation() {
763 let subtrees: Vec<SubtreeData> = (0..MAX_SUBTREES_PER_REQUEST)
765 .map(|i| make_subtree(i as u8, vec![], 1))
766 .collect();
767 let at_limit = SubtreePrefetchResponse::complete(subtrees);
768 assert!(at_limit.is_valid());
769
770 let subtrees: Vec<SubtreeData> = (0..=MAX_SUBTREES_PER_REQUEST)
772 .map(|i| make_subtree(i as u8, vec![], 1))
773 .collect();
774 let over_limit = SubtreePrefetchResponse::complete(subtrees);
775 assert!(!over_limit.is_valid());
776
777 let not_found: Vec<[u8; 32]> = (0..=MAX_SUBTREES_PER_REQUEST)
779 .map(|i| [i as u8; 32])
780 .collect();
781 let over_not_found = SubtreePrefetchResponse::not_found(not_found);
782 assert!(!over_not_found.is_valid());
783
784 let metadata = LeafMetadata::new(CrdtType::lww_register("test"), 100, [1; 32]);
786 let invalid_leaf = TreeLeafData::new([1; 32], vec![0u8; MAX_LEAF_VALUE_SIZE + 1], metadata);
787 let invalid_subtree = SubtreeData::new([1; 32], [2; 32], vec![invalid_leaf], 2);
788 let response_with_invalid = SubtreePrefetchResponse::complete(vec![invalid_subtree]);
789 assert!(!response_with_invalid.is_valid());
790 }
791
792 #[test]
797 fn test_heuristic_constants_are_sensible() {
798 assert!(DEEP_TREE_THRESHOLD > 0);
800 assert!(DEEP_TREE_THRESHOLD < MAX_SUBTREE_DEPTH);
801 assert!(MAX_DIVERGENCE_RATIO > 0.0);
802 assert!(MAX_DIVERGENCE_RATIO < 1.0);
803 assert!(MAX_CLUSTERED_SUBTREES > 0);
804 assert!(MAX_CLUSTERED_SUBTREES <= MAX_SUBTREES_PER_REQUEST);
805 }
806
807 #[test]
808 fn test_should_use_subtree_prefetch_basic() {
809 assert!(should_use_subtree_prefetch(5, 0.10, 3));
811
812 assert!(!should_use_subtree_prefetch(5, 0.30, 3));
814
815 assert!(!should_use_subtree_prefetch(2, 0.10, 3));
817
818 assert!(!should_use_subtree_prefetch(5, 0.10, 10));
820 }
821
822 #[test]
823 fn test_should_use_subtree_prefetch_boundary_conditions() {
824 assert!(!should_use_subtree_prefetch(DEEP_TREE_THRESHOLD, 0.10, 3));
826 assert!(should_use_subtree_prefetch(
827 DEEP_TREE_THRESHOLD + 1,
828 0.10,
829 3
830 ));
831
832 assert!(!should_use_subtree_prefetch(5, MAX_DIVERGENCE_RATIO, 3));
834 assert!(should_use_subtree_prefetch(
835 5,
836 MAX_DIVERGENCE_RATIO - 0.01,
837 3
838 ));
839 assert!(should_use_subtree_prefetch(
840 5,
841 MAX_DIVERGENCE_RATIO - 0.000001,
842 3
843 )); assert!(should_use_subtree_prefetch(5, 0.10, MAX_CLUSTERED_SUBTREES));
847 assert!(!should_use_subtree_prefetch(
848 5,
849 0.10,
850 MAX_CLUSTERED_SUBTREES + 1
851 ));
852 }
853
854 #[test]
855 fn test_should_use_subtree_prefetch_edge_cases() {
856 assert!(!should_use_subtree_prefetch(0, 0.10, 3)); assert!(should_use_subtree_prefetch(5, 0.0, 3)); assert!(should_use_subtree_prefetch(5, 0.10, 0)); assert!(should_use_subtree_prefetch(1000, 0.10, 3)); assert!(!should_use_subtree_prefetch(5, 1.0, 3)); assert!(!should_use_subtree_prefetch(5, 10.0, 3)); assert!(!should_use_subtree_prefetch(5, 0.10, 1000)); assert!(!should_use_subtree_prefetch(2, 0.50, 10));
869
870 assert!(should_use_subtree_prefetch(100, 0.001, 1));
872 }
873
874 #[test]
875 fn test_should_use_subtree_prefetch_typical_scenarios() {
876 assert!(should_use_subtree_prefetch(10, 0.05, 2));
878
879 assert!(!should_use_subtree_prefetch(2, 0.05, 2));
881
882 assert!(!should_use_subtree_prefetch(10, 0.05, 20));
884
885 assert!(!should_use_subtree_prefetch(10, 0.60, 2));
887
888 assert!(should_use_subtree_prefetch(4, 0.15, 5));
890 }
891
892 #[test]
897 fn test_subtree_data_validation_entity_limit() {
898 let leaves: Vec<TreeLeafData> = (0..MAX_ENTITIES_PER_SUBTREE)
900 .map(|i| make_leaf(i as u8, vec![i as u8]))
901 .collect();
902 let at_limit = SubtreeData::new([1; 32], [2; 32], leaves, 5);
903 assert!(at_limit.is_valid());
904
905 let leaves: Vec<TreeLeafData> = (0..=MAX_ENTITIES_PER_SUBTREE)
907 .map(|i| make_leaf(i as u8, vec![i as u8]))
908 .collect();
909 let over_limit = SubtreeData::new([1; 32], [2; 32], leaves, 5);
910 assert!(!over_limit.is_valid());
911 }
912
913 #[test]
914 fn test_subtree_data_validation_depth_limit() {
915 let leaf = make_leaf(1, vec![1, 2, 3]);
916
917 let at_limit = SubtreeData::new([1; 32], [2; 32], vec![leaf.clone()], MAX_SUBTREE_DEPTH);
919 assert!(at_limit.is_valid());
920
921 let over_limit = SubtreeData::new([1; 32], [2; 32], vec![leaf], MAX_SUBTREE_DEPTH + 1);
923 assert!(!over_limit.is_valid());
924 }
925
926 #[test]
927 fn test_subtree_response_validation_total_entity_limit() {
928 use super::MAX_TOTAL_ENTITIES;
929
930 let entities_per_subtree = 1000;
933 let num_subtrees = (MAX_TOTAL_ENTITIES / entities_per_subtree) + 1;
934
935 let subtrees: Vec<SubtreeData> = (0..num_subtrees)
936 .map(|i| {
937 let leaves: Vec<TreeLeafData> = (0..entities_per_subtree)
938 .map(|j| make_leaf((i * 100 + j) as u8, vec![(i * 100 + j) as u8]))
939 .collect();
940 SubtreeData::new([i as u8; 32], [(i + 100) as u8; 32], leaves, 5)
941 })
942 .collect();
943
944 let response = SubtreePrefetchResponse::complete(subtrees);
945 assert!(!response.is_valid()); }
947
948 #[test]
953 fn test_subtree_request_memory_exhaustion_prevention() {
954 let roots: Vec<[u8; 32]> = (0..MAX_SUBTREES_PER_REQUEST)
956 .map(|i| [i as u8; 32])
957 .collect();
958 let valid = SubtreePrefetchRequest::new(roots);
959 assert!(valid.is_valid());
960
961 let roots: Vec<[u8; 32]> = (0..=MAX_SUBTREES_PER_REQUEST)
963 .map(|i| [i as u8; 32])
964 .collect();
965 let invalid = SubtreePrefetchRequest::new(roots);
966 assert!(!invalid.is_valid());
967 }
968
969 #[test]
970 fn test_subtree_depth_exhaustion_prevention() {
971 let request = SubtreePrefetchRequest::with_depth(vec![[1u8; 32]], usize::MAX);
973 assert_eq!(request.depth(), MAX_SUBTREE_DEPTH);
974 assert!(request.is_valid());
975
976 let unlimited = SubtreePrefetchRequest::unlimited_depth(vec![[1u8; 32]]);
978 assert_eq!(unlimited.depth(), MAX_SUBTREE_DEPTH);
979 assert!(unlimited.is_valid());
980 }
981
982 #[test]
983 fn test_subtree_request_max_depth_validation() {
984 let at_limit = SubtreePrefetchRequest::with_depth(vec![[1u8; 32]], MAX_SUBTREE_DEPTH);
986 assert!(at_limit.is_valid());
987
988 let valid = SubtreePrefetchRequest::with_depth(vec![[1u8; 32]], 10);
991 let mut bytes = borsh::to_vec(&valid).expect("serialize");
992
993 let depth_offset = 4 + 32 + 1; bytes[depth_offset..depth_offset + 8]
999 .copy_from_slice(&(MAX_SUBTREE_DEPTH as u64 + 100).to_le_bytes());
1000
1001 let corrupted: SubtreePrefetchRequest = borsh::from_slice(&bytes).expect("deserialize");
1002 assert_eq!(corrupted.depth(), MAX_SUBTREE_DEPTH);
1004 assert!(!corrupted.is_valid());
1006 }
1007
1008 #[test]
1009 fn test_subtree_total_entity_count_overflow_prevention() {
1010 let leaf = make_leaf(1, vec![1, 2, 3]);
1013 let subtree = SubtreeData::new([1; 32], [2; 32], vec![leaf], 2);
1014
1015 let response = SubtreePrefetchResponse::complete(vec![subtree]);
1016
1017 let count = response.total_entity_count();
1019 assert_eq!(count, 1);
1020 }
1021
1022 #[test]
1023 fn test_subtree_cross_validation_consistency() {
1024 let metadata = LeafMetadata::new(CrdtType::lww_register("test"), 100, [1; 32]);
1026 let oversized_leaf =
1027 TreeLeafData::new([1; 32], vec![0u8; MAX_LEAF_VALUE_SIZE + 1], metadata);
1028 let invalid_subtree = SubtreeData::new([1; 32], [2; 32], vec![oversized_leaf], 2);
1029
1030 assert!(!invalid_subtree.is_valid());
1032
1033 let response = SubtreePrefetchResponse::complete(vec![invalid_subtree]);
1035 assert!(!response.is_valid());
1036 }
1037
1038 #[test]
1039 fn test_subtree_special_values() {
1040 let zeros_subtree = SubtreeData::new([0u8; 32], [0u8; 32], vec![], 0);
1042 assert!(zeros_subtree.is_valid());
1043
1044 let ones_subtree = SubtreeData::new([0xFF; 32], [0xFF; 32], vec![], MAX_SUBTREE_DEPTH);
1046 assert!(ones_subtree.is_valid());
1047
1048 let request = SubtreePrefetchRequest::new(vec![[0u8; 32]]);
1050 assert!(request.is_valid());
1051
1052 let request = SubtreePrefetchRequest::new(vec![[0xFF; 32]]);
1054 assert!(request.is_valid());
1055 }
1056
1057 #[test]
1058 fn test_subtree_serialization_roundtrip_with_edge_values() {
1059 let leaf = make_leaf(0xFF, vec![0xFF; 100]);
1061 let subtree = SubtreeData::truncated([0xFF; 32], [0u8; 32], vec![leaf], MAX_SUBTREE_DEPTH);
1062
1063 let encoded = borsh::to_vec(&subtree).expect("serialize");
1064 let decoded: SubtreeData = borsh::from_slice(&encoded).expect("deserialize");
1065
1066 assert_eq!(subtree, decoded);
1067 assert!(decoded.is_valid());
1068 assert!(decoded.is_truncated());
1069 assert_eq!(decoded.depth, MAX_SUBTREE_DEPTH);
1070 }
1071
1072 #[test]
1073 fn test_subtree_response_all_not_found() {
1074 let not_found: Vec<[u8; 32]> = (0..50).map(|i| [i as u8; 32]).collect();
1076 let response = SubtreePrefetchResponse::not_found(not_found);
1077
1078 assert!(!response.is_complete());
1079 assert!(!response.is_empty());
1080 assert_eq!(response.subtree_count(), 0);
1081 assert_eq!(response.total_entity_count(), 0);
1082 assert!(response.is_valid());
1083 }
1084
1085 #[test]
1086 fn test_subtree_empty_entities_is_valid() {
1087 let empty_subtree = SubtreeData::new([1; 32], [2; 32], vec![], 5);
1089 assert!(empty_subtree.is_valid());
1090 assert!(empty_subtree.is_empty());
1091 assert_eq!(empty_subtree.entity_count(), 0);
1092 }
1093}