1use ant_merkle::Hasher;
10use serde::{Deserialize, Serialize};
11use std::time::{SystemTime, UNIX_EPOCH};
12use thiserror::Error;
13use xor_name::XorName;
14
15pub use evmlib::merkle_batch_payment::MAX_MERKLE_DEPTH;
17
18pub const MIN_LEAVES: usize = 2;
20
21pub const MAX_LEAVES: usize = 1 << MAX_MERKLE_DEPTH;
23
24pub const MERKLE_PAYMENT_EXPIRATION: u64 = 7 * 24 * 60 * 60; pub fn expected_reward_pools(depth: u8) -> usize {
47 1 << midpoint_proof_depth(depth)
48}
49
50#[derive(Debug, Error)]
52pub enum MerkleTreeError {
53 #[error("Too few leaves: got {got}, minimum is {MIN_LEAVES}")]
54 TooFewLeaves { got: usize },
55 #[error("Too many leaves: got {got}, maximum is {MAX_LEAVES}")]
56 TooManyLeaves { got: usize },
57 #[error("Invalid leaf index: {index} (tree has {leaf_count} leaves)")]
58 InvalidLeafIndex { index: usize, leaf_count: usize },
59 #[error("Invalid midpoint index: {index} (tree has {midpoint_count} midpoints)")]
60 InvalidMidpointIndex { index: usize, midpoint_count: usize },
61 #[error("Invalid proof")]
62 InvalidProof,
63 #[error("Internal error: {0}")]
64 Internal(String),
65}
66
67pub type Result<T> = std::result::Result<T, MerkleTreeError>;
68
69pub struct MerkleTree {
78 inner: ant_merkle::MerkleTree<XorNameHasher>,
80
81 leaf_count: usize,
83
84 depth: u8,
86
87 root: XorName,
89
90 salts: Vec<[u8; 32]>,
93}
94
95impl MerkleTree {
96 pub fn from_xornames(leaves: Vec<XorName>) -> Result<Self> {
125 let leaf_count = leaves.len();
126
127 if leaf_count < MIN_LEAVES {
129 return Err(MerkleTreeError::TooFewLeaves { got: leaf_count });
130 }
131 if leaf_count > MAX_LEAVES {
132 return Err(MerkleTreeError::TooManyLeaves { got: leaf_count });
133 }
134
135 let mut rng = rand::thread_rng();
137 let salts: Vec<[u8; 32]> = (0..leaf_count)
138 .map(|_| {
139 let mut salt = [0u8; 32];
140 rand::Rng::fill(&mut rng, &mut salt);
141 salt
142 })
143 .collect();
144
145 let depth = tree_depth(leaf_count);
147 let padded_size = 1 << depth;
148
149 let mut salted_leaves: Vec<[u8; 32]> = leaves
151 .iter()
152 .zip(&salts)
153 .map(|(address, salt)| {
154 let mut data = Vec::with_capacity(64);
156 data.extend_from_slice(address.as_ref());
157 data.extend_from_slice(salt);
158 XorNameHasher::hash(&data)
159 })
160 .collect();
161
162 if leaf_count < padded_size {
164 for _ in leaf_count..padded_size {
165 let mut dummy = [0u8; 32];
166 rand::Rng::fill(&mut rng, &mut dummy);
167 salted_leaves.push(dummy);
168 }
169 }
170
171 let inner = ant_merkle::MerkleTree::<XorNameHasher>::from_leaves(&salted_leaves);
173
174 let root = inner.root().ok_or(MerkleTreeError::Internal(
175 "Tree must have root after construction".to_string(),
176 ))?;
177
178 Ok(Self {
179 inner,
180 root: XorName(root),
181 leaf_count,
182 depth,
183 salts,
184 })
185 }
186
187 pub fn root(&self) -> XorName {
191 self.root
192 }
193
194 pub fn depth(&self) -> u8 {
196 self.depth
197 }
198
199 pub fn leaf_count(&self) -> usize {
201 self.leaf_count
202 }
203
204 fn midpoints(&self) -> Result<Vec<MerkleMidpoint>> {
211 let level = midpoint_level(self.depth);
212
213 let nodes = self
214 .inner
215 .get_nodes_at_level(level)
216 .ok_or(MerkleTreeError::Internal(
217 "Midpoint level must exist".to_string(),
218 ))?;
219
220 let midpoints: Vec<MerkleMidpoint> = nodes
221 .into_iter()
222 .map(|(index, hash)| MerkleMidpoint {
223 hash: XorName(hash),
224 index,
225 })
226 .collect();
227
228 Ok(midpoints)
229 }
230
231 pub fn reward_candidates(&self, merkle_payment_timestamp: u64) -> Result<Vec<MidpointProof>> {
263 let midpoints = self.midpoints()?;
264
265 midpoints
266 .into_iter()
267 .map(|midpoint| {
268 let branch = self.generate_midpoint_proof(midpoint.index, midpoint.hash)?;
270
271 Ok(MidpointProof {
272 branch,
273 merkle_payment_timestamp,
274 })
275 })
276 .collect()
277 }
278
279 pub fn generate_address_proof(
326 &self,
327 address_index: usize,
328 address_hash: XorName,
329 ) -> Result<MerkleBranch> {
330 if address_index >= self.leaf_count {
331 return Err(MerkleTreeError::InvalidLeafIndex {
332 index: address_index,
333 leaf_count: self.leaf_count,
334 });
335 }
336
337 let indices = vec![address_index];
338 let proof = self.inner.proof(&indices);
339
340 let padded_size = 1 << self.depth;
342
343 let root = self.root();
344
345 let salt = self.salts[address_index];
347
348 Ok(MerkleBranch::from_rs_merkle_proof(
349 proof,
350 address_index,
351 padded_size,
352 address_hash,
353 root,
354 Some(salt),
355 ))
356 }
357
358 fn generate_midpoint_proof(
375 &self,
376 midpoint_index: usize,
377 midpoint_hash: XorName,
378 ) -> Result<MerkleBranch> {
379 let level = midpoint_level(self.depth);
381 let midpoint_count = expected_reward_pools(self.depth);
382
383 if midpoint_index >= midpoint_count {
384 return Err(MerkleTreeError::InvalidMidpointIndex {
385 index: midpoint_index,
386 midpoint_count,
387 });
388 }
389
390 let proof = self
391 .inner
392 .proof_from_node(level, midpoint_index)
393 .ok_or_else(|| {
394 MerkleTreeError::Internal("Failed to generate midpoint proof".to_string())
395 })?;
396
397 let effective_leaf_count = midpoint_count;
400
401 let root = self.root();
402
403 Ok(MerkleBranch::from_rs_merkle_proof(
404 proof,
405 midpoint_index,
406 effective_leaf_count,
407 midpoint_hash,
408 root,
409 None, ))
411 }
412}
413
414#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
418struct MerkleMidpoint {
419 hash: XorName,
421
422 index: usize,
424}
425
426#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
432pub struct MidpointProof {
433 pub branch: MerkleBranch,
435
436 pub merkle_payment_timestamp: u64,
439}
440
441impl MidpointProof {
442 pub fn root(&self) -> &XorName {
446 self.branch.root()
447 }
448
449 pub fn address(&self) -> XorName {
454 let mut data = Vec::with_capacity(32 + 32 + 8);
455 data.extend_from_slice(self.branch.leaf_hash().as_ref());
456 data.extend_from_slice(self.branch.root().as_ref());
457 data.extend_from_slice(&self.merkle_payment_timestamp.to_le_bytes());
458 XorName::from_content(&data)
459 }
460
461 pub fn hash(&self) -> XorName {
466 let mut bytes = Vec::new();
467
468 for proof_hash in &self.branch.proof_hashes {
470 bytes.extend_from_slice(proof_hash);
471 }
472
473 bytes.extend_from_slice(&(self.branch.leaf_index as u64).to_le_bytes());
475 bytes.extend_from_slice(&(self.branch.total_leaves_count as u64).to_le_bytes());
476
477 bytes.extend_from_slice(self.branch.unsalted_leaf_hash.as_ref());
478 bytes.extend_from_slice(self.branch.root.as_ref());
479 if let Some(salt) = &self.branch.salt {
480 bytes.push(1); bytes.extend_from_slice(salt);
482 } else {
483 bytes.push(0); }
485
486 bytes.extend_from_slice(&self.merkle_payment_timestamp.to_le_bytes());
488
489 XorName::from_content(&bytes)
490 }
491}
492
493#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
508pub struct MerkleBranch {
509 proof_hashes: Vec<[u8; 32]>,
511
512 leaf_index: usize,
514
515 total_leaves_count: usize,
519
520 unsalted_leaf_hash: XorName,
524
525 root: XorName,
527
528 salt: Option<[u8; 32]>,
532}
533
534impl MerkleBranch {
535 fn from_rs_merkle_proof(
537 proof: ant_merkle::MerkleProof<XorNameHasher>,
538 leaf_index: usize,
539 total_leaves_count: usize,
540 unsalted_leaf_hash: XorName,
541 root: XorName,
542 salt: Option<[u8; 32]>,
543 ) -> Self {
544 let proof_hashes = proof.proof_hashes().to_vec();
545 Self {
546 proof_hashes,
547 leaf_index,
548 total_leaves_count,
549 unsalted_leaf_hash,
550 root,
551 salt,
552 }
553 }
554
555 pub fn leaf_hash(&self) -> &XorName {
559 &self.unsalted_leaf_hash
560 }
561
562 pub fn root(&self) -> &XorName {
564 &self.root
565 }
566
567 pub fn verify(&self) -> bool {
585 let hash = if let Some(salt) = &self.salt {
587 let mut data = Vec::with_capacity(64);
589 data.extend_from_slice(self.unsalted_leaf_hash.as_ref());
590 data.extend_from_slice(salt);
591 XorNameHasher::hash(&data)
592 } else {
593 let leaf_bytes = self.unsalted_leaf_hash.as_ref();
595 let mut hash = [0u8; 32];
596 hash.copy_from_slice(leaf_bytes);
597 hash
598 };
599
600 let root_bytes = self.root.as_ref();
601 let mut expected_root = [0u8; 32];
602 expected_root.copy_from_slice(root_bytes);
603
604 let proof = ant_merkle::MerkleProof::<XorNameHasher>::new(self.proof_hashes.clone());
607 proof.verify(
608 expected_root,
609 &[self.leaf_index],
610 &[hash],
611 self.total_leaves_count,
612 )
613 }
614
615 pub fn depth(&self) -> usize {
617 self.proof_hashes.len()
618 }
619}
620
621pub fn tree_depth(leaf_count: usize) -> u8 {
623 if leaf_count <= 1 {
624 return 0;
625 }
626
627 let mut depth = 0;
628 let mut n = leaf_count - 1;
629 while n > 0 {
630 depth += 1;
631 n >>= 1;
632 }
633 depth
634}
635
636pub fn midpoint_proof_depth(depth: u8) -> u8 {
638 depth.div_ceil(2)
639}
640
641fn midpoint_level(depth: u8) -> usize {
643 (depth / 2) as usize
644}
645
646#[derive(Debug, Clone, PartialEq, Eq, Error)]
651pub enum BadMerkleProof {
652 #[error("Address branch proof failed Merkle verification")]
653 InvalidAddressBranchProof,
654 #[error("Winner/intersection branch proof failed Merkle verification")]
655 InvalidWinnerBranchProof,
656 #[error("Address proof depth mismatch: expected {expected}, got {got}")]
657 AddressProofDepthMismatch { expected: usize, got: usize },
658 #[error("Winner proof depth mismatch: expected {expected}, got {got}")]
659 WinnerProofDepthMismatch { expected: usize, got: usize },
660 #[error(
661 "Address branch root doesn't match smart contract root: smart_contract={smart_contract_root}, branch={branch_root}"
662 )]
663 AddressBranchRootMismatch {
664 smart_contract_root: XorName,
665 branch_root: XorName,
666 },
667 #[error(
668 "Winner branch root doesn't match smart contract root: smart_contract={smart_contract_root}, branch={branch_root}"
669 )]
670 WinnerBranchRootMismatch {
671 smart_contract_root: XorName,
672 branch_root: XorName,
673 },
674 #[error(
675 "Payment timestamp {payment_timestamp} is in the future (current time: {current_time})"
676 )]
677 TimestampInFuture {
678 payment_timestamp: u64,
679 current_time: u64,
680 },
681 #[error(
682 "Payment expired: timestamp {payment_timestamp} is {age_seconds}s old (max: {MERKLE_PAYMENT_EXPIRATION}s)"
683 )]
684 PaymentExpired {
685 payment_timestamp: u64,
686 current_time: u64,
687 age_seconds: u64,
688 },
689 #[error("Failed to get current system time: {0}")]
690 SystemTimeError(String),
691 #[error(
692 "Winner pool timestamp {pool_timestamp} doesn't match smart contract timestamp {contract_timestamp}"
693 )]
694 TimestampMismatch {
695 pool_timestamp: u64,
696 contract_timestamp: u64,
697 },
698 #[error("Address hash not matching branch leaf: leaf={leaf}, address={address}")]
699 AddressHashNotBranchLeaf { leaf: XorName, address: XorName },
700}
701
702fn validate_payment_timestamp(
709 payment_timestamp: u64,
710 pool_timestamp: u64,
711) -> std::result::Result<(), BadMerkleProof> {
712 let current_time = SystemTime::now()
713 .duration_since(UNIX_EPOCH)
714 .map_err(|e| BadMerkleProof::SystemTimeError(e.to_string()))?
715 .as_secs();
716
717 if payment_timestamp > current_time {
719 return Err(BadMerkleProof::TimestampInFuture {
720 payment_timestamp,
721 current_time,
722 });
723 }
724
725 let age = current_time - payment_timestamp;
727 if age > MERKLE_PAYMENT_EXPIRATION {
728 return Err(BadMerkleProof::PaymentExpired {
729 payment_timestamp,
730 current_time,
731 age_seconds: age,
732 });
733 }
734
735 if pool_timestamp != payment_timestamp {
737 return Err(BadMerkleProof::TimestampMismatch {
738 pool_timestamp,
739 contract_timestamp: payment_timestamp,
740 });
741 }
742
743 Ok(())
744}
745
746pub fn verify_merkle_proof(
785 address_hash: &XorName,
786 address_branch: &MerkleBranch,
787 winner_pool_midpoint_proof: &MidpointProof,
788 smart_contract_depth: u8,
789 smart_contract_root: &XorName,
790 smart_contract_timestamp: u64,
791) -> std::result::Result<(), BadMerkleProof> {
792 validate_payment_timestamp(
794 smart_contract_timestamp,
795 winner_pool_midpoint_proof.merkle_payment_timestamp,
796 )?;
797
798 let address_depth = address_branch.depth();
800 let expected_address_depth = smart_contract_depth as usize;
801 if address_depth != expected_address_depth {
802 return Err(BadMerkleProof::AddressProofDepthMismatch {
803 expected: expected_address_depth,
804 got: address_depth,
805 });
806 }
807
808 let winner_depth = winner_pool_midpoint_proof.branch.depth();
810 let expected_winner_depth = midpoint_proof_depth(smart_contract_depth) as usize;
811 if winner_depth != expected_winner_depth {
812 return Err(BadMerkleProof::WinnerProofDepthMismatch {
813 expected: expected_winner_depth,
814 got: winner_depth,
815 });
816 }
817
818 if !address_branch.verify() {
820 return Err(BadMerkleProof::InvalidAddressBranchProof);
821 }
822
823 if !winner_pool_midpoint_proof.branch.verify() {
825 return Err(BadMerkleProof::InvalidWinnerBranchProof);
826 }
827
828 if address_hash != address_branch.leaf_hash() {
830 return Err(BadMerkleProof::AddressHashNotBranchLeaf {
831 leaf: *address_branch.leaf_hash(),
832 address: *address_hash,
833 });
834 }
835
836 if address_branch.root() != smart_contract_root {
838 return Err(BadMerkleProof::AddressBranchRootMismatch {
839 smart_contract_root: *smart_contract_root,
840 branch_root: *address_branch.root(),
841 });
842 }
843
844 if winner_pool_midpoint_proof.branch.root() != smart_contract_root {
846 return Err(BadMerkleProof::WinnerBranchRootMismatch {
847 smart_contract_root: *smart_contract_root,
848 branch_root: *winner_pool_midpoint_proof.branch.root(),
849 });
850 }
851
852 Ok(())
853}
854
855#[derive(Clone)]
859struct XorNameHasher;
860
861impl ant_merkle::Hasher for XorNameHasher {
862 type Hash = [u8; 32];
863
864 fn hash(data: &[u8]) -> Self::Hash {
865 XorName::from_content(data).0
866 }
867
868 fn concat_and_hash(left: &Self::Hash, right: Option<&Self::Hash>) -> Self::Hash {
869 if let Some(right) = right {
870 XorName::from_content_parts(&[left, right]).0
871 } else {
872 XorName::from_content(left).0
873 }
874 }
875
876 fn hash_size() -> usize {
877 32
878 }
879}
880
881#[cfg(test)]
882mod tests {
883 use super::*;
884
885 fn make_test_leaves(count: usize) -> Vec<XorName> {
886 (0..count)
887 .map(|i| XorName::from_content(&i.to_le_bytes()))
888 .collect()
889 }
890
891 #[test]
892 fn test_reward_candidate_pool_hash_fixed_width_encoding() {
893 let leaves = make_test_leaves(16);
895 let tree = MerkleTree::from_xornames(leaves).unwrap();
896 let timestamp = 1234567890u64;
897 let pools = tree.reward_candidates(timestamp).unwrap();
898 let pool = &pools[0];
899
900 let hash1 = pool.hash();
902
903 let mut bytes = Vec::new();
905 for proof_hash in &pool.branch.proof_hashes {
906 bytes.extend_from_slice(proof_hash);
907 }
908 bytes.extend_from_slice(&(pool.branch.leaf_index as u64).to_le_bytes());
909 bytes.extend_from_slice(&(pool.branch.total_leaves_count as u64).to_le_bytes());
910 bytes.extend_from_slice(pool.branch.unsalted_leaf_hash.as_ref());
911 bytes.extend_from_slice(pool.branch.root.as_ref());
912 if let Some(salt) = &pool.branch.salt {
913 bytes.push(1);
914 bytes.extend_from_slice(salt);
915 } else {
916 bytes.push(0);
917 }
918 bytes.extend_from_slice(&pool.merkle_payment_timestamp.to_le_bytes());
919
920 let hash2 = XorName::from_content(&bytes);
921
922 assert_eq!(
923 hash1, hash2,
924 "RewardCandidatePool::hash should match manual u64-encoded hash"
925 );
926 }
927
928 #[test]
929 fn test_reward_candidate_pool_hash_architecture_independence() {
930 let leaves = make_test_leaves(4);
932 let tree = MerkleTree::from_xornames(leaves).unwrap();
933 let timestamp = u64::MAX;
934 let pools = tree.reward_candidates(timestamp).unwrap();
935
936 let hash1 = pools[0].hash();
938 let hash2 = pools[0].hash();
939
940 assert_eq!(hash1, hash2, "Same pool should produce identical hash");
941
942 let pool = &pools[0];
944 let mut bytes = Vec::new();
945 for proof_hash in &pool.branch.proof_hashes {
946 bytes.extend_from_slice(proof_hash);
947 }
948
949 let start_offset = bytes.len();
950 bytes.extend_from_slice(&(pool.branch.leaf_index as u64).to_le_bytes());
951 bytes.extend_from_slice(&(pool.branch.total_leaves_count as u64).to_le_bytes());
952
953 assert_eq!(
955 bytes.len() - start_offset,
956 16, "Should use 8 bytes per usize field regardless of platform"
958 );
959
960 let leaf_index_bytes = &bytes[start_offset..start_offset + 8];
962 let leaf_index = u64::from_le_bytes(leaf_index_bytes.try_into().unwrap());
963 assert_eq!(
964 leaf_index, pool.branch.leaf_index as u64,
965 "leaf_index should be preserved in u64 encoding"
966 );
967 }
968
969 #[test]
970 fn test_expected_reward_pools() {
971 assert_eq!(expected_reward_pools(1), 2); assert_eq!(expected_reward_pools(2), 2); assert_eq!(expected_reward_pools(3), 4); assert_eq!(expected_reward_pools(4), 4); assert_eq!(expected_reward_pools(5), 8); assert_eq!(expected_reward_pools(6), 8); assert_eq!(expected_reward_pools(7), 16); assert_eq!(expected_reward_pools(8), 16); assert_eq!(expected_reward_pools(16), 256); }
982
983 #[test]
984 fn test_blake2b_output_size() {
985 let hash1 = XorNameHasher::hash(b"test data");
987 let hash2 = XorNameHasher::concat_and_hash(&hash1, Some(&hash1));
988
989 assert_eq!(hash1.len(), 32, "Hash should be 32 bytes (256 bits)");
991 assert_eq!(
992 hash2.len(),
993 32,
994 "Concatenated hash should be 32 bytes (256 bits)"
995 );
996
997 let hash3 = XorNameHasher::hash(b"different data");
999 assert_ne!(
1000 hash1, hash3,
1001 "Different inputs should produce different hashes"
1002 );
1003
1004 println!("Blake2b hash size verified: 32 bytes (256 bits)");
1005 println!("Sample hash: {:02x?}", &hash1[..8]);
1006 }
1007
1008 #[test]
1009 fn test_reward_candidate_pool_hash() {
1010 let leaves = make_test_leaves(16);
1011 let tree = MerkleTree::from_xornames(leaves).unwrap();
1012 let candidates = tree.reward_candidates(12345).unwrap();
1013
1014 let mut seen = std::collections::HashSet::new();
1016 for candidate in &candidates {
1017 assert!(seen.insert(candidate));
1018 }
1019 assert_eq!(seen.len(), candidates.len());
1020
1021 let hash1 = candidates[0].hash();
1023 let hash2 = candidates[0].hash();
1024 assert_eq!(hash1, hash2, "Hash should be deterministic");
1025
1026 let hash3 = candidates[1].hash();
1028 assert_ne!(
1029 hash1, hash3,
1030 "Different candidates should have different hashes"
1031 );
1032 }
1033
1034 #[test]
1035 fn test_min_leaves_validation() {
1036 let leaves = make_test_leaves(1);
1037 let result = MerkleTree::from_xornames(leaves);
1038 assert!(matches!(result, Err(MerkleTreeError::TooFewLeaves { .. })));
1039 }
1040
1041 #[test]
1042 fn test_max_leaves_validation() {
1043 let leaves = make_test_leaves(MAX_LEAVES + 1);
1044 let result = MerkleTree::from_xornames(leaves);
1045 assert!(matches!(result, Err(MerkleTreeError::TooManyLeaves { .. })));
1046 }
1047
1048 #[test]
1049 fn test_basic_tree_construction() {
1050 let leaves = make_test_leaves(100);
1051 let tree = MerkleTree::from_xornames(leaves).unwrap();
1052
1053 assert_eq!(tree.leaf_count(), 100);
1054 assert_eq!(tree.depth(), 7); }
1056
1057 #[test]
1058 fn test_power_of_two_leaves() {
1059 for power in 1..=MAX_MERKLE_DEPTH {
1060 let count = 1 << power; let leaves = make_test_leaves(count);
1062 let tree = MerkleTree::from_xornames(leaves).unwrap();
1063
1064 assert_eq!(tree.depth(), power);
1065 assert_eq!(tree.leaf_count(), count);
1066 }
1067 }
1068
1069 #[test]
1070 fn test_midpoints() {
1071 let leaves = make_test_leaves(1024);
1072 let tree = MerkleTree::from_xornames(leaves).unwrap();
1073
1074 let midpoints = tree.midpoints().unwrap();
1075
1076 assert_eq!(midpoints.len(), 32);
1078
1079 for (i, midpoint) in midpoints.iter().enumerate() {
1081 assert_eq!(midpoint.index, i);
1082 }
1083 }
1084
1085 #[test]
1086 fn test_reward_candidates() {
1087 let leaves = make_test_leaves(1024);
1088 let tree = MerkleTree::from_xornames(leaves).unwrap();
1089
1090 let merkle_payment_timestamp = 1234567890u64;
1091 let candidates = tree.reward_candidates(merkle_payment_timestamp).unwrap();
1092
1093 assert_eq!(candidates.len(), 32);
1095
1096 let mut addresses = std::collections::HashSet::new();
1098 for candidate in &candidates {
1099 assert!(addresses.insert(candidate.address()));
1100 }
1101
1102 for candidate in &candidates {
1104 assert!(
1105 candidate.branch.verify(),
1106 "Candidate branch should be valid"
1107 );
1108 }
1109
1110 let candidates2 = tree.reward_candidates(merkle_payment_timestamp).unwrap();
1112 assert_eq!(candidates, candidates2);
1113
1114 let candidates3 = tree
1116 .reward_candidates(merkle_payment_timestamp + 1)
1117 .unwrap();
1118 assert_ne!(candidates[0].address(), candidates3[0].address());
1119
1120 for candidate in &candidates3 {
1122 assert!(
1123 candidate.branch.verify(),
1124 "Candidate branch with different timestamp should still be valid"
1125 );
1126 }
1127
1128 let tree_root = tree.root();
1130 let expected_address = candidates[0].address();
1131
1132 let mut data = Vec::with_capacity(32 + 32 + 8);
1134 data.extend_from_slice(candidates[0].branch.leaf_hash().as_ref());
1135 data.extend_from_slice(tree_root.as_ref());
1136 data.extend_from_slice(&merkle_payment_timestamp.to_le_bytes());
1137 let manually_computed = XorName::from_content(&data);
1138 assert_eq!(expected_address, manually_computed);
1139
1140 assert!(candidates[0].branch.verify());
1142
1143 assert_eq!(
1145 candidates[0].merkle_payment_timestamp,
1146 merkle_payment_timestamp
1147 );
1148 assert_eq!(candidates[0].address(), candidates[0].address()); assert_eq!(candidates[0].branch.root(), &tree_root);
1150 assert_eq!(
1151 candidates[0].branch.leaf_hash(),
1152 candidates[0].branch.leaf_hash()
1153 );
1154 }
1155
1156 #[test]
1157 fn test_address_proof_generation_and_verification() {
1158 let leaves = make_test_leaves(100);
1159 let tree = MerkleTree::from_xornames(leaves.clone()).unwrap();
1160
1161 let proof = tree.generate_address_proof(0, leaves[0]).unwrap();
1163 assert!(proof.verify());
1164
1165 let proof = tree.generate_address_proof(99, leaves[99]).unwrap();
1167 assert!(proof.verify());
1168
1169 let proof = tree.generate_address_proof(50, leaves[50]).unwrap();
1171 assert!(proof.verify());
1172 }
1173
1174 #[test]
1175 fn test_invalid_address_index() {
1176 let leaves = make_test_leaves(100);
1177 let tree = MerkleTree::from_xornames(leaves.clone()).unwrap();
1178
1179 let dummy_hash = leaves[0]; let result = tree.generate_address_proof(100, dummy_hash);
1181 assert!(matches!(
1182 result,
1183 Err(MerkleTreeError::InvalidLeafIndex { .. })
1184 ));
1185 }
1186
1187 #[test]
1188 fn test_midpoint_proof_generation_and_verification() {
1189 let leaves = make_test_leaves(1024);
1190 let tree = MerkleTree::from_xornames(leaves).unwrap();
1191
1192 let midpoints = tree.midpoints().unwrap();
1193
1194 let proof = tree.generate_midpoint_proof(0, midpoints[0].hash).unwrap();
1196 assert!(proof.verify());
1197
1198 let proof = tree
1200 .generate_midpoint_proof(31, midpoints[31].hash)
1201 .unwrap();
1202 assert!(proof.verify());
1203 }
1204
1205 #[test]
1206 fn test_proof_depth() {
1207 let leaves = make_test_leaves(16);
1208 let tree = MerkleTree::from_xornames(leaves.clone()).unwrap();
1209
1210 let address_proof = tree.generate_address_proof(0, leaves[0]).unwrap();
1212 assert_eq!(address_proof.depth(), 4);
1213
1214 let midpoints = tree.midpoints().unwrap();
1216 let midpoint_proof = tree.generate_midpoint_proof(0, midpoints[0].hash).unwrap();
1217 assert_eq!(midpoint_proof.depth(), 2);
1218 }
1219
1220 #[test]
1221 fn test_non_deterministic_root_due_to_salts() {
1222 let leaves = make_test_leaves(100);
1225
1226 let tree1 = MerkleTree::from_xornames(leaves.clone()).unwrap();
1227 let tree2 = MerkleTree::from_xornames(leaves).unwrap();
1228
1229 assert_ne!(tree1.root(), tree2.root());
1231
1232 assert_eq!(tree1.depth(), tree2.depth());
1234 assert_eq!(tree1.leaf_count(), tree2.leaf_count());
1235 }
1236
1237 #[test]
1238 fn test_invalid_proof_rejection() {
1239 let leaves = make_test_leaves(10);
1240 let tree = MerkleTree::from_xornames(leaves.clone()).unwrap();
1241
1242 let wrong_leaf = XorName::from_content(b"wrong");
1244 let wrong_proof = tree.generate_address_proof(0, wrong_leaf).unwrap();
1245 assert!(!wrong_proof.verify());
1246
1247 }
1251
1252 #[test]
1253 fn test_proof_hashes_length_for_depth_4() {
1254 let leaves = make_test_leaves(16); let tree = MerkleTree::from_xornames(leaves.clone()).unwrap();
1257
1258 println!("Tree depth: {}", tree.depth());
1259 println!("Tree leaf count: {}", tree.leaf_count());
1260
1261 let address_proof = tree.generate_address_proof(0, leaves[0]).unwrap();
1262 println!(
1263 "Address proof depth (proof_hashes.len()): {}",
1264 address_proof.depth()
1265 );
1266
1267 let midpoints = tree.midpoints().unwrap();
1268 let midpoint_proof = tree.generate_midpoint_proof(0, midpoints[0].hash).unwrap();
1269 println!(
1270 "Midpoint proof depth (proof_hashes.len()): {}",
1271 midpoint_proof.depth()
1272 );
1273
1274 assert_eq!(tree.depth(), 4);
1276 assert_eq!(
1277 address_proof.depth(),
1278 4,
1279 "Address proof should have 4 siblings (levels 0->1->2->3->4)"
1280 );
1281 assert_eq!(
1282 midpoint_proof.depth(),
1283 2,
1284 "Midpoint proof should have 2 siblings (levels 2->3->4)"
1285 );
1286 }
1287
1288 #[test]
1289 fn test_verify_works_correctly() {
1290 let leaves = make_test_leaves(16); let tree = MerkleTree::from_xornames(leaves.clone()).unwrap();
1293
1294 println!("Testing address proof verification...");
1295
1296 let proof_0 = tree.generate_address_proof(0, leaves[0]).unwrap();
1298 println!("Address 0 proof depth: {}", proof_0.depth());
1299 let valid = proof_0.verify();
1300 println!("Address 0 verification: {valid}");
1301 assert!(valid, "Proof for address 0 should be valid");
1302
1303 let proof_15 = tree.generate_address_proof(15, leaves[15]).unwrap();
1305 println!("Address 15 proof depth: {}", proof_15.depth());
1306 let valid = proof_15.verify();
1307 println!("Address 15 verification: {valid}");
1308 assert!(valid, "Proof for address 15 should be valid");
1309
1310 let proof_7 = tree.generate_address_proof(7, leaves[7]).unwrap();
1312 println!("Address 7 proof depth: {}", proof_7.depth());
1313 let valid = proof_7.verify();
1314 println!("Address 7 verification: {valid}");
1315 assert!(valid, "Proof for address 7 should be valid");
1316
1317 println!("\nTesting midpoint proof verification...");
1318
1319 let midpoints = tree.midpoints().unwrap();
1321 println!("Number of midpoints: {}", midpoints.len());
1322
1323 let int_proof_0 = tree.generate_midpoint_proof(0, midpoints[0].hash).unwrap();
1324 println!("Midpoint 0 proof depth: {}", int_proof_0.depth());
1325 let valid = int_proof_0.verify();
1326 println!("Midpoint 0 verification: {valid}");
1327 assert!(valid, "Proof for midpoint 0 should be valid");
1328
1329 let int_proof_3 = tree.generate_midpoint_proof(3, midpoints[3].hash).unwrap();
1330 println!("Midpoint 3 proof depth: {}", int_proof_3.depth());
1331 let valid = int_proof_3.verify();
1332 println!("Midpoint 3 verification: {valid}");
1333 assert!(valid, "Proof for midpoint 3 should be valid");
1334
1335 println!("\nTesting invalid proofs are rejected...");
1336
1337 let wrong_leaf = XorName::from_content(b"wrong_leaf");
1339 let wrong_proof = tree.generate_address_proof(0, wrong_leaf).unwrap();
1340 let valid = wrong_proof.verify();
1341 println!("Wrong leaf verification: {valid}");
1342 assert!(!valid, "Proof with wrong leaf should fail");
1343
1344 let wrong_index_proof = tree.generate_address_proof(0, leaves[1]).unwrap();
1346 let valid = wrong_index_proof.verify();
1347 println!("Wrong leaf index verification: {valid}");
1348 assert!(!valid, "Proof for leaf 0 with hash from leaf 1 should fail");
1349
1350 println!("\nAll verification tests passed!");
1351 }
1352
1353 #[test]
1354 fn test_complete_batch_payment_flow() {
1355 println!("\n=== SIMULATING COMPLETE MERKLE BATCH PAYMENT FLOW ===\n");
1364
1365 println!("PHASE 1: CLIENT PREPARES DATA");
1369 println!("------------------------------");
1370
1371 let real_address_count = 100;
1373 let addresses = make_test_leaves(real_address_count);
1374 println!("✓ Generated {real_address_count} real addresses from self-encryption");
1375
1376 println!("\nPHASE 2: CLIENT BUILDS MERKLE TREE");
1380 println!("----------------------------------");
1381
1382 let tree = MerkleTree::from_xornames(addresses.clone()).unwrap();
1383 let depth = tree.depth();
1384 let root = tree.root();
1385 let leaf_count = tree.leaf_count();
1386
1387 println!("✓ Tree depth: {depth}");
1388 println!("✓ Real addresses: {leaf_count}");
1389 println!("✓ Padded size: {} (2^{})", 1 << depth, depth);
1390 println!("✓ Dummy addresses added: {}", (1 << depth) - leaf_count);
1391 println!("✓ Merkle root: {root:?}");
1392
1393 assert_eq!(depth, 7); assert_eq!(leaf_count, 100);
1395
1396 println!("\nPHASE 3: CLIENT GETS REWARD CANDIDATES");
1400 println!("---------------------------------------");
1401
1402 let merkle_payment_timestamp = SystemTime::now()
1404 .duration_since(UNIX_EPOCH)
1405 .expect("Failed to get current time")
1406 .as_secs();
1407 println!("✓ Transaction timestamp: {merkle_payment_timestamp}");
1408
1409 let candidates = tree.reward_candidates(merkle_payment_timestamp).unwrap();
1411 let midpoint_count = expected_reward_pools(depth);
1412 let level = midpoint_level(depth);
1413 let proof_depth = midpoint_proof_depth(depth);
1414
1415 println!("✓ Midpoint level: {level}");
1416 println!("✓ Midpoint proof depth: {proof_depth}");
1417 println!("✓ Number of midpoint nodes (candidate pools): {midpoint_count}");
1418 println!("✓ Tree depth: {depth}");
1419 println!(
1420 "✓ Total nodes queried: {} × {} = {}",
1421 candidates.len(),
1422 depth,
1423 candidates.len() * depth as usize
1424 );
1425
1426 assert_eq!(candidates.len(), midpoint_count);
1427
1428 println!("✓ Generated {} candidate pools", candidates.len());
1431
1432 let first_candidate = &candidates[0];
1434 let midpoint_hash = first_candidate.branch.leaf_hash();
1435 let candidate_root = first_candidate.branch.root();
1436
1437 println!("\n Example candidate #0:");
1438 println!(" Midpoint hash: {midpoint_hash:?}");
1439 println!(" Root: {candidate_root:?}");
1440 println!(
1441 " Timestamp: {}",
1442 first_candidate.merkle_payment_timestamp
1443 );
1444 println!(" Address: {:?}", first_candidate.address());
1445 println!(" (Address = hash(midpoint || root || timestamp))");
1446
1447 println!("\nPHASE 4: SMART CONTRACT RECEIVES PAYMENT");
1451 println!("-----------------------------------------");
1452
1453 let smart_contract_root = root;
1461 let smart_contract_depth = depth;
1462 let smart_contract_timestamp = merkle_payment_timestamp;
1463
1464 println!("✓ Smart contract received payment");
1465 println!("✓ Stored root: {smart_contract_root:?}");
1466 println!("✓ Stored depth: {smart_contract_depth}");
1467 println!("✓ Stored timestamp: {smart_contract_timestamp}");
1468 println!("✓ Stored {} candidate pools", candidates.len());
1469
1470 let winner_pool_midpoint_proof_index = 0; let winner_candidate = &candidates[winner_pool_midpoint_proof_index];
1473
1474 let smart_contract_winner_pool_midpoint_proof_hash = winner_candidate.hash();
1476
1477 println!("✓ Winner pool selected: index {winner_pool_midpoint_proof_index}");
1478 println!("✓ Winner pool hash stored: {smart_contract_winner_pool_midpoint_proof_hash:?}");
1479 println!("✓ Payment distributed to {depth} nodes (depth)");
1480
1481 println!("\nPHASE 5: CLIENT UPLOADS CHUNKS WITH PROOFS");
1485 println!("-------------------------------------------");
1486
1487 let mut address_proofs = Vec::new();
1489 for (i, address_hash) in addresses.iter().enumerate() {
1490 let proof = tree.generate_address_proof(i, *address_hash).unwrap();
1491 address_proofs.push(proof);
1492 }
1493
1494 println!("✓ Generated {} address proofs", address_proofs.len());
1495 println!("✓ Each proof includes:");
1496 println!(" - Merkle proof (siblings from leaf to root)");
1497 println!(" - Salt (for privacy)");
1498 println!(" - Node hash (address being proven)");
1499 println!(" - Root (expected Merkle root)");
1500
1501 println!("\nPHASE 6: NODES VERIFY AND STORE CHUNKS");
1505 println!("---------------------------------------");
1506
1507 let mut verified_count = 0;
1513 for (i, address_proof) in address_proofs.iter().enumerate() {
1514 let address_hash = &addresses[i];
1517
1518 let result = verify_merkle_proof(
1521 address_hash,
1522 address_proof,
1523 winner_candidate,
1524 smart_contract_depth,
1525 &smart_contract_root,
1526 smart_contract_timestamp,
1527 );
1528
1529 assert!(
1530 result.is_ok(),
1531 "Address {} verification failed: {:?}",
1532 i,
1533 result.err()
1534 );
1535
1536 verified_count += 1;
1543 }
1544
1545 println!("✓ All {verified_count} addresses verified using verify_merkle_proof()");
1546 println!("✓ Core Merkle verification includes:");
1547 println!(" 1. Timestamp not in future");
1548 println!(" 2. Payment not expired (< {MERKLE_PAYMENT_EXPIRATION} seconds old)");
1549 println!(" 3. Winner pool timestamp matches smart contract timestamp");
1550 println!(" 4. Address Merkle proof valid (address ∈ tree)");
1551 println!(" 5. Winner Merkle proof valid (midpoint ∈ tree)");
1552 println!(" 6. Address proof depth matches on-chain depth");
1553 println!(" 7. Winner proof depth matches expected for midpoint");
1554 println!(" 8. Address proof root matches on-chain root");
1555 println!(" 9. Winner proof root matches on-chain root");
1556 println!(" Note: Winner pool hash verification happens in MerklePaymentProof::verify()");
1557
1558 println!("\nPHASE 7: VERIFY PROOF STRUCTURE");
1562 println!("--------------------------------");
1563
1564 let first_proof = &address_proofs[0];
1566 let claimed_depth = depth; let expected_address_depth = claimed_depth as usize;
1568 println!("✓ Address proof depth: {}", first_proof.depth());
1569 println!(
1570 "✓ Expected address proof depth (from claimed depth {claimed_depth}): {expected_address_depth}"
1571 );
1572 println!("✓ Number of sibling hashes: {}", first_proof.depth());
1573 println!("✓ Has salt: {}", first_proof.salt.is_some());
1574
1575 assert_eq!(
1576 first_proof.depth(),
1577 expected_address_depth,
1578 "Proof depth should match expected"
1579 );
1580
1581 let winner_branch = &winner_candidate.branch;
1583 let expected_midpoint_depth = midpoint_proof_depth(claimed_depth) as usize;
1584 let level = midpoint_level(claimed_depth);
1585
1586 println!("\n✓ Winner midpoint proof depth: {}", winner_branch.depth());
1587 println!("✓ Expected midpoint proof depth: {expected_midpoint_depth}");
1588 println!("✓ Midpoint level: {level}");
1589 println!("✓ Tree depth: {claimed_depth}");
1590 println!("✓ No salt (midpoints are intermediate hashes)");
1591
1592 assert_eq!(
1593 winner_branch.depth(),
1594 expected_midpoint_depth,
1595 "Midpoint proof depth should match expected"
1596 );
1597 assert!(
1598 winner_branch.salt.is_none(),
1599 "Midpoint proofs should not have salt"
1600 );
1601
1602 println!("\nPHASE 8: VERIFY PRIVACY PROPERTIES");
1606 println!("-----------------------------------");
1607
1608 let salts: Vec<_> = address_proofs.iter().map(|p| p.salt.unwrap()).collect();
1610
1611 let unique_salts: std::collections::HashSet<_> = salts.iter().collect();
1612 assert_eq!(
1613 unique_salts.len(),
1614 salts.len(),
1615 "All salts should be unique"
1616 );
1617 println!("✓ All {} addresses have unique salts", salts.len());
1618
1619 let tree2 = MerkleTree::from_xornames(addresses.clone()).unwrap();
1621 assert_ne!(tree.root(), tree2.root(), "Different salt → different root");
1622 println!("✓ Random salts ensure non-deterministic roots");
1623 println!("✓ Privacy: address content cannot be inferred from tree structure");
1624
1625 println!("\nPHASE 9: COST COMPARISON");
1629 println!("-------------------------");
1630
1631 let old_payments = real_address_count * 3; let new_payments = depth as usize; println!("Old system (per-address payment):");
1635 println!(
1636 " {real_address_count} addresses × 3 nodes = {old_payments} payment transactions"
1637 );
1638
1639 println!("\nNew system (Merkle batch payment):");
1640 println!(" 1 batch payment → {new_payments} winner nodes");
1641 println!(
1642 " Nodes queried: {} (only query phase, no storage payment)",
1643 candidates.len() * depth as usize
1644 );
1645
1646 let savings_pct = ((old_payments - new_payments) as f64 / old_payments as f64) * 100.0;
1647 println!("\n✓ Gas savings: {savings_pct:.1}% reduction");
1648 println!(
1649 "✓ Network query overhead: {}% of old system",
1650 (candidates.len() * depth as usize * 100) / old_payments
1651 );
1652
1653 println!("\n=== FLOW COMPLETE ===");
1657 println!("✓ {real_address_count} real addresses uploaded");
1658 println!("✓ {} dummy addresses padded", (1 << depth) - leaf_count);
1659 println!("✓ {} candidate pools formed", candidates.len());
1660 println!("✓ 1 winner pool paid ({depth} nodes)");
1661 println!("✓ All addresses verified and stored");
1662 println!("✓ Privacy preserved with random salts");
1663 println!("✓ {savings_pct:.1}% gas cost reduction achieved\n");
1664 }
1665
1666 #[test]
1667 fn test_get_nodes_at_level_with_padding() {
1668 println!("\n=== TESTING OUR PADDED TREE STRUCTURE ===\n");
1670
1671 let leaves = make_test_leaves(100); let tree = MerkleTree::from_xornames(leaves).unwrap();
1673
1674 let depth = tree.depth();
1675 println!("Tree with 100 leaves:");
1676 println!(" Depth: {depth}");
1677 println!(" Original leaves: {}", tree.leaf_count());
1678 println!(" Padded size: {} (2^{})", 1 << depth, depth);
1679
1680 for level in 0..=depth {
1682 let expected_count = 1 << (depth - level); if let Some(nodes) = tree.inner.get_nodes_at_level(level as usize) {
1685 let actual_count = nodes.len();
1686
1687 println!("\nLevel {level}:");
1688 println!(" Expected: {} nodes (2^{})", expected_count, depth - level);
1689 println!(" Actual: {actual_count} nodes");
1690
1691 if level as usize == midpoint_level(depth) {
1692 println!(" >>> MIDPOINT LEVEL <<<");
1693 println!(
1694 " Our workaround takes: {} nodes",
1695 std::cmp::min(actual_count, 1 << midpoint_proof_depth(depth))
1696 );
1697 }
1698
1699 if actual_count != expected_count {
1700 println!(" ⚠ Mismatch! This is why we need .take() workaround");
1701 }
1702 }
1703 }
1704
1705 println!("\n=== END TEST ===\n");
1706 }
1707
1708 #[test]
1709 fn test_proof_hashes_length_matches_depth() {
1710 let leaves = make_test_leaves(16);
1714 let tree = MerkleTree::from_xornames(leaves.clone()).unwrap();
1715 assert_eq!(tree.depth(), 4);
1716
1717 let address_proof = tree.generate_address_proof(0, leaves[0]).unwrap();
1718 assert_eq!(address_proof.depth(), 4);
1720
1721 let midpoints = tree.midpoints().unwrap();
1722 let midpoint_proof = tree.generate_midpoint_proof(0, midpoints[0].hash).unwrap();
1723 assert_eq!(midpoint_proof.depth(), 2);
1725
1726 let leaves = make_test_leaves(1024);
1728 let tree = MerkleTree::from_xornames(leaves.clone()).unwrap();
1729 assert_eq!(tree.depth(), 10);
1730
1731 let address_proof = tree.generate_address_proof(0, leaves[0]).unwrap();
1732 assert_eq!(address_proof.depth(), 10);
1734
1735 let midpoints = tree.midpoints().unwrap();
1736 let midpoint_proof = tree.generate_midpoint_proof(0, midpoints[0].hash).unwrap();
1737 assert_eq!(midpoint_proof.depth(), 5);
1739
1740 let leaves = make_test_leaves(100);
1742 let tree = MerkleTree::from_xornames(leaves.clone()).unwrap();
1743 assert_eq!(tree.depth(), 7);
1744
1745 let address_proof = tree.generate_address_proof(0, leaves[0]).unwrap();
1746 assert_eq!(address_proof.depth(), 7);
1748
1749 let midpoints = tree.midpoints().unwrap();
1750 let midpoint_proof = tree.generate_midpoint_proof(0, midpoints[0].hash).unwrap();
1751 assert_eq!(midpoint_proof.depth(), 4);
1753 }
1754
1755 #[test]
1756 fn test_verify_merkle_proof_errors() {
1757 use std::time::{SystemTime, UNIX_EPOCH};
1758
1759 let leaves = make_test_leaves(16);
1760 let tree = MerkleTree::from_xornames(leaves.clone()).unwrap();
1761 let merkle_payment_timestamp = SystemTime::now()
1762 .duration_since(UNIX_EPOCH)
1763 .unwrap()
1764 .as_secs();
1765
1766 let candidates = tree.reward_candidates(merkle_payment_timestamp).unwrap();
1767 let winner_pool_midpoint_proof = &candidates[0];
1768 let address_proof = tree.generate_address_proof(0, leaves[0]).unwrap();
1769 let root = tree.root();
1770 let depth = tree.depth();
1771
1772 let wrong_root = XorName::from_content(b"wrong root");
1774 let result = verify_merkle_proof(
1775 &leaves[0],
1776 &address_proof,
1777 winner_pool_midpoint_proof,
1778 depth,
1779 &wrong_root,
1780 merkle_payment_timestamp,
1781 );
1782 assert!(matches!(
1783 result,
1784 Err(BadMerkleProof::AddressBranchRootMismatch { .. })
1785 ));
1786
1787 let result = verify_merkle_proof(
1789 &leaves[0],
1790 &address_proof,
1791 winner_pool_midpoint_proof,
1792 depth + 1, &root,
1794 merkle_payment_timestamp,
1795 );
1796 assert!(matches!(
1797 result,
1798 Err(BadMerkleProof::AddressProofDepthMismatch { .. })
1799 ));
1800
1801 let mut wrong_winner = winner_pool_midpoint_proof.clone();
1803 let wrong_tree = MerkleTree::from_xornames(make_test_leaves(16)).unwrap();
1805 let wrong_candidates = wrong_tree
1806 .reward_candidates(merkle_payment_timestamp)
1807 .unwrap();
1808 wrong_winner.branch = wrong_candidates[0].branch.clone();
1809
1810 let result = verify_merkle_proof(
1811 &leaves[0],
1812 &address_proof,
1813 &wrong_winner,
1814 depth,
1815 &root,
1816 merkle_payment_timestamp,
1817 );
1818 assert!(matches!(
1819 result,
1820 Err(BadMerkleProof::WinnerBranchRootMismatch { .. })
1821 ));
1822
1823 let future_timestamp = merkle_payment_timestamp + 1000;
1825 let result = verify_merkle_proof(
1826 &leaves[0],
1827 &address_proof,
1828 winner_pool_midpoint_proof,
1829 depth,
1830 &root,
1831 future_timestamp,
1832 );
1833 assert!(matches!(
1834 result,
1835 Err(BadMerkleProof::TimestampInFuture { .. })
1836 ));
1837
1838 let old_timestamp = merkle_payment_timestamp - MERKLE_PAYMENT_EXPIRATION - 1;
1840 let old_candidates = tree.reward_candidates(old_timestamp).unwrap();
1841 let result = verify_merkle_proof(
1842 &leaves[0],
1843 &address_proof,
1844 &old_candidates[0],
1845 depth,
1846 &root,
1847 old_timestamp,
1848 );
1849 assert!(matches!(result, Err(BadMerkleProof::PaymentExpired { .. })));
1850
1851 let different_timestamp = merkle_payment_timestamp - 100;
1854 let result = verify_merkle_proof(
1855 &leaves[0],
1856 &address_proof,
1857 winner_pool_midpoint_proof,
1858 depth,
1859 &root,
1860 different_timestamp,
1861 );
1862 assert!(matches!(
1863 result,
1864 Err(BadMerkleProof::TimestampMismatch { .. })
1865 ));
1866 }
1867
1868 #[test]
1869 fn test_invalid_midpoint_index() {
1870 let leaves = make_test_leaves(16);
1871 let tree = MerkleTree::from_xornames(leaves).unwrap();
1872
1873 let midpoints = tree.midpoints().unwrap();
1874 let midpoint_count = midpoints.len();
1875
1876 let result = tree.generate_midpoint_proof(midpoint_count, XorName::from_content(b"test"));
1878
1879 assert!(matches!(
1880 result,
1881 Err(MerkleTreeError::InvalidMidpointIndex { .. })
1882 ));
1883 }
1884
1885 #[test]
1886 fn test_reward_candidate_pool_address() {
1887 let leaves = make_test_leaves(16);
1888 let tree = MerkleTree::from_xornames(leaves).unwrap();
1889
1890 let timestamp1 = 12345u64;
1891 let timestamp2 = 67890u64;
1892
1893 let candidates1 = tree.reward_candidates(timestamp1).unwrap();
1894 let candidates2 = tree.reward_candidates(timestamp2).unwrap();
1895
1896 assert_ne!(candidates1[0].address(), candidates2[0].address());
1898
1899 assert_eq!(candidates1[0].address(), candidates1[0].address());
1901
1902 let addr = candidates1[0].address();
1904 let mut data = Vec::with_capacity(32 + 32 + 8);
1905 data.extend_from_slice(candidates1[0].branch.leaf_hash().as_ref());
1906 data.extend_from_slice(candidates1[0].branch.root().as_ref());
1907 data.extend_from_slice(×tamp1.to_le_bytes());
1908 let expected = XorName::from_content(&data);
1909 assert_eq!(addr, expected);
1910 }
1911
1912 #[test]
1913 fn test_calculate_depth_edge_cases() {
1914 let test_cases = vec![
1916 (2, 1), (3, 2), (4, 2), (5, 3), (8, 3), (9, 4), (16, 4), (17, 5), (100, 7), (1024, 10), ];
1927
1928 for (leaf_count, expected_depth) in test_cases {
1929 let leaves = make_test_leaves(leaf_count);
1930 let tree = MerkleTree::from_xornames(leaves).unwrap();
1931 assert_eq!(
1932 tree.depth(),
1933 expected_depth,
1934 "Depth mismatch for {leaf_count} leaves"
1935 );
1936 }
1937 }
1938}