Run cargo fmt on the whole code base (#9394)

* Run cargo fmt on the whole code base

* Second run

* Add CI check

* Fix compilation

* More unnecessary braces

* Handle weights

* Use --all

* Use correct attributes...

* Fix UI tests

* AHHHHHHHHH

* 🤦

* Docs

* Fix compilation

* 🤷

* Please stop

* 🤦 x 2

* More

* make rustfmt.toml consistent with polkadot

Co-authored-by: André Silva <andrerfosilva@gmail.com>
This commit is contained in:
Bastian Köcher
2021-07-21 16:32:32 +02:00
committed by GitHub
parent d451c38c1c
commit 7b56ab15b4
1010 changed files with 53339 additions and 51208 deletions
File diff suppressed because it is too large Load Diff
@@ -78,20 +78,20 @@ pub(crate) struct IncompleteCachedBuildData<N> {
}
impl<H, N> BuildCache<H, N>
where
N: Eq + ::std::hash::Hash,
H: Eq + ::std::hash::Hash + Clone,
where
N: Eq + ::std::hash::Hash,
H: Eq + ::std::hash::Hash + Clone,
{
/// Create new changes trie build cache.
pub fn new() -> Self {
BuildCache {
roots_by_number: HashMap::new(),
changed_keys: HashMap::new(),
}
BuildCache { roots_by_number: HashMap::new(), changed_keys: HashMap::new() }
}
/// Get cached changed keys for changes trie with given root.
pub fn get(&self, root: &H) -> Option<&HashMap<Option<PrefixedStorageKey>, HashSet<StorageKey>>> {
pub fn get(
&self,
root: &H,
) -> Option<&HashMap<Option<PrefixedStorageKey>, HashSet<StorageKey>>> {
self.changed_keys.get(&root)
}
@@ -158,7 +158,9 @@ impl<N> IncompleteCacheAction<N> {
pub(crate) fn set_digest_input_blocks(self, digest_input_blocks: Vec<N>) -> Self {
match self {
IncompleteCacheAction::CacheBuildData(build_data) =>
IncompleteCacheAction::CacheBuildData(build_data.set_digest_input_blocks(digest_input_blocks)),
IncompleteCacheAction::CacheBuildData(
build_data.set_digest_input_blocks(digest_input_blocks),
),
IncompleteCacheAction::Clear => IncompleteCacheAction::Clear,
}
}
@@ -180,10 +182,7 @@ impl<N> IncompleteCacheAction<N> {
impl<N> IncompleteCachedBuildData<N> {
/// Create new cached data.
pub(crate) fn new() -> Self {
IncompleteCachedBuildData {
digest_input_blocks: Vec::new(),
changed_keys: HashMap::new(),
}
IncompleteCachedBuildData { digest_input_blocks: Vec::new(), changed_keys: HashMap::new() }
}
fn complete<H>(self, block: N, trie_root: H) -> CachedBuildData<H, N> {
@@ -232,30 +231,42 @@ mod tests {
#[test]
fn obsolete_entries_are_purged_when_new_ct_is_built() {
let mut cache = BuildCache::<u32, u32>::new();
cache.perform(CacheAction::CacheBuildData(IncompleteCachedBuildData::new()
.insert(None, vec![vec![1]].into_iter().collect())
.complete(1, 1)));
cache.perform(CacheAction::CacheBuildData(IncompleteCachedBuildData::new()
.insert(None, vec![vec![2]].into_iter().collect())
.complete(2, 2)));
cache.perform(CacheAction::CacheBuildData(IncompleteCachedBuildData::new()
.insert(None, vec![vec![3]].into_iter().collect())
.complete(3, 3)));
cache.perform(CacheAction::CacheBuildData(
IncompleteCachedBuildData::new()
.insert(None, vec![vec![1]].into_iter().collect())
.complete(1, 1),
));
cache.perform(CacheAction::CacheBuildData(
IncompleteCachedBuildData::new()
.insert(None, vec![vec![2]].into_iter().collect())
.complete(2, 2),
));
cache.perform(CacheAction::CacheBuildData(
IncompleteCachedBuildData::new()
.insert(None, vec![vec![3]].into_iter().collect())
.complete(3, 3),
));
assert_eq!(cache.changed_keys.len(), 3);
cache.perform(CacheAction::CacheBuildData(IncompleteCachedBuildData::new()
.set_digest_input_blocks(vec![1, 2, 3])
.complete(4, 4)));
cache.perform(CacheAction::CacheBuildData(
IncompleteCachedBuildData::new()
.set_digest_input_blocks(vec![1, 2, 3])
.complete(4, 4),
));
assert_eq!(cache.changed_keys.len(), 1);
cache.perform(CacheAction::CacheBuildData(IncompleteCachedBuildData::new()
.insert(None, vec![vec![8]].into_iter().collect())
.complete(8, 8)));
cache.perform(CacheAction::CacheBuildData(IncompleteCachedBuildData::new()
.insert(None, vec![vec![12]].into_iter().collect())
.complete(12, 12)));
cache.perform(CacheAction::CacheBuildData(
IncompleteCachedBuildData::new()
.insert(None, vec![vec![8]].into_iter().collect())
.complete(8, 8),
));
cache.perform(CacheAction::CacheBuildData(
IncompleteCachedBuildData::new()
.insert(None, vec![vec![12]].into_iter().collect())
.complete(12, 12),
));
assert_eq!(cache.changed_keys.len(), 3);
@@ -18,8 +18,8 @@
//! Structures and functions to return blocks whose changes are to be included
//! in given block's changes trie.
use crate::changes_trie::{BlockNumber, ConfigurationRange};
use num_traits::Zero;
use crate::changes_trie::{ConfigurationRange, BlockNumber};
/// Returns iterator of OTHER blocks that are required for inclusion into
/// changes trie of given block. Blocks are guaranteed to be returned in
@@ -31,13 +31,19 @@ pub fn digest_build_iterator<'a, Number: BlockNumber>(
block: Number,
) -> DigestBuildIterator<Number> {
// prepare digest build parameters
let (_, _, digest_step) = match config.config.digest_level_at_block(config.zero, block.clone()) {
let (_, _, digest_step) = match config.config.digest_level_at_block(config.zero, block.clone())
{
Some((current_level, digest_interval, digest_step)) =>
(current_level, digest_interval, digest_step),
None => return DigestBuildIterator::empty(),
};
DigestBuildIterator::new(block.clone(), config.end.unwrap_or(block), config.config.digest_interval, digest_step)
DigestBuildIterator::new(
block.clone(),
config.end.unwrap_or(block),
config.config.digest_interval,
digest_step,
)
}
/// Changes trie build iterator that returns numbers of OTHER blocks that are
@@ -56,7 +62,6 @@ pub struct DigestBuildIterator<Number: BlockNumber> {
max_step: u32,
// Mutable data below:
/// Step of current blocks range.
current_step: u32,
/// Reverse step of current blocks range.
@@ -98,7 +103,7 @@ impl<Number: BlockNumber> Iterator for DigestBuildIterator<Number> {
if let Some(next) = self.current_range.as_mut().and_then(|iter| iter.next()) {
if next < self.end {
self.last_block = Some(next.clone());
return Some(next);
return Some(next)
}
}
@@ -112,14 +117,16 @@ impl<Number: BlockNumber> Iterator for DigestBuildIterator<Number> {
self.current_step_reverse * self.digest_interval
};
if next_step_reverse > self.max_step {
return None;
return None
}
self.current_step_reverse = next_step_reverse;
self.current_range = Some(BlocksRange::new(
match self.last_block.clone() {
Some(last_block) => last_block + self.current_step.into(),
None => self.block.clone() - (self.current_step * self.digest_interval - self.current_step).into(),
None =>
self.block.clone() -
(self.current_step * self.digest_interval - self.current_step).into(),
},
self.block.clone(),
self.current_step.into(),
@@ -143,11 +150,7 @@ struct BlocksRange<Number: BlockNumber> {
impl<Number: BlockNumber> BlocksRange<Number> {
pub fn new(begin: Number, end: Number, step: Number) -> Self {
BlocksRange {
current: begin,
end,
step,
}
BlocksRange { current: begin, end, step }
}
}
@@ -156,7 +159,7 @@ impl<Number: BlockNumber> Iterator for BlocksRange<Number> {
fn next(&mut self) -> Option<Self::Item> {
if self.current >= self.end {
return None;
return None
}
let current = Some(self.current.clone());
@@ -167,8 +170,8 @@ impl<Number: BlockNumber> Iterator for BlocksRange<Number> {
#[cfg(test)]
mod tests {
use crate::changes_trie::Configuration;
use super::*;
use crate::changes_trie::Configuration;
fn digest_build_iterator(
digest_interval: u32,
@@ -179,10 +182,7 @@ mod tests {
) -> DigestBuildIterator<u64> {
super::digest_build_iterator(
ConfigurationRange {
config: &Configuration {
digest_interval,
digest_levels,
},
config: &Configuration { digest_interval, digest_levels },
zero,
end,
},
@@ -215,9 +215,21 @@ mod tests {
fn test_with_zero(zero: u64) {
let empty = (0, 0, 0);
assert_eq!(digest_build_iterator_basic(4, 16, zero, zero + 0), empty, "block is 0");
assert_eq!(digest_build_iterator_basic(0, 16, zero, zero + 64), empty, "digest_interval is 0");
assert_eq!(digest_build_iterator_basic(1, 16, zero, zero + 64), empty, "digest_interval is 1");
assert_eq!(digest_build_iterator_basic(4, 0, zero, zero + 64), empty, "digest_levels is 0");
assert_eq!(
digest_build_iterator_basic(0, 16, zero, zero + 64),
empty,
"digest_interval is 0"
);
assert_eq!(
digest_build_iterator_basic(1, 16, zero, zero + 64),
empty,
"digest_interval is 1"
);
assert_eq!(
digest_build_iterator_basic(4, 0, zero, zero + 64),
empty,
"digest_levels is 0"
);
assert_eq!(
digest_build_iterator_basic(4, 16, zero, zero + 1),
empty,
@@ -238,12 +250,11 @@ mod tests {
empty,
"digest is not required for this block",
);
assert_eq!(digest_build_iterator_basic(
::std::u32::MAX / 2 + 1,
16,
zero,
::std::u64::MAX,
), empty, "digest_interval * 2 is greater than u64::MAX");
assert_eq!(
digest_build_iterator_basic(::std::u32::MAX / 2 + 1, 16, zero, ::std::u64::MAX,),
empty,
"digest_interval * 2 is greater than u64::MAX"
);
}
test_with_zero(0);
@@ -326,18 +337,37 @@ mod tests {
#[test]
fn digest_iterator_returns_level1_blocks() {
fn test_with_zero(zero: u64) {
assert_eq!(digest_build_iterator_blocks(16, 1, zero, zero + 16, None),
assert_eq!(
digest_build_iterator_blocks(16, 1, zero, zero + 16, None),
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
.iter().map(|item| zero + item).collect::<Vec<_>>());
assert_eq!(digest_build_iterator_blocks(16, 1, zero, zero + 256, None),
.iter()
.map(|item| zero + item)
.collect::<Vec<_>>()
);
assert_eq!(
digest_build_iterator_blocks(16, 1, zero, zero + 256, None),
[241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255]
.iter().map(|item| zero + item).collect::<Vec<_>>());
assert_eq!(digest_build_iterator_blocks(16, 2, zero, zero + 32, None),
.iter()
.map(|item| zero + item)
.collect::<Vec<_>>()
);
assert_eq!(
digest_build_iterator_blocks(16, 2, zero, zero + 32, None),
[17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]
.iter().map(|item| zero + item).collect::<Vec<_>>());
assert_eq!(digest_build_iterator_blocks(16, 3, zero, zero + 4080, None),
[4065, 4066, 4067, 4068, 4069, 4070, 4071, 4072, 4073, 4074, 4075, 4076, 4077, 4078, 4079]
.iter().map(|item| zero + item).collect::<Vec<_>>());
.iter()
.map(|item| zero + item)
.collect::<Vec<_>>()
);
assert_eq!(
digest_build_iterator_blocks(16, 3, zero, zero + 4080, None),
[
4065, 4066, 4067, 4068, 4069, 4070, 4071, 4072, 4073, 4074, 4075, 4076, 4077,
4078, 4079
]
.iter()
.map(|item| zero + item)
.collect::<Vec<_>>()
);
}
test_with_zero(0);
@@ -348,21 +378,30 @@ mod tests {
#[test]
fn digest_iterator_returns_level1_and_level2_blocks() {
fn test_with_zero(zero: u64) {
assert_eq!(digest_build_iterator_blocks(16, 2, zero, zero + 256, None),
assert_eq!(
digest_build_iterator_blocks(16, 2, zero, zero + 256, None),
[
// level2 points to previous 16-1 level1 digests:
16, 32, 48, 64, 80, 96, 112, 128, 144, 160, 176, 192, 208, 224, 240,
// level2 is a level1 digest of 16-1 previous blocks:
241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255,
].iter().map(|item| zero + item).collect::<Vec<_>>(),
]
.iter()
.map(|item| zero + item)
.collect::<Vec<_>>(),
);
assert_eq!(digest_build_iterator_blocks(16, 2, zero, zero + 4096, None),
assert_eq!(
digest_build_iterator_blocks(16, 2, zero, zero + 4096, None),
[
// level2 points to previous 16-1 level1 digests:
3856, 3872, 3888, 3904, 3920, 3936, 3952, 3968, 3984, 4000, 4016, 4032, 4048, 4064, 4080,
// level2 is a level1 digest of 16-1 previous blocks:
4081, 4082, 4083, 4084, 4085, 4086, 4087, 4088, 4089, 4090, 4091, 4092, 4093, 4094, 4095,
].iter().map(|item| zero + item).collect::<Vec<_>>(),
3856, 3872, 3888, 3904, 3920, 3936, 3952, 3968, 3984, 4000, 4016, 4032, 4048,
4064, 4080, // level2 is a level1 digest of 16-1 previous blocks:
4081, 4082, 4083, 4084, 4085, 4086, 4087, 4088, 4089, 4090, 4091, 4092, 4093,
4094, 4095,
]
.iter()
.map(|item| zero + item)
.collect::<Vec<_>>(),
);
}
@@ -374,15 +413,20 @@ mod tests {
#[test]
fn digest_iterator_returns_level1_and_level2_and_level3_blocks() {
fn test_with_zero(zero: u64) {
assert_eq!(digest_build_iterator_blocks(16, 3, zero, zero + 4096, None),
assert_eq!(
digest_build_iterator_blocks(16, 3, zero, zero + 4096, None),
[
// level3 points to previous 16-1 level2 digests:
256, 512, 768, 1024, 1280, 1536, 1792, 2048, 2304, 2560, 2816, 3072, 3328, 3584, 3840,
// level3 points to previous 16-1 level1 digests:
3856, 3872, 3888, 3904, 3920, 3936, 3952, 3968, 3984, 4000, 4016, 4032, 4048, 4064, 4080,
// level3 is a level1 digest of 16-1 previous blocks:
4081, 4082, 4083, 4084, 4085, 4086, 4087, 4088, 4089, 4090, 4091, 4092, 4093, 4094, 4095,
].iter().map(|item| zero + item).collect::<Vec<_>>(),
256, 512, 768, 1024, 1280, 1536, 1792, 2048, 2304, 2560, 2816, 3072, 3328, 3584,
3840, // level3 points to previous 16-1 level1 digests:
3856, 3872, 3888, 3904, 3920, 3936, 3952, 3968, 3984, 4000, 4016, 4032, 4048,
4064, 4080, // level3 is a level1 digest of 16-1 previous blocks:
4081, 4082, 4083, 4084, 4085, 4086, 4087, 4088, 4089, 4090, 4091, 4092, 4093,
4094, 4095,
]
.iter()
.map(|item| zero + item)
.collect::<Vec<_>>(),
);
}
@@ -394,7 +438,8 @@ mod tests {
#[test]
fn digest_iterator_returns_skewed_digest_blocks() {
fn test_with_zero(zero: u64) {
assert_eq!(digest_build_iterator_blocks(16, 3, zero, zero + 4096, Some(zero + 1338)),
assert_eq!(
digest_build_iterator_blocks(16, 3, zero, zero + 4096, Some(zero + 1338)),
[
// level3 MUST point to previous 16-1 level2 digests, BUT there are only 5:
256, 512, 768, 1024, 1280,
@@ -402,7 +447,10 @@ mod tests {
1296, 1312, 1328,
// level3 MUST be a level1 digest of 16-1 previous blocks, BUT there are only 9:
1329, 1330, 1331, 1332, 1333, 1334, 1335, 1336, 1337,
].iter().map(|item| zero + item).collect::<Vec<_>>(),
]
.iter()
.map(|item| zero + item)
.collect::<Vec<_>>(),
);
}
@@ -414,14 +462,18 @@ mod tests {
#[test]
fn digest_iterator_returns_skewed_digest_blocks_skipping_level() {
fn test_with_zero(zero: u64) {
assert_eq!(digest_build_iterator_blocks(16, 3, zero, zero + 4096, Some(zero + 1284)),
assert_eq!(
digest_build_iterator_blocks(16, 3, zero, zero + 4096, Some(zero + 1284)),
[
// level3 MUST point to previous 16-1 level2 digests, BUT there are only 5:
256, 512, 768, 1024, 1280,
// level3 MUST point to previous 16-1 level1 digests, BUT there are NO ANY L1-digests:
// level3 MUST be a level1 digest of 16-1 previous blocks, BUT there are only 3:
1281, 1282, 1283,
].iter().map(|item| zero + item).collect::<Vec<_>>(),
]
.iter()
.map(|item| zero + item)
.collect::<Vec<_>>(),
);
}
@@ -18,20 +18,22 @@
//! Functions + iterator that traverses changes tries and returns all
//! (block, extrinsic) pairs where given key has been changed.
use std::cell::RefCell;
use std::collections::VecDeque;
use codec::{Decode, Encode, Codec};
use crate::{
changes_trie::{
input::{ChildIndex, DigestIndex, DigestIndexValue, ExtrinsicIndex, ExtrinsicIndexValue},
storage::{InMemoryStorage, TrieBackendAdapter},
surface_iterator::{surface_iterator, SurfaceIterator},
AnchorBlockId, BlockNumber, ConfigurationRange, RootsStorage, Storage,
},
proving_backend::ProvingBackendRecorder,
trie_backend_essence::TrieBackendEssence,
};
use codec::{Codec, Decode, Encode};
use hash_db::Hasher;
use num_traits::Zero;
use sp_core::storage::PrefixedStorageKey;
use sp_trie::Recorder;
use crate::changes_trie::{AnchorBlockId, ConfigurationRange, RootsStorage, Storage, BlockNumber};
use crate::changes_trie::input::{DigestIndex, ExtrinsicIndex, DigestIndexValue, ExtrinsicIndexValue};
use crate::changes_trie::storage::{TrieBackendAdapter, InMemoryStorage};
use crate::changes_trie::input::ChildIndex;
use crate::changes_trie::surface_iterator::{surface_iterator, SurfaceIterator};
use crate::proving_backend::ProvingBackendRecorder;
use crate::trie_backend_essence::{TrieBackendEssence};
use std::{cell::RefCell, collections::VecDeque};
/// Return changes of given key at given blocks range.
/// `max` is the number of best known block.
@@ -57,12 +59,7 @@ pub fn key_changes<'a, H: Hasher, Number: BlockNumber>(
begin: begin.clone(),
end,
config: config.clone(),
surface: surface_iterator(
config,
max,
begin,
end.number.clone(),
)?,
surface: surface_iterator(config, max, begin, end.number.clone())?,
extrinsics: Default::default(),
blocks: Default::default(),
@@ -72,7 +69,6 @@ pub fn key_changes<'a, H: Hasher, Number: BlockNumber>(
})
}
/// Returns proof of changes of given key at given blocks range.
/// `max` is the number of best known block.
pub fn key_changes_proof<'a, H: Hasher, Number: BlockNumber>(
@@ -83,7 +79,10 @@ pub fn key_changes_proof<'a, H: Hasher, Number: BlockNumber>(
max: Number,
storage_key: Option<&PrefixedStorageKey>,
key: &[u8],
) -> Result<Vec<Vec<u8>>, String> where H::Out: Codec {
) -> Result<Vec<Vec<u8>>, String>
where
H::Out: Codec,
{
// we can't query any roots before root
let max = std::cmp::min(max, end.number.clone());
@@ -96,12 +95,7 @@ pub fn key_changes_proof<'a, H: Hasher, Number: BlockNumber>(
begin: begin.clone(),
end,
config: config.clone(),
surface: surface_iterator(
config,
max,
begin,
end.number.clone(),
)?,
surface: surface_iterator(config, max, begin, end.number.clone())?,
extrinsics: Default::default(),
blocks: Default::default(),
@@ -130,8 +124,11 @@ pub fn key_changes_proof_check<'a, H: Hasher, Number: BlockNumber>(
end: &AnchorBlockId<H::Out, Number>,
max: Number,
storage_key: Option<&PrefixedStorageKey>,
key: &[u8]
) -> Result<Vec<(Number, u32)>, String> where H::Out: Encode {
key: &[u8],
) -> Result<Vec<(Number, u32)>, String>
where
H::Out: Encode,
{
key_changes_proof_check_with_db(
config,
roots_storage,
@@ -153,8 +150,11 @@ pub fn key_changes_proof_check_with_db<'a, H: Hasher, Number: BlockNumber>(
end: &AnchorBlockId<H::Out, Number>,
max: Number,
storage_key: Option<&PrefixedStorageKey>,
key: &[u8]
) -> Result<Vec<(Number, u32)>, String> where H::Out: Encode {
key: &[u8],
) -> Result<Vec<(Number, u32)>, String>
where
H::Out: Encode,
{
// we can't query any roots before root
let max = std::cmp::min(max, end.number.clone());
@@ -167,28 +167,24 @@ pub fn key_changes_proof_check_with_db<'a, H: Hasher, Number: BlockNumber>(
begin: begin.clone(),
end,
config: config.clone(),
surface: surface_iterator(
config,
max,
begin,
end.number.clone(),
)?,
surface: surface_iterator(config, max, begin, end.number.clone())?,
extrinsics: Default::default(),
blocks: Default::default(),
_hasher: ::std::marker::PhantomData::<H>::default(),
},
}.collect()
}
.collect()
}
/// Drilldown iterator - receives 'digest points' from surface iterator and explores
/// every point until extrinsic is found.
pub struct DrilldownIteratorEssence<'a, H, Number>
where
H: Hasher,
Number: BlockNumber,
H::Out: 'a,
where
H: Hasher,
Number: BlockNumber,
H::Out: 'a,
{
storage_key: Option<&'a PrefixedStorageKey>,
key: &'a [u8],
@@ -206,14 +202,14 @@ pub struct DrilldownIteratorEssence<'a, H, Number>
}
impl<'a, H, Number> DrilldownIteratorEssence<'a, H, Number>
where
H: Hasher,
Number: BlockNumber,
H::Out: 'a,
where
H: Hasher,
Number: BlockNumber,
H::Out: 'a,
{
pub fn next<F>(&mut self, trie_reader: F) -> Option<Result<(Number, u32), String>>
where
F: FnMut(&dyn Storage<H, Number>, H::Out, &[u8]) -> Result<Option<Vec<u8>>, String>,
where
F: FnMut(&dyn Storage<H, Number>, H::Out, &[u8]) -> Result<Option<Vec<u8>>, String>,
{
match self.do_next(trie_reader) {
Ok(Some(res)) => Some(Ok(res)),
@@ -223,25 +219,26 @@ impl<'a, H, Number> DrilldownIteratorEssence<'a, H, Number>
}
fn do_next<F>(&mut self, mut trie_reader: F) -> Result<Option<(Number, u32)>, String>
where
F: FnMut(&dyn Storage<H, Number>, H::Out, &[u8]) -> Result<Option<Vec<u8>>, String>,
where
F: FnMut(&dyn Storage<H, Number>, H::Out, &[u8]) -> Result<Option<Vec<u8>>, String>,
{
loop {
if let Some((block, extrinsic)) = self.extrinsics.pop_front() {
return Ok(Some((block, extrinsic)));
return Ok(Some((block, extrinsic)))
}
if let Some((block, level)) = self.blocks.pop_front() {
// not having a changes trie root is an error because:
// we never query roots for future blocks
// AND trie roots for old blocks are known (both on full + light node)
let trie_root = self.roots_storage.root(&self.end, block.clone())?
.ok_or_else(|| format!("Changes trie root for block {} is not found", block.clone()))?;
let trie_root =
self.roots_storage.root(&self.end, block.clone())?.ok_or_else(|| {
format!("Changes trie root for block {} is not found", block.clone())
})?;
let trie_root = if let Some(storage_key) = self.storage_key {
let child_key = ChildIndex {
block: block.clone(),
storage_key: storage_key.clone(),
}.encode();
let child_key =
ChildIndex { block: block.clone(), storage_key: storage_key.clone() }
.encode();
if let Some(trie_root) = trie_reader(self.storage, trie_root, &child_key)?
.and_then(|v| <Vec<u8>>::decode(&mut &v[..]).ok())
.map(|v| {
@@ -251,7 +248,7 @@ impl<'a, H, Number> DrilldownIteratorEssence<'a, H, Number>
}) {
trie_root
} else {
continue;
continue
}
} else {
trie_root
@@ -260,18 +257,24 @@ impl<'a, H, Number> DrilldownIteratorEssence<'a, H, Number>
// only return extrinsics for blocks before self.max
// most of blocks will be filtered out before pushing to `self.blocks`
// here we just throwing away changes at digest blocks we're processing
debug_assert!(block >= self.begin, "We shall not touch digests earlier than a range' begin");
debug_assert!(
block >= self.begin,
"We shall not touch digests earlier than a range' begin"
);
if block <= self.end.number {
let extrinsics_key = ExtrinsicIndex { block: block.clone(), key: self.key.to_vec() }.encode();
let extrinsics_key =
ExtrinsicIndex { block: block.clone(), key: self.key.to_vec() }.encode();
let extrinsics = trie_reader(self.storage, trie_root, &extrinsics_key);
if let Some(extrinsics) = extrinsics? {
if let Ok(extrinsics) = ExtrinsicIndexValue::decode(&mut &extrinsics[..]) {
self.extrinsics.extend(extrinsics.into_iter().rev().map(|e| (block.clone(), e)));
self.extrinsics
.extend(extrinsics.into_iter().rev().map(|e| (block.clone(), e)));
}
}
}
let blocks_key = DigestIndex { block: block.clone(), key: self.key.to_vec() }.encode();
let blocks_key =
DigestIndex { block: block.clone(), key: self.key.to_vec() }.encode();
let blocks = trie_reader(self.storage, trie_root, &blocks_key);
if let Some(blocks) = blocks? {
if let Ok(blocks) = <DigestIndexValue<Number>>::decode(&mut &blocks[..]) {
@@ -280,23 +283,35 @@ impl<'a, H, Number> DrilldownIteratorEssence<'a, H, Number>
let begin = self.begin.clone();
let end = self.end.number.clone();
let config = self.config.clone();
self.blocks.extend(blocks.into_iter()
.rev()
.filter(|b| level.map(|level| level > 1).unwrap_or(true) || (*b >= begin && *b <= end))
.map(|b| {
let prev_level = level
.map(|level| Some(level - 1))
.unwrap_or_else(||
Some(config.config.digest_level_at_block(config.zero.clone(), b.clone())
.map(|(level, _, _)| level)
.unwrap_or_else(|| Zero::zero())));
(b, prev_level)
})
self.blocks.extend(
blocks
.into_iter()
.rev()
.filter(|b| {
level.map(|level| level > 1).unwrap_or(true) ||
(*b >= begin && *b <= end)
})
.map(|b| {
let prev_level =
level.map(|level| Some(level - 1)).unwrap_or_else(|| {
Some(
config
.config
.digest_level_at_block(
config.zero.clone(),
b.clone(),
)
.map(|(level, _, _)| level)
.unwrap_or_else(|| Zero::zero()),
)
});
(b, prev_level)
}),
);
}
}
continue;
continue
}
match self.surface.next() {
@@ -310,46 +325,50 @@ impl<'a, H, Number> DrilldownIteratorEssence<'a, H, Number>
/// Exploring drilldown operator.
pub struct DrilldownIterator<'a, H, Number>
where
Number: BlockNumber,
H: Hasher,
H::Out: 'a,
where
Number: BlockNumber,
H: Hasher,
H::Out: 'a,
{
essence: DrilldownIteratorEssence<'a, H, Number>,
}
impl<'a, H: Hasher, Number: BlockNumber> Iterator for DrilldownIterator<'a, H, Number>
where H::Out: Encode
where
H::Out: Encode,
{
type Item = Result<(Number, u32), String>;
fn next(&mut self) -> Option<Self::Item> {
self.essence.next(|storage, root, key|
TrieBackendEssence::<_, H>::new(TrieBackendAdapter::new(storage), root).storage(key))
self.essence.next(|storage, root, key| {
TrieBackendEssence::<_, H>::new(TrieBackendAdapter::new(storage), root).storage(key)
})
}
}
/// Proving drilldown iterator.
struct ProvingDrilldownIterator<'a, H, Number>
where
Number: BlockNumber,
H: Hasher,
H::Out: 'a,
where
Number: BlockNumber,
H: Hasher,
H::Out: 'a,
{
essence: DrilldownIteratorEssence<'a, H, Number>,
proof_recorder: RefCell<Recorder<H::Out>>,
}
impl<'a, H, Number> ProvingDrilldownIterator<'a, H, Number>
where
Number: BlockNumber,
H: Hasher,
H::Out: 'a,
where
Number: BlockNumber,
H: Hasher,
H::Out: 'a,
{
/// Consume the iterator, extracting the gathered proof in lexicographical order
/// by value.
pub fn extract_proof(self) -> Vec<Vec<u8>> {
self.proof_recorder.into_inner().drain()
self.proof_recorder
.into_inner()
.drain()
.into_iter()
.map(|n| n.data.to_vec())
.collect()
@@ -357,32 +376,34 @@ impl<'a, H, Number> ProvingDrilldownIterator<'a, H, Number>
}
impl<'a, H, Number> Iterator for ProvingDrilldownIterator<'a, H, Number>
where
Number: BlockNumber,
H: Hasher,
H::Out: 'a + Codec,
where
Number: BlockNumber,
H: Hasher,
H::Out: 'a + Codec,
{
type Item = Result<(Number, u32), String>;
fn next(&mut self) -> Option<Self::Item> {
let proof_recorder = &mut *self.proof_recorder.try_borrow_mut()
let proof_recorder = &mut *self
.proof_recorder
.try_borrow_mut()
.expect("only fails when already borrowed; storage() is non-reentrant; qed");
self.essence.next(|storage, root, key|
self.essence.next(|storage, root, key| {
ProvingBackendRecorder::<_, H> {
backend: &TrieBackendEssence::new(TrieBackendAdapter::new(storage), root),
proof_recorder,
}.storage(key))
}
.storage(key)
})
}
}
#[cfg(test)]
mod tests {
use std::iter::FromIterator;
use crate::changes_trie::Configuration;
use crate::changes_trie::input::InputPair;
use crate::changes_trie::storage::InMemoryStorage;
use sp_runtime::traits::BlakeTwo256;
use super::*;
use crate::changes_trie::{input::InputPair, storage::InMemoryStorage, Configuration};
use sp_runtime::traits::BlakeTwo256;
use std::iter::FromIterator;
fn child_key() -> PrefixedStorageKey {
let child_info = sp_core::storage::ChildInfo::new_default(&b"1"[..]);
@@ -391,64 +412,98 @@ mod tests {
fn prepare_for_drilldown() -> (Configuration, InMemoryStorage<BlakeTwo256, u64>) {
let config = Configuration { digest_interval: 4, digest_levels: 2 };
let backend = InMemoryStorage::with_inputs(vec![
// digest: 1..4 => [(3, 0)]
(1, vec![
]),
(2, vec![
]),
(3, vec![
InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 3, key: vec![42] }, vec![0]),
]),
(4, vec![
InputPair::DigestIndex(DigestIndex { block: 4, key: vec![42] }, vec![3]),
]),
// digest: 5..8 => [(6, 3), (8, 1+2)]
(5, vec![]),
(6, vec![
InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 6, key: vec![42] }, vec![3]),
]),
(7, vec![]),
(8, vec![
InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 8, key: vec![42] }, vec![1, 2]),
InputPair::DigestIndex(DigestIndex { block: 8, key: vec![42] }, vec![6]),
]),
// digest: 9..12 => []
(9, vec![]),
(10, vec![]),
(11, vec![]),
(12, vec![]),
// digest: 0..16 => [4, 8]
(13, vec![]),
(14, vec![]),
(15, vec![]),
(16, vec![
InputPair::DigestIndex(DigestIndex { block: 16, key: vec![42] }, vec![4, 8]),
]),
], vec![(child_key(), vec![
(1, vec![
InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 1, key: vec![42] }, vec![0]),
]),
(2, vec![
InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 2, key: vec![42] }, vec![3]),
]),
(16, vec![
InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 16, key: vec![42] }, vec![5]),
InputPair::DigestIndex(DigestIndex { block: 16, key: vec![42] }, vec![2]),
]),
]),
]);
let backend = InMemoryStorage::with_inputs(
vec![
// digest: 1..4 => [(3, 0)]
(1, vec![]),
(2, vec![]),
(
3,
vec![InputPair::ExtrinsicIndex(
ExtrinsicIndex { block: 3, key: vec![42] },
vec![0],
)],
),
(4, vec![InputPair::DigestIndex(DigestIndex { block: 4, key: vec![42] }, vec![3])]),
// digest: 5..8 => [(6, 3), (8, 1+2)]
(5, vec![]),
(
6,
vec![InputPair::ExtrinsicIndex(
ExtrinsicIndex { block: 6, key: vec![42] },
vec![3],
)],
),
(7, vec![]),
(
8,
vec![
InputPair::ExtrinsicIndex(
ExtrinsicIndex { block: 8, key: vec![42] },
vec![1, 2],
),
InputPair::DigestIndex(DigestIndex { block: 8, key: vec![42] }, vec![6]),
],
),
// digest: 9..12 => []
(9, vec![]),
(10, vec![]),
(11, vec![]),
(12, vec![]),
// digest: 0..16 => [4, 8]
(13, vec![]),
(14, vec![]),
(15, vec![]),
(
16,
vec![InputPair::DigestIndex(
DigestIndex { block: 16, key: vec![42] },
vec![4, 8],
)],
),
],
vec![(
child_key(),
vec![
(
1,
vec![InputPair::ExtrinsicIndex(
ExtrinsicIndex { block: 1, key: vec![42] },
vec![0],
)],
),
(
2,
vec![InputPair::ExtrinsicIndex(
ExtrinsicIndex { block: 2, key: vec![42] },
vec![3],
)],
),
(
16,
vec![
InputPair::ExtrinsicIndex(
ExtrinsicIndex { block: 16, key: vec![42] },
vec![5],
),
InputPair::DigestIndex(
DigestIndex { block: 16, key: vec![42] },
vec![2],
),
],
),
],
)],
);
(config, backend)
}
fn configuration_range<'a>(config: &'a Configuration, zero: u64) -> ConfigurationRange<'a, u64> {
ConfigurationRange {
config,
zero,
end: None,
}
fn configuration_range<'a>(
config: &'a Configuration,
zero: u64,
) -> ConfigurationRange<'a, u64> {
ConfigurationRange { config, zero, end: None }
}
#[test]
@@ -462,7 +517,8 @@ mod tests {
16,
None,
&[42],
).and_then(Result::from_iter);
)
.and_then(Result::from_iter);
assert_eq!(drilldown_result, Ok(vec![(8, 2), (8, 1), (6, 3), (3, 0)]));
let drilldown_result = key_changes::<BlakeTwo256, u64>(
@@ -473,7 +529,8 @@ mod tests {
4,
None,
&[42],
).and_then(Result::from_iter);
)
.and_then(Result::from_iter);
assert_eq!(drilldown_result, Ok(vec![]));
let drilldown_result = key_changes::<BlakeTwo256, u64>(
@@ -484,7 +541,8 @@ mod tests {
4,
None,
&[42],
).and_then(Result::from_iter);
)
.and_then(Result::from_iter);
assert_eq!(drilldown_result, Ok(vec![(3, 0)]));
let drilldown_result = key_changes::<BlakeTwo256, u64>(
@@ -495,7 +553,8 @@ mod tests {
7,
None,
&[42],
).and_then(Result::from_iter);
)
.and_then(Result::from_iter);
assert_eq!(drilldown_result, Ok(vec![(6, 3), (3, 0)]));
let drilldown_result = key_changes::<BlakeTwo256, u64>(
@@ -506,7 +565,8 @@ mod tests {
8,
None,
&[42],
).and_then(Result::from_iter);
)
.and_then(Result::from_iter);
assert_eq!(drilldown_result, Ok(vec![(8, 2), (8, 1)]));
let drilldown_result = key_changes::<BlakeTwo256, u64>(
@@ -517,7 +577,8 @@ mod tests {
8,
None,
&[42],
).and_then(Result::from_iter);
)
.and_then(Result::from_iter);
assert_eq!(drilldown_result, Ok(vec![(6, 3)]));
}
@@ -534,7 +595,9 @@ mod tests {
1000,
None,
&[42],
).and_then(|i| i.collect::<Result<Vec<_>, _>>()).is_err());
)
.and_then(|i| i.collect::<Result<Vec<_>, _>>())
.is_err());
assert!(key_changes::<BlakeTwo256, u64>(
configuration_range(&config, 0),
@@ -544,7 +607,9 @@ mod tests {
1000,
Some(&child_key()),
&[42],
).and_then(|i| i.collect::<Result<Vec<_>, _>>()).is_err());
)
.and_then(|i| i.collect::<Result<Vec<_>, _>>())
.is_err());
}
#[test]
@@ -558,7 +623,8 @@ mod tests {
50,
None,
&[42],
).is_err());
)
.is_err());
assert!(key_changes::<BlakeTwo256, u64>(
configuration_range(&config, 0),
&storage,
@@ -567,10 +633,10 @@ mod tests {
100,
None,
&[42],
).is_err());
)
.is_err());
}
#[test]
fn proving_drilldown_iterator_works() {
// happens on remote full node:
@@ -578,13 +644,27 @@ mod tests {
// create drilldown iterator that records all trie nodes during drilldown
let (remote_config, remote_storage) = prepare_for_drilldown();
let remote_proof = key_changes_proof::<BlakeTwo256, u64>(
configuration_range(&remote_config, 0), &remote_storage, 1,
&AnchorBlockId { hash: Default::default(), number: 16 }, 16, None, &[42]).unwrap();
configuration_range(&remote_config, 0),
&remote_storage,
1,
&AnchorBlockId { hash: Default::default(), number: 16 },
16,
None,
&[42],
)
.unwrap();
let (remote_config, remote_storage) = prepare_for_drilldown();
let remote_proof_child = key_changes_proof::<BlakeTwo256, u64>(
configuration_range(&remote_config, 0), &remote_storage, 1,
&AnchorBlockId { hash: Default::default(), number: 16 }, 16, Some(&child_key()), &[42]).unwrap();
configuration_range(&remote_config, 0),
&remote_storage,
1,
&AnchorBlockId { hash: Default::default(), number: 16 },
16,
Some(&child_key()),
&[42],
)
.unwrap();
// happens on local light node:
@@ -592,14 +672,28 @@ mod tests {
let (local_config, local_storage) = prepare_for_drilldown();
local_storage.clear_storage();
let local_result = key_changes_proof_check::<BlakeTwo256, u64>(
configuration_range(&local_config, 0), &local_storage, remote_proof, 1,
&AnchorBlockId { hash: Default::default(), number: 16 }, 16, None, &[42]);
configuration_range(&local_config, 0),
&local_storage,
remote_proof,
1,
&AnchorBlockId { hash: Default::default(), number: 16 },
16,
None,
&[42],
);
let (local_config, local_storage) = prepare_for_drilldown();
local_storage.clear_storage();
let local_result_child = key_changes_proof_check::<BlakeTwo256, u64>(
configuration_range(&local_config, 0), &local_storage, remote_proof_child, 1,
&AnchorBlockId { hash: Default::default(), number: 16 }, 16, Some(&child_key()), &[42]);
configuration_range(&local_config, 0),
&local_storage,
remote_proof_child,
1,
&AnchorBlockId { hash: Default::default(), number: 16 },
16,
Some(&child_key()),
&[42],
);
// check that drilldown result is the same as if it was happening at the full node
assert_eq!(local_result, Ok(vec![(8, 2), (8, 1), (6, 3), (3, 0)]));
@@ -620,12 +714,22 @@ mod tests {
// regular blocks: 89, 90, 91
let mut input = (1u64..92u64).map(|b| (b, vec![])).collect::<Vec<_>>();
// changed at block#63 and covered by L3 digest at block#64
input[63 - 1].1.push(InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 63, key: vec![42] }, vec![0]));
input[64 - 1].1.push(InputPair::DigestIndex(DigestIndex { block: 64, key: vec![42] }, vec![63]));
input[63 - 1]
.1
.push(InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 63, key: vec![42] }, vec![0]));
input[64 - 1]
.1
.push(InputPair::DigestIndex(DigestIndex { block: 64, key: vec![42] }, vec![63]));
// changed at block#79 and covered by L2 digest at block#80 + skewed digest at block#91
input[79 - 1].1.push(InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 79, key: vec![42] }, vec![1]));
input[80 - 1].1.push(InputPair::DigestIndex(DigestIndex { block: 80, key: vec![42] }, vec![79]));
input[91 - 1].1.push(InputPair::DigestIndex(DigestIndex { block: 91, key: vec![42] }, vec![80]));
input[79 - 1]
.1
.push(InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 79, key: vec![42] }, vec![1]));
input[80 - 1]
.1
.push(InputPair::DigestIndex(DigestIndex { block: 80, key: vec![42] }, vec![79]));
input[91 - 1]
.1
.push(InputPair::DigestIndex(DigestIndex { block: 91, key: vec![42] }, vec![80]));
let storage = InMemoryStorage::with_inputs(input, vec![]);
let drilldown_result = key_changes::<BlakeTwo256, u64>(
@@ -636,7 +740,8 @@ mod tests {
100_000u64,
None,
&[42],
).and_then(Result::from_iter);
)
.and_then(Result::from_iter);
assert_eq!(drilldown_result, Ok(vec![(79, 1), (63, 0)]));
}
}
@@ -17,11 +17,8 @@
//! Different types of changes trie input pairs.
use codec::{Decode, Encode, Input, Output, Error};
use crate::{
StorageKey, StorageValue,
changes_trie::BlockNumber
};
use crate::{changes_trie::BlockNumber, StorageKey, StorageValue};
use codec::{Decode, Encode, Error, Input, Output};
use sp_core::storage::PrefixedStorageKey;
/// Key of { changed key => set of extrinsic indices } mapping.
@@ -140,7 +137,6 @@ impl<Number: BlockNumber> DigestIndex<Number> {
}
}
impl<Number: BlockNumber> Encode for DigestIndex<Number> {
fn encode_to<W: Output + ?Sized>(&self, dest: &mut W) {
dest.push_byte(2);
@@ -58,63 +58,86 @@ mod prune;
mod storage;
mod surface_iterator;
pub use self::build_cache::{BuildCache, CachedBuildData, CacheAction};
pub use self::storage::InMemoryStorage;
pub use self::changes_iterator::{
key_changes, key_changes_proof,
key_changes_proof_check, key_changes_proof_check_with_db,
pub use self::{
build_cache::{BuildCache, CacheAction, CachedBuildData},
changes_iterator::{
key_changes, key_changes_proof, key_changes_proof_check, key_changes_proof_check_with_db,
},
prune::prune,
storage::InMemoryStorage,
};
pub use self::prune::prune;
use std::collections::{HashMap, HashSet};
use std::convert::TryInto;
use hash_db::{Hasher, Prefix};
use num_traits::{One, Zero};
use codec::{Decode, Encode};
use sp_core;
use sp_core::storage::PrefixedStorageKey;
use sp_trie::{MemoryDB, DBValue, TrieMut};
use sp_trie::trie_types::TrieDBMut;
use crate::{
StorageKey,
backend::Backend,
overlayed_changes::OverlayedChanges,
changes_trie::{
build::prepare_input,
build_cache::{IncompleteCachedBuildData, IncompleteCacheAction},
build_cache::{IncompleteCacheAction, IncompleteCachedBuildData},
},
overlayed_changes::OverlayedChanges,
StorageKey,
};
use codec::{Decode, Encode};
use hash_db::{Hasher, Prefix};
use num_traits::{One, Zero};
use sp_core::{self, storage::PrefixedStorageKey};
use sp_trie::{trie_types::TrieDBMut, DBValue, MemoryDB, TrieMut};
use std::{
collections::{HashMap, HashSet},
convert::TryInto,
};
/// Requirements for block number that can be used with changes tries.
pub trait BlockNumber:
Send + Sync + 'static +
std::fmt::Display +
Clone +
From<u32> + TryInto<u32> + One + Zero +
PartialEq + Ord +
std::hash::Hash +
std::ops::Add<Self, Output=Self> + ::std::ops::Sub<Self, Output=Self> +
std::ops::Mul<Self, Output=Self> + ::std::ops::Div<Self, Output=Self> +
std::ops::Rem<Self, Output=Self> +
std::ops::AddAssign<Self> +
num_traits::CheckedMul + num_traits::CheckedSub +
Decode + Encode
{}
Send
+ Sync
+ 'static
+ std::fmt::Display
+ Clone
+ From<u32>
+ TryInto<u32>
+ One
+ Zero
+ PartialEq
+ Ord
+ std::hash::Hash
+ std::ops::Add<Self, Output = Self>
+ ::std::ops::Sub<Self, Output = Self>
+ std::ops::Mul<Self, Output = Self>
+ ::std::ops::Div<Self, Output = Self>
+ std::ops::Rem<Self, Output = Self>
+ std::ops::AddAssign<Self>
+ num_traits::CheckedMul
+ num_traits::CheckedSub
+ Decode
+ Encode
{
}
impl<T> BlockNumber for T where T:
Send + Sync + 'static +
std::fmt::Display +
Clone +
From<u32> + TryInto<u32> + One + Zero +
PartialEq + Ord +
std::hash::Hash +
std::ops::Add<Self, Output=Self> + ::std::ops::Sub<Self, Output=Self> +
std::ops::Mul<Self, Output=Self> + ::std::ops::Div<Self, Output=Self> +
std::ops::Rem<Self, Output=Self> +
std::ops::AddAssign<Self> +
num_traits::CheckedMul + num_traits::CheckedSub +
Decode + Encode,
{}
impl<T> BlockNumber for T where
T: Send
+ Sync
+ 'static
+ std::fmt::Display
+ Clone
+ From<u32>
+ TryInto<u32>
+ One
+ Zero
+ PartialEq
+ Ord
+ std::hash::Hash
+ std::ops::Add<Self, Output = Self>
+ ::std::ops::Sub<Self, Output = Self>
+ std::ops::Mul<Self, Output = Self>
+ ::std::ops::Div<Self, Output = Self>
+ std::ops::Rem<Self, Output = Self>
+ std::ops::AddAssign<Self>
+ num_traits::CheckedMul
+ num_traits::CheckedSub
+ Decode
+ Encode
{
}
/// Block identifier that could be used to determine fork of this block.
#[derive(Debug)]
@@ -143,7 +166,11 @@ pub trait RootsStorage<H: Hasher, Number: BlockNumber>: Send + Sync {
fn build_anchor(&self, hash: H::Out) -> Result<AnchorBlockId<H::Out, Number>, String>;
/// Get changes trie root for the block with given number which is an ancestor (or the block
/// itself) of the anchor_block (i.e. anchor_block.number >= block).
fn root(&self, anchor: &AnchorBlockId<H::Out, Number>, block: Number) -> Result<Option<H::Out>, String>;
fn root(
&self,
anchor: &AnchorBlockId<H::Out, Number>,
block: Number,
) -> Result<Option<H::Out>, String>;
}
/// Changes trie storage. Provides access to trie roots and trie nodes.
@@ -162,9 +189,13 @@ pub trait Storage<H: Hasher, Number: BlockNumber>: RootsStorage<H, Number> {
}
/// Changes trie storage -> trie backend essence adapter.
pub struct TrieBackendStorageAdapter<'a, H: Hasher, Number: BlockNumber>(pub &'a dyn Storage<H, Number>);
pub struct TrieBackendStorageAdapter<'a, H: Hasher, Number: BlockNumber>(
pub &'a dyn Storage<H, Number>,
);
impl<'a, H: Hasher, N: BlockNumber> crate::TrieBackendStorage<H> for TrieBackendStorageAdapter<'a, H, N> {
impl<'a, H: Hasher, N: BlockNumber> crate::TrieBackendStorage<H>
for TrieBackendStorageAdapter<'a, H, N>
{
type Overlay = sp_trie::MemoryDB<H>;
fn get(&self, key: &H::Out, prefix: Prefix) -> Result<Option<DBValue>, String> {
@@ -188,26 +219,14 @@ pub struct ConfigurationRange<'a, N> {
impl<'a, H, Number> State<'a, H, Number> {
/// Create state with given config and storage.
pub fn new(
config: Configuration,
zero: Number,
storage: &'a dyn Storage<H, Number>,
) -> Self {
Self {
config,
zero,
storage,
}
pub fn new(config: Configuration, zero: Number, storage: &'a dyn Storage<H, Number>) -> Self {
Self { config, zero, storage }
}
}
impl<'a, H, Number: Clone> Clone for State<'a, H, Number> {
fn clone(&self) -> Self {
State {
config: self.config.clone(),
zero: self.zero.clone(),
storage: self.storage,
}
State { config: self.config.clone(), zero: self.zero.clone(), storage: self.storage }
}
}
@@ -227,20 +246,24 @@ pub fn build_changes_trie<'a, B: Backend<H>, H: Hasher, Number: BlockNumber>(
parent_hash: H::Out,
panic_on_storage_error: bool,
) -> Result<Option<(MemoryDB<H>, H::Out, CacheAction<H::Out, Number>)>, ()>
where
H::Out: Ord + 'static + Encode,
where
H::Out: Ord + 'static + Encode,
{
/// Panics when `res.is_err() && panic`, otherwise it returns `Err(())` on an error.
fn maybe_panic<R, E: std::fmt::Debug>(
res: std::result::Result<R, E>,
panic: bool,
) -> std::result::Result<R, ()> {
res.map(Ok)
.unwrap_or_else(|e| if panic {
panic!("changes trie: storage access is not allowed to fail within runtime: {:?}", e)
res.map(Ok).unwrap_or_else(|e| {
if panic {
panic!(
"changes trie: storage access is not allowed to fail within runtime: {:?}",
e
)
} else {
Err(())
})
}
})
}
// when storage isn't provided, changes tries aren't created
@@ -255,11 +278,12 @@ pub fn build_changes_trie<'a, B: Backend<H>, H: Hasher, Number: BlockNumber>(
// prepare configuration range - we already know zero block. Current block may be the end block if configuration
// has been changed in this block
let is_config_changed = match changes.storage(sp_core::storage::well_known_keys::CHANGES_TRIE_CONFIG) {
Some(Some(new_config)) => new_config != &state.config.encode()[..],
Some(None) => true,
None => false,
};
let is_config_changed =
match changes.storage(sp_core::storage::well_known_keys::CHANGES_TRIE_CONFIG) {
Some(Some(new_config)) => new_config != &state.config.encode()[..],
Some(None) => true,
None => false,
};
let config_range = ConfigurationRange {
config: &state.config,
zero: state.zero.clone(),
@@ -303,10 +327,8 @@ pub fn build_changes_trie<'a, B: Backend<H>, H: Hasher, Number: BlockNumber>(
maybe_panic(trie.insert(&key, &value), panic_on_storage_error)?;
}
cache_action = cache_action.insert(
Some(child_index.storage_key.clone()),
storage_changed_keys,
);
cache_action =
cache_action.insert(Some(child_index.storage_key.clone()), storage_changed_keys);
}
if not_empty {
child_roots.push(input::InputPair::ChildIndex(child_index, root.as_ref().to_vec()));
@@ -331,10 +353,7 @@ pub fn build_changes_trie<'a, B: Backend<H>, H: Hasher, Number: BlockNumber>(
maybe_panic(trie.insert(&key, &value), panic_on_storage_error)?;
}
cache_action = cache_action.insert(
None,
storage_changed_keys,
);
cache_action = cache_action.insert(None, storage_changed_keys);
}
let cache_action = cache_action.complete(block, &root);
@@ -350,20 +369,21 @@ fn prepare_cached_build_data<Number: BlockNumber>(
// because it'll never be used again for building other tries
// => let's clear the cache
if !config.config.is_digest_build_enabled() {
return IncompleteCacheAction::Clear;
return IncompleteCacheAction::Clear
}
// when this is the last block where current configuration is active
// => let's clear the cache
if config.end.as_ref() == Some(&block) {
return IncompleteCacheAction::Clear;
return IncompleteCacheAction::Clear
}
// we do not need to cache anything when top-level digest trie is created, because
// it'll never be used again for building other tries
// => let's clear the cache
match config.config.digest_level_at_block(config.zero.clone(), block) {
Some((digest_level, _, _)) if digest_level == config.config.digest_levels => IncompleteCacheAction::Clear,
Some((digest_level, _, _)) if digest_level == config.config.digest_levels =>
IncompleteCacheAction::Clear,
_ => IncompleteCacheAction::CacheBuildData(IncompleteCachedBuildData::new()),
}
}
@@ -399,6 +419,9 @@ mod tests {
fn cache_is_cleared_when_end_block_of_configuration_is_built() {
let config = Configuration { digest_interval: 8, digest_levels: 2 };
let config_range = ConfigurationRange { zero: 0, end: Some(4u32), config: &config };
assert_eq!(prepare_cached_build_data(config_range.clone(), 4u32), IncompleteCacheAction::Clear);
assert_eq!(
prepare_cached_build_data(config_range.clone(), 4u32),
IncompleteCacheAction::Clear
);
}
}
@@ -17,16 +17,20 @@
//! Changes trie pruning-related functions.
use crate::{
changes_trie::{
input::{ChildIndex, InputKey},
storage::TrieBackendAdapter,
AnchorBlockId, BlockNumber, Storage,
},
proving_backend::ProvingBackendRecorder,
trie_backend_essence::TrieBackendEssence,
};
use codec::{Codec, Decode};
use hash_db::Hasher;
use sp_trie::Recorder;
use log::warn;
use num_traits::One;
use crate::proving_backend::ProvingBackendRecorder;
use crate::trie_backend_essence::TrieBackendEssence;
use crate::changes_trie::{AnchorBlockId, Storage, BlockNumber};
use crate::changes_trie::storage::TrieBackendAdapter;
use crate::changes_trie::input::{ChildIndex, InputKey};
use codec::{Decode, Codec};
use sp_trie::Recorder;
/// Prune obsolete changes tries. Pruning happens at the same block, where highest
/// level digest is created. Pruning guarantees to save changes tries for last
@@ -38,12 +42,14 @@ pub fn prune<H: Hasher, Number: BlockNumber, F: FnMut(H::Out)>(
last: Number,
current_block: &AnchorBlockId<H::Out, Number>,
mut remove_trie_node: F,
) where H::Out: Codec {
) where
H::Out: Codec,
{
// delete changes trie for every block in range
let mut block = first;
loop {
if block >= last.clone() + One::one() {
break;
break
}
let prev_block = block.clone();
@@ -56,7 +62,7 @@ pub fn prune<H: Hasher, Number: BlockNumber, F: FnMut(H::Out)>(
Err(error) => {
// try to delete other tries
warn!(target: "trie", "Failed to read changes trie root from DB: {}", error);
continue;
continue
},
};
let children_roots = {
@@ -91,8 +97,9 @@ fn prune_trie<H: Hasher, Number: BlockNumber, F: FnMut(H::Out)>(
storage: &dyn Storage<H, Number>,
root: H::Out,
remove_trie_node: &mut F,
) where H::Out: Codec {
) where
H::Out: Codec,
{
// enumerate all changes trie' keys, recording all nodes that have been 'touched'
// (effectively - all changes trie nodes)
let mut proof_recorder: Recorder<H::Out> = Default::default();
@@ -113,14 +120,13 @@ fn prune_trie<H: Hasher, Number: BlockNumber, F: FnMut(H::Out)>(
#[cfg(test)]
mod tests {
use std::collections::HashSet;
use sp_trie::MemoryDB;
use sp_core::H256;
use crate::backend::insert_into_memory_db;
use crate::changes_trie::storage::InMemoryStorage;
use codec::Encode;
use sp_runtime::traits::BlakeTwo256;
use super::*;
use crate::{backend::insert_into_memory_db, changes_trie::storage::InMemoryStorage};
use codec::Encode;
use sp_core::H256;
use sp_runtime::traits::BlakeTwo256;
use sp_trie::MemoryDB;
use std::collections::HashSet;
fn prune_by_collect(
storage: &dyn Storage<BlakeTwo256, u64>,
@@ -130,8 +136,9 @@ mod tests {
) -> HashSet<H256> {
let mut pruned_trie_nodes = HashSet::new();
let anchor = AnchorBlockId { hash: Default::default(), number: current_block };
prune(storage, first, last, &anchor,
|node| { pruned_trie_nodes.insert(node); });
prune(storage, first, last, &anchor, |node| {
pruned_trie_nodes.insert(node);
});
pruned_trie_nodes
}
@@ -139,28 +146,36 @@ mod tests {
fn prune_works() {
fn prepare_storage() -> InMemoryStorage<BlakeTwo256, u64> {
let child_info = sp_core::storage::ChildInfo::new_default(&b"1"[..]);
let child_key = ChildIndex { block: 67u64, storage_key: child_info.prefixed_storage_key() }.encode();
let child_key =
ChildIndex { block: 67u64, storage_key: child_info.prefixed_storage_key() }
.encode();
let mut mdb1 = MemoryDB::<BlakeTwo256>::default();
let root1 = insert_into_memory_db::<BlakeTwo256, _>(
&mut mdb1, vec![(vec![10], vec![20])]).unwrap();
let root1 =
insert_into_memory_db::<BlakeTwo256, _>(&mut mdb1, vec![(vec![10], vec![20])])
.unwrap();
let mut mdb2 = MemoryDB::<BlakeTwo256>::default();
let root2 = insert_into_memory_db::<BlakeTwo256, _>(
&mut mdb2,
vec![(vec![11], vec![21]), (vec![12], vec![22])],
).unwrap();
)
.unwrap();
let mut mdb3 = MemoryDB::<BlakeTwo256>::default();
let ch_root3 = insert_into_memory_db::<BlakeTwo256, _>(
&mut mdb3, vec![(vec![110], vec![120])]).unwrap();
let root3 = insert_into_memory_db::<BlakeTwo256, _>(&mut mdb3, vec![
(vec![13], vec![23]),
(vec![14], vec![24]),
(child_key, ch_root3.as_ref().encode()),
]).unwrap();
let ch_root3 =
insert_into_memory_db::<BlakeTwo256, _>(&mut mdb3, vec![(vec![110], vec![120])])
.unwrap();
let root3 = insert_into_memory_db::<BlakeTwo256, _>(
&mut mdb3,
vec![
(vec![13], vec![23]),
(vec![14], vec![24]),
(child_key, ch_root3.as_ref().encode()),
],
)
.unwrap();
let mut mdb4 = MemoryDB::<BlakeTwo256>::default();
let root4 = insert_into_memory_db::<BlakeTwo256, _>(
&mut mdb4,
vec![(vec![15], vec![25])],
).unwrap();
let root4 =
insert_into_memory_db::<BlakeTwo256, _>(&mut mdb4, vec![(vec![15], vec![25])])
.unwrap();
let storage = InMemoryStorage::new();
storage.insert(65, root1, mdb1);
storage.insert(66, root2, mdb2);
@@ -17,22 +17,21 @@
//! Changes trie storage utilities.
use std::collections::{BTreeMap, HashSet, HashMap};
use hash_db::{Hasher, Prefix, EMPTY_PREFIX};
use sp_core::storage::PrefixedStorageKey;
use sp_trie::DBValue;
use sp_trie::MemoryDB;
use parking_lot::RwLock;
use crate::{
StorageKey,
changes_trie::{AnchorBlockId, BlockNumber, BuildCache, RootsStorage, Storage},
trie_backend_essence::TrieBackendStorage,
changes_trie::{BuildCache, RootsStorage, Storage, AnchorBlockId, BlockNumber},
StorageKey,
};
use hash_db::{Hasher, Prefix, EMPTY_PREFIX};
use parking_lot::RwLock;
use sp_core::storage::PrefixedStorageKey;
use sp_trie::{DBValue, MemoryDB};
use std::collections::{BTreeMap, HashMap, HashSet};
#[cfg(test)]
use crate::backend::insert_into_memory_db;
#[cfg(test)]
use crate::changes_trie::input::{InputPair, ChildIndex};
use crate::changes_trie::input::{ChildIndex, InputPair};
/// In-memory implementation of changes trie storage.
pub struct InMemoryStorage<H: Hasher, Number: BlockNumber> {
@@ -55,10 +54,7 @@ impl<H: Hasher, Number: BlockNumber> InMemoryStorage<H, Number> {
/// Creates storage from given in-memory database.
pub fn with_db(mdb: MemoryDB<H>) -> Self {
Self {
data: RwLock::new(InMemoryStorageData {
roots: BTreeMap::new(),
mdb,
}),
data: RwLock::new(InMemoryStorageData { roots: BTreeMap::new(), mdb }),
cache: BuildCache::new(),
}
}
@@ -72,7 +68,7 @@ impl<H: Hasher, Number: BlockNumber> InMemoryStorage<H, Number> {
pub fn with_proof(proof: Vec<Vec<u8>>) -> Self {
use hash_db::HashDB;
let mut proof_db = MemoryDB::<H>::default();
let mut proof_db = MemoryDB::<H>::default();
for item in proof {
proof_db.insert(EMPTY_PREFIX, &item);
}
@@ -104,7 +100,8 @@ impl<H: Hasher, Number: BlockNumber> InMemoryStorage<H, Number> {
let mut roots = BTreeMap::new();
for (storage_key, child_input) in children_inputs {
for (block, pairs) in child_input {
let root = insert_into_memory_db::<H, _>(&mut mdb, pairs.into_iter().map(Into::into));
let root =
insert_into_memory_db::<H, _>(&mut mdb, pairs.into_iter().map(Into::into));
if let Some(root) = root {
let ix = if let Some(ix) = top_inputs.iter().position(|v| v.0 == block) {
@@ -129,17 +126,14 @@ impl<H: Hasher, Number: BlockNumber> InMemoryStorage<H, Number> {
}
InMemoryStorage {
data: RwLock::new(InMemoryStorageData {
roots,
mdb,
}),
data: RwLock::new(InMemoryStorageData { roots, mdb }),
cache: BuildCache::new(),
}
}
#[cfg(test)]
pub fn clear_storage(&self) {
self.data.write().mdb = MemoryDB::default(); // use new to be more correct
self.data.write().mdb = MemoryDB::default(); // use new to be more correct
}
#[cfg(test)]
@@ -165,13 +159,20 @@ impl<H: Hasher, Number: BlockNumber> InMemoryStorage<H, Number> {
impl<H: Hasher, Number: BlockNumber> RootsStorage<H, Number> for InMemoryStorage<H, Number> {
fn build_anchor(&self, parent_hash: H::Out) -> Result<AnchorBlockId<H::Out, Number>, String> {
self.data.read().roots.iter()
self.data
.read()
.roots
.iter()
.find(|(_, v)| **v == parent_hash)
.map(|(k, _)| AnchorBlockId { hash: parent_hash, number: k.clone() })
.ok_or_else(|| format!("Can't find associated number for block {:?}", parent_hash))
}
fn root(&self, _anchor_block: &AnchorBlockId<H::Out, Number>, block: Number) -> Result<Option<H::Out>, String> {
fn root(
&self,
_anchor_block: &AnchorBlockId<H::Out, Number>,
block: Number,
) -> Result<Option<H::Out>, String> {
Ok(self.data.read().roots.get(&block).cloned())
}
}
@@ -201,9 +202,9 @@ impl<'a, H: Hasher, Number: BlockNumber> TrieBackendAdapter<'a, H, Number> {
}
impl<'a, H, Number> TrieBackendStorage<H> for TrieBackendAdapter<'a, H, Number>
where
Number: BlockNumber,
H: Hasher,
where
Number: BlockNumber,
H: Hasher,
{
type Overlay = MemoryDB<H>;
@@ -21,8 +21,8 @@
//! of points at the terrain (mountains and valleys) inside this range that have to be drilled down to
//! search for gems.
use crate::changes_trie::{BlockNumber, ConfigurationRange};
use num_traits::One;
use crate::changes_trie::{ConfigurationRange, BlockNumber};
/// Returns surface iterator for given range of blocks.
///
@@ -34,12 +34,8 @@ pub fn surface_iterator<'a, Number: BlockNumber>(
begin: Number,
end: Number,
) -> Result<SurfaceIterator<'a, Number>, String> {
let (current, current_begin, digest_step, digest_level) = lower_bound_max_digest(
config.clone(),
max.clone(),
begin.clone(),
end,
)?;
let (current, current_begin, digest_step, digest_level) =
lower_bound_max_digest(config.clone(), max.clone(), begin.clone(), end)?;
Ok(SurfaceIterator {
config,
begin,
@@ -89,7 +85,8 @@ impl<'a, Number: BlockNumber> Iterator for SurfaceIterator<'a, Number> {
self.begin.clone(),
next,
);
let (current, current_begin, digest_step, digest_level) = match max_digest_interval {
let (current, current_begin, digest_step, digest_level) = match max_digest_interval
{
Err(err) => return Some(Err(err)),
Ok(range) => range,
};
@@ -114,14 +111,21 @@ fn lower_bound_max_digest<'a, Number: BlockNumber>(
end: Number,
) -> Result<(Number, Number, u32, Option<u32>), String> {
if end > max || begin > end {
return Err(format!("invalid changes range: {}..{}/{}", begin, end, max));
return Err(format!("invalid changes range: {}..{}/{}", begin, end, max))
}
if begin <= config.zero || config.end.as_ref().map(|config_end| end > *config_end).unwrap_or(false) {
return Err(format!("changes trie range is not covered by configuration: {}..{}/{}..{}",
begin, end, config.zero, match config.end.as_ref() {
if begin <= config.zero ||
config.end.as_ref().map(|config_end| end > *config_end).unwrap_or(false)
{
return Err(format!(
"changes trie range is not covered by configuration: {}..{}/{}..{}",
begin,
end,
config.zero,
match config.end.as_ref() {
Some(config_end) => format!("{}", config_end),
None => "None".into(),
}));
}
))
}
let mut digest_level = 0u32;
@@ -135,10 +139,16 @@ fn lower_bound_max_digest<'a, Number: BlockNumber>(
let new_digest_level = digest_level + 1;
let new_digest_step = digest_step * config.config.digest_interval;
let new_digest_interval = config.config.digest_interval * {
if digest_interval == 0 { 1 } else { digest_interval }
if digest_interval == 0 {
1
} else {
digest_interval
}
};
let new_digest_begin = config.zero.clone() + ((current.clone() - One::one() - config.zero.clone())
/ new_digest_interval.into()) * new_digest_interval.into();
let new_digest_begin = config.zero.clone() +
((current.clone() - One::one() - config.zero.clone()) /
new_digest_interval.into()) *
new_digest_interval.into();
let new_digest_end = new_digest_begin.clone() + new_digest_interval.into();
let new_current = new_digest_begin.clone() + new_digest_interval.into();
@@ -150,16 +160,20 @@ fn lower_bound_max_digest<'a, Number: BlockNumber>(
skewed_digest_end.clone(),
);
if let Some(skewed_digest_start) = skewed_digest_start {
let skewed_digest_range = (skewed_digest_end.clone() - skewed_digest_start.clone())
.try_into().ok()
.expect("skewed digest range is always <= max level digest range;\
max level digest range always fits u32; qed");
let skewed_digest_range = (skewed_digest_end.clone() -
skewed_digest_start.clone())
.try_into()
.ok()
.expect(
"skewed digest range is always <= max level digest range;\
max level digest range always fits u32; qed",
);
return Ok((
skewed_digest_end.clone(),
skewed_digest_start,
skewed_digest_range,
None,
));
))
}
}
}
@@ -169,7 +183,7 @@ fn lower_bound_max_digest<'a, Number: BlockNumber>(
if begin < new_digest_begin {
current_begin = new_digest_begin;
}
break;
break
}
// we can (and will) use this digest
@@ -181,30 +195,24 @@ fn lower_bound_max_digest<'a, Number: BlockNumber>(
// if current digest covers the whole range => no need to use next level digest
if current_begin <= begin && new_digest_end >= end {
break;
break
}
}
}
Ok((
current,
current_begin,
digest_step,
Some(digest_level),
))
Ok((current, current_begin, digest_step, Some(digest_level)))
}
#[cfg(test)]
mod tests {
use crate::changes_trie::{Configuration};
use super::*;
use crate::changes_trie::Configuration;
fn configuration_range<'a>(config: &'a Configuration, zero: u64) -> ConfigurationRange<'a, u64> {
ConfigurationRange {
config,
zero,
end: None,
}
fn configuration_range<'a>(
config: &'a Configuration,
zero: u64,
) -> ConfigurationRange<'a, u64> {
ConfigurationRange { config, zero, end: None }
}
#[test]
@@ -213,13 +221,15 @@ mod tests {
// when config activates at 0
assert_eq!(
lower_bound_max_digest(configuration_range(&config, 0u64), 100_000u64, 20u64, 180u64).unwrap(),
lower_bound_max_digest(configuration_range(&config, 0u64), 100_000u64, 20u64, 180u64)
.unwrap(),
(192, 176, 16, Some(2)),
);
// when config activates at 30
assert_eq!(
lower_bound_max_digest(configuration_range(&config, 30u64), 100_000u64, 50u64, 210u64).unwrap(),
lower_bound_max_digest(configuration_range(&config, 30u64), 100_000u64, 50u64, 210u64)
.unwrap(),
(222, 206, 16, Some(2)),
);
}
@@ -230,40 +240,61 @@ mod tests {
// when config activates at 0
assert_eq!(
surface_iterator(
configuration_range(&config, 0u64),
100_000u64,
40u64,
180u64,
).unwrap().collect::<Vec<_>>(),
surface_iterator(configuration_range(&config, 0u64), 100_000u64, 40u64, 180u64,)
.unwrap()
.collect::<Vec<_>>(),
vec![
Ok((192, Some(2))), Ok((176, Some(2))), Ok((160, Some(2))), Ok((144, Some(2))),
Ok((128, Some(2))), Ok((112, Some(2))), Ok((96, Some(2))), Ok((80, Some(2))),
Ok((64, Some(2))), Ok((48, Some(2))),
Ok((192, Some(2))),
Ok((176, Some(2))),
Ok((160, Some(2))),
Ok((144, Some(2))),
Ok((128, Some(2))),
Ok((112, Some(2))),
Ok((96, Some(2))),
Ok((80, Some(2))),
Ok((64, Some(2))),
Ok((48, Some(2))),
],
);
// when config activates at 30
assert_eq!(
surface_iterator(
configuration_range(&config, 30u64),
100_000u64,
40u64,
180u64,
).unwrap().collect::<Vec<_>>(),
surface_iterator(configuration_range(&config, 30u64), 100_000u64, 40u64, 180u64,)
.unwrap()
.collect::<Vec<_>>(),
vec![
Ok((190, Some(2))), Ok((174, Some(2))), Ok((158, Some(2))), Ok((142, Some(2))), Ok((126, Some(2))),
Ok((110, Some(2))), Ok((94, Some(2))), Ok((78, Some(2))), Ok((62, Some(2))), Ok((46, Some(2))),
Ok((190, Some(2))),
Ok((174, Some(2))),
Ok((158, Some(2))),
Ok((142, Some(2))),
Ok((126, Some(2))),
Ok((110, Some(2))),
Ok((94, Some(2))),
Ok((78, Some(2))),
Ok((62, Some(2))),
Ok((46, Some(2))),
],
);
// when config activates at 0 AND max block is before next digest
assert_eq!(
surface_iterator(configuration_range(&config, 0u64), 183u64, 40u64, 183u64).unwrap().collect::<Vec<_>>(),
surface_iterator(configuration_range(&config, 0u64), 183u64, 40u64, 183u64)
.unwrap()
.collect::<Vec<_>>(),
vec![
Ok((183, Some(0))), Ok((182, Some(0))), Ok((181, Some(0))), Ok((180, Some(1))),
Ok((176, Some(2))), Ok((160, Some(2))), Ok((144, Some(2))), Ok((128, Some(2))), Ok((112, Some(2))),
Ok((96, Some(2))), Ok((80, Some(2))), Ok((64, Some(2))), Ok((48, Some(2))),
Ok((183, Some(0))),
Ok((182, Some(0))),
Ok((181, Some(0))),
Ok((180, Some(1))),
Ok((176, Some(2))),
Ok((160, Some(2))),
Ok((144, Some(2))),
Ok((128, Some(2))),
Ok((112, Some(2))),
Ok((96, Some(2))),
Ok((80, Some(2))),
Ok((64, Some(2))),
Ok((48, Some(2))),
],
);
}
@@ -276,10 +307,19 @@ mod tests {
// when config activates at 0 AND ends at 170
config_range.end = Some(170);
assert_eq!(
surface_iterator(config_range, 100_000u64, 40u64, 170u64).unwrap().collect::<Vec<_>>(),
surface_iterator(config_range, 100_000u64, 40u64, 170u64)
.unwrap()
.collect::<Vec<_>>(),
vec![
Ok((170, None)), Ok((160, Some(2))), Ok((144, Some(2))), Ok((128, Some(2))), Ok((112, Some(2))),
Ok((96, Some(2))), Ok((80, Some(2))), Ok((64, Some(2))), Ok((48, Some(2))),
Ok((170, None)),
Ok((160, Some(2))),
Ok((144, Some(2))),
Ok((128, Some(2))),
Ok((112, Some(2))),
Ok((96, Some(2))),
Ok((80, Some(2))),
Ok((64, Some(2))),
Ok((48, Some(2))),
],
);
}