Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

merkle: return rfc6962 hash for empty merkle tree #514

Merged
merged 3 commits into from
Aug 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions light-client/tests/light_client.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use std::collections::HashMap;
use std::convert::TryInto;
use std::fs;
use std::{
path::{Path, PathBuf},
Expand Down Expand Up @@ -127,7 +126,7 @@ fn run_bisection_test(tc: TestBisection<LightBlock>) -> BisectionTestResult {
println!(" - {}", tc.description);

let primary = default_peer_id();
let untrusted_height = tc.height_to_verify.try_into().unwrap();
let untrusted_height = tc.height_to_verify;
let trust_threshold = tc.trust_options.trust_level;
let trusting_period = tc.trust_options.period;
let now = tc.now;
Expand All @@ -147,7 +146,7 @@ fn run_bisection_test(tc: TestBisection<LightBlock>) -> BisectionTestResult {
let provider = tc.primary;
let io = MockIo::new(provider.chain_id, provider.lite_blocks);

let trusted_height = tc.trust_options.height.try_into().unwrap();
let trusted_height = tc.trust_options.height;
let trusted_state = io
.fetch_light_block(primary, AtHeight::At(trusted_height))
.expect("could not 'request' light block");
Expand Down Expand Up @@ -200,7 +199,7 @@ fn run_single_step_tests(dir: &str) {
}
}

fn foreach_bisection_test(dir: &str, f: impl Fn(String, TestBisection<LightBlock>) -> ()) {
fn foreach_bisection_test(dir: &str, f: impl Fn(String, TestBisection<LightBlock>)) {
let paths = fs::read_dir(PathBuf::from(TEST_FILES_PATH).join(dir)).unwrap();

for file_path in paths {
Expand Down
3 changes: 1 addition & 2 deletions light-client/tests/supervisor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ use tendermint_light_client::{
};

use std::collections::HashMap;
use std::convert::TryInto;
use std::{
fs,
path::{Path, PathBuf},
Expand Down Expand Up @@ -110,7 +109,7 @@ fn run_multipeer_test(tc: TestBisection<LightBlock>) {
let handle = supervisor.handle();
std::thread::spawn(|| supervisor.run());

let target_height = tc.height_to_verify.try_into().unwrap();
let target_height = tc.height_to_verify;

match handle.verify_to_target(target_height) {
Ok(new_state) => {
Expand Down
31 changes: 28 additions & 3 deletions tendermint/src/merkle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ pub fn simple_hash_from_byte_vectors(byte_vecs: Vec<Vec<u8>>) -> Hash {
fn simple_hash_from_byte_slices_inner(byte_slices: &[Vec<u8>]) -> Hash {
let length = byte_slices.len();
match length {
0 => [0; HASH_SIZE],
0 => empty_hash(),
1 => leaf_hash(byte_slices[0].as_slice()),
_ => {
let k = get_split_point(length);
Expand All @@ -42,6 +42,20 @@ fn get_split_point(length: usize) -> usize {
}
}

// tmhash({})
fn empty_hash() -> Hash {
// the empty string / byte slice
let empty = Vec::with_capacity(0);

// hash it !
let digest = Sha256::digest(&empty);

// copy the GenericArray out
let mut hash_bytes = [0u8; HASH_SIZE];
hash_bytes.copy_from_slice(&digest);
hash_bytes
}

// tmhash(0x00 || leaf)
fn leaf_hash(bytes: &[u8]) -> Hash {
// make a new array starting with 0 and copy in the bytes
Expand Down Expand Up @@ -94,14 +108,25 @@ mod tests {
assert_eq!(get_split_point(257), 256);
}

#[test]
fn test_rfc6962_empty_tree() {
let empty_tree_root_hex =
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
let empty_tree_root = &hex::decode(empty_tree_root_hex).unwrap();
let empty_tree: Vec<Vec<u8>> = vec![vec![]; 0];

let root = simple_hash_from_byte_vectors(empty_tree);
assert_eq!(empty_tree_root, &root);
}

#[test]
fn test_rfc6962_empty_leaf() {
let empty_leaf_root_hex =
"6e340b9cffb37a989ca544e6bb780a2c78901d3fb33738768511a30617afa01d";
let empty_leaf_root = &hex::decode(empty_leaf_root_hex).unwrap();
let empty_tree: Vec<Vec<u8>> = vec![vec![]; 1];
let one_empty_leaf: Vec<Vec<u8>> = vec![vec![]; 1];

let root = simple_hash_from_byte_vectors(empty_tree);
let root = simple_hash_from_byte_vectors(one_empty_leaf);
assert_eq!(empty_leaf_root, &root);
}

Expand Down