casper_types/
access_rights.rs

1use alloc::{
2    collections::{btree_map::Entry, BTreeMap},
3    vec::Vec,
4};
5use core::fmt::{self, Display, Formatter};
6
7use rand::{
8    distributions::{Distribution, Standard},
9    Rng,
10};
11use serde::{de::Error as SerdeError, Deserialize, Deserializer, Serialize, Serializer};
12
13use crate::{bytesrepr, Key, URef, URefAddr};
14pub use private::AccessRights;
15
16/// The number of bytes in a serialized [`AccessRights`].
17pub const ACCESS_RIGHTS_SERIALIZED_LENGTH: usize = 1;
18
19// Module exists only to restrict the scope of the following `#allow`.
20#[allow(clippy::bad_bit_mask)]
21mod private {
22    use bitflags::bitflags;
23    #[cfg(feature = "datasize")]
24    use datasize::DataSize;
25
26    bitflags! {
27        /// A struct which behaves like a set of bitflags to define access rights associated with a
28        /// [`URef`](crate::URef).
29        #[allow(clippy::derived_hash_with_manual_eq)]
30        #[cfg_attr(feature = "datasize", derive(DataSize))]
31        pub struct AccessRights: u8 {
32            /// No permissions
33            const NONE = 0;
34            /// Permission to read the value under the associated `URef`.
35            const READ  = 0b001;
36            /// Permission to write a value under the associated `URef`.
37            const WRITE = 0b010;
38            /// Permission to add to the value under the associated `URef`.
39            const ADD   = 0b100;
40            /// Permission to read or add to the value under the associated `URef`.
41            const READ_ADD       = Self::READ.bits | Self::ADD.bits;
42            /// Permission to read or write the value under the associated `URef`.
43            const READ_WRITE     = Self::READ.bits | Self::WRITE.bits;
44            /// Permission to add to, or write the value under the associated `URef`.
45            const ADD_WRITE      = Self::ADD.bits  | Self::WRITE.bits;
46            /// Permission to read, add to, or write the value under the associated `URef`.
47            const READ_ADD_WRITE = Self::READ.bits | Self::ADD.bits | Self::WRITE.bits;
48        }
49    }
50}
51
52impl Default for AccessRights {
53    fn default() -> Self {
54        AccessRights::NONE
55    }
56}
57
58impl AccessRights {
59    /// Returns `true` if the `READ` flag is set.
60    pub fn is_readable(self) -> bool {
61        self & AccessRights::READ == AccessRights::READ
62    }
63
64    /// Returns `true` if the `WRITE` flag is set.
65    pub fn is_writeable(self) -> bool {
66        self & AccessRights::WRITE == AccessRights::WRITE
67    }
68
69    /// Returns `true` if the `ADD` flag is set.
70    pub fn is_addable(self) -> bool {
71        self & AccessRights::ADD == AccessRights::ADD
72    }
73
74    /// Returns `true` if no flags are set.
75    pub fn is_none(self) -> bool {
76        self == AccessRights::NONE
77    }
78}
79
80impl Display for AccessRights {
81    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
82        match *self {
83            AccessRights::NONE => write!(f, "NONE"),
84            AccessRights::READ => write!(f, "READ"),
85            AccessRights::WRITE => write!(f, "WRITE"),
86            AccessRights::ADD => write!(f, "ADD"),
87            AccessRights::READ_ADD => write!(f, "READ_ADD"),
88            AccessRights::READ_WRITE => write!(f, "READ_WRITE"),
89            AccessRights::ADD_WRITE => write!(f, "ADD_WRITE"),
90            AccessRights::READ_ADD_WRITE => write!(f, "READ_ADD_WRITE"),
91            _ => write!(f, "UNKNOWN"),
92        }
93    }
94}
95
96impl bytesrepr::ToBytes for AccessRights {
97    fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
98        self.bits().to_bytes()
99    }
100
101    fn serialized_length(&self) -> usize {
102        ACCESS_RIGHTS_SERIALIZED_LENGTH
103    }
104
105    fn write_bytes(&self, writer: &mut Vec<u8>) -> Result<(), bytesrepr::Error> {
106        writer.push(self.bits());
107        Ok(())
108    }
109}
110
111impl bytesrepr::FromBytes for AccessRights {
112    fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
113        let (id, rem) = u8::from_bytes(bytes)?;
114        match AccessRights::from_bits(id) {
115            Some(rights) => Ok((rights, rem)),
116            None => Err(bytesrepr::Error::Formatting),
117        }
118    }
119}
120
121impl Serialize for AccessRights {
122    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
123        self.bits().serialize(serializer)
124    }
125}
126
127impl<'de> Deserialize<'de> for AccessRights {
128    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
129        let bits = u8::deserialize(deserializer)?;
130        AccessRights::from_bits(bits).ok_or_else(|| SerdeError::custom("invalid bits"))
131    }
132}
133
134impl Distribution<AccessRights> for Standard {
135    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> AccessRights {
136        let mut result = AccessRights::NONE;
137        if rng.gen() {
138            result |= AccessRights::READ;
139        }
140        if rng.gen() {
141            result |= AccessRights::WRITE;
142        }
143        if rng.gen() {
144            result |= AccessRights::ADD;
145        }
146        result
147    }
148}
149
150/// Used to indicate if a granted [`URef`] was already held by the context.
151#[derive(Debug, PartialEq, Eq)]
152pub enum GrantedAccess {
153    /// No new set of access rights were granted.
154    PreExisting,
155    /// A new set of access rights were granted.
156    Granted {
157        /// The address of the URef.
158        uref_addr: URefAddr,
159        /// The set of the newly granted access rights.
160        newly_granted_access_rights: AccessRights,
161    },
162}
163
164/// Access rights for a given runtime context.
165#[derive(Debug, PartialEq, Eq)]
166pub struct ContextAccessRights {
167    context_key: Key,
168    access_rights: BTreeMap<URefAddr, AccessRights>,
169}
170
171impl ContextAccessRights {
172    /// Creates a new instance of access rights from an iterator of URefs merging any duplicates,
173    /// taking the union of their rights.
174    pub fn new<T: IntoIterator<Item = URef>>(context_key: Key, uref_iter: T) -> Self {
175        let mut context_access_rights = ContextAccessRights {
176            context_key,
177            access_rights: BTreeMap::new(),
178        };
179        context_access_rights.do_extend(uref_iter);
180        context_access_rights
181    }
182
183    /// Returns the current context key.
184    pub fn context_key(&self) -> Key {
185        self.context_key
186    }
187
188    /// Extends the current access rights from a given set of URefs.
189    pub fn extend(&mut self, urefs: &[URef]) {
190        self.do_extend(urefs.iter().copied())
191    }
192
193    /// Extends the current access rights from a given set of URefs.
194    fn do_extend<T: IntoIterator<Item = URef>>(&mut self, uref_iter: T) {
195        for uref in uref_iter {
196            match self.access_rights.entry(uref.addr()) {
197                Entry::Occupied(rights) => {
198                    *rights.into_mut() = rights.get().union(uref.access_rights());
199                }
200                Entry::Vacant(rights) => {
201                    rights.insert(uref.access_rights());
202                }
203            }
204        }
205    }
206
207    /// Checks whether given uref has enough access rights.
208    pub fn has_access_rights_to_uref(&self, uref: &URef) -> bool {
209        if let Some(known_rights) = self.access_rights.get(&uref.addr()) {
210            let rights_to_check = uref.access_rights();
211            known_rights.contains(rights_to_check)
212        } else {
213            // URef is not known
214            false
215        }
216    }
217
218    /// Grants access to a [`URef`]; unless access was pre-existing.
219    pub fn grant_access(&mut self, uref: URef) -> GrantedAccess {
220        match self.access_rights.entry(uref.addr()) {
221            Entry::Occupied(existing_rights) => {
222                let newly_granted_access_rights =
223                    uref.access_rights().difference(*existing_rights.get());
224                *existing_rights.into_mut() = existing_rights.get().union(uref.access_rights());
225                if newly_granted_access_rights.is_none() {
226                    GrantedAccess::PreExisting
227                } else {
228                    GrantedAccess::Granted {
229                        uref_addr: uref.addr(),
230                        newly_granted_access_rights,
231                    }
232                }
233            }
234            Entry::Vacant(rights) => {
235                rights.insert(uref.access_rights());
236                GrantedAccess::Granted {
237                    uref_addr: uref.addr(),
238                    newly_granted_access_rights: uref.access_rights(),
239                }
240            }
241        }
242    }
243
244    /// Remove access for a given `URef`.
245    pub fn remove_access(&mut self, uref_addr: URefAddr, access_rights: AccessRights) {
246        if let Some(current_access_rights) = self.access_rights.get_mut(&uref_addr) {
247            current_access_rights.remove(access_rights)
248        }
249    }
250}
251
252#[cfg(test)]
253mod tests {
254    use super::*;
255    use crate::UREF_ADDR_LENGTH;
256
257    const UREF_ADDRESS: [u8; UREF_ADDR_LENGTH] = [1; UREF_ADDR_LENGTH];
258    const KEY: Key = Key::URef(URef::new(UREF_ADDRESS, AccessRights::empty()));
259    const UREF_NO_PERMISSIONS: URef = URef::new(UREF_ADDRESS, AccessRights::empty());
260    const UREF_READ: URef = URef::new(UREF_ADDRESS, AccessRights::READ);
261    const UREF_ADD: URef = URef::new(UREF_ADDRESS, AccessRights::ADD);
262    const UREF_WRITE: URef = URef::new(UREF_ADDRESS, AccessRights::WRITE);
263    const UREF_READ_ADD: URef = URef::new(UREF_ADDRESS, AccessRights::READ_ADD);
264    const UREF_READ_ADD_WRITE: URef = URef::new(UREF_ADDRESS, AccessRights::READ_ADD_WRITE);
265
266    fn test_readable(right: AccessRights, is_true: bool) {
267        assert_eq!(right.is_readable(), is_true)
268    }
269
270    #[test]
271    fn test_is_readable() {
272        test_readable(AccessRights::READ, true);
273        test_readable(AccessRights::READ_ADD, true);
274        test_readable(AccessRights::READ_WRITE, true);
275        test_readable(AccessRights::READ_ADD_WRITE, true);
276        test_readable(AccessRights::ADD, false);
277        test_readable(AccessRights::ADD_WRITE, false);
278        test_readable(AccessRights::WRITE, false);
279    }
280
281    fn test_writable(right: AccessRights, is_true: bool) {
282        assert_eq!(right.is_writeable(), is_true)
283    }
284
285    #[test]
286    fn test_is_writable() {
287        test_writable(AccessRights::WRITE, true);
288        test_writable(AccessRights::READ_WRITE, true);
289        test_writable(AccessRights::ADD_WRITE, true);
290        test_writable(AccessRights::READ, false);
291        test_writable(AccessRights::ADD, false);
292        test_writable(AccessRights::READ_ADD, false);
293        test_writable(AccessRights::READ_ADD_WRITE, true);
294    }
295
296    fn test_addable(right: AccessRights, is_true: bool) {
297        assert_eq!(right.is_addable(), is_true)
298    }
299
300    #[test]
301    fn test_is_addable() {
302        test_addable(AccessRights::ADD, true);
303        test_addable(AccessRights::READ_ADD, true);
304        test_addable(AccessRights::READ_WRITE, false);
305        test_addable(AccessRights::ADD_WRITE, true);
306        test_addable(AccessRights::READ, false);
307        test_addable(AccessRights::WRITE, false);
308        test_addable(AccessRights::READ_ADD_WRITE, true);
309    }
310
311    #[test]
312    fn should_check_has_access_rights_to_uref() {
313        let context_rights = ContextAccessRights::new(KEY, vec![UREF_READ_ADD]);
314        assert!(context_rights.has_access_rights_to_uref(&UREF_READ_ADD));
315        assert!(context_rights.has_access_rights_to_uref(&UREF_READ));
316        assert!(context_rights.has_access_rights_to_uref(&UREF_ADD));
317        assert!(context_rights.has_access_rights_to_uref(&UREF_NO_PERMISSIONS));
318    }
319
320    #[test]
321    fn should_check_does_not_have_access_rights_to_uref() {
322        let context_rights = ContextAccessRights::new(KEY, vec![UREF_READ_ADD]);
323        assert!(!context_rights.has_access_rights_to_uref(&UREF_READ_ADD_WRITE));
324        assert!(!context_rights
325            .has_access_rights_to_uref(&URef::new([2; UREF_ADDR_LENGTH], AccessRights::empty())));
326    }
327
328    #[test]
329    fn should_extend_access_rights() {
330        // Start with uref with no permissions.
331        let mut context_rights = ContextAccessRights::new(KEY, vec![UREF_NO_PERMISSIONS]);
332        let mut expected_rights = BTreeMap::new();
333        expected_rights.insert(UREF_ADDRESS, AccessRights::empty());
334        assert_eq!(context_rights.access_rights, expected_rights);
335
336        // Extend with a READ_ADD: should merge to single READ_ADD.
337        context_rights.extend(&[UREF_READ_ADD]);
338        *expected_rights.get_mut(&UREF_ADDRESS).unwrap() = AccessRights::READ_ADD;
339        assert_eq!(context_rights.access_rights, expected_rights);
340
341        // Extend with a READ: should have no observable effect.
342        context_rights.extend(&[UREF_READ]);
343        assert_eq!(context_rights.access_rights, expected_rights);
344
345        // Extend with a WRITE: should merge to single READ_ADD_WRITE.
346        context_rights.extend(&[UREF_WRITE]);
347        *expected_rights.get_mut(&UREF_ADDRESS).unwrap() = AccessRights::READ_ADD_WRITE;
348        assert_eq!(context_rights.access_rights, expected_rights);
349    }
350
351    #[test]
352    fn should_perform_union_of_access_rights_in_new() {
353        let context_rights =
354            ContextAccessRights::new(KEY, vec![UREF_NO_PERMISSIONS, UREF_READ, UREF_ADD]);
355
356        // Expect the three discrete URefs' rights to be unioned into READ_ADD.
357        let mut expected_rights = BTreeMap::new();
358        expected_rights.insert(UREF_ADDRESS, AccessRights::READ_ADD);
359        assert_eq!(context_rights.access_rights, expected_rights);
360    }
361
362    #[test]
363    fn should_grant_access_rights() {
364        let mut context_rights = ContextAccessRights::new(KEY, vec![UREF_READ_ADD]);
365        let granted_access = context_rights.grant_access(UREF_READ);
366        assert_eq!(granted_access, GrantedAccess::PreExisting);
367        let granted_access = context_rights.grant_access(UREF_READ_ADD_WRITE);
368        assert_eq!(
369            granted_access,
370            GrantedAccess::Granted {
371                uref_addr: UREF_ADDRESS,
372                newly_granted_access_rights: AccessRights::WRITE
373            }
374        );
375        assert!(context_rights.has_access_rights_to_uref(&UREF_READ_ADD_WRITE));
376        let new_uref = URef::new([3; 32], AccessRights::all());
377        let granted_access = context_rights.grant_access(new_uref);
378        assert_eq!(
379            granted_access,
380            GrantedAccess::Granted {
381                uref_addr: new_uref.addr(),
382                newly_granted_access_rights: AccessRights::all()
383            }
384        );
385        assert!(context_rights.has_access_rights_to_uref(&new_uref));
386    }
387
388    #[test]
389    fn should_remove_access_rights() {
390        let mut context_rights = ContextAccessRights::new(KEY, vec![UREF_READ_ADD_WRITE]);
391        assert!(context_rights.has_access_rights_to_uref(&UREF_READ_ADD_WRITE));
392
393        // Strip write access from the context rights.
394        context_rights.remove_access(UREF_ADDRESS, AccessRights::WRITE);
395        assert!(
396            !context_rights.has_access_rights_to_uref(&UREF_READ_ADD_WRITE),
397            "Write access should have been removed"
398        );
399
400        // Strip the access again to ensure that the bit is not flipped back.
401        context_rights.remove_access(UREF_ADDRESS, AccessRights::WRITE);
402        assert!(
403            !context_rights.has_access_rights_to_uref(&UREF_READ_ADD_WRITE),
404            "Write access should not have been granted back"
405        );
406        assert!(
407            context_rights.has_access_rights_to_uref(&UREF_READ_ADD),
408            "Read and add access should be preserved."
409        );
410
411        // Strip both read and add access from the context rights.
412        context_rights.remove_access(UREF_ADDRESS, AccessRights::READ_ADD);
413        assert!(
414            !context_rights.has_access_rights_to_uref(&UREF_READ_ADD),
415            "Read and add access should have been removed"
416        );
417        assert!(
418            context_rights.has_access_rights_to_uref(&UREF_NO_PERMISSIONS),
419            "The access rights should be empty"
420        );
421    }
422}