fn compute_merkle_root_and_path(
        &self,
        mut index: usize,
        mut path: Option<&mut Vec<Option<H256>>>,
        side: Option<Side>,
    ) -> H256 {
        let depth = tree_depth_by_size(self.binary_tree_size);
        if let Some(path) = path.as_deref_mut() {
            path.reserve(depth);
        }

        let mut hashes = self.hashes.clone();
        let mut absolute_start_index = self.start_index;

        for level in 0..depth {
            // If the first untrimmed leaf is a right sibling,
            // add it's left sibling to `hashes` from cache for convenient iteration later.
            if absolute_start_index % 2 == 1 {
                hashes.push_front(self.cache[level].expect("cache is invalid"));
                index += 1;
            }
            // At this point `hashes` always starts from the left sibling node.
            // If it ends on the left sibling node, add the right sibling node to `hashes`
            // for convenient iteration later.
            if hashes.len() % 2 == 1 {
                hashes.push_back(self.hasher.empty_subtree_hash(level));
            }
            if let Some(path) = path.as_deref_mut() {
                let hash = match side {
                    Some(Side::Left) if index % 2 == 0 => None,
                    Some(Side::Right) if index % 2 == 1 => None,
                    _ => hashes.get(index ^ 1).copied(),
                };
                path.push(hash);
            }

            let level_len = hashes.len() / 2;
            // Since `hashes` has an even number of elements, we can simply iterate over the pairs.
            for i in 0..level_len {
                hashes[i] = self.hasher.compress(&hashes[2 * i], &hashes[2 * i + 1]);
            }

            hashes.truncate(level_len);
            index /= 2;
            absolute_start_index /= 2;
        }

        hashes[0]
    }
Computes the Merkle root hash.
If `path` is `Some`, also computes the Merkle path to the leaf with the specified
`index` (relative to `self.start_index`).
If `side` is `Some`, only the corresponding side subset of the path is computed
(`Some` for elements in the `side` subset of the path, `None` for the other elements).
core/lib/mini_merkle_tree/src/lib.rs