cosmwasm_std/storage_keys/
length_prefixed.rs

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