essential_asm/
effects.rs

1use crate::{Access, Op, StateRead};
2use bitflags::bitflags;
3
4/// Flags representing the set of effects caused by a given slice of operations.
5#[derive(Debug, Copy, Clone, PartialEq, Eq)]
6pub struct Effects(u8);
7
8bitflags! {
9    impl Effects: u8 {
10        /// Flag for [´StateRead::KeyRange´]
11        const KeyRange = 1 << 0;
12        /// Flag for [´StateRead::KeyRangeExtern´]
13        const KeyRangeExtern = 1 << 1;
14        /// Flag for [´Access::ThisAddress´]
15        const ThisAddress = 1 << 2;
16        /// Flag for [´Access::ThisContractAddress´]
17        const ThisContractAddress = 1 << 3;
18    }
19}
20
21/// Determine effects of the given program.
22pub fn analyze(ops: &[Op]) -> Effects {
23    let mut effects = Effects::empty();
24
25    for op in ops {
26        match op {
27            Op::StateRead(StateRead::KeyRangeExtern) => effects |= Effects::KeyRangeExtern,
28            Op::StateRead(StateRead::KeyRange) => effects |= Effects::KeyRange,
29            Op::Access(Access::ThisAddress) => effects |= Effects::ThisAddress,
30            Op::Access(Access::ThisContractAddress) => effects |= Effects::ThisContractAddress,
31            _ => {}
32        }
33
34        // Short circuit if all flags are found.
35        if effects == Effects::all() {
36            break;
37        }
38    }
39    effects
40}
41
42#[cfg(test)]
43mod test {
44    use super::{analyze, Access, Effects, Op, StateRead};
45
46    #[test]
47    fn none() {
48        let ops = &[];
49        assert_eq!(analyze(ops), Effects::empty());
50    }
51
52    #[test]
53    fn key_range() {
54        let ops = &[Op::StateRead(StateRead::KeyRange)];
55        let effects = analyze(ops);
56        assert!(effects.contains(Effects::KeyRange));
57    }
58
59    #[test]
60    fn key_range_extern() {
61        let ops = &[Op::StateRead(StateRead::KeyRangeExtern)];
62        let effects = analyze(ops);
63        assert!(effects.contains(Effects::KeyRangeExtern));
64    }
65
66    #[test]
67    fn this_address() {
68        let ops = &[Op::Access(Access::ThisAddress)];
69        let effects = analyze(ops);
70        assert!(effects.contains(Effects::ThisAddress));
71    }
72
73    #[test]
74    fn this_contract_address() {
75        let ops = &[Op::Access(Access::ThisContractAddress)];
76        let effects = analyze(ops);
77        assert!(effects.contains(Effects::ThisContractAddress));
78    }
79
80    #[test]
81    fn all_effects() {
82        let ops = &[
83            Op::StateRead(StateRead::KeyRange),
84            Op::StateRead(StateRead::KeyRangeExtern),
85            Op::Access(Access::ThisAddress),
86            Op::Access(Access::ThisContractAddress),
87        ];
88        let effects = analyze(ops);
89        assert!(effects.contains(Effects::KeyRange));
90        assert!(effects.contains(Effects::KeyRangeExtern));
91        assert!(effects.contains(Effects::ThisAddress));
92        assert!(effects.contains(Effects::ThisContractAddress));
93    }
94}