1use alloc::vec::Vec;
7use serde::{Deserialize, Serialize};
8
9use crate::hash::Hash;
10use crate::tagged_hash::csv_tagged_hash;
11
12#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
14pub struct DAGNode {
15 pub node_id: Hash,
17 pub bytecode: Vec<u8>,
19 pub signatures: Vec<Vec<u8>>,
21 pub witnesses: Vec<Vec<u8>>,
23 pub parents: Vec<Hash>,
25}
26
27impl DAGNode {
28 pub fn new(
30 node_id: Hash,
31 bytecode: Vec<u8>,
32 signatures: Vec<Vec<u8>>,
33 witnesses: Vec<Vec<u8>>,
34 parents: Vec<Hash>,
35 ) -> Self {
36 Self {
37 node_id,
38 bytecode,
39 signatures,
40 witnesses,
41 parents,
42 }
43 }
44
45 pub fn hash(&self) -> Hash {
47 let mut data = Vec::new();
48 data.extend_from_slice(self.node_id.as_bytes());
49 data.extend_from_slice(&self.bytecode);
50 for sig in &self.signatures {
51 data.extend_from_slice(sig);
52 }
53 for witness in &self.witnesses {
54 data.extend_from_slice(witness);
55 }
56 for parent in &self.parents {
57 data.extend_from_slice(parent.as_bytes());
58 }
59
60 Hash::new(csv_tagged_hash("dag-node", &data))
61 }
62}
63
64#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
66pub struct DAGSegment {
67 pub nodes: Vec<DAGNode>,
69 pub root_commitment: Hash,
71}
72
73impl DAGSegment {
74 pub fn new(nodes: Vec<DAGNode>, root_commitment: Hash) -> Self {
76 Self {
77 nodes,
78 root_commitment,
79 }
80 }
81
82 pub fn validate_structure(&self) -> Result<(), &'static str> {
84 let node_ids: alloc::collections::BTreeSet<_> =
86 self.nodes.iter().map(|n| n.node_id).collect();
87
88 for node in &self.nodes {
89 for parent in &node.parents {
90 if !node_ids.contains(parent) {
91 return Err("Parent node not found in DAG segment");
92 }
93 }
94 }
95
96 Ok(())
97 }
98}
99
100#[cfg(test)]
101mod tests {
102 use super::*;
103 use alloc::vec;
104
105 #[test]
110 fn test_dag_node_creation() {
111 let node = DAGNode::new(
112 Hash::new([1u8; 32]),
113 vec![0x01, 0x02, 0x03],
114 vec![vec![0xAB; 64]],
115 vec![vec![0xCD; 32]],
116 vec![],
117 );
118 assert_eq!(node.bytecode, vec![0x01, 0x02, 0x03]);
119 }
120
121 #[test]
122 fn test_dag_node_hash() {
123 let node = DAGNode::new(
124 Hash::new([1u8; 32]),
125 vec![0x01, 0x02],
126 vec![],
127 vec![],
128 vec![],
129 );
130 let hash = node.hash();
131 assert_eq!(hash.as_bytes().len(), 32);
132 }
133
134 #[test]
135 fn test_dag_segment_validation() {
136 let parent = DAGNode::new(Hash::new([1u8; 32]), vec![], vec![], vec![], vec![]);
137
138 let child = DAGNode::new(
139 Hash::new([2u8; 32]),
140 vec![],
141 vec![],
142 vec![],
143 vec![Hash::new([1u8; 32])],
144 );
145
146 let segment = DAGSegment::new(vec![parent, child], Hash::zero());
147
148 assert!(segment.validate_structure().is_ok());
149 }
150
151 #[test]
152 fn test_dag_segment_invalid_parent() {
153 let node = DAGNode::new(
154 Hash::new([1u8; 32]),
155 vec![],
156 vec![],
157 vec![],
158 vec![Hash::new([99u8; 32])], );
160
161 let segment = DAGSegment::new(vec![node], Hash::zero());
162 assert!(segment.validate_structure().is_err());
163 }
164
165 #[test]
170 fn test_dag_node_hash_deterministic() {
171 let node1 = DAGNode::new(
172 Hash::new([1u8; 32]),
173 vec![0x01, 0x02, 0x03],
174 vec![vec![0xAB; 64]],
175 vec![vec![0xCD; 32]],
176 vec![Hash::new([4u8; 32])],
177 );
178 let node2 = DAGNode::new(
179 Hash::new([1u8; 32]),
180 vec![0x01, 0x02, 0x03],
181 vec![vec![0xAB; 64]],
182 vec![vec![0xCD; 32]],
183 vec![Hash::new([4u8; 32])],
184 );
185 assert_eq!(node1.hash(), node2.hash());
187 }
188
189 #[test]
194 fn test_dag_node_hash_differs_by_node_id() {
195 let node_a = DAGNode::new(Hash::new([1u8; 32]), vec![0x01], vec![], vec![], vec![]);
196 let node_b = DAGNode::new(Hash::new([2u8; 32]), vec![0x01], vec![], vec![], vec![]);
197 assert_ne!(node_a.hash(), node_b.hash());
198 }
199
200 #[test]
201 fn test_dag_node_hash_differs_by_bytecode() {
202 let node_a = DAGNode::new(
203 Hash::new([1u8; 32]),
204 vec![0x01, 0x02],
205 vec![],
206 vec![],
207 vec![],
208 );
209 let node_b = DAGNode::new(
210 Hash::new([1u8; 32]),
211 vec![0x03, 0x04],
212 vec![],
213 vec![],
214 vec![],
215 );
216 assert_ne!(node_a.hash(), node_b.hash());
217 }
218
219 #[test]
220 fn test_dag_node_hash_differs_by_signatures() {
221 let node_a = DAGNode::new(
222 Hash::new([1u8; 32]),
223 vec![],
224 vec![vec![0xAA; 64]],
225 vec![],
226 vec![],
227 );
228 let node_b = DAGNode::new(
229 Hash::new([1u8; 32]),
230 vec![],
231 vec![vec![0xBB; 64]],
232 vec![],
233 vec![],
234 );
235 assert_ne!(node_a.hash(), node_b.hash());
236 }
237
238 #[test]
239 fn test_dag_node_hash_differs_by_witnesses() {
240 let node_a = DAGNode::new(
241 Hash::new([1u8; 32]),
242 vec![],
243 vec![],
244 vec![vec![0xCC; 32]],
245 vec![],
246 );
247 let node_b = DAGNode::new(
248 Hash::new([1u8; 32]),
249 vec![],
250 vec![],
251 vec![vec![0xDD; 32]],
252 vec![],
253 );
254 assert_ne!(node_a.hash(), node_b.hash());
255 }
256
257 #[test]
258 fn test_dag_node_hash_differs_by_parents() {
259 let node_a = DAGNode::new(
260 Hash::new([1u8; 32]),
261 vec![],
262 vec![],
263 vec![],
264 vec![Hash::new([10u8; 32])],
265 );
266 let node_b = DAGNode::new(
267 Hash::new([1u8; 32]),
268 vec![],
269 vec![],
270 vec![],
271 vec![Hash::new([20u8; 32])],
272 );
273 assert_ne!(node_a.hash(), node_b.hash());
274 }
275
276 #[test]
281 fn test_dag_segment_multi_parent_validation() {
282 let parent_a = DAGNode::new(Hash::new([1u8; 32]), vec![], vec![], vec![], vec![]);
283 let parent_b = DAGNode::new(Hash::new([2u8; 32]), vec![], vec![], vec![], vec![]);
284 let child = DAGNode::new(
285 Hash::new([3u8; 32]),
286 vec![],
287 vec![],
288 vec![],
289 vec![Hash::new([1u8; 32]), Hash::new([2u8; 32])],
290 );
291
292 let segment = DAGSegment::new(vec![parent_a, parent_b, child], Hash::zero());
293 assert!(segment.validate_structure().is_ok());
294 }
295
296 #[test]
297 fn test_dag_segment_multi_parent_missing_one() {
298 let parent_a = DAGNode::new(Hash::new([1u8; 32]), vec![], vec![], vec![], vec![]);
299 let child = DAGNode::new(
300 Hash::new([3u8; 32]),
301 vec![],
302 vec![],
303 vec![],
304 vec![Hash::new([1u8; 32]), Hash::new([99u8; 32])],
305 );
306
307 let segment = DAGSegment::new(vec![parent_a, child], Hash::zero());
308 assert!(segment.validate_structure().is_err());
309 }
310
311 #[test]
316 fn test_dag_root_node_has_no_parents() {
317 let root = DAGNode::new(Hash::new([1u8; 32]), vec![0x01], vec![], vec![], vec![]);
318 assert!(root.parents.is_empty());
319
320 let segment = DAGSegment::new(vec![root.clone()], Hash::zero());
321 assert!(segment.validate_structure().is_ok());
322 }
323
324 #[test]
329 fn test_dag_segment_empty_valid() {
330 let segment = DAGSegment::new(vec![], Hash::zero());
331 assert!(segment.validate_structure().is_ok());
332 }
333
334 #[test]
339 fn test_dag_node_serialization_roundtrip() {
340 let node = DAGNode::new(
341 Hash::new([1u8; 32]),
342 vec![0x01, 0x02, 0x03],
343 vec![vec![0xAB; 64]],
344 vec![vec![0xCD; 32]],
345 vec![Hash::new([4u8; 32])],
346 );
347
348 let bytes = bincode::serialize(&node).unwrap();
349 let restored: DAGNode = bincode::deserialize(&bytes).unwrap();
350 assert_eq!(node, restored);
351 }
352
353 #[test]
354 fn test_dag_segment_serialization_roundtrip() {
355 let parent = DAGNode::new(Hash::new([1u8; 32]), vec![0x01], vec![], vec![], vec![]);
356 let child = DAGNode::new(
357 Hash::new([2u8; 32]),
358 vec![0x02],
359 vec![vec![0xAB; 64]],
360 vec![],
361 vec![Hash::new([1u8; 32])],
362 );
363
364 let segment = DAGSegment::new(vec![parent, child], Hash::new([99u8; 32]));
365
366 let bytes = bincode::serialize(&segment).unwrap();
367 let restored: DAGSegment = bincode::deserialize(&bytes).unwrap();
368 assert_eq!(segment, restored);
369 }
370
371 #[test]
372 fn test_dag_node_serialization_preserves_hash() {
373 let node = DAGNode::new(
374 Hash::new([1u8; 32]),
375 vec![0x01, 0x02],
376 vec![vec![0xAB; 64]],
377 vec![],
378 vec![],
379 );
380 let original_hash = node.hash();
381
382 let bytes = bincode::serialize(&node).unwrap();
383 let restored: DAGNode = bincode::deserialize(&bytes).unwrap();
384 assert_eq!(original_hash, restored.hash());
385 }
386
387 #[test]
392 fn test_dag_segment_large_chain() {
393 let mut nodes = Vec::new();
394
395 for i in 0..100u8 {
397 let mut id = [0u8; 32];
398 id[0] = i + 1;
399
400 let parents = if i == 0 {
401 vec![]
403 } else {
404 let mut prev_id = [0u8; 32];
405 prev_id[0] = i;
406 vec![Hash::new(prev_id)]
407 };
408
409 let node = DAGNode::new(Hash::new(id), vec![i], vec![], vec![], parents);
410 nodes.push(node);
411 }
412
413 let segment = DAGSegment::new(nodes, Hash::zero());
414 assert!(segment.validate_structure().is_ok());
415 }
416
417 #[test]
418 fn test_dag_segment_large_diamond() {
419 let root = DAGNode::new(Hash::new([0u8; 32]), vec![], vec![], vec![], vec![]);
421 let node_a = DAGNode::new(
422 Hash::new([1u8; 32]),
423 vec![],
424 vec![],
425 vec![],
426 vec![Hash::new([0u8; 32])],
427 );
428 let node_b = DAGNode::new(
429 Hash::new([2u8; 32]),
430 vec![],
431 vec![],
432 vec![],
433 vec![Hash::new([0u8; 32])],
434 );
435 let leaf = DAGNode::new(
436 Hash::new([3u8; 32]),
437 vec![],
438 vec![],
439 vec![],
440 vec![Hash::new([1u8; 32]), Hash::new([2u8; 32])],
441 );
442
443 let segment = DAGSegment::new(vec![root, node_a, node_b, leaf], Hash::zero());
444 assert!(segment.validate_structure().is_ok());
445 }
446
447 #[test]
452 fn test_dag_segment_duplicate_node_ids_still_valid() {
453 let node_a = DAGNode::new(Hash::new([1u8; 32]), vec![0x01], vec![], vec![], vec![]);
455 let node_b = DAGNode::new(
456 Hash::new([1u8; 32]), vec![0x02],
458 vec![],
459 vec![],
460 vec![],
461 );
462 let child = DAGNode::new(
463 Hash::new([3u8; 32]),
464 vec![],
465 vec![],
466 vec![],
467 vec![Hash::new([1u8; 32])],
468 );
469
470 let segment = DAGSegment::new(vec![node_a, node_b, child], Hash::zero());
471 assert!(segment.validate_structure().is_ok());
473 }
474
475 #[test]
480 fn test_dag_node_hash_bytecode_order_sensitive() {
481 let node_a = DAGNode::new(
482 Hash::new([1u8; 32]),
483 vec![0x01, 0x02, 0x03],
484 vec![],
485 vec![],
486 vec![],
487 );
488 let node_b = DAGNode::new(
489 Hash::new([1u8; 32]),
490 vec![0x03, 0x02, 0x01],
491 vec![],
492 vec![],
493 vec![],
494 );
495 assert_ne!(node_a.hash(), node_b.hash());
496 }
497
498 #[test]
503 fn test_dag_node_hash_signature_order_sensitive() {
504 let node_a = DAGNode::new(
505 Hash::new([1u8; 32]),
506 vec![],
507 vec![vec![0xAA; 64], vec![0xBB; 64]],
508 vec![],
509 vec![],
510 );
511 let node_b = DAGNode::new(
512 Hash::new([1u8; 32]),
513 vec![],
514 vec![vec![0xBB; 64], vec![0xAA; 64]],
515 vec![],
516 vec![],
517 );
518 assert_ne!(node_a.hash(), node_b.hash());
519 }
520
521 #[test]
522 fn test_dag_node_hash_witness_order_sensitive() {
523 let node_a = DAGNode::new(
524 Hash::new([1u8; 32]),
525 vec![],
526 vec![],
527 vec![vec![0xCC; 32], vec![0xDD; 32]],
528 vec![],
529 );
530 let node_b = DAGNode::new(
531 Hash::new([1u8; 32]),
532 vec![],
533 vec![],
534 vec![vec![0xDD; 32], vec![0xCC; 32]],
535 vec![],
536 );
537 assert_ne!(node_a.hash(), node_b.hash());
538 }
539
540 #[test]
541 fn test_dag_node_hash_parent_order_sensitive() {
542 let node_a = DAGNode::new(
543 Hash::new([1u8; 32]),
544 vec![],
545 vec![],
546 vec![],
547 vec![Hash::new([10u8; 32]), Hash::new([20u8; 32])],
548 );
549 let node_b = DAGNode::new(
550 Hash::new([1u8; 32]),
551 vec![],
552 vec![],
553 vec![],
554 vec![Hash::new([20u8; 32]), Hash::new([10u8; 32])],
555 );
556 assert_ne!(node_a.hash(), node_b.hash());
557 }
558
559 #[test]
564 fn test_dag_complex_structure_with_signatures_and_witnesses() {
565 let root = DAGNode::new(
566 Hash::new([1u8; 32]),
567 vec![0x01, 0x02],
568 vec![vec![0xAA; 64]],
569 vec![vec![0xBB; 32]],
570 vec![],
571 );
572 let child = DAGNode::new(
573 Hash::new([2u8; 32]),
574 vec![0x03, 0x04],
575 vec![vec![0xCC; 64], vec![0xDD; 64]],
576 vec![vec![0xEE; 32]],
577 vec![Hash::new([1u8; 32])],
578 );
579
580 let segment = DAGSegment::new(vec![root, child], Hash::zero());
581 assert!(segment.validate_structure().is_ok());
582 assert_ne!(segment.nodes[0].hash(), segment.nodes[1].hash());
583 }
584
585 #[cfg(feature = "std")]
590 mod integration {
591 use super::*;
592 use crate::commitment::Commitment;
593 use crate::proof::ProofBundle;
594 use crate::seal::SealRef;
595
596 #[test]
597 fn test_dag_hash_used_in_commitment() {
598 let node = DAGNode::new(
599 Hash::new([1u8; 32]),
600 vec![0x01, 0x02],
601 vec![vec![0xAB; 64]],
602 vec![],
603 vec![],
604 );
605 let dag_hash = node.hash();
606
607 let seal = SealRef::new(vec![0xAA; 16], Some(42)).unwrap();
609 let domain = [0xBB; 32];
610 let commitment =
611 Commitment::simple(Hash::new([2u8; 32]), Hash::zero(), dag_hash, &seal, domain);
612
613 assert_eq!(commitment.hash().as_bytes().len(), 32);
615 }
616
617 #[test]
618 fn test_dag_inside_proof_bundle_roundtrip() {
619 let node = DAGNode::new(
620 Hash::new([1u8; 32]),
621 vec![0x01],
622 vec![vec![0xAB; 64]],
623 vec![],
624 vec![],
625 );
626 let segment = DAGSegment::new(vec![node], Hash::new([99u8; 32]));
627
628 let bundle = ProofBundle::new(
629 segment.clone(),
630 vec![vec![0xCC; 64]],
631 SealRef::new(vec![1, 2, 3], Some(42)).unwrap(),
632 crate::seal::AnchorRef::new(vec![4, 5, 6], 100, vec![]).unwrap(),
633 crate::proof::InclusionProof::new(vec![], Hash::zero(), 0).unwrap(),
634 crate::proof::FinalityProof::new(vec![], 6, false).unwrap(),
635 )
636 .unwrap();
637
638 let bytes = bundle.to_bytes().unwrap();
640 let restored = ProofBundle::from_bytes(&bytes).unwrap();
641 assert_eq!(bundle.transition_dag, restored.transition_dag);
642 }
643
644 #[test]
645 fn test_dag_in_verify_proof_pipeline() {
646 use secp256k1::{Message, Secp256k1, SecretKey};
647 let root_commitment = Hash::new([99u8; 32]);
649 let message: [u8; 32] = *root_commitment.as_bytes();
650 let secp = Secp256k1::new();
651 let secret_key = SecretKey::new(&mut secp256k1::rand::thread_rng());
652 let public_key = secp256k1::PublicKey::from_secret_key(&secp, &secret_key);
653 let msg = Message::from_digest_slice(&message).unwrap();
654 let signature_ecdsa = secp.sign_ecdsa(&msg, &secret_key);
655 let sig_bytes = signature_ecdsa.serialize_compact();
656 let pubkey_bytes = public_key.serialize();
657 let mut signature = Vec::with_capacity(4 + pubkey_bytes.len() + sig_bytes.len());
658 signature.extend_from_slice(&(pubkey_bytes.len() as u32).to_le_bytes());
659 signature.extend_from_slice(&pubkey_bytes);
660 signature.extend_from_slice(&sig_bytes);
661
662 let node = DAGNode::new(
663 Hash::new([1u8; 32]),
664 vec![0x01, 0x02],
665 vec![signature.clone()],
666 vec![],
667 vec![],
668 );
669 let segment = DAGSegment::new(vec![node], Hash::new([99u8; 32]));
670
671 let bundle = ProofBundle::new(
672 segment,
673 vec![signature],
674 SealRef::new(vec![1, 2, 3], Some(42)).unwrap(),
675 crate::seal::AnchorRef::new(vec![4, 5, 6], 100, vec![]).unwrap(),
676 crate::proof::InclusionProof::new(vec![0xDD; 32], Hash::new([10u8; 32]), 0)
677 .unwrap(),
678 crate::proof::FinalityProof::new(vec![], 6, false).unwrap(),
679 )
680 .unwrap();
681
682 let seal_registry = |_id: &[u8]| false;
684 assert!(crate::proof_verify::verify_proof(
685 &bundle,
686 seal_registry,
687 crate::signature::SignatureScheme::Secp256k1
688 )
689 .is_ok());
690 }
691
692 #[test]
693 fn test_dag_with_invalid_parent_fails_in_proof_bundle() {
694 use secp256k1::{Message, Secp256k1, SecretKey};
695 let root_commitment = Hash::zero();
696 let message: [u8; 32] = *root_commitment.as_bytes();
697 let secp = Secp256k1::new();
698 let secret_key = SecretKey::new(&mut secp256k1::rand::thread_rng());
699 let public_key = secp256k1::PublicKey::from_secret_key(&secp, &secret_key);
700 let msg = Message::from_digest_slice(&message).unwrap();
701 let signature_ecdsa = secp.sign_ecdsa(&msg, &secret_key);
702 let sig_bytes = signature_ecdsa.serialize_compact();
703 let pubkey_bytes = public_key.serialize();
704 let mut signature = Vec::with_capacity(4 + pubkey_bytes.len() + sig_bytes.len());
705 signature.extend_from_slice(&(pubkey_bytes.len() as u32).to_le_bytes());
706 signature.extend_from_slice(&pubkey_bytes);
707 signature.extend_from_slice(&sig_bytes);
708
709 let node = DAGNode::new(
710 Hash::new([1u8; 32]),
711 vec![0x01],
712 vec![signature.clone()],
713 vec![],
714 vec![Hash::new([99u8; 32])], );
716 let segment = DAGSegment::new(vec![node], Hash::zero());
717
718 let bundle = ProofBundle::new(
719 segment,
720 vec![signature],
721 SealRef::new(vec![1, 2, 3], Some(42)).unwrap(),
722 crate::seal::AnchorRef::new(vec![4, 5, 6], 100, vec![]).unwrap(),
723 crate::proof::InclusionProof::new(vec![0xDD; 32], Hash::new([10u8; 32]), 0)
724 .unwrap(),
725 crate::proof::FinalityProof::new(vec![], 6, false).unwrap(),
726 )
727 .unwrap();
728
729 let seal_registry = |_id: &[u8]| false;
730 let result = crate::proof_verify::verify_proof(
731 &bundle,
732 seal_registry,
733 crate::signature::SignatureScheme::Secp256k1,
734 );
735 assert!(result.is_err());
736 }
737
738 #[test]
739 fn test_same_dag_produces_same_commitment_hash() {
740 fn build_dag() -> DAGSegment {
742 let root = DAGNode::new(
743 Hash::new([1u8; 32]),
744 vec![0x01, 0x02],
745 vec![vec![0xAA; 64]],
746 vec![vec![0xBB; 32]],
747 vec![],
748 );
749 let child = DAGNode::new(
750 Hash::new([2u8; 32]),
751 vec![0x03],
752 vec![vec![0xCC; 64]],
753 vec![],
754 vec![Hash::new([1u8; 32])],
755 );
756 DAGSegment::new(vec![root, child], Hash::new([3u8; 32]))
757 }
758
759 let dag_a = build_dag();
760 let dag_b = build_dag();
761
762 let seal = SealRef::new(vec![0xFF; 16], Some(1)).unwrap();
764 let domain = [0xEE; 32];
765
766 let commitment_a = Commitment::simple(
767 Hash::new([10u8; 32]),
768 Hash::zero(),
769 dag_a.root_commitment,
770 &seal,
771 domain,
772 );
773 let commitment_b = Commitment::simple(
774 Hash::new([10u8; 32]),
775 Hash::zero(),
776 dag_b.root_commitment,
777 &seal,
778 domain,
779 );
780
781 assert_eq!(commitment_a.hash(), commitment_b.hash());
782 }
783 }
784}