|
17 | 17 | use std::io; |
18 | 18 |
|
19 | 19 | use bitcoin; |
| 20 | +use bitcoin::hashes::{Hash, sha256, sha256d}; |
20 | 21 | #[cfg(feature = "serde")] use serde::{Deserialize, Deserializer, Serialize, Serializer}; |
21 | 22 | #[cfg(feature = "serde")] use std::fmt; |
22 | 23 |
|
@@ -125,6 +126,28 @@ impl Params { |
125 | 126 | Params::Full { ref extension_space, ..} => Some(extension_space), |
126 | 127 | } |
127 | 128 | } |
| 129 | + |
| 130 | + /// Calculate the root of this [Params]. |
| 131 | + pub fn calculate_root(&self) -> sha256::Midstate { |
| 132 | + fn serialize_hash<E: Encodable>(obj: &E) -> sha256d::Hash { |
| 133 | + let mut engine = sha256d::Hash::engine(); |
| 134 | + obj.consensus_encode(&mut engine).expect("engines don't error"); |
| 135 | + sha256d::Hash::from_engine(engine) |
| 136 | + } |
| 137 | + |
| 138 | + if self.is_null() { |
| 139 | + return sha256::Midstate::from_inner([0u8; 32]); |
| 140 | + } |
| 141 | + |
| 142 | + let leaves = [ |
| 143 | + serialize_hash(self.signblockscript().unwrap()).into_inner(), |
| 144 | + serialize_hash(&self.signblock_witness_limit().unwrap()).into_inner(), |
| 145 | + serialize_hash(self.fedpeg_program().unwrap_or(&bitcoin::Script::new())).into_inner(), |
| 146 | + serialize_hash(self.fedpegscript().unwrap_or(&Vec::new())).into_inner(), |
| 147 | + serialize_hash(self.extension_space().unwrap_or(&Vec::new())).into_inner(), |
| 148 | + ]; |
| 149 | + ::fast_merkle_root::fast_merkle_root(&leaves[..]) |
| 150 | + } |
128 | 151 | } |
129 | 152 |
|
130 | 153 | #[cfg(feature = "serde")] |
@@ -346,3 +369,81 @@ impl Decodable for Params { |
346 | 369 | } |
347 | 370 | } |
348 | 371 | } |
| 372 | + |
| 373 | +#[cfg(test)] |
| 374 | +mod tests { |
| 375 | + use super::*; |
| 376 | + |
| 377 | + use bitcoin; |
| 378 | + use bitcoin::hashes::hex::ToHex; |
| 379 | + |
| 380 | + #[test] |
| 381 | + fn test_param_roots() { |
| 382 | + // Taken from the following Elements Core test: |
| 383 | + |
| 384 | + // CScript signblockscript(opcodetype(1)); |
| 385 | + // uint32_t signblock_wl(2); |
| 386 | + // CScript fp_program(opcodetype(3)); |
| 387 | + // CScript fp_script(opcodetype(4)); |
| 388 | + // std::vector<std::vector<unsigned char>> ext{ {5, 6}, {7} }; |
| 389 | + // |
| 390 | + // DynaFedParamEntry compact_entry = DynaFedParamEntry(signblockscript, signblock_wl); |
| 391 | + // BOOST_CHECK_EQUAL( |
| 392 | + // compact_entry.CalculateRoot().GetHex(), |
| 393 | + // "dff5f3793abc06a6d75e80fe3cfd47406f732fa4ec9305960ae2a229222a1ad5" |
| 394 | + // ); |
| 395 | + // |
| 396 | + // DynaFedParamEntry full_entry = |
| 397 | + // DynaFedParamEntry(signblockscript, signblock_wl, fp_program, fp_script, ext); |
| 398 | + // BOOST_CHECK_EQUAL( |
| 399 | + // full_entry.CalculateRoot().GetHex(), |
| 400 | + // "175be2087ba7cc0e33348bef493bd3e34f31f64bf9226e5881ab310dafa432ff" |
| 401 | + // ); |
| 402 | + // |
| 403 | + // DynaFedParams params = DynaFedParams(compact_entry, full_entry); |
| 404 | + // BOOST_CHECK_EQUAL( |
| 405 | + // params.CalculateRoot().GetHex(), |
| 406 | + // "e56cf79487952dfa85fe6a85829600adc19714ba6ab1157fdff02b25ae60cee2" |
| 407 | + // ); |
| 408 | + |
| 409 | + let signblockscript: bitcoin::Script = vec![1].into(); |
| 410 | + let signblock_wl = 2; |
| 411 | + let fp_program: bitcoin::Script = vec![3].into(); |
| 412 | + let fp_script = vec![4]; |
| 413 | + let ext = vec![vec![5, 6], vec![7]]; |
| 414 | + |
| 415 | + let compact_entry = Params::Compact { |
| 416 | + signblockscript: signblockscript.clone(), |
| 417 | + signblock_witness_limit: signblock_wl, |
| 418 | + }; |
| 419 | + assert_eq!( |
| 420 | + compact_entry.calculate_root().to_hex(), |
| 421 | + "dff5f3793abc06a6d75e80fe3cfd47406f732fa4ec9305960ae2a229222a1ad5" |
| 422 | + ); |
| 423 | + |
| 424 | + let full_entry = Params::Full { |
| 425 | + signblockscript: signblockscript, |
| 426 | + signblock_witness_limit: signblock_wl, |
| 427 | + fedpeg_program: fp_program, |
| 428 | + fedpegscript: fp_script, |
| 429 | + extension_space: ext, |
| 430 | + }; |
| 431 | + assert_eq!( |
| 432 | + full_entry.calculate_root().to_hex(), |
| 433 | + "175be2087ba7cc0e33348bef493bd3e34f31f64bf9226e5881ab310dafa432ff" |
| 434 | + ); |
| 435 | + |
| 436 | + let header = ::block::BlockHeader{ |
| 437 | + ext: ::block::ExtData::Dynafed { |
| 438 | + current: compact_entry, |
| 439 | + proposed: full_entry, |
| 440 | + signblock_witness: vec![], |
| 441 | + }, |
| 442 | + ..Default::default() |
| 443 | + }; |
| 444 | + assert_eq!( |
| 445 | + header.calculate_dynafed_params_root().unwrap().to_hex(), |
| 446 | + "e56cf79487952dfa85fe6a85829600adc19714ba6ab1157fdff02b25ae60cee2" |
| 447 | + ); |
| 448 | + } |
| 449 | +} |
0 commit comments