sui_types/
global_state_hash.rs

1// Copyright (c) Mysten Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4/// A type to represent the root hash of all live objects in the network.
5pub type GlobalStateHash = fastcrypto::hash::EllipticCurveMultisetHash;
6
7#[cfg(test)]
8mod tests {
9    use crate::base_types::ObjectDigest;
10    use crate::global_state_hash::GlobalStateHash;
11    use fastcrypto::hash::MultisetHash;
12    use rand::seq::SliceRandom;
13
14    #[test]
15    fn test_global_state_hash() {
16        let ref1 = ObjectDigest::random();
17        let ref2 = ObjectDigest::random();
18        let ref3 = ObjectDigest::random();
19        let ref4 = ObjectDigest::random();
20
21        let mut a1 = GlobalStateHash::default();
22        a1.insert(ref1);
23        a1.insert(ref2);
24        a1.insert(ref3);
25
26        // Insertion out of order should arrive at the same result.
27        let mut a2 = GlobalStateHash::default();
28        a2.insert(ref3);
29        assert_ne!(a1, a2);
30        a2.insert(ref2);
31        assert_ne!(a1, a2);
32        a2.insert(ref1);
33        assert_eq!(a1, a2);
34
35        // GlobalStateHash is not a set, and inserting the same element twice will change the result.
36        a2.insert(ref3);
37        assert_ne!(a1, a2);
38        a2.remove(ref3);
39
40        a2.insert(ref4);
41        assert_ne!(a1, a2);
42
43        // Supports removal.
44        a2.remove(ref4);
45        assert_eq!(a1, a2);
46
47        // Removing elements out of order should arrive at the same result.
48        a2.remove(ref3);
49        a2.remove(ref1);
50
51        a1.remove(ref1);
52        a1.remove(ref3);
53
54        assert_eq!(a1, a2);
55
56        // After removing all elements, it should be the same as an empty one.
57        a1.remove(ref2);
58        assert_eq!(a1, GlobalStateHash::default());
59    }
60
61    #[test]
62    fn test_global_state_hash_commutativity() {
63        let ref1 = ObjectDigest::random();
64        let ref2 = ObjectDigest::random();
65        let ref3 = ObjectDigest::random();
66
67        let mut a1 = GlobalStateHash::default();
68        a1.remove(ref1);
69        a1.remove(ref2);
70        a1.insert(ref1);
71        a1.insert(ref2);
72
73        // Removal before insertion should yield the same result
74        assert_eq!(a1, GlobalStateHash::default());
75
76        a1.insert(ref1);
77        a1.insert(ref2);
78
79        // Insertion out of order should arrive at the same result.
80        let mut a2 = GlobalStateHash::default();
81        a2.remove(ref1);
82        a2.remove(ref2);
83
84        // Unioning where all objects from a are removed in b should
85        // result in empty global_state_hash
86        a1.union(&a2);
87        assert_eq!(a1, GlobalStateHash::default());
88
89        a1.insert(ref1);
90        a1.insert(ref2);
91        a1.insert(ref3);
92
93        let mut a3 = GlobalStateHash::default();
94        a3.insert(ref3);
95
96        // a1: (+ref1, +ref2, +ref3)
97        // a2: (-ref1, -ref2)
98        // a3: (+ref3)
99        // a1 + a2 = a3
100
101        a1.union(&a2);
102        assert_eq!(a1, a3);
103    }
104
105    #[test]
106    fn test_global_state_hash_insert_stress() {
107        let mut refs: Vec<_> = (0..100).map(|_| ObjectDigest::random()).collect();
108        let mut global_state_hash = GlobalStateHash::default();
109        global_state_hash.insert_all(&refs);
110        let mut rng = rand::thread_rng();
111        (0..10).for_each(|_| {
112            refs.shuffle(&mut rng);
113            let mut a = GlobalStateHash::default();
114            a.insert_all(&refs);
115            assert_eq!(global_state_hash, a);
116        })
117    }
118
119    #[test]
120    fn test_global_state_hash_remove_stress() {
121        let mut refs1: Vec<_> = (0..100).map(|_| ObjectDigest::random()).collect();
122        let mut refs2: Vec<_> = (0..100).map(|_| ObjectDigest::random()).collect();
123        let mut global_state_hash = GlobalStateHash::default();
124        global_state_hash.insert_all(&refs1);
125
126        let mut rng = rand::thread_rng();
127        (0..10).for_each(|_| {
128            refs1.shuffle(&mut rng);
129            let mut a = GlobalStateHash::default();
130            a.insert_all(&refs1);
131            a.insert_all(&refs2);
132            refs2.shuffle(&mut rng);
133            a.remove_all(&refs2);
134            assert_eq!(global_state_hash, a);
135        })
136    }
137}