1use codec::Encode;
2use jam_types::{
3 Hash, SegmentTreeRoot, WorkPackage, WorkPackageHash, PROVEN_PER_SEGMENT, SEGMENT_LEN,
4};
5
6use crate::{cd_merkle_proof, cd_merkle_root, hash_raw, hash_raw_concat, CdMerkleProof};
7
8pub struct ImportData {
10 pub segment: Vec<u8>,
12 pub proof: CdMerkleProof,
14}
15
16pub fn build_encoded_bundle(
31 package: &WorkPackage,
32 chunked_extrinsics: impl IntoIterator<Item = impl AsRef<[u8]>>,
33 imports: &[Vec<ImportData>],
34) -> (WorkPackageHash, Vec<u8>) {
35 let mut encoded = Vec::new();
36 package.encode_to(&mut encoded);
37 let wp_hash = hash_raw(&encoded);
38 for chunk in chunked_extrinsics {
39 encoded.extend_from_slice(chunk.as_ref());
40 }
41 for item_imports in imports {
42 for import in item_imports {
43 encoded.extend_from_slice(&import.segment);
44 }
45 }
46 for item_imports in imports {
47 for import in item_imports {
48 import.proof.encode_to(&mut encoded);
49 }
50 }
51 (wp_hash.into(), encoded)
52}
53
54pub fn import_proofs(
57 segments: &[impl AsRef<[u8; SEGMENT_LEN]>],
58) -> (Vec<CdMerkleProof>, SegmentTreeRoot) {
59 let (page_proofs, root) = import_proof_data(segments);
60 let proofs = page_proofs
61 .into_iter()
62 .enumerate()
63 .flat_map(|(i, (prefix, hashes))| {
64 let padded_len =
65 if i > 0 { PROVEN_PER_SEGMENT } else { hashes.len().next_power_of_two() };
66 (0..hashes.len()).map(move |index| {
67 let mut proof = prefix.to_vec();
68 proof.extend(cd_merkle_proof(&hashes, padded_len, index).0);
69 proof
70 })
71 })
72 .collect::<Vec<_>>();
73 (proofs, root)
74}
75
76pub fn import_proof_data(
80 segments: &[impl AsRef<[u8; SEGMENT_LEN]>],
81) -> (impl IntoIterator<Item = (CdMerkleProof, Vec<Hash>)>, SegmentTreeRoot) {
82 let pages = segments
84 .chunks(PROVEN_PER_SEGMENT)
85 .map(|i| {
86 i.iter()
87 .map(|s| hash_raw_concat([b"leaf", s.as_ref().as_slice()]))
88 .collect::<Vec<_>>()
89 })
90 .collect::<Vec<_>>();
91 let subtree_roots = pages
93 .iter()
94 .map(|s| {
95 let padded_len =
96 if pages.len() > 1 { PROVEN_PER_SEGMENT } else { s.len().next_power_of_two() };
97 cd_merkle_root(s, padded_len)
98 })
99 .collect::<Vec<_>>();
100
101 let mut tree = vec![];
103 let root = if !segments.is_empty() {
104 tree = vec![subtree_roots];
105 let leafs = pages.len().next_power_of_two();
106 if tree[0].len() < leafs {
107 let empty_root = cd_merkle_root(&[], PROVEN_PER_SEGMENT);
108 tree[0].resize(leafs, empty_root);
109 }
110 tree.reserve(leafs.trailing_zeros() as usize + 1);
112 loop {
113 let last = tree.last().expect(
114 "Initially the tree has exactly one node, \
115 we don't remove the nodes in the loop",
116 );
117 if last.len() <= 1 {
118 break;
119 }
120 let next = last.chunks(2).map(|c| cd_merkle_root(c, 2)).collect::<Vec<_>>();
121 tree.push(next);
122 }
123
124 tree.pop().expect(
125 "Initially the tree has exactly one node, \
126 we don't remove the nodes in the loop",
127 )[0]
128 .into()
129 } else {
130 Default::default()
131 };
132
133 let pages = pages.into_iter().enumerate().map(move |(i, page)| {
135 let proof: CdMerkleProof = tree
136 .iter()
137 .enumerate()
138 .map(|(level, row)| row[(i >> level) ^ 1])
139 .rev()
140 .collect();
141 (proof, page)
142 });
143 (pages, root)
144}
145
146#[test]
147fn import_proof_data_empty_hash_when_empty() {
148 let empty: [jam_types::SegmentBytes; 0] = [];
149 let (_, root) = import_proof_data(&empty);
150 assert_eq!(root, Default::default())
151}