Skip to content

Commit b454cf8

Browse files
committed
Return None from merkle_root functions
The merkle_root of an empty tree is undefined, this is the only error case we have for the two `bitcoin_merkle_root*` functions. We can fully describe this error case by returning an `Option` if args are found to be empty. We can do the same for the wrapper functions in `block` module. While we are at it, refactor out a recursive helper function to make reading the code between the two functions easier.
1 parent 7a8b017 commit b454cf8

File tree

3 files changed

+75
-46
lines changed

3 files changed

+75
-46
lines changed

src/blockdata/block.rs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,10 @@ impl Block {
176176

177177
/// check if merkle root of header matches merkle root of the transaction list
178178
pub fn check_merkle_root (&self) -> bool {
179-
self.header.merkle_root == self.merkle_root()
179+
match self.merkle_root() {
180+
Some(merkle_root) => self.header.merkle_root == merkle_root,
181+
None => false,
182+
}
180183
}
181184

182185
/// check if witness commitment in coinbase is matching the transaction list
@@ -197,8 +200,10 @@ impl Block {
197200
let commitment = WitnessCommitment::from_slice(&coinbase.output[pos].script_pubkey.as_bytes()[6..38]).unwrap();
198201
// witness reserved value is in coinbase input witness
199202
if coinbase.input[0].witness.len() == 1 && coinbase.input[0].witness[0].len() == 32 {
200-
let witness_root = self.witness_root();
201-
return commitment == Self::compute_witness_commitment(&witness_root, coinbase.input[0].witness[0].as_slice())
203+
match self.witness_root() {
204+
Some(witness_root) => return commitment == Self::compute_witness_commitment(&witness_root, coinbase.input[0].witness[0].as_slice()),
205+
None => return false,
206+
}
202207
}
203208
}
204209
}
@@ -207,9 +212,9 @@ impl Block {
207212
}
208213

209214
/// Calculate the transaction merkle root.
210-
pub fn merkle_root(&self) -> TxMerkleNode {
215+
pub fn merkle_root(&self) -> Option<TxMerkleNode> {
211216
let hashes = self.txdata.iter().map(|obj| obj.txid().as_hash());
212-
bitcoin_merkle_root(hashes).into()
217+
bitcoin_merkle_root(hashes).map(|h| h.into())
213218
}
214219

215220
/// compute witness commitment for the transaction list
@@ -221,7 +226,7 @@ impl Block {
221226
}
222227

223228
/// Merkle root of transactions hashed for witness
224-
pub fn witness_root(&self) -> WitnessMerkleNode {
229+
pub fn witness_root(&self) -> Option<WitnessMerkleNode> {
225230
let hashes = self.txdata.iter().enumerate().map(|(i, t)|
226231
if i == 0 {
227232
// Replace the first hash with zeroes.
@@ -230,7 +235,7 @@ impl Block {
230235
t.wtxid().as_hash()
231236
}
232237
);
233-
bitcoin_merkle_root(hashes).into()
238+
bitcoin_merkle_root(hashes).map(|h| h.into())
234239
}
235240

236241
/// The size of the header + the size of the varint with the tx count + the txs themselves
@@ -371,7 +376,7 @@ mod tests {
371376
let real_decode = decode.unwrap();
372377
assert_eq!(real_decode.header.version, 1);
373378
assert_eq!(serialize(&real_decode.header.prev_blockhash), prevhash);
374-
assert_eq!(real_decode.header.merkle_root, real_decode.merkle_root());
379+
assert_eq!(real_decode.header.merkle_root, real_decode.merkle_root().unwrap());
375380
assert_eq!(serialize(&real_decode.header.merkle_root), merkle);
376381
assert_eq!(real_decode.header.time, 1231965655);
377382
assert_eq!(real_decode.header.bits, 486604799);
@@ -407,7 +412,7 @@ mod tests {
407412
assert_eq!(real_decode.header.version, 0x20000000); // VERSIONBITS but no bits set
408413
assert_eq!(serialize(&real_decode.header.prev_blockhash), prevhash);
409414
assert_eq!(serialize(&real_decode.header.merkle_root), merkle);
410-
assert_eq!(real_decode.header.merkle_root, real_decode.merkle_root());
415+
assert_eq!(real_decode.header.merkle_root, real_decode.merkle_root().unwrap());
411416
assert_eq!(real_decode.header.time, 1472004949);
412417
assert_eq!(real_decode.header.bits, 0x1a06d450);
413418
assert_eq!(real_decode.header.nonce, 1879759182);

src/util/hash.rs

Lines changed: 60 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
//! merkleization.
1818
//!
1919
20+
use core::iter;
21+
2022
use prelude::*;
2123

2224
use io;
@@ -25,59 +27,81 @@ use core::cmp::min;
2527
use hashes::Hash;
2628
use consensus::encode::Encodable;
2729

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`.
3031
///
3132
/// 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>
3339
where T: Hash + Encodable,
3440
<T as Hash>::Engine: io::Write,
3541
{
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)),
5146
}
52-
let half_len = data.len() / 2 + data.len() % 2;
53-
bitcoin_merkle_root_inline(&mut data[0..half_len])
5447
}
5548

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>
5856
where T: Hash + Encodable,
5957
<T as Hash>::Engine: io::Write,
60-
I: ExactSizeIterator<Item = T>,
58+
I: Iterator<Item = T>,
6159
{
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() {
7374
// 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);
7576
let mut encoder = T::engine();
7677
hash1.consensus_encode(&mut encoder).expect("in-memory writers don't error");
7778
hash2.consensus_encode(&mut encoder).expect("in-memory writers don't error");
7879
alloc.push(T::from_engine(encoder));
7980
}
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])
81105
}
82106

83107
#[cfg(test)]

src/util/merkleblock.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -543,7 +543,7 @@ mod tests {
543543

544544
// Calculate the merkle root and height
545545
let hashes = txids.iter().map(|t| t.as_hash());
546-
let merkle_root_1: TxMerkleNode = bitcoin_merkle_root(hashes).into();
546+
let merkle_root_1: TxMerkleNode = bitcoin_merkle_root(hashes).expect("hashes is not empty").into();
547547
let mut height = 1;
548548
let mut ntx = num_tx;
549549
while ntx > 1 {

0 commit comments

Comments
 (0)