1use alloc::borrow::ToOwned;
2use alloc::collections::btree_map::BTreeMap as HashMap;
3use alloc::vec::Vec;
4use prost::Message;
5
6use crate::helpers::Result;
7use crate::ics23;
8
9pub fn is_compressed(proof: &ics23::CommitmentProof) -> bool {
10 matches!(
11 &proof.proof,
12 Some(ics23::commitment_proof::Proof::Compressed(_))
13 )
14}
15
16pub fn compress(proof: &ics23::CommitmentProof) -> Result<ics23::CommitmentProof> {
17 if let Some(ics23::commitment_proof::Proof::Batch(batch)) = &proof.proof {
18 compress_batch(batch)
19 } else {
20 Ok(proof.to_owned())
21 }
22}
23
24pub fn decompress(proof: &ics23::CommitmentProof) -> Result<ics23::CommitmentProof> {
25 if let Some(ics23::commitment_proof::Proof::Compressed(compressed)) = &proof.proof {
26 decompress_batch(compressed)
27 } else {
28 Ok(proof.to_owned())
29 }
30}
31
32pub fn compress_batch(proof: &ics23::BatchProof) -> Result<ics23::CommitmentProof> {
33 let mut lookup = Vec::new();
34 let mut registry = HashMap::new();
35
36 let centries = proof
37 .entries
38 .iter()
39 .map(|entry| match &entry.proof {
40 Some(ics23::batch_entry::Proof::Exist(ex)) => {
41 let exist = compress_exist(ex, &mut lookup, &mut registry)?;
42 Ok(ics23::CompressedBatchEntry {
43 proof: Some(ics23::compressed_batch_entry::Proof::Exist(exist)),
44 })
45 }
46 Some(ics23::batch_entry::Proof::Nonexist(non)) => {
47 let left = non
48 .left
49 .as_ref()
50 .map(|l| compress_exist(l, &mut lookup, &mut registry))
51 .transpose()?;
52 let right = non
53 .right
54 .as_ref()
55 .map(|r| compress_exist(r, &mut lookup, &mut registry))
56 .transpose()?;
57 let nonexist = ics23::CompressedNonExistenceProof {
58 key: non.key.clone(),
59 left,
60 right,
61 };
62 Ok(ics23::CompressedBatchEntry {
63 proof: Some(ics23::compressed_batch_entry::Proof::Nonexist(nonexist)),
64 })
65 }
66 None => Ok(ics23::CompressedBatchEntry { proof: None }),
67 })
68 .collect::<Result<_>>()?;
69
70 Ok(ics23::CommitmentProof {
71 proof: Some(ics23::commitment_proof::Proof::Compressed(
72 ics23::CompressedBatchProof {
73 entries: centries,
74 lookup_inners: lookup,
75 },
76 )),
77 })
78}
79
80pub fn compress_exist(
81 exist: &ics23::ExistenceProof,
82 lookup: &mut Vec<ics23::InnerOp>,
83 registry: &mut HashMap<Vec<u8>, i32>,
84) -> Result<ics23::CompressedExistenceProof> {
85 let path = exist
86 .path
87 .iter()
88 .map(|x| {
89 let buf = x.encode_to_vec();
90 let idx = *registry.entry(buf).or_insert_with(|| {
91 let idx = lookup.len() as i32;
92 lookup.push(x.to_owned());
93 idx
94 });
95 Ok(idx)
96 })
97 .collect::<Result<_>>()?;
98
99 Ok(ics23::CompressedExistenceProof {
100 key: exist.key.clone(),
101 value: exist.value.clone(),
102 leaf: exist.leaf.clone(),
103 path,
104 })
105}
106
107pub fn decompress_batch(proof: &ics23::CompressedBatchProof) -> Result<ics23::CommitmentProof> {
108 let lookup = &proof.lookup_inners;
109 let entries = proof
110 .entries
111 .iter()
112 .map(|cent| match ¢.proof {
113 Some(ics23::compressed_batch_entry::Proof::Exist(ex)) => {
114 let exist = decompress_exist(ex, lookup);
115 Ok(ics23::BatchEntry {
116 proof: Some(ics23::batch_entry::Proof::Exist(exist)),
117 })
118 }
119 Some(ics23::compressed_batch_entry::Proof::Nonexist(non)) => {
120 let left = non.left.as_ref().map(|l| decompress_exist(l, lookup));
121 let right = non.right.as_ref().map(|r| decompress_exist(r, lookup));
122 let nonexist = ics23::NonExistenceProof {
123 key: non.key.clone(),
124 left,
125 right,
126 };
127 Ok(ics23::BatchEntry {
128 proof: Some(ics23::batch_entry::Proof::Nonexist(nonexist)),
129 })
130 }
131 None => Ok(ics23::BatchEntry { proof: None }),
132 })
133 .collect::<Result<_>>()?;
134
135 Ok(ics23::CommitmentProof {
136 proof: Some(ics23::commitment_proof::Proof::Batch(ics23::BatchProof {
137 entries,
138 })),
139 })
140}
141
142fn decompress_exist(
143 exist: &ics23::CompressedExistenceProof,
144 lookup: &[ics23::InnerOp],
145) -> ics23::ExistenceProof {
146 let path = exist
147 .path
148 .iter()
149 .map(|&x| lookup.get(x as usize).cloned())
150 .collect::<Option<Vec<_>>>()
151 .unwrap_or_default();
152 ics23::ExistenceProof {
153 key: exist.key.clone(),
154 value: exist.value.clone(),
155 leaf: exist.leaf.clone(),
156 path,
157 }
158}