Skip to content

Commit d7d5c5d

Browse files
committed
Support for calculating consensus params roots
1 parent 2c9c2fb commit d7d5c5d

2 files changed

Lines changed: 118 additions & 1 deletion

File tree

src/block.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use std::io;
1919

2020
use bitcoin::blockdata::script::Script;
2121
use bitcoin::BitcoinHash;
22-
use bitcoin::hashes::{Hash, sha256d};
22+
use bitcoin::hashes::{Hash, sha256d, sha256};
2323
#[cfg(feature = "serde")] use serde::{Deserialize, Deserializer, Serialize, Serializer};
2424
#[cfg(feature = "serde")] use std::fmt;
2525

@@ -222,6 +222,22 @@ pub struct BlockHeader {
222222
}
223223
serde_struct_impl!(BlockHeader, version, prev_blockhash, merkle_root, time, height, ext);
224224

225+
impl BlockHeader {
226+
/// Calculate the root of the dynafed params. Returns [None] when not dynafed.
227+
pub fn calculate_dynafed_params_root(&self) -> Option<sha256::Midstate> {
228+
match self.ext {
229+
ExtData::Proof { .. } => None,
230+
ExtData::Dynafed { ref current, ref proposed, .. } => {
231+
let leaves = [
232+
current.calculate_root().into_inner(),
233+
proposed.calculate_root().into_inner(),
234+
];
235+
Some(::fast_merkle_root::fast_merkle_root(&leaves[..]))
236+
}
237+
}
238+
}
239+
}
240+
225241
impl Encodable for BlockHeader {
226242
fn consensus_encode<S: io::Write>(&self, mut s: S) -> Result<usize, encode::Error> {
227243
let version = if let ExtData::Dynafed { .. } = self.ext {

src/dynafed.rs

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use std::io;
1818

1919
use bitcoin;
20+
use bitcoin::hashes::{Hash, sha256, sha256d};
2021
#[cfg(feature = "serde")] use serde::{Deserialize, Deserializer, Serialize, Serializer};
2122
#[cfg(feature = "serde")] use std::fmt;
2223

@@ -125,6 +126,28 @@ impl Params {
125126
Params::Full { ref extension_space, ..} => Some(extension_space),
126127
}
127128
}
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+
}
128151
}
129152

130153
#[cfg(feature = "serde")]
@@ -346,3 +369,81 @@ impl Decodable for Params {
346369
}
347370
}
348371
}
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

Comments
 (0)