hide CHT internals from header chain
This commit is contained in:
@@ -22,6 +22,7 @@ time = "0.1"
|
||||
smallvec = "0.3.1"
|
||||
futures = "0.1"
|
||||
rand = "0.3"
|
||||
itertools = "0.5"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
||||
@@ -34,7 +34,7 @@ macro_rules! val {
|
||||
($hash: expr, $td: expr) => {{
|
||||
let mut stream = RlpStream::new_list(2);
|
||||
stream.append(&$hash).append(&$td);
|
||||
stream.out()
|
||||
stream.drain()
|
||||
}}
|
||||
}
|
||||
|
||||
@@ -116,6 +116,26 @@ pub fn build<F>(cht_num: u64, mut fetcher: F) -> Option<CHT<MemoryDB>>
|
||||
})
|
||||
}
|
||||
|
||||
/// Compute a CHT root from an iterator of (hash, td) pairs. Fails if shorter than
|
||||
/// SIZE items. The items are assumed to proceed sequentially from `start_number(cht_num)`.
|
||||
/// Discards the trie's nodes.
|
||||
pub fn compute_root<I>(cht_num: u64, iterable: I) -> Option<H256>
|
||||
where I: IntoIterator<Item=(H256, U256)>
|
||||
{
|
||||
let mut v = Vec::with_capacity(SIZE as usize);
|
||||
let start_num = start_number(cht_num) as usize;
|
||||
|
||||
for (i, (h, td)) in iterable.into_iter().take(SIZE as usize).enumerate() {
|
||||
v.push((key!(i + start_num).to_vec(), val!(h, td).to_vec()))
|
||||
}
|
||||
|
||||
if v.len() == SIZE as usize {
|
||||
Some(::util::triehash::trie_root(v))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a block number to a CHT number.
|
||||
/// Returns `None` for `block_num` == 0, `Some` otherwise.
|
||||
pub fn block_to_cht_number(block_num: u64) -> Option<u64> {
|
||||
|
||||
@@ -173,26 +173,34 @@ impl HeaderChain {
|
||||
// produce next CHT root if it's time.
|
||||
let earliest_era = *candidates.keys().next().expect("at least one era just created; qed");
|
||||
if earliest_era + HISTORY + cht::SIZE <= number {
|
||||
let mut values = Vec::with_capacity(cht::SIZE as usize);
|
||||
{
|
||||
let mut headers = self.headers.write();
|
||||
for i in (0..cht::SIZE).map(|x| x + earliest_era) {
|
||||
let cht_num = cht::block_to_cht_number(earliest_era)
|
||||
.expect("fails only for number == 0; genesis never imported; qed");
|
||||
debug_assert_eq!(cht_num as usize, self.cht_roots.lock().len());
|
||||
|
||||
let mut headers = self.headers.write();
|
||||
|
||||
let cht_root = {
|
||||
let mut i = earliest_era;
|
||||
|
||||
// iterable function which removes the candidates as it goes
|
||||
// along. this will only be called until the CHT is complete.
|
||||
let iter = || {
|
||||
let era_entry = candidates.remove(&i)
|
||||
.expect("all eras are sequential with no gaps; qed");
|
||||
i += 1;
|
||||
|
||||
for ancient in &era_entry.candidates {
|
||||
headers.remove(&ancient.hash);
|
||||
}
|
||||
|
||||
values.push((
|
||||
::rlp::encode(&i).to_vec(),
|
||||
::rlp::encode(&era_entry.canonical_hash).to_vec(),
|
||||
));
|
||||
}
|
||||
}
|
||||
let canon = &era_entry.candidates[0];
|
||||
(canon.hash, canon.total_difficulty)
|
||||
};
|
||||
cht::compute_root(cht_num, ::itertools::repeat_call(iter))
|
||||
.expect("fails only when too few items; this is checked; qed")
|
||||
};
|
||||
|
||||
let cht_root = ::util::triehash::trie_root(values);
|
||||
debug!(target: "chain", "Produced CHT {} root: {:?}", (earliest_era - 1) % cht::SIZE, cht_root);
|
||||
debug!(target: "chain", "Produced CHT {} root: {:?}", cht_num, cht_root);
|
||||
|
||||
self.cht_roots.lock().push(cht_root);
|
||||
}
|
||||
|
||||
@@ -68,6 +68,7 @@ extern crate smallvec;
|
||||
extern crate time;
|
||||
extern crate futures;
|
||||
extern crate rand;
|
||||
extern crate itertools;
|
||||
|
||||
#[cfg(feature = "ipc")]
|
||||
extern crate ethcore_ipc as ipc;
|
||||
|
||||
Reference in New Issue
Block a user