@@ -38,6 +38,34 @@ impl<'a> FromIterator<&'a Hash> for RecentBlockhashes {
38
38
}
39
39
}
40
40
41
+ // This is cherry-picked from HEAD of rust-lang's master (ref1) because it's
42
+ // a nightly-only experimental API.
43
+ // (binary_heap_into_iter_sorted [rustc issue #59278])
44
+ // Remove this and use the standard API once BinaryHeap::into_iter_sorted (ref2)
45
+ // is stabilized.
46
+ // ref1: https://github.com/rust-lang/rust/blob/2f688ac602d50129388bb2a5519942049096cbff/src/liballoc/collections/binary_heap.rs#L1149
47
+ // ref2: https://doc.rust-lang.org/std/collections/struct.BinaryHeap.html#into_iter_sorted.v
48
+
49
+ #[ derive( Clone , Debug ) ]
50
+ pub struct IntoIterSorted < T > {
51
+ inner : BinaryHeap < T > ,
52
+ }
53
+
54
+ impl < T : Ord > Iterator for IntoIterSorted < T > {
55
+ type Item = T ;
56
+
57
+ #[ inline]
58
+ fn next ( & mut self ) -> Option < T > {
59
+ self . inner . pop ( )
60
+ }
61
+
62
+ #[ inline]
63
+ fn size_hint ( & self ) -> ( usize , Option < usize > ) {
64
+ let exact = self . inner . len ( ) ;
65
+ ( exact, Some ( exact) )
66
+ }
67
+ }
68
+
41
69
impl Sysvar for RecentBlockhashes {
42
70
fn biggest ( ) -> Self {
43
71
RecentBlockhashes ( vec ! [ Hash :: default ( ) ; MAX_ENTRIES ] )
60
88
I : IntoIterator < Item = ( u64 , & ' a Hash ) > ,
61
89
{
62
90
let sorted = BinaryHeap :: from_iter ( recent_blockhash_iter) ;
63
- let recent_blockhash_iter = sorted. into_iter ( ) . take ( MAX_ENTRIES ) . map ( |( _, hash) | hash) ;
91
+ let sorted_iter = IntoIterSorted { inner : sorted } ;
92
+ let recent_blockhash_iter = sorted_iter. take ( MAX_ENTRIES ) . map ( |( _, hash) | hash) ;
64
93
let recent_blockhashes = RecentBlockhashes :: from_iter ( recent_blockhash_iter) ;
65
94
recent_blockhashes. to_account ( account)
66
95
}
@@ -84,7 +113,9 @@ pub fn create_test_recent_blockhashes(start: usize) -> RecentBlockhashes {
84
113
#[ cfg( test) ]
85
114
mod tests {
86
115
use super :: * ;
87
- use crate :: hash:: Hash ;
116
+ use crate :: hash:: HASH_BYTES ;
117
+ use rand:: seq:: SliceRandom ;
118
+ use rand:: thread_rng;
88
119
89
120
#[ test]
90
121
fn test_create_account_empty ( ) {
@@ -110,4 +141,34 @@ mod tests {
110
141
let recent_blockhashes = RecentBlockhashes :: from_account ( & account) . unwrap ( ) ;
111
142
assert_eq ! ( recent_blockhashes. len( ) , MAX_ENTRIES ) ;
112
143
}
144
+
145
+ #[ test]
146
+ fn test_create_account_unsorted ( ) {
147
+ let mut unsorted_recent_blockhashes: Vec < _ > = ( 0 ..MAX_ENTRIES )
148
+ . map ( |i| {
149
+ ( i as u64 , {
150
+ // create hash with visibly recognizable ordering
151
+ let mut h = [ 0 ; HASH_BYTES ] ;
152
+ h[ HASH_BYTES - 1 ] = i as u8 ;
153
+ Hash :: new ( & h)
154
+ } )
155
+ } )
156
+ . collect ( ) ;
157
+ unsorted_recent_blockhashes. shuffle ( & mut thread_rng ( ) ) ;
158
+
159
+ let account = create_account_with_data (
160
+ 42 ,
161
+ unsorted_recent_blockhashes
162
+ . iter ( )
163
+ . map ( |( i, hash) | ( * i, hash) ) ,
164
+ ) ;
165
+ let recent_blockhashes = RecentBlockhashes :: from_account ( & account) . unwrap ( ) ;
166
+
167
+ let mut expected_recent_blockhashes: Vec < _ > =
168
+ ( unsorted_recent_blockhashes. into_iter ( ) . map ( |( _, b) | b) ) . collect ( ) ;
169
+ expected_recent_blockhashes. sort ( ) ;
170
+ expected_recent_blockhashes. reverse ( ) ;
171
+
172
+ assert_eq ! ( * recent_blockhashes, expected_recent_blockhashes) ;
173
+ }
113
174
}
0 commit comments