Skip to content

Commit a5391b2

Browse files
committed
Merge #34: Add some inspector methods to dynafed::Params + support root calculation
d7d5c5d Support for calculating consensus params roots (Steven Roose) 2c9c2fb Add some inspector methods to dynafed::Params (Steven Roose) Pull request description: The Rust enum stuff is all fancy and such, but it's often a real pain in the ass to either just check which of the vairants is used or to get a field out if you already know what the variant is. ACKs for top commit: jonasnick: ACK d7d5c5d Tree-SHA512: 50dda4991cce964d6cfe102b20ee12d855565961df41989adb619f8f246bffc40fff8d93a3fed0c23e090d80091b3c94f23d7a0e6c9a59960029b467cf42db1e
2 parents ddb9277 + d7d5c5d commit a5391b2

2 files changed

Lines changed: 192 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: 175 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

@@ -53,6 +54,102 @@ pub enum Params {
5354
},
5455
}
5556

57+
impl Params {
58+
/// Check whether this is [Params::Null].
59+
pub fn is_null(&self) -> bool {
60+
match *self {
61+
Params::Null => true,
62+
Params::Compact { .. } => false,
63+
Params::Full { .. } => false,
64+
}
65+
}
66+
67+
/// Check whether this is [Params::Compact].
68+
pub fn is_compact(&self) -> bool {
69+
match *self {
70+
Params::Null => false,
71+
Params::Compact { .. } => true,
72+
Params::Full { .. } => false,
73+
}
74+
}
75+
76+
/// Check whether this is [Params::Full].
77+
pub fn is_full(&self) -> bool {
78+
match *self {
79+
Params::Null => false,
80+
Params::Compact { .. } => false,
81+
Params::Full { .. } => true,
82+
}
83+
}
84+
85+
/// Get the signblockscript. Is [None] for [Null] params.
86+
pub fn signblockscript(&self) -> Option<&bitcoin::Script> {
87+
match *self {
88+
Params::Null => None,
89+
Params::Compact { ref signblockscript, ..} => Some(signblockscript),
90+
Params::Full { ref signblockscript, ..} => Some(signblockscript),
91+
}
92+
}
93+
94+
/// Get the signblock_witness_limit. Is [None] for [Null] params.
95+
pub fn signblock_witness_limit(&self) -> Option<u32> {
96+
match *self {
97+
Params::Null => None,
98+
Params::Compact { signblock_witness_limit, ..} => Some(signblock_witness_limit),
99+
Params::Full { signblock_witness_limit, ..} => Some(signblock_witness_limit),
100+
}
101+
}
102+
103+
/// Get the fedpeg_program. Is [None] for non-[Full] params.
104+
pub fn fedpeg_program(&self) -> Option<&bitcoin::Script> {
105+
match *self {
106+
Params::Null => None,
107+
Params::Compact { .. } => None,
108+
Params::Full { ref fedpeg_program, ..} => Some(fedpeg_program),
109+
}
110+
}
111+
112+
/// Get the fedpegscript. Is [None] for non-[Full] params.
113+
pub fn fedpegscript(&self) -> Option<&Vec<u8>> {
114+
match *self {
115+
Params::Null => None,
116+
Params::Compact { .. } => None,
117+
Params::Full { ref fedpegscript, ..} => Some(fedpegscript),
118+
}
119+
}
120+
121+
/// Get the extension_space. Is [None] for non-[Full] params.
122+
pub fn extension_space(&self) -> Option<&Vec<Vec<u8>>> {
123+
match *self {
124+
Params::Null => None,
125+
Params::Compact { .. } => None,
126+
Params::Full { ref extension_space, ..} => Some(extension_space),
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+
}
151+
}
152+
56153
#[cfg(feature = "serde")]
57154
impl<'de> Deserialize<'de> for Params {
58155
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
@@ -272,3 +369,81 @@ impl Decodable for Params {
272369
}
273370
}
274371
}
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)