1use std::collections::HashMap;
10use elastic_array::ElasticArray1024;
11use common::{BLOCKS_RLP_SWAPPER, SNAPSHOT_RLP_SWAPPER};
12use {UntrustedRlp, Compressible, encode, RlpStream};
13
14pub struct InvalidRlpSwapper<'a> {
16 invalid_to_valid: HashMap<&'a [u8], &'a [u8]>,
17 valid_to_invalid: HashMap<&'a [u8], &'a [u8]>,
18}
19
20impl<'a> InvalidRlpSwapper<'a> {
21 pub fn new(rlps_to_swap: &[&'a [u8]], invalid_rlps: &[&'a [u8]]) -> Self {
23 if rlps_to_swap.len() > 0x7e {
24 panic!("Invalid usage, only 127 RLPs can be swappable.");
25 }
26 let mut invalid_to_valid = HashMap::new();
27 let mut valid_to_invalid = HashMap::new();
28 for (&rlp, &invalid) in rlps_to_swap.iter().zip(invalid_rlps.iter()) {
29 invalid_to_valid.insert(invalid, rlp);
30 valid_to_invalid.insert(rlp, invalid);
31 }
32 InvalidRlpSwapper {
33 invalid_to_valid: invalid_to_valid,
34 valid_to_invalid: valid_to_invalid
35 }
36 }
37 fn get_valid(&self, invalid_rlp: &[u8]) -> Option<&[u8]> {
39 self.invalid_to_valid.get(invalid_rlp).cloned()
40 }
41 fn get_invalid(&self, valid_rlp: &[u8]) -> Option<&[u8]> {
43 self.valid_to_invalid.get(valid_rlp).cloned()
44 }
45}
46
47pub enum RlpType {
49 Blocks,
51 Snapshot,
53}
54
55fn to_elastic(slice: &[u8]) -> ElasticArray1024<u8> {
56 let mut out = ElasticArray1024::new();
57 out.append_slice(slice);
58 out
59}
60
61fn map_rlp<F>(rlp: &UntrustedRlp, f: F) -> Option<ElasticArray1024<u8>> where
62 F: Fn(&UntrustedRlp) -> Option<ElasticArray1024<u8>> {
63 match rlp.iter()
64 .fold((false, RlpStream::new_list(rlp.item_count().unwrap_or(0))),
65 |(is_some, mut acc), subrlp| {
66 let new = f(&subrlp);
67 if let Some(ref insert) = new {
68 acc.append_raw(&insert[..], 1);
69 } else {
70 acc.append_raw(subrlp.as_raw(), 1);
71 }
72 (is_some || new.is_some(), acc)
73 }) {
74 (true, s) => Some(s.drain()),
75 _ => None,
76 }
77}
78
79fn simple_compress(rlp: &UntrustedRlp, swapper: &InvalidRlpSwapper) -> ElasticArray1024<u8> {
81 if rlp.is_data() {
82 to_elastic(swapper.get_invalid(rlp.as_raw()).unwrap_or_else(|| rlp.as_raw()))
83 } else {
84 map_rlp(rlp, |r| Some(simple_compress(r, swapper))).unwrap_or_else(|| to_elastic(rlp.as_raw()))
85 }
86}
87
88fn simple_decompress(rlp: &UntrustedRlp, swapper: &InvalidRlpSwapper) -> ElasticArray1024<u8> {
90 if rlp.is_data() {
91 to_elastic(swapper.get_valid(rlp.as_raw()).unwrap_or_else(|| rlp.as_raw()))
92 } else {
93 map_rlp(rlp, |r| Some(simple_decompress(r, swapper))).unwrap_or_else(|| to_elastic(rlp.as_raw()))
94 }
95}
96
97fn deep_compress(rlp: &UntrustedRlp, swapper: &InvalidRlpSwapper) -> Option<ElasticArray1024<u8>> {
100 let simple_swap = ||
101 swapper.get_invalid(rlp.as_raw()).map(to_elastic);
102 if rlp.is_data() {
103 return match rlp.payload_info() {
105 Ok(ref p) if p.value_len < 70 => simple_swap(),
107 _ => {
108 if let Ok(d) = rlp.data() {
109 let internal_rlp = UntrustedRlp::new(d);
110 if let Some(new_d) = deep_compress(&internal_rlp, swapper) {
111 let mut rlp = RlpStream::new_list(2);
113 rlp.append_raw(&[0x81, 0x7f], 1);
114 rlp.append_raw(&new_d[..], 1);
115 return Some(rlp.drain());
116 }
117 }
118 simple_swap()
119 },
120 };
121 }
122 map_rlp(rlp, |r| deep_compress(r, swapper))
124}
125
126fn deep_decompress(rlp: &UntrustedRlp, swapper: &InvalidRlpSwapper) -> Option<ElasticArray1024<u8>> {
129 let simple_swap = ||
130 swapper.get_valid(rlp.as_raw()).map(to_elastic);
131 if rlp.is_data() { return simple_swap(); }
133 match rlp.item_count().unwrap_or(0) {
134 2 if rlp.at(0).map(|r| r.as_raw() == &[0x81, 0x7f]).unwrap_or(false) =>
136 rlp.at(1).ok().map_or(simple_swap(),
137 |r| deep_decompress(&r, swapper).map(|d| { let v = d.to_vec(); encode(&v) })),
138 _ => map_rlp(rlp, |r| deep_decompress(r, swapper)),
140 }
141}
142
143impl<'a> Compressible for UntrustedRlp<'a> {
144 type DataType = RlpType;
145
146 fn compress(&self, t: RlpType) -> ElasticArray1024<u8> {
147 match t {
148 RlpType::Snapshot => simple_compress(self, &SNAPSHOT_RLP_SWAPPER),
149 RlpType::Blocks => deep_compress(self, &BLOCKS_RLP_SWAPPER).unwrap_or_else(|| to_elastic(self.as_raw())),
150 }
151 }
152
153 fn decompress(&self, t: RlpType) -> ElasticArray1024<u8> {
154 match t {
155 RlpType::Snapshot => simple_decompress(self, &SNAPSHOT_RLP_SWAPPER),
156 RlpType::Blocks => deep_decompress(self, &BLOCKS_RLP_SWAPPER).unwrap_or_else(|| to_elastic(self.as_raw())),
157 }
158 }
159}
160
161#[cfg(test)]
162mod tests {
163 use compression::InvalidRlpSwapper;
164 use {UntrustedRlp, Compressible, RlpType};
165
166 #[test]
167 fn invalid_rlp_swapper() {
168 let to_swap: &[&[u8]] = &[&[0x83, b'c', b'a', b't'], &[0x83, b'd', b'o', b'g']];
169 let invalid_rlp: &[&[u8]] = &[&[0x81, 0x00], &[0x81, 0x01]];
170 let swapper = InvalidRlpSwapper::new(to_swap, invalid_rlp);
171 assert_eq!(Some(invalid_rlp[0]), swapper.get_invalid(&[0x83, b'c', b'a', b't']));
172 assert_eq!(None, swapper.get_invalid(&[0x83, b'b', b'a', b't']));
173 assert_eq!(Some(to_swap[1]), swapper.get_valid(invalid_rlp[1]));
174 }
175
176 #[test]
177 fn simple_compression() {
178 let basic_account_rlp = vec![248, 68, 4, 2, 160, 86, 232, 31, 23, 27, 204, 85, 166, 255, 131, 69, 230, 146, 192, 248, 110, 91, 72, 224, 27, 153, 108, 173, 192, 1, 98, 47, 181, 227, 99, 180, 33, 160, 197, 210, 70, 1, 134, 247, 35, 60, 146, 126, 125, 178, 220, 199, 3, 192, 229, 0, 182, 83, 202, 130, 39, 59, 123, 250, 216, 4, 93, 133, 164, 112];
179 let rlp = UntrustedRlp::new(&basic_account_rlp);
180 let compressed = rlp.compress(RlpType::Snapshot).to_vec();
181 assert_eq!(compressed, vec![198, 4, 2, 129, 0, 129, 1]);
182 let compressed_rlp = UntrustedRlp::new(&compressed);
183 assert_eq!(compressed_rlp.decompress(RlpType::Snapshot).to_vec(), basic_account_rlp);
184 }
185
186 #[test]
187 fn data_compression() {
188 let data_basic_account_rlp = vec![184, 70, 248, 68, 4, 2, 160, 86, 232, 31, 23, 27, 204, 85, 166, 255, 131, 69, 230, 146, 192, 248, 110, 91, 72, 224, 27, 153, 108, 173, 192, 1, 98, 47, 181, 227, 99, 180, 33, 160, 197, 210, 70, 1, 134, 247, 35, 60, 146, 126, 125, 178, 220, 199, 3, 192, 229, 0, 182, 83, 202, 130, 39, 59, 123, 250, 216, 4, 93, 133, 164, 112];
189 let data_rlp = UntrustedRlp::new(&data_basic_account_rlp);
190 let compressed = data_rlp.compress(RlpType::Blocks).to_vec();
191 assert_eq!(compressed, vec![201, 129, 127, 198, 4, 2, 129, 0, 129, 1]);
192 let compressed_rlp = UntrustedRlp::new(&compressed);
193 assert_eq!(compressed_rlp.decompress(RlpType::Blocks).to_vec(), data_basic_account_rlp);
194 }
195
196 #[test]
197 fn nested_list_rlp() {
198 let nested_basic_account_rlp = vec![228, 4, 226, 2, 160, 86, 232, 31, 23, 27, 204, 85, 166, 255, 131, 69, 230, 146, 192, 248, 110, 91, 72, 224, 27, 153, 108, 173, 192, 1, 98, 47, 181, 227, 99, 180, 33];
199 let nested_rlp = UntrustedRlp::new(&nested_basic_account_rlp);
200 let compressed = nested_rlp.compress(RlpType::Blocks).to_vec();
201 assert_eq!(compressed, vec![197, 4, 195, 2, 129, 0]);
202 let compressed_rlp = UntrustedRlp::new(&compressed);
203 assert_eq!(compressed_rlp.decompress(RlpType::Blocks).to_vec(), nested_basic_account_rlp);
204 let compressed = nested_rlp.compress(RlpType::Snapshot).to_vec();
205 assert_eq!(compressed, vec![197, 4, 195, 2, 129, 0]);
206 let compressed_rlp = UntrustedRlp::new(&compressed);
207 assert_eq!(compressed_rlp.decompress(RlpType::Snapshot).to_vec(), nested_basic_account_rlp);
208 }
209
210 #[test]
211 fn malformed_rlp() {
212 let malformed = vec![248, 81, 128, 128, 128, 128, 128, 160, 12, 51, 241, 93, 69, 218, 74, 138, 79, 115, 227, 44, 216, 81, 46, 132, 85, 235, 96, 45, 252, 48, 181, 29, 75, 141, 217, 215, 86, 160, 109, 130, 160, 140, 36, 93, 200, 109, 215, 100, 241, 246, 99, 135, 92, 168, 149, 170, 114, 9, 143, 4, 93, 25, 76, 54, 176, 119, 230, 170, 154, 105, 47, 121, 10, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128];
213 let malformed_rlp = UntrustedRlp::new(&malformed);
214 assert_eq!(malformed_rlp.decompress(RlpType::Blocks).to_vec(), malformed);
215 }
216}