cw_multi_test/prefixed_storage/
namespace_helpers.rs

1use cosmwasm_std::Storage;
2use cosmwasm_std::{Order, Record};
3
4pub(crate) fn get_with_prefix(
5    storage: &dyn Storage,
6    namespace: &[u8],
7    key: &[u8],
8) -> Option<Vec<u8>> {
9    storage.get(&concat(namespace, key))
10}
11
12pub(crate) fn set_with_prefix(
13    storage: &mut dyn Storage,
14    namespace: &[u8],
15    key: &[u8],
16    value: &[u8],
17) {
18    storage.set(&concat(namespace, key), value);
19}
20
21pub(crate) fn remove_with_prefix(storage: &mut dyn Storage, namespace: &[u8], key: &[u8]) {
22    storage.remove(&concat(namespace, key));
23}
24
25#[inline]
26fn concat(namespace: &[u8], key: &[u8]) -> Vec<u8> {
27    let mut k = namespace.to_vec();
28    k.extend_from_slice(key);
29    k
30}
31
32pub(crate) fn range_with_prefix<'a>(
33    storage: &'a dyn Storage,
34    namespace: &[u8],
35    start: Option<&[u8]>,
36    end: Option<&[u8]>,
37    order: Order,
38) -> Box<dyn Iterator<Item = Record> + 'a> {
39    // prepare start, end with prefix
40    let start = match start {
41        Some(s) => concat(namespace, s),
42        None => namespace.to_vec(),
43    };
44    let end = match end {
45        Some(e) => concat(namespace, e),
46        // end is updating last byte by one
47        None => namespace_upper_bound(namespace),
48    };
49
50    // get iterator from storage
51    let base_iterator = storage.range(Some(&start), Some(&end), order);
52
53    // make a copy for the closure to handle lifetimes safely
54    let prefix = namespace.to_vec();
55    let mapped = base_iterator.map(move |(k, v)| (trim(&prefix, &k), v));
56    Box::new(mapped)
57}
58
59#[inline]
60fn trim(namespace: &[u8], key: &[u8]) -> Vec<u8> {
61    key[namespace.len()..].to_vec()
62}
63
64/// Returns a new vec of same length and last byte incremented by one
65/// If last bytes are 255, we handle overflow up the chain.
66/// If all bytes are 255, this returns wrong data - but that is never possible as a namespace
67fn namespace_upper_bound(input: &[u8]) -> Vec<u8> {
68    let mut copy = input.to_vec();
69    // zero out all trailing 255, increment first that is not such
70    for i in (0..input.len()).rev() {
71        if copy[i] == 255 {
72            copy[i] = 0;
73        } else {
74            copy[i] += 1;
75            break;
76        }
77    }
78    copy
79}
80
81#[cfg(test)]
82mod tests {
83    use super::super::length_prefixed::to_length_prefixed;
84    use super::*;
85    use cosmwasm_std::testing::MockStorage;
86
87    #[test]
88    fn prefix_get_set() {
89        let mut storage = MockStorage::new();
90        let prefix = to_length_prefixed(b"foo");
91
92        set_with_prefix(&mut storage, &prefix, b"bar", b"gotcha");
93        let value = get_with_prefix(&storage, &prefix, b"bar");
94        assert_eq!(value, Some(b"gotcha".to_vec()));
95
96        // no collisions with other prefixes
97        let other_prefix = to_length_prefixed(b"fo");
98        let collision = get_with_prefix(&storage, &other_prefix, b"obar");
99        assert_eq!(collision, None);
100    }
101
102    #[test]
103    fn range_works() {
104        let mut storage = MockStorage::new();
105        let prefix = to_length_prefixed(b"foo");
106        let other_prefix = to_length_prefixed(b"food");
107
108        // set some values in this range
109        set_with_prefix(&mut storage, &prefix, b"bar", b"none");
110        set_with_prefix(&mut storage, &prefix, b"snowy", b"day");
111
112        // set some values outside this range
113        set_with_prefix(&mut storage, &other_prefix, b"moon", b"buggy");
114
115        // ensure we get proper result from prefixed_range iterator
116        let mut iter = range_with_prefix(&storage, &prefix, None, None, Order::Descending);
117        let first = iter.next().unwrap();
118        assert_eq!(first, (b"snowy".to_vec(), b"day".to_vec()));
119        let second = iter.next().unwrap();
120        assert_eq!(second, (b"bar".to_vec(), b"none".to_vec()));
121        assert!(iter.next().is_none());
122
123        // ensure we get raw result from base range
124        let iter = storage.range(None, None, Order::Ascending);
125        assert_eq!(3, iter.count());
126
127        // foo comes first
128        let mut iter = storage.range(None, None, Order::Ascending);
129        let first = iter.next().unwrap();
130        let expected_key = concat(&prefix, b"bar");
131        assert_eq!(first, (expected_key, b"none".to_vec()));
132    }
133
134    #[test]
135    fn range_with_prefix_wrap_over() {
136        let mut storage = MockStorage::new();
137        // if we don't properly wrap over there will be issues here (note 255+1 is used to calculate end)
138        let prefix = to_length_prefixed(b"f\xff\xff");
139        let other_prefix = to_length_prefixed(b"f\xff\x44");
140
141        // set some values in this range
142        set_with_prefix(&mut storage, &prefix, b"bar", b"none");
143        set_with_prefix(&mut storage, &prefix, b"snowy", b"day");
144
145        // set some values outside this range
146        set_with_prefix(&mut storage, &other_prefix, b"moon", b"buggy");
147
148        // ensure we get proper result from prefixed_range iterator
149        let iter = range_with_prefix(&storage, &prefix, None, None, Order::Descending);
150        let elements: Vec<Record> = iter.collect();
151        assert_eq!(
152            elements,
153            vec![
154                (b"snowy".to_vec(), b"day".to_vec()),
155                (b"bar".to_vec(), b"none".to_vec()),
156            ]
157        );
158    }
159
160    #[test]
161    fn range_with_start_end_set() {
162        let mut storage = MockStorage::new();
163        // if we don't properly wrap over there will be issues here (note 255+1 is used to calculate end)
164        let prefix = to_length_prefixed(b"f\xff\xff");
165        let other_prefix = to_length_prefixed(b"f\xff\x44");
166
167        // set some values in this range
168        set_with_prefix(&mut storage, &prefix, b"bar", b"none");
169        set_with_prefix(&mut storage, &prefix, b"snowy", b"day");
170
171        // set some values outside this range
172        set_with_prefix(&mut storage, &other_prefix, b"moon", b"buggy");
173
174        // make sure start and end are applied properly
175        let res: Vec<Record> =
176            range_with_prefix(&storage, &prefix, Some(b"b"), Some(b"c"), Order::Ascending)
177                .collect();
178        assert_eq!(res.len(), 1);
179        assert_eq!(res[0], (b"bar".to_vec(), b"none".to_vec()));
180
181        // make sure start and end are applied properly
182        let res_count = range_with_prefix(
183            &storage,
184            &prefix,
185            Some(b"bas"),
186            Some(b"sno"),
187            Order::Ascending,
188        )
189        .count();
190        assert_eq!(res_count, 0);
191
192        let res: Vec<Record> =
193            range_with_prefix(&storage, &prefix, Some(b"ant"), None, Order::Ascending).collect();
194        assert_eq!(res.len(), 2);
195        assert_eq!(res[0], (b"bar".to_vec(), b"none".to_vec()));
196        assert_eq!(res[1], (b"snowy".to_vec(), b"day".to_vec()));
197    }
198
199    #[test]
200    fn namespace_upper_bound_works() {
201        assert_eq!(namespace_upper_bound(b"bob"), b"boc".to_vec());
202        assert_eq!(namespace_upper_bound(b"fo\xfe"), b"fo\xff".to_vec());
203        assert_eq!(namespace_upper_bound(b"fo\xff"), b"fp\x00".to_vec());
204        // multiple \xff roll over
205        assert_eq!(
206            namespace_upper_bound(b"fo\xff\xff\xff"),
207            b"fp\x00\x00\x00".to_vec()
208        );
209        // \xff not at the end are ignored
210        assert_eq!(namespace_upper_bound(b"\xffabc"), b"\xffabd".to_vec());
211    }
212}