1
1
use bitvec:: prelude:: * ;
2
2
use bitvec:: vec:: BitVec ;
3
+ use rand:: Rng ;
3
4
/// When deserializing a clvm object, a stack of deserialized child objects
4
5
/// is created, which can be used with back-references. A `ReadCacheLookup` keeps
5
6
/// track of the state of this stack and all child objects under each root
@@ -23,27 +24,43 @@ use std::hash::{BuildHasher, Hasher};
23
24
use super :: bytes32:: { hash_blob, hash_blobs, Bytes32 } ;
24
25
25
26
#[ derive( Default , Clone , Copy ) ]
26
- pub struct IdentityHash ( u64 ) ;
27
+ pub struct IdentityHash ( u64 , u64 ) ;
28
+
29
+ impl IdentityHash {
30
+ fn new ( salt : u64 ) -> Self {
31
+ Self ( 0 , salt)
32
+ }
33
+ }
27
34
28
35
impl Hasher for IdentityHash {
29
36
fn finish ( & self ) -> u64 {
30
37
self . 0
31
38
}
32
39
33
40
fn write ( & mut self , bytes : & [ u8 ] ) {
34
- self . 0 = u64:: from_le_bytes ( bytes[ 0 ..8 ] . try_into ( ) . expect ( "expected 32 byte hashes" ) ) ;
41
+ self . 0 =
42
+ u64:: from_le_bytes ( bytes[ 0 ..8 ] . try_into ( ) . expect ( "expected 32 byte hashes" ) ) ^ self . 1 ;
35
43
}
36
44
37
45
fn write_u64 ( & mut self , _i : u64 ) {
38
46
panic ! ( "This hasher only takes bytes" ) ;
39
47
}
40
48
}
41
49
42
- impl BuildHasher for IdentityHash {
43
- type Hasher = Self ;
50
+ pub struct RandomState ( u64 ) ;
51
+
52
+ impl RandomState {
53
+ fn new ( ) -> Self {
54
+ let mut rng = rand:: thread_rng ( ) ;
55
+ Self ( rng. gen ( ) )
56
+ }
57
+ }
58
+
59
+ impl BuildHasher for RandomState {
60
+ type Hasher = IdentityHash ;
44
61
45
62
fn build_hasher ( & self ) -> Self :: Hasher {
46
- * self
63
+ IdentityHash :: new ( self . 0 )
47
64
}
48
65
}
49
66
@@ -56,10 +73,10 @@ pub struct ReadCacheLookup {
56
73
/// the tree hashes of the contents on the left and right
57
74
read_stack : Vec < ( Bytes32 , Bytes32 ) > ,
58
75
59
- count : HashMap < Bytes32 , u32 , IdentityHash > ,
76
+ count : HashMap < Bytes32 , u32 , RandomState > ,
60
77
61
78
/// a mapping of tree hashes to `(parent, is_right)` tuples
62
- parent_lookup : HashMap < Bytes32 , Vec < ( Bytes32 , bool ) > , IdentityHash > ,
79
+ parent_lookup : HashMap < Bytes32 , Vec < ( Bytes32 , bool ) > , RandomState > ,
63
80
}
64
81
65
82
impl Default for ReadCacheLookup {
@@ -74,9 +91,9 @@ impl ReadCacheLookup {
74
91
let read_stack = Vec :: with_capacity ( 1000 ) ;
75
92
// all keys in count and parent_lookup are tree-hashes. There's no need
76
93
// to hash them again for the hash map
77
- let mut count = HashMap :: with_hasher ( IdentityHash :: default ( ) ) ;
94
+ let mut count = HashMap :: with_hasher ( RandomState :: new ( ) ) ;
78
95
count. insert ( root_hash, 1 ) ;
79
- let parent_lookup = HashMap :: with_hasher ( IdentityHash :: default ( ) ) ;
96
+ let parent_lookup = HashMap :: with_hasher ( RandomState :: new ( ) ) ;
80
97
Self {
81
98
root_hash,
82
99
read_stack,
@@ -161,10 +178,8 @@ impl ReadCacheLookup {
161
178
162
179
// all the values we put in this hash set are themselves sha256 hashes.
163
180
// There's no point in hashing the hashes
164
- let mut seen_ids = HashSet :: < & Bytes32 , IdentityHash > :: with_capacity_and_hasher (
165
- 1000 ,
166
- IdentityHash :: default ( ) ,
167
- ) ;
181
+ let mut seen_ids =
182
+ HashSet :: < & Bytes32 , RandomState > :: with_capacity_and_hasher ( 1000 , RandomState :: new ( ) ) ;
168
183
169
184
let max_bytes_for_path_encoding = serialized_length - 2 ; // 1 byte for 0xfe, 1 min byte for savings
170
185
let max_path_length: usize = ( max_bytes_for_path_encoding. saturating_mul ( 8 ) - 1 )
0 commit comments