1use std::path::PathBuf;
2
3use bitcoin::hashes::{sha256d, Hash};
4
5use crate::bitcoin::CoinType;
6
7pub fn merkle_root(hashes: Vec<sha256d::Hash>) -> sha256d::Hash {
10 let mut hashes = hashes;
11
12 while hashes.len() > 1 {
13 let mut new_hashes = hashes
15 .chunks(2)
16 .filter(|c| c.len() == 2)
17 .map(|c| sha256d::Hash::hash(&[c[0], c[1]].concat()))
18 .collect::<Vec<sha256d::Hash>>();
19
20 if hashes.len() % 2 == 1 {
22 let last_hash = hashes.last().unwrap();
23 new_hashes.push(sha256d::Hash::hash(
24 &[&last_hash[..], &last_hash[..]].concat(),
25 ));
26 }
27 hashes = new_hashes;
28 }
29 *hashes
30 .first()
31 .expect("unable to calculate merkle root on empty hashes")
32}
33
34pub fn arr_to_hex(data: &[u8]) -> String {
35 data.iter().map(|b| format!("{:02x?}", b)).collect()
36}
37
38#[allow(dead_code)]
39pub fn hex_to_vec(hex_str: &str) -> Vec<u8> {
40 if hex_str.len() % 2 != 0 {
41 panic!("string length is not even");
42 }
43
44 (0..hex_str.len())
45 .step_by(2)
46 .map(|i| u8::from_str_radix(&hex_str[i..i + 2], 16).unwrap())
47 .collect()
48}
49
50#[allow(dead_code)]
52pub fn get_absolute_blockchain_dir(coin: &CoinType) -> PathBuf {
53 dirs::home_dir()
54 .expect("Unable to get home path from env!")
55 .join(&coin.default_folder)
56}
57
58#[allow(dead_code)]
60pub fn get_mean(slice: &[u32]) -> f64 {
61 if slice.is_empty() {
62 return 0.00;
63 }
64 let sum = slice.iter().sum::<u32>();
65 sum as f64 / slice.len() as f64
66}
67
68#[cfg(test)]
69mod tests {
70 use super::*;
71
72 #[test]
73 fn test_arr_to_hex() {
74 let test = [
75 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0xd6, 0x68, 0x9c, 0x08, 0x5a, 0xe1, 0x65, 0x83,
76 0x1e, 0x93, 0x4f, 0xf7, 0x63, 0xae, 0x46, 0xa2, 0xa6, 0xc1, 0x72, 0xb3, 0xf1, 0xb6,
77 0x0a, 0x8c, 0xe2, 0x6f,
78 ];
79 let expected = "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f";
80 assert_eq!(arr_to_hex(&test), expected);
81 }
82
83 #[test]
84 fn test_merkle_root() {
85 let hashes = Vec::from([
86 sha256d::Hash::from_byte_array([
87 0x8c, 0xb1, 0xdf, 0x74, 0xdb, 0xe9, 0x80, 0xc6, 0xb9, 0x20, 0x2e, 0x91, 0x95, 0x97,
88 0xa5, 0xea, 0xbe, 0xb2, 0xd3, 0x2e, 0x4d, 0xe0, 0x21, 0x4a, 0x39, 0xf8, 0x0c, 0x5f,
89 0xab, 0x9e, 0x45, 0x3a,
90 ]),
91 sha256d::Hash::from_byte_array([
92 0xb7, 0xa6, 0x06, 0x8e, 0x58, 0x14, 0x73, 0x84, 0x22, 0x76, 0x8b, 0x92, 0xb7, 0xff,
93 0x81, 0xb8, 0x07, 0xfd, 0x51, 0x58, 0x71, 0xed, 0x6a, 0x41, 0x72, 0xba, 0xcc, 0x0e,
94 0x6f, 0xf4, 0x38, 0xbe,
95 ]),
96 sha256d::Hash::from_byte_array([
97 0xbe, 0x32, 0x73, 0x29, 0xc9, 0x6d, 0x01, 0xbb, 0x0e, 0xf9, 0x39, 0x77, 0xd0, 0x26,
98 0xb8, 0x02, 0xdb, 0x0b, 0x59, 0xbb, 0x7b, 0xfe, 0xd9, 0x77, 0x3a, 0xf6, 0x6f, 0x2b,
99 0xa1, 0xf2, 0x73, 0xd1,
100 ]),
101 sha256d::Hash::from_byte_array([
102 0x2f, 0x05, 0xc7, 0x5f, 0x38, 0x82, 0x9e, 0xee, 0xaf, 0x84, 0x34, 0x55, 0xdf, 0x87,
103 0xaa, 0xc0, 0xa7, 0xf2, 0xbb, 0x3c, 0xf2, 0x4f, 0x23, 0x91, 0xb4, 0xbb, 0x68, 0x52,
104 0x3e, 0xe8, 0xd1, 0x59,
105 ]),
106 sha256d::Hash::from_byte_array([
107 0x0c, 0xc6, 0x7a, 0x79, 0xdd, 0x56, 0x4d, 0x24, 0x55, 0xdf, 0x58, 0xb3, 0x71, 0xaf,
108 0xde, 0xb1, 0xa3, 0x1f, 0x44, 0xff, 0xa0, 0x08, 0x3b, 0x9e, 0xb7, 0xef, 0x06, 0x9d,
109 0xa6, 0x77, 0xce, 0xf1,
110 ]),
111 sha256d::Hash::from_byte_array([
112 0xe0, 0x52, 0xdf, 0x8e, 0x7d, 0x50, 0xda, 0x4b, 0xe4, 0x74, 0xcd, 0x50, 0x5b, 0x21,
113 0x99, 0x6b, 0x74, 0xe3, 0xd0, 0x2f, 0xbf, 0xa1, 0xaf, 0xd3, 0x9f, 0x65, 0xfe, 0x91,
114 0xba, 0x3c, 0x05, 0x84,
115 ]),
116 ]);
117
118 let expected = sha256d::Hash::from_byte_array([
119 0x52, 0xed, 0x57, 0x8c, 0xb6, 0xed, 0x9a, 0xe5, 0xf5, 0x31, 0x6d, 0x45, 0x42, 0x9b,
120 0xf6, 0x9c, 0xfd, 0xde, 0x2b, 0xe3, 0x94, 0x97, 0xba, 0x31, 0x57, 0x01, 0x64, 0xeb,
121 0x22, 0x77, 0xdf, 0x9c,
122 ]);
123
124 let merkle_hash = merkle_root(hashes);
125 assert_eq!(merkle_hash, expected);
126 }
127}