Pruning changes tries (#856)

* changes trie pruning

* add comment

* do not prune changes tries on archive nodes
This commit is contained in:
Svyatoslav Nikolsky
2018-10-17 11:08:45 +03:00
committed by Gav Wood
parent 8bc5242c92
commit 9886d12c26
10 changed files with 536 additions and 44 deletions
@@ -28,3 +28,100 @@ pub struct ChangesTrieConfiguration {
/// 2 means that every digest_interval^2 there will be a level2-digest, and so on.
pub digest_levels: u32,
}
impl ChangesTrieConfiguration {
/// Is digest build enabled?
pub fn is_digest_build_enabled(&self) -> bool {
self.digest_interval > 1 && self.digest_levels > 0
}
/// Do we need to build digest at given block?
pub fn is_digest_build_required_at_block(&self, block: u64) -> bool {
block != 0
&& self.is_digest_build_enabled()
&& block % self.digest_interval == 0
}
/// Returns Some if digest must be built at given block number.
/// The tuple is:
/// (
/// digest level
/// digest interval (in blocks)
/// step between blocks we're interested in when digest is built
/// )
pub fn digest_level_at_block(&self, block: u64) -> Option<(u32, u64, u64)> {
if !self.is_digest_build_required_at_block(block) {
return None;
}
let mut digest_interval = self.digest_interval;
let mut current_level = 1u32;
let mut digest_step = 1u64;
while current_level < self.digest_levels {
let new_digest_interval = match digest_interval.checked_mul(self.digest_interval) {
Some(new_digest_interval) if block % new_digest_interval == 0 => new_digest_interval,
_ => break,
};
digest_step = digest_interval;
digest_interval = new_digest_interval;
current_level = current_level + 1;
}
Some((
current_level,
digest_interval,
digest_step,
))
}
}
#[cfg(test)]
mod tests {
use super::ChangesTrieConfiguration;
fn config(interval: u64, levels: u32) -> ChangesTrieConfiguration {
ChangesTrieConfiguration {
digest_interval: interval,
digest_levels: levels,
}
}
#[test]
fn is_digest_build_enabled_works() {
assert!(!config(0, 100).is_digest_build_enabled());
assert!(!config(1, 100).is_digest_build_enabled());
assert!(config(2, 100).is_digest_build_enabled());
assert!(!config(100, 0).is_digest_build_enabled());
assert!(config(100, 1).is_digest_build_enabled());
}
#[test]
fn is_digest_build_required_at_block_works() {
assert!(!config(8, 4).is_digest_build_required_at_block(0));
assert!(!config(8, 4).is_digest_build_required_at_block(1));
assert!(!config(8, 4).is_digest_build_required_at_block(2));
assert!(!config(8, 4).is_digest_build_required_at_block(4));
assert!(config(8, 4).is_digest_build_required_at_block(8));
assert!(!config(8, 4).is_digest_build_required_at_block(9));
assert!(config(8, 4).is_digest_build_required_at_block(64));
assert!(config(8, 4).is_digest_build_required_at_block(64));
assert!(config(8, 4).is_digest_build_required_at_block(512));
assert!(config(8, 4).is_digest_build_required_at_block(4096));
assert!(!config(8, 4).is_digest_build_required_at_block(4103));
assert!(config(8, 4).is_digest_build_required_at_block(4104));
assert!(!config(8, 4).is_digest_build_required_at_block(4108));
}
#[test]
fn digest_level_at_block_works() {
assert_eq!(config(8, 4).digest_level_at_block(0), None);
assert_eq!(config(8, 4).digest_level_at_block(7), None);
assert_eq!(config(8, 4).digest_level_at_block(63), None);
assert_eq!(config(8, 4).digest_level_at_block(8), Some((1, 8, 1)));
assert_eq!(config(8, 4).digest_level_at_block(64), Some((2, 64, 8)));
assert_eq!(config(8, 4).digest_level_at_block(512), Some((3, 512, 64)));
assert_eq!(config(8, 4).digest_level_at_block(4096), Some((4, 4096, 512)));
assert_eq!(config(8, 4).digest_level_at_block(4112), Some((1, 8, 1)));
}
}