17
17
//! merkleization.
18
18
//!
19
19
20
+ use core:: iter;
21
+
20
22
use prelude:: * ;
21
23
22
24
use io;
@@ -25,59 +27,81 @@ use core::cmp::min;
25
27
use hashes:: Hash ;
26
28
use consensus:: encode:: Encodable ;
27
29
28
- /// Calculates the merkle root of a list of hashes inline
29
- /// into the allocated slice.
30
+ /// Calculates the merkle root of a list of *hashes*, inline (in place) in `hashes`.
30
31
///
31
32
/// In most cases, you'll want to use [bitcoin_merkle_root] instead.
32
- pub fn bitcoin_merkle_root_inline < T > ( data : & mut [ T ] ) -> T
33
+ ///
34
+ /// # Returns
35
+ /// - `None` if `hashes` is empty. The merkle root of an empty tree of hashes is undefined.
36
+ /// - `Some(hash)` if `hashes` contains one element. A single hash is by definition the merkle root.
37
+ /// - `Some(merkle_root)` if length of `hashes` is greater than one.
38
+ pub fn bitcoin_merkle_root_inline < T > ( hashes : & mut [ T ] ) -> Option < T >
33
39
where T : Hash + Encodable ,
34
40
<T as Hash >:: Engine : io:: Write ,
35
41
{
36
- // Base case
37
- if data. is_empty ( ) {
38
- return Default :: default ( ) ;
39
- }
40
- if data. len ( ) < 2 {
41
- return T :: from_inner ( data[ 0 ] . into_inner ( ) ) ;
42
- }
43
- // Recursion
44
- for idx in 0 ..( ( data. len ( ) + 1 ) / 2 ) {
45
- let idx1 = 2 * idx;
46
- let idx2 = min ( idx1 + 1 , data. len ( ) - 1 ) ;
47
- let mut encoder = T :: engine ( ) ;
48
- data[ idx1] . consensus_encode ( & mut encoder) . expect ( "in-memory writers don't error" ) ;
49
- data[ idx2] . consensus_encode ( & mut encoder) . expect ( "in-memory writers don't error" ) ;
50
- data[ idx] = T :: from_engine ( encoder) ;
42
+ match hashes. len ( ) {
43
+ 0 => None ,
44
+ 1 => Some ( hashes[ 0 ] ) ,
45
+ _ => Some ( merkle_root_r ( hashes) ) ,
51
46
}
52
- let half_len = data. len ( ) / 2 + data. len ( ) % 2 ;
53
- bitcoin_merkle_root_inline ( & mut data[ 0 ..half_len] )
54
47
}
55
48
56
- /// Calculates the merkle root of an iterator of hashes.
57
- pub fn bitcoin_merkle_root < T , I > ( mut iter : I ) -> T
49
+ /// Calculates the merkle root of an iterator of *hashes*.
50
+ ///
51
+ /// # Returns
52
+ /// - `None` if `hashes` is empty. The merkle root of an empty tree of hashes is undefined.
53
+ /// - `Some(hash)` if `hashes` contains one element. A single hash is by definition the merkle root.
54
+ /// - `Some(merkle_root)` if length of `hashes` is greater than one.
55
+ pub fn bitcoin_merkle_root < T , I > ( mut hashes : I ) -> Option < T >
58
56
where T : Hash + Encodable ,
59
57
<T as Hash >:: Engine : io:: Write ,
60
- I : ExactSizeIterator < Item = T > ,
58
+ I : Iterator < Item = T > ,
61
59
{
62
- // Base case
63
- if iter. len ( ) == 0 {
64
- return Default :: default ( ) ;
65
- }
66
- if iter. len ( ) == 1 {
67
- return T :: from_inner ( iter. next ( ) . unwrap ( ) . into_inner ( ) ) ;
68
- }
69
- // Recursion
70
- let half_len = iter. len ( ) / 2 + iter. len ( ) % 2 ;
71
- let mut alloc = Vec :: with_capacity ( half_len) ;
72
- while let Some ( hash1) = iter. next ( ) {
60
+ let first = hashes. next ( ) ?;
61
+ let second = match hashes. next ( ) {
62
+ Some ( second) => second,
63
+ None => return Some ( first) ,
64
+ } ;
65
+
66
+ let mut hashes = iter:: once ( first) . chain ( iter:: once ( second) ) . chain ( hashes) ;
67
+
68
+ // We need a local copy to pass to `merkle_root_r`. It's more efficient to do the first loop of
69
+ // processing as we make the copy instead of copying the whole iterator.
70
+ let ( min, max) = hashes. size_hint ( ) ;
71
+ let mut alloc = Vec :: with_capacity ( max. unwrap_or ( min) / 2 + 1 ) ;
72
+
73
+ while let Some ( hash1) = hashes. next ( ) {
73
74
// If the size is odd, use the last element twice.
74
- let hash2 = iter . next ( ) . unwrap_or ( hash1) ;
75
+ let hash2 = hashes . next ( ) . unwrap_or ( hash1) ;
75
76
let mut encoder = T :: engine ( ) ;
76
77
hash1. consensus_encode ( & mut encoder) . expect ( "in-memory writers don't error" ) ;
77
78
hash2. consensus_encode ( & mut encoder) . expect ( "in-memory writers don't error" ) ;
78
79
alloc. push ( T :: from_engine ( encoder) ) ;
79
80
}
80
- bitcoin_merkle_root_inline ( & mut alloc)
81
+
82
+ Some ( merkle_root_r ( & mut alloc) )
83
+ }
84
+
85
+ // `hashes` must contain at least one hash.
86
+ fn merkle_root_r < T > ( hashes : & mut [ T ] ) -> T
87
+ where T : Hash + Encodable ,
88
+ <T as Hash >:: Engine : io:: Write ,
89
+ {
90
+ if hashes. len ( ) == 1 {
91
+ return hashes[ 0 ]
92
+ }
93
+
94
+ for idx in 0 ..( ( hashes. len ( ) + 1 ) / 2 ) {
95
+ let idx1 = 2 * idx;
96
+ let idx2 = min ( idx1 + 1 , hashes. len ( ) - 1 ) ;
97
+ let mut encoder = T :: engine ( ) ;
98
+ hashes[ idx1] . consensus_encode ( & mut encoder) . expect ( "in-memory writers don't error" ) ;
99
+ hashes[ idx2] . consensus_encode ( & mut encoder) . expect ( "in-memory writers don't error" ) ;
100
+ hashes[ idx] = T :: from_engine ( encoder) ;
101
+ }
102
+ let half_len = hashes. len ( ) / 2 + hashes. len ( ) % 2 ;
103
+
104
+ merkle_root_r ( & mut hashes[ 0 ..half_len] )
81
105
}
82
106
83
107
#[ cfg( test) ]
0 commit comments