cosmwasm_std/storage_keys/
length_prefixed.rs

1//! This module is an implemention of a namespacing scheme described
2//! in https://github.com/webmaster128/key-namespacing#length-prefixed-keys
3//!
4//! Everything in this file is only responsible for building such keys
5//! and is in no way specific to any kind of storage.
6
7/// Calculates the raw key prefix for a given namespace as documented
8/// in https://github.com/webmaster128/key-namespacing#length-prefixed-keys
9pub fn to_length_prefixed(namespace_component: &[u8]) -> Vec<u8> {
10    let mut out = Vec::with_capacity(namespace_component.len() + 2);
11    out.extend_from_slice(&encode_length(namespace_component));
12    out.extend_from_slice(namespace_component);
13    out
14}
15
16/// Calculates the raw key prefix for a given nested namespace
17/// as documented in https://github.com/webmaster128/key-namespacing#nesting
18pub fn to_length_prefixed_nested(namespace: &[&[u8]]) -> Vec<u8> {
19    let mut size = 0;
20    for component in namespace {
21        size += component.len() + 2;
22    }
23
24    let mut out = Vec::with_capacity(size);
25    for component in namespace {
26        out.extend_from_slice(&encode_length(component));
27        out.extend_from_slice(component);
28    }
29    out
30}
31
32/// Encodes the length of a given namespace component
33/// as a 2 byte big endian encoded integer
34fn encode_length(namespace_component: &[u8]) -> [u8; 2] {
35    if namespace_component.len() > 0xFFFF {
36        panic!("only supports namespace components up to length 0xFFFF")
37    }
38    let length_bytes = (namespace_component.len() as u32).to_be_bytes();
39    [length_bytes[2], length_bytes[3]]
40}
41
42/// Encodes a namespace + key to a raw storage key.
43///
44/// This is equivalent concat(to_length_prefixed_nested(namespace), key)
45/// but more efficient when the namespace serialization is not persisted because
46/// here we only need one vector allocation.
47pub fn namespace_with_key(namespace: &[&[u8]], key: &[u8]) -> Vec<u8> {
48    // As documented in docs/STORAGE_KEYS.md, we know the final size of the key,
49    // which allows us to avoid reallocations of vectors.
50    let mut size = key.len();
51    for component in namespace {
52        size += 2 /* encoded component length */ + component.len() /* the actual component data */;
53    }
54
55    let mut out = Vec::with_capacity(size);
56    for component in namespace {
57        out.extend_from_slice(&encode_length(component));
58        out.extend_from_slice(component);
59    }
60    out.extend_from_slice(key);
61    out
62}
63
64#[cfg(test)]
65mod tests {
66    use super::*;
67
68    #[test]
69    fn to_length_prefixed_works() {
70        assert_eq!(to_length_prefixed(b""), b"\x00\x00");
71        assert_eq!(to_length_prefixed(b"a"), b"\x00\x01a");
72        assert_eq!(to_length_prefixed(b"ab"), b"\x00\x02ab");
73        assert_eq!(to_length_prefixed(b"abc"), b"\x00\x03abc");
74    }
75
76    #[test]
77    fn to_length_prefixed_works_for_long_prefix() {
78        let long_namespace1 = vec![0; 256];
79        let prefix1 = to_length_prefixed(&long_namespace1);
80        assert_eq!(prefix1.len(), 256 + 2);
81        assert_eq!(&prefix1[0..2], b"\x01\x00");
82
83        let long_namespace2 = vec![0; 30000];
84        let prefix2 = to_length_prefixed(&long_namespace2);
85        assert_eq!(prefix2.len(), 30000 + 2);
86        assert_eq!(&prefix2[0..2], b"\x75\x30");
87
88        let long_namespace3 = vec![0; 0xFFFF];
89        let prefix3 = to_length_prefixed(&long_namespace3);
90        assert_eq!(prefix3.len(), 0xFFFF + 2);
91        assert_eq!(&prefix3[0..2], b"\xFF\xFF");
92    }
93
94    #[test]
95    #[should_panic(expected = "only supports namespace components up to length 0xFFFF")]
96    fn to_length_prefixed_panics_for_too_long_prefix() {
97        let limit = 0xFFFF;
98        let long_namespace = vec![0; limit + 1];
99        to_length_prefixed(&long_namespace);
100    }
101
102    #[test]
103    fn to_length_prefixed_calculates_capacity_correctly() {
104        // Those tests cannot guarantee the required capacity was calculated correctly before
105        // the vector allocation but increase the likelyhood of a proper implementation.
106
107        let key = to_length_prefixed(b"");
108        assert_eq!(key.capacity(), key.len());
109
110        let key = to_length_prefixed(b"h");
111        assert_eq!(key.capacity(), key.len());
112
113        let key = to_length_prefixed(b"hij");
114        assert_eq!(key.capacity(), key.len());
115    }
116
117    #[test]
118    fn to_length_prefixed_nested_works() {
119        assert_eq!(to_length_prefixed_nested(&[]), b"");
120        assert_eq!(to_length_prefixed_nested(&[b""]), b"\x00\x00");
121        assert_eq!(to_length_prefixed_nested(&[b"", b""]), b"\x00\x00\x00\x00");
122
123        assert_eq!(to_length_prefixed_nested(&[b"a"]), b"\x00\x01a");
124        assert_eq!(
125            to_length_prefixed_nested(&[b"a", b"ab"]),
126            b"\x00\x01a\x00\x02ab"
127        );
128        assert_eq!(
129            to_length_prefixed_nested(&[b"a", b"ab", b"abc"]),
130            b"\x00\x01a\x00\x02ab\x00\x03abc"
131        );
132    }
133
134    #[test]
135    fn to_length_prefixed_nested_returns_the_same_as_to_length_prefixed_for_one_element() {
136        let tests = [b"" as &[u8], b"x" as &[u8], b"abababab" as &[u8]];
137
138        for test in tests {
139            assert_eq!(to_length_prefixed_nested(&[test]), to_length_prefixed(test));
140        }
141    }
142
143    #[test]
144    fn to_length_prefixed_nested_allows_many_long_namespaces() {
145        // The 0xFFFF limit is for each namespace, not for the combination of them
146
147        let long_namespace1 = vec![0xaa; 0xFFFD];
148        let long_namespace2 = vec![0xbb; 0xFFFE];
149        let long_namespace3 = vec![0xcc; 0xFFFF];
150
151        let prefix =
152            to_length_prefixed_nested(&[&long_namespace1, &long_namespace2, &long_namespace3]);
153        assert_eq!(&prefix[0..2], b"\xFF\xFD");
154        assert_eq!(&prefix[2..(2 + 0xFFFD)], long_namespace1.as_slice());
155        assert_eq!(&prefix[(2 + 0xFFFD)..(2 + 0xFFFD + 2)], b"\xFF\xFe");
156        assert_eq!(
157            &prefix[(2 + 0xFFFD + 2)..(2 + 0xFFFD + 2 + 0xFFFE)],
158            long_namespace2.as_slice()
159        );
160        assert_eq!(
161            &prefix[(2 + 0xFFFD + 2 + 0xFFFE)..(2 + 0xFFFD + 2 + 0xFFFE + 2)],
162            b"\xFF\xFf"
163        );
164        assert_eq!(
165            &prefix[(2 + 0xFFFD + 2 + 0xFFFE + 2)..(2 + 0xFFFD + 2 + 0xFFFE + 2 + 0xFFFF)],
166            long_namespace3.as_slice()
167        );
168    }
169
170    #[test]
171    fn to_length_prefixed_nested_calculates_capacity_correctly() {
172        // Those tests cannot guarantee the required capacity was calculated correctly before
173        // the vector allocation but increase the likelyhood of a proper implementation.
174
175        let key = to_length_prefixed_nested(&[]);
176        assert_eq!(key.capacity(), key.len());
177
178        let key = to_length_prefixed_nested(&[b""]);
179        assert_eq!(key.capacity(), key.len());
180
181        let key = to_length_prefixed_nested(&[b"a"]);
182        assert_eq!(key.capacity(), key.len());
183
184        let key = to_length_prefixed_nested(&[b"a", b"bc"]);
185        assert_eq!(key.capacity(), key.len());
186
187        let key = to_length_prefixed_nested(&[b"a", b"bc", b"def"]);
188        assert_eq!(key.capacity(), key.len());
189    }
190
191    #[test]
192    fn encode_length_works() {
193        assert_eq!(encode_length(b""), *b"\x00\x00");
194        assert_eq!(encode_length(b"a"), *b"\x00\x01");
195        assert_eq!(encode_length(b"aa"), *b"\x00\x02");
196        assert_eq!(encode_length(b"aaa"), *b"\x00\x03");
197        assert_eq!(encode_length(&vec![1; 255]), *b"\x00\xff");
198        assert_eq!(encode_length(&vec![1; 256]), *b"\x01\x00");
199        assert_eq!(encode_length(&vec![1; 12345]), *b"\x30\x39");
200        assert_eq!(encode_length(&vec![1; 65535]), *b"\xff\xff");
201    }
202
203    #[test]
204    #[should_panic(expected = "only supports namespace components up to length 0xFFFF")]
205    fn encode_length_panics_for_large_values() {
206        encode_length(&vec![1; 65536]);
207    }
208
209    #[test]
210    fn namespace_with_key_works() {
211        // Empty namespace
212        let enc = namespace_with_key(&[], b"foo");
213        assert_eq!(enc, b"foo");
214        let enc = namespace_with_key(&[], b"");
215        assert_eq!(enc, b"");
216
217        // One component namespace
218        let enc = namespace_with_key(&[b"bar"], b"foo");
219        assert_eq!(enc, b"\x00\x03barfoo");
220        let enc = namespace_with_key(&[b"bar"], b"");
221        assert_eq!(enc, b"\x00\x03bar");
222
223        // Multi component namespace
224        let enc = namespace_with_key(&[b"bar", b"cool"], b"foo");
225        assert_eq!(enc, b"\x00\x03bar\x00\x04coolfoo");
226        let enc = namespace_with_key(&[b"bar", b"cool"], b"");
227        assert_eq!(enc, b"\x00\x03bar\x00\x04cool");
228    }
229}