this repo has no description
1use crate::sync::verify::{CarVerifier, VerifyError}; 2use bytes::Bytes; 3use cid::Cid; 4use sha2::{Digest, Sha256}; 5use std::collections::HashMap; 6 7fn make_cid(data: &[u8]) -> Cid { 8 let mut hasher = Sha256::new(); 9 hasher.update(data); 10 let hash = hasher.finalize(); 11 let multihash = multihash::Multihash::wrap(0x12, &hash).unwrap(); 12 Cid::new_v1(0x71, multihash) 13} 14 15#[test] 16fn test_verifier_creation() { 17 let _verifier = CarVerifier::new(); 18} 19 20#[test] 21fn test_verify_error_display() { 22 let err = VerifyError::DidMismatch { 23 commit_did: "did:plc:abc".to_string(), 24 expected_did: "did:plc:xyz".to_string(), 25 }; 26 assert!(err.to_string().contains("did:plc:abc")); 27 assert!(err.to_string().contains("did:plc:xyz")); 28 let err = VerifyError::InvalidSignature; 29 assert!(err.to_string().contains("signature")); 30 let err = VerifyError::NoSigningKey; 31 assert!(err.to_string().contains("signing key")); 32 let err = VerifyError::MstValidationFailed("test error".to_string()); 33 assert!(err.to_string().contains("test error")); 34} 35 36#[test] 37fn test_mst_validation_missing_root_block() { 38 let verifier = CarVerifier::new(); 39 let blocks: HashMap<Cid, Bytes> = HashMap::new(); 40 let fake_cid = make_cid(b"fake data"); 41 let result = verifier.verify_mst_structure(&fake_cid, &blocks); 42 assert!(result.is_err()); 43 let err = result.unwrap_err(); 44 assert!(matches!(err, VerifyError::BlockNotFound(_))); 45} 46 47#[test] 48fn test_mst_validation_invalid_cbor() { 49 let verifier = CarVerifier::new(); 50 let bad_cbor = Bytes::from(vec![0xFF, 0xFF, 0xFF]); 51 let cid = make_cid(&bad_cbor); 52 let mut blocks = HashMap::new(); 53 blocks.insert(cid, bad_cbor); 54 let result = verifier.verify_mst_structure(&cid, &blocks); 55 assert!(result.is_err()); 56 let err = result.unwrap_err(); 57 assert!(matches!(err, VerifyError::InvalidCbor(_))); 58} 59 60#[test] 61fn test_mst_validation_empty_node() { 62 let verifier = CarVerifier::new(); 63 let empty_node = serde_ipld_dagcbor::to_vec(&serde_json::json!({ 64 "e": [] 65 })) 66 .unwrap(); 67 let cid = make_cid(&empty_node); 68 let mut blocks = HashMap::new(); 69 blocks.insert(cid, Bytes::from(empty_node)); 70 let result = verifier.verify_mst_structure(&cid, &blocks); 71 assert!(result.is_ok()); 72} 73 74#[test] 75fn test_mst_validation_missing_left_pointer() { 76 use ipld_core::ipld::Ipld; 77 78 let verifier = CarVerifier::new(); 79 let missing_left_cid = make_cid(b"missing left"); 80 let node = Ipld::Map(std::collections::BTreeMap::from([ 81 ("l".to_string(), Ipld::Link(missing_left_cid)), 82 ("e".to_string(), Ipld::List(vec![])), 83 ])); 84 let node_bytes = serde_ipld_dagcbor::to_vec(&node).unwrap(); 85 let cid = make_cid(&node_bytes); 86 let mut blocks = HashMap::new(); 87 blocks.insert(cid, Bytes::from(node_bytes)); 88 let result = verifier.verify_mst_structure(&cid, &blocks); 89 assert!(result.is_err()); 90 let err = result.unwrap_err(); 91 assert!(matches!(err, VerifyError::BlockNotFound(_))); 92 assert!(err.to_string().contains("left pointer")); 93} 94 95#[test] 96fn test_mst_validation_missing_subtree() { 97 use ipld_core::ipld::Ipld; 98 99 let verifier = CarVerifier::new(); 100 let missing_subtree_cid = make_cid(b"missing subtree"); 101 let record_cid = make_cid(b"record"); 102 let entry = Ipld::Map(std::collections::BTreeMap::from([ 103 ("k".to_string(), Ipld::Bytes(b"key1".to_vec())), 104 ("v".to_string(), Ipld::Link(record_cid)), 105 ("p".to_string(), Ipld::Integer(0)), 106 ("t".to_string(), Ipld::Link(missing_subtree_cid)), 107 ])); 108 let node = Ipld::Map(std::collections::BTreeMap::from([( 109 "e".to_string(), 110 Ipld::List(vec![entry]), 111 )])); 112 let node_bytes = serde_ipld_dagcbor::to_vec(&node).unwrap(); 113 let cid = make_cid(&node_bytes); 114 let mut blocks = HashMap::new(); 115 blocks.insert(cid, Bytes::from(node_bytes)); 116 let result = verifier.verify_mst_structure(&cid, &blocks); 117 assert!(result.is_err()); 118 let err = result.unwrap_err(); 119 assert!(matches!(err, VerifyError::BlockNotFound(_))); 120 assert!(err.to_string().contains("subtree")); 121} 122 123#[test] 124fn test_mst_validation_unsorted_keys() { 125 use ipld_core::ipld::Ipld; 126 127 let verifier = CarVerifier::new(); 128 let record_cid = make_cid(b"record"); 129 let entry1 = Ipld::Map(std::collections::BTreeMap::from([ 130 ("k".to_string(), Ipld::Bytes(b"zzz".to_vec())), 131 ("v".to_string(), Ipld::Link(record_cid)), 132 ("p".to_string(), Ipld::Integer(0)), 133 ])); 134 let entry2 = Ipld::Map(std::collections::BTreeMap::from([ 135 ("k".to_string(), Ipld::Bytes(b"aaa".to_vec())), 136 ("v".to_string(), Ipld::Link(record_cid)), 137 ("p".to_string(), Ipld::Integer(0)), 138 ])); 139 let node = Ipld::Map(std::collections::BTreeMap::from([( 140 "e".to_string(), 141 Ipld::List(vec![entry1, entry2]), 142 )])); 143 let node_bytes = serde_ipld_dagcbor::to_vec(&node).unwrap(); 144 let cid = make_cid(&node_bytes); 145 let mut blocks = HashMap::new(); 146 blocks.insert(cid, Bytes::from(node_bytes)); 147 let result = verifier.verify_mst_structure(&cid, &blocks); 148 assert!(result.is_err()); 149 let err = result.unwrap_err(); 150 assert!(matches!(err, VerifyError::MstValidationFailed(_))); 151 assert!(err.to_string().contains("sorted")); 152} 153 154#[test] 155fn test_mst_validation_sorted_keys_ok() { 156 use ipld_core::ipld::Ipld; 157 158 let verifier = CarVerifier::new(); 159 let record_cid = make_cid(b"record"); 160 let entry1 = Ipld::Map(std::collections::BTreeMap::from([ 161 ("k".to_string(), Ipld::Bytes(b"aaa".to_vec())), 162 ("v".to_string(), Ipld::Link(record_cid)), 163 ("p".to_string(), Ipld::Integer(0)), 164 ])); 165 let entry2 = Ipld::Map(std::collections::BTreeMap::from([ 166 ("k".to_string(), Ipld::Bytes(b"bbb".to_vec())), 167 ("v".to_string(), Ipld::Link(record_cid)), 168 ("p".to_string(), Ipld::Integer(0)), 169 ])); 170 let entry3 = Ipld::Map(std::collections::BTreeMap::from([ 171 ("k".to_string(), Ipld::Bytes(b"zzz".to_vec())), 172 ("v".to_string(), Ipld::Link(record_cid)), 173 ("p".to_string(), Ipld::Integer(0)), 174 ])); 175 let node = Ipld::Map(std::collections::BTreeMap::from([( 176 "e".to_string(), 177 Ipld::List(vec![entry1, entry2, entry3]), 178 )])); 179 let node_bytes = serde_ipld_dagcbor::to_vec(&node).unwrap(); 180 let cid = make_cid(&node_bytes); 181 let mut blocks = HashMap::new(); 182 blocks.insert(cid, Bytes::from(node_bytes)); 183 let result = verifier.verify_mst_structure(&cid, &blocks); 184 assert!(result.is_ok()); 185} 186 187#[test] 188fn test_mst_validation_with_valid_left_pointer() { 189 use ipld_core::ipld::Ipld; 190 191 let verifier = CarVerifier::new(); 192 let left_node = Ipld::Map(std::collections::BTreeMap::from([( 193 "e".to_string(), 194 Ipld::List(vec![]), 195 )])); 196 let left_node_bytes = serde_ipld_dagcbor::to_vec(&left_node).unwrap(); 197 let left_cid = make_cid(&left_node_bytes); 198 let root_node = Ipld::Map(std::collections::BTreeMap::from([ 199 ("l".to_string(), Ipld::Link(left_cid)), 200 ("e".to_string(), Ipld::List(vec![])), 201 ])); 202 let root_node_bytes = serde_ipld_dagcbor::to_vec(&root_node).unwrap(); 203 let root_cid = make_cid(&root_node_bytes); 204 let mut blocks = HashMap::new(); 205 blocks.insert(root_cid, Bytes::from(root_node_bytes)); 206 blocks.insert(left_cid, Bytes::from(left_node_bytes)); 207 let result = verifier.verify_mst_structure(&root_cid, &blocks); 208 assert!(result.is_ok()); 209} 210 211#[test] 212fn test_mst_validation_cycle_detection() { 213 let verifier = CarVerifier::new(); 214 let node = serde_ipld_dagcbor::to_vec(&serde_json::json!({ 215 "e": [] 216 })) 217 .unwrap(); 218 let cid = make_cid(&node); 219 let mut blocks = HashMap::new(); 220 blocks.insert(cid, Bytes::from(node)); 221 let result = verifier.verify_mst_structure(&cid, &blocks); 222 assert!(result.is_ok()); 223} 224 225#[tokio::test] 226async fn test_unsupported_did_method() { 227 let verifier = CarVerifier::new(); 228 let result = verifier.resolve_did_document("did:unknown:test").await; 229 assert!(result.is_err()); 230 let err = result.unwrap_err(); 231 assert!(matches!(err, VerifyError::DidResolutionFailed(_))); 232 assert!(err.to_string().contains("Unsupported")); 233} 234 235#[test] 236fn test_mst_validation_with_prefix_compression() { 237 use ipld_core::ipld::Ipld; 238 239 let verifier = CarVerifier::new(); 240 let record_cid = make_cid(b"record"); 241 let entry1 = Ipld::Map(std::collections::BTreeMap::from([ 242 ( 243 "k".to_string(), 244 Ipld::Bytes(b"app.bsky.feed.post/abc".to_vec()), 245 ), 246 ("v".to_string(), Ipld::Link(record_cid)), 247 ("p".to_string(), Ipld::Integer(0)), 248 ])); 249 let entry2 = Ipld::Map(std::collections::BTreeMap::from([ 250 ("k".to_string(), Ipld::Bytes(b"def".to_vec())), 251 ("v".to_string(), Ipld::Link(record_cid)), 252 ("p".to_string(), Ipld::Integer(19)), 253 ])); 254 let entry3 = Ipld::Map(std::collections::BTreeMap::from([ 255 ("k".to_string(), Ipld::Bytes(b"xyz".to_vec())), 256 ("v".to_string(), Ipld::Link(record_cid)), 257 ("p".to_string(), Ipld::Integer(19)), 258 ])); 259 let node = Ipld::Map(std::collections::BTreeMap::from([( 260 "e".to_string(), 261 Ipld::List(vec![entry1, entry2, entry3]), 262 )])); 263 let node_bytes = serde_ipld_dagcbor::to_vec(&node).unwrap(); 264 let cid = make_cid(&node_bytes); 265 let mut blocks = HashMap::new(); 266 blocks.insert(cid, Bytes::from(node_bytes)); 267 let result = verifier.verify_mst_structure(&cid, &blocks); 268 assert!( 269 result.is_ok(), 270 "Prefix-compressed keys should be validated correctly" 271 ); 272} 273 274#[test] 275fn test_mst_validation_prefix_compression_unsorted() { 276 use ipld_core::ipld::Ipld; 277 278 let verifier = CarVerifier::new(); 279 let record_cid = make_cid(b"record"); 280 let entry1 = Ipld::Map(std::collections::BTreeMap::from([ 281 ( 282 "k".to_string(), 283 Ipld::Bytes(b"app.bsky.feed.post/xyz".to_vec()), 284 ), 285 ("v".to_string(), Ipld::Link(record_cid)), 286 ("p".to_string(), Ipld::Integer(0)), 287 ])); 288 let entry2 = Ipld::Map(std::collections::BTreeMap::from([ 289 ("k".to_string(), Ipld::Bytes(b"abc".to_vec())), 290 ("v".to_string(), Ipld::Link(record_cid)), 291 ("p".to_string(), Ipld::Integer(19)), 292 ])); 293 let node = Ipld::Map(std::collections::BTreeMap::from([( 294 "e".to_string(), 295 Ipld::List(vec![entry1, entry2]), 296 )])); 297 let node_bytes = serde_ipld_dagcbor::to_vec(&node).unwrap(); 298 let cid = make_cid(&node_bytes); 299 let mut blocks = HashMap::new(); 300 blocks.insert(cid, Bytes::from(node_bytes)); 301 let result = verifier.verify_mst_structure(&cid, &blocks); 302 assert!( 303 result.is_err(), 304 "Unsorted prefix-compressed keys should fail validation" 305 ); 306 let err = result.unwrap_err(); 307 assert!(matches!(err, VerifyError::MstValidationFailed(_))); 308}