tp_state_machine/changes_trie/
changes_iterator.rs

1// This file is part of Tetcore.
2
3// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! Functions + iterator that traverses changes tries and returns all
19//! (block, extrinsic) pairs where given key has been changed.
20
21use std::cell::RefCell;
22use std::collections::VecDeque;
23use codec::{Decode, Encode, Codec};
24use tetsy_hash_db::Hasher;
25use num_traits::Zero;
26use tet_core::storage::PrefixedStorageKey;
27use tp_trie::Recorder;
28use crate::changes_trie::{AnchorBlockId, ConfigurationRange, RootsStorage, Storage, BlockNumber};
29use crate::changes_trie::input::{DigestIndex, ExtrinsicIndex, DigestIndexValue, ExtrinsicIndexValue};
30use crate::changes_trie::storage::{TrieBackendAdapter, InMemoryStorage};
31use crate::changes_trie::input::ChildIndex;
32use crate::changes_trie::surface_iterator::{surface_iterator, SurfaceIterator};
33use crate::proving_backend::ProvingBackendRecorder;
34use crate::trie_backend_essence::{TrieBackendEssence};
35
36/// Return changes of given key at given blocks range.
37/// `max` is the number of best known block.
38/// Changes are returned in descending order (i.e. last block comes first).
39pub fn key_changes<'a, H: Hasher, Number: BlockNumber>(
40	config: ConfigurationRange<'a, Number>,
41	storage: &'a dyn Storage<H, Number>,
42	begin: Number,
43	end: &'a AnchorBlockId<H::Out, Number>,
44	max: Number,
45	storage_key: Option<&'a PrefixedStorageKey>,
46	key: &'a [u8],
47) -> Result<DrilldownIterator<'a, H, Number>, String> {
48	// we can't query any roots before root
49	let max = std::cmp::min(max, end.number.clone());
50
51	Ok(DrilldownIterator {
52		essence: DrilldownIteratorEssence {
53			storage_key,
54			key,
55			roots_storage: storage.as_roots_storage(),
56			storage,
57			begin: begin.clone(),
58			end,
59			config: config.clone(),
60			surface: surface_iterator(
61				config,
62				max,
63				begin,
64				end.number.clone(),
65			)?,
66
67			extrinsics: Default::default(),
68			blocks: Default::default(),
69
70			_hasher: ::std::marker::PhantomData::<H>::default(),
71		},
72	})
73}
74
75
76/// Returns proof of changes of given key at given blocks range.
77/// `max` is the number of best known block.
78pub fn key_changes_proof<'a, H: Hasher, Number: BlockNumber>(
79	config: ConfigurationRange<'a, Number>,
80	storage: &dyn Storage<H, Number>,
81	begin: Number,
82	end: &AnchorBlockId<H::Out, Number>,
83	max: Number,
84	storage_key: Option<&PrefixedStorageKey>,
85	key: &[u8],
86) -> Result<Vec<Vec<u8>>, String> where H::Out: Codec {
87	// we can't query any roots before root
88	let max = std::cmp::min(max, end.number.clone());
89
90	let mut iter = ProvingDrilldownIterator {
91		essence: DrilldownIteratorEssence {
92			storage_key,
93			key,
94			roots_storage: storage.as_roots_storage(),
95			storage,
96			begin: begin.clone(),
97			end,
98			config: config.clone(),
99			surface: surface_iterator(
100				config,
101				max,
102				begin,
103				end.number.clone(),
104			)?,
105
106			extrinsics: Default::default(),
107			blocks: Default::default(),
108
109			_hasher: ::std::marker::PhantomData::<H>::default(),
110		},
111		proof_recorder: Default::default(),
112	};
113
114	// iterate to collect proof
115	while let Some(item) = iter.next() {
116		item?;
117	}
118
119	Ok(iter.extract_proof())
120}
121
122/// Check key changes proof and return changes of the key at given blocks range.
123/// `max` is the number of best known block.
124/// Changes are returned in descending order (i.e. last block comes first).
125pub fn key_changes_proof_check<'a, H: Hasher, Number: BlockNumber>(
126	config: ConfigurationRange<'a, Number>,
127	roots_storage: &dyn RootsStorage<H, Number>,
128	proof: Vec<Vec<u8>>,
129	begin: Number,
130	end: &AnchorBlockId<H::Out, Number>,
131	max: Number,
132	storage_key: Option<&PrefixedStorageKey>,
133	key: &[u8]
134) -> Result<Vec<(Number, u32)>, String> where H::Out: Encode {
135	key_changes_proof_check_with_db(
136		config,
137		roots_storage,
138		&InMemoryStorage::with_proof(proof),
139		begin,
140		end,
141		max,
142		storage_key,
143		key,
144	)
145}
146
147/// Similar to the `key_changes_proof_check` function, but works with prepared proof storage.
148pub fn key_changes_proof_check_with_db<'a, H: Hasher, Number: BlockNumber>(
149	config: ConfigurationRange<'a, Number>,
150	roots_storage: &dyn RootsStorage<H, Number>,
151	proof_db: &InMemoryStorage<H, Number>,
152	begin: Number,
153	end: &AnchorBlockId<H::Out, Number>,
154	max: Number,
155	storage_key: Option<&PrefixedStorageKey>,
156	key: &[u8]
157) -> Result<Vec<(Number, u32)>, String> where H::Out: Encode {
158	// we can't query any roots before root
159	let max = std::cmp::min(max, end.number.clone());
160
161	DrilldownIterator {
162		essence: DrilldownIteratorEssence {
163			storage_key,
164			key,
165			roots_storage,
166			storage: proof_db,
167			begin: begin.clone(),
168			end,
169			config: config.clone(),
170			surface: surface_iterator(
171				config,
172				max,
173				begin,
174				end.number.clone(),
175			)?,
176
177			extrinsics: Default::default(),
178			blocks: Default::default(),
179
180			_hasher: ::std::marker::PhantomData::<H>::default(),
181		},
182	}.collect()
183}
184
185/// Drilldown iterator - receives 'digest points' from surface iterator and explores
186/// every point until extrinsic is found.
187pub struct DrilldownIteratorEssence<'a, H, Number>
188	where
189		H: Hasher,
190		Number: BlockNumber,
191		H::Out: 'a,
192{
193	storage_key: Option<&'a PrefixedStorageKey>,
194	key: &'a [u8],
195	roots_storage: &'a dyn RootsStorage<H, Number>,
196	storage: &'a dyn Storage<H, Number>,
197	begin: Number,
198	end: &'a AnchorBlockId<H::Out, Number>,
199	config: ConfigurationRange<'a, Number>,
200	surface: SurfaceIterator<'a, Number>,
201
202	extrinsics: VecDeque<(Number, u32)>,
203	blocks: VecDeque<(Number, Option<u32>)>,
204
205	_hasher: ::std::marker::PhantomData<H>,
206}
207
208impl<'a, H, Number> DrilldownIteratorEssence<'a, H, Number>
209	where
210		H: Hasher,
211		Number: BlockNumber,
212		H::Out: 'a,
213{
214	pub fn next<F>(&mut self, trie_reader: F) -> Option<Result<(Number, u32), String>>
215		where
216			F: FnMut(&dyn Storage<H, Number>, H::Out, &[u8]) -> Result<Option<Vec<u8>>, String>,
217	{
218		match self.do_next(trie_reader) {
219			Ok(Some(res)) => Some(Ok(res)),
220			Ok(None) => None,
221			Err(err) => Some(Err(err)),
222		}
223	}
224
225	fn do_next<F>(&mut self, mut trie_reader: F) -> Result<Option<(Number, u32)>, String>
226		where
227			F: FnMut(&dyn Storage<H, Number>, H::Out, &[u8]) -> Result<Option<Vec<u8>>, String>,
228	{
229		loop {
230			if let Some((block, extrinsic)) = self.extrinsics.pop_front() {
231				return Ok(Some((block, extrinsic)));
232			}
233
234			if let Some((block, level)) = self.blocks.pop_front() {
235				// not having a changes trie root is an error because:
236				// we never query roots for future blocks
237				// AND trie roots for old blocks are known (both on full + light node)
238				let trie_root = self.roots_storage.root(&self.end, block.clone())?
239					.ok_or_else(|| format!("Changes trie root for block {} is not found", block.clone()))?;
240				let trie_root = if let Some(storage_key) = self.storage_key {
241					let child_key = ChildIndex {
242						block: block.clone(),
243						storage_key: storage_key.clone(),
244					}.encode();
245					if let Some(trie_root) = trie_reader(self.storage, trie_root, &child_key)?
246						.and_then(|v| <Vec<u8>>::decode(&mut &v[..]).ok())
247						.map(|v| {
248							let mut hash = H::Out::default();
249							hash.as_mut().copy_from_slice(&v[..]);
250							hash
251						}) {
252						trie_root
253					} else {
254						continue;
255					}
256				} else {
257					trie_root
258				};
259
260				// only return extrinsics for blocks before self.max
261				// most of blocks will be filtered out before pushing to `self.blocks`
262				// here we just throwing away changes at digest blocks we're processing
263				debug_assert!(block >= self.begin, "We shall not touch digests earlier than a range' begin");
264				if block <= self.end.number {
265					let extrinsics_key = ExtrinsicIndex { block: block.clone(), key: self.key.to_vec() }.encode();
266					let extrinsics = trie_reader(self.storage, trie_root, &extrinsics_key);
267					if let Some(extrinsics) = extrinsics? {
268						if let Ok(extrinsics) = ExtrinsicIndexValue::decode(&mut &extrinsics[..]) {
269							self.extrinsics.extend(extrinsics.into_iter().rev().map(|e| (block.clone(), e)));
270						}
271					}
272				}
273
274				let blocks_key = DigestIndex { block: block.clone(), key: self.key.to_vec() }.encode();
275				let blocks = trie_reader(self.storage, trie_root, &blocks_key);
276				if let Some(blocks) = blocks? {
277					if let Ok(blocks) = <DigestIndexValue<Number>>::decode(&mut &blocks[..]) {
278						// filter level0 blocks here because we tend to use digest blocks,
279						// AND digest block changes could also include changes for out-of-range blocks
280						let begin = self.begin.clone();
281						let end = self.end.number.clone();
282						let config = self.config.clone();
283						self.blocks.extend(blocks.into_iter()
284							.rev()
285							.filter(|b| level.map(|level| level > 1).unwrap_or(true) || (*b >= begin && *b <= end))
286							.map(|b| {
287								let prev_level = level
288									.map(|level| Some(level - 1))
289									.unwrap_or_else(||
290										Some(config.config.digest_level_at_block(config.zero.clone(), b.clone())
291											.map(|(level, _, _)| level)
292											.unwrap_or_else(|| Zero::zero())));
293								(b, prev_level)
294							})
295						);
296					}
297				}
298
299				continue;
300			}
301
302			match self.surface.next() {
303				Some(Ok(block)) => self.blocks.push_back(block),
304				Some(Err(err)) => return Err(err),
305				None => return Ok(None),
306			}
307		}
308	}
309}
310
311/// Exploring drilldown operator.
312pub struct DrilldownIterator<'a, H, Number>
313	where
314		Number: BlockNumber,
315		H: Hasher,
316		H::Out: 'a,
317{
318	essence: DrilldownIteratorEssence<'a, H, Number>,
319}
320
321impl<'a, H: Hasher, Number: BlockNumber> Iterator for DrilldownIterator<'a, H, Number>
322	where H::Out: Encode
323{
324	type Item = Result<(Number, u32), String>;
325
326	fn next(&mut self) -> Option<Self::Item> {
327		self.essence.next(|storage, root, key|
328			TrieBackendEssence::<_, H>::new(TrieBackendAdapter::new(storage), root).storage(key))
329	}
330}
331
332/// Proving drilldown iterator.
333struct ProvingDrilldownIterator<'a, H, Number>
334	where
335		Number: BlockNumber,
336		H: Hasher,
337		H::Out: 'a,
338{
339	essence: DrilldownIteratorEssence<'a, H, Number>,
340	proof_recorder: RefCell<Recorder<H::Out>>,
341}
342
343impl<'a, H, Number> ProvingDrilldownIterator<'a, H, Number>
344	where
345		Number: BlockNumber,
346		H: Hasher,
347		H::Out: 'a,
348{
349	/// Consume the iterator, extracting the gathered proof in lexicographical order
350	/// by value.
351	pub fn extract_proof(self) -> Vec<Vec<u8>> {
352		self.proof_recorder.into_inner().drain()
353			.into_iter()
354			.map(|n| n.data.to_vec())
355			.collect()
356	}
357}
358
359impl<'a, H, Number> Iterator for ProvingDrilldownIterator<'a, H, Number>
360	where
361		Number: BlockNumber,
362		H: Hasher,
363		H::Out: 'a + Codec,
364{
365	type Item = Result<(Number, u32), String>;
366
367	fn next(&mut self) -> Option<Self::Item> {
368		let proof_recorder = &mut *self.proof_recorder.try_borrow_mut()
369			.expect("only fails when already borrowed; storage() is non-reentrant; qed");
370		self.essence.next(|storage, root, key|
371			ProvingBackendRecorder::<_, H> {
372				backend: &TrieBackendEssence::new(TrieBackendAdapter::new(storage), root),
373				proof_recorder,
374			}.storage(key))
375	}
376}
377
378#[cfg(test)]
379mod tests {
380	use std::iter::FromIterator;
381	use crate::changes_trie::Configuration;
382	use crate::changes_trie::input::InputPair;
383	use crate::changes_trie::storage::InMemoryStorage;
384	use tp_runtime::traits::BlakeTwo256;
385	use super::*;
386
387	fn child_key() -> PrefixedStorageKey {
388		let child_info = tet_core::storage::ChildInfo::new_default(&b"1"[..]);
389		child_info.prefixed_storage_key()
390	}
391
392	fn prepare_for_drilldown() -> (Configuration, InMemoryStorage<BlakeTwo256, u64>) {
393		let config = Configuration { digest_interval: 4, digest_levels: 2 };
394		let backend = InMemoryStorage::with_inputs(vec![
395			// digest: 1..4 => [(3, 0)]
396			(1, vec![
397			]),
398			(2, vec![
399			]),
400			(3, vec![
401				InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 3, key: vec![42] }, vec![0]),
402			]),
403			(4, vec![
404				InputPair::DigestIndex(DigestIndex { block: 4, key: vec![42] }, vec![3]),
405			]),
406			// digest: 5..8 => [(6, 3), (8, 1+2)]
407			(5, vec![]),
408			(6, vec![
409				InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 6, key: vec![42] }, vec![3]),
410			]),
411			(7, vec![]),
412			(8, vec![
413				InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 8, key: vec![42] }, vec![1, 2]),
414				InputPair::DigestIndex(DigestIndex { block: 8, key: vec![42] }, vec![6]),
415			]),
416			// digest: 9..12 => []
417			(9, vec![]),
418			(10, vec![]),
419			(11, vec![]),
420			(12, vec![]),
421			// digest: 0..16 => [4, 8]
422			(13, vec![]),
423			(14, vec![]),
424			(15, vec![]),
425			(16, vec![
426				InputPair::DigestIndex(DigestIndex { block: 16, key: vec![42] }, vec![4, 8]),
427			]),
428		], vec![(child_key(), vec![
429				(1, vec![
430					InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 1, key: vec![42] }, vec![0]),
431				]),
432				(2, vec![
433					InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 2, key: vec![42] }, vec![3]),
434				]),
435				(16, vec![
436					InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 16, key: vec![42] }, vec![5]),
437
438					InputPair::DigestIndex(DigestIndex { block: 16, key: vec![42] }, vec![2]),
439				]),
440			]),
441		]);
442
443		(config, backend)
444	}
445
446	fn configuration_range<'a>(config: &'a Configuration, zero: u64) -> ConfigurationRange<'a, u64> {
447		ConfigurationRange {
448			config,
449			zero,
450			end: None,
451		}
452	}
453
454	#[test]
455	fn drilldown_iterator_works() {
456		let (config, storage) = prepare_for_drilldown();
457		let drilldown_result = key_changes::<BlakeTwo256, u64>(
458			configuration_range(&config, 0),
459			&storage,
460			1,
461			&AnchorBlockId { hash: Default::default(), number: 16 },
462			16,
463			None,
464			&[42],
465		).and_then(Result::from_iter);
466		assert_eq!(drilldown_result, Ok(vec![(8, 2), (8, 1), (6, 3), (3, 0)]));
467
468		let drilldown_result = key_changes::<BlakeTwo256, u64>(
469			configuration_range(&config, 0),
470			&storage,
471			1,
472			&AnchorBlockId { hash: Default::default(), number: 2 },
473			4,
474			None,
475			&[42],
476		).and_then(Result::from_iter);
477		assert_eq!(drilldown_result, Ok(vec![]));
478
479		let drilldown_result = key_changes::<BlakeTwo256, u64>(
480			configuration_range(&config, 0),
481			&storage,
482			1,
483			&AnchorBlockId { hash: Default::default(), number: 3 },
484			4,
485			None,
486			&[42],
487		).and_then(Result::from_iter);
488		assert_eq!(drilldown_result, Ok(vec![(3, 0)]));
489
490		let drilldown_result = key_changes::<BlakeTwo256, u64>(
491			configuration_range(&config, 0),
492			&storage,
493			1,
494			&AnchorBlockId { hash: Default::default(), number: 7 },
495			7,
496			None,
497			&[42],
498		).and_then(Result::from_iter);
499		assert_eq!(drilldown_result, Ok(vec![(6, 3), (3, 0)]));
500
501		let drilldown_result = key_changes::<BlakeTwo256, u64>(
502			configuration_range(&config, 0),
503			&storage,
504			7,
505			&AnchorBlockId { hash: Default::default(), number: 8 },
506			8,
507			None,
508			&[42],
509		).and_then(Result::from_iter);
510		assert_eq!(drilldown_result, Ok(vec![(8, 2), (8, 1)]));
511
512		let drilldown_result = key_changes::<BlakeTwo256, u64>(
513			configuration_range(&config, 0),
514			&storage,
515			5,
516			&AnchorBlockId { hash: Default::default(), number: 7 },
517			8,
518			None,
519			&[42],
520		).and_then(Result::from_iter);
521		assert_eq!(drilldown_result, Ok(vec![(6, 3)]));
522	}
523
524	#[test]
525	fn drilldown_iterator_fails_when_storage_fails() {
526		let (config, storage) = prepare_for_drilldown();
527		storage.clear_storage();
528
529		assert!(key_changes::<BlakeTwo256, u64>(
530			configuration_range(&config, 0),
531			&storage,
532			1,
533			&AnchorBlockId { hash: Default::default(), number: 100 },
534			1000,
535			None,
536			&[42],
537		).and_then(|i| i.collect::<Result<Vec<_>, _>>()).is_err());
538
539		assert!(key_changes::<BlakeTwo256, u64>(
540			configuration_range(&config, 0),
541			&storage,
542			1,
543			&AnchorBlockId { hash: Default::default(), number: 100 },
544			1000,
545			Some(&child_key()),
546			&[42],
547		).and_then(|i| i.collect::<Result<Vec<_>, _>>()).is_err());
548	}
549
550	#[test]
551	fn drilldown_iterator_fails_when_range_is_invalid() {
552		let (config, storage) = prepare_for_drilldown();
553		assert!(key_changes::<BlakeTwo256, u64>(
554			configuration_range(&config, 0),
555			&storage,
556			1,
557			&AnchorBlockId { hash: Default::default(), number: 100 },
558			50,
559			None,
560			&[42],
561		).is_err());
562		assert!(key_changes::<BlakeTwo256, u64>(
563			configuration_range(&config, 0),
564			&storage,
565			20,
566			&AnchorBlockId { hash: Default::default(), number: 10 },
567			100,
568			None,
569			&[42],
570		).is_err());
571	}
572
573
574	#[test]
575	fn proving_drilldown_iterator_works() {
576		// happens on remote full node:
577
578		// create drilldown iterator that records all trie nodes during drilldown
579		let (remote_config, remote_storage) = prepare_for_drilldown();
580		let remote_proof = key_changes_proof::<BlakeTwo256, u64>(
581			configuration_range(&remote_config, 0), &remote_storage, 1,
582			&AnchorBlockId { hash: Default::default(), number: 16 }, 16, None, &[42]).unwrap();
583
584		let (remote_config, remote_storage) = prepare_for_drilldown();
585		let remote_proof_child = key_changes_proof::<BlakeTwo256, u64>(
586			configuration_range(&remote_config, 0), &remote_storage, 1,
587			&AnchorBlockId { hash: Default::default(), number: 16 }, 16, Some(&child_key()), &[42]).unwrap();
588
589		// happens on local light node:
590
591		// create drilldown iterator that works the same, but only depends on trie
592		let (local_config, local_storage) = prepare_for_drilldown();
593		local_storage.clear_storage();
594		let local_result = key_changes_proof_check::<BlakeTwo256, u64>(
595			configuration_range(&local_config, 0), &local_storage, remote_proof, 1,
596			&AnchorBlockId { hash: Default::default(), number: 16 }, 16, None, &[42]);
597
598		let (local_config, local_storage) = prepare_for_drilldown();
599		local_storage.clear_storage();
600		let local_result_child = key_changes_proof_check::<BlakeTwo256, u64>(
601			configuration_range(&local_config, 0), &local_storage, remote_proof_child, 1,
602			&AnchorBlockId { hash: Default::default(), number: 16 }, 16, Some(&child_key()), &[42]);
603
604		// check that drilldown result is the same as if it was happening at the full node
605		assert_eq!(local_result, Ok(vec![(8, 2), (8, 1), (6, 3), (3, 0)]));
606		assert_eq!(local_result_child, Ok(vec![(16, 5), (2, 3)]));
607	}
608
609	#[test]
610	fn drilldown_iterator_works_with_skewed_digest() {
611		let config = Configuration { digest_interval: 4, digest_levels: 3 };
612		let mut config_range = configuration_range(&config, 0);
613		config_range.end = Some(91);
614
615		// when 4^3 deactivates at block 91:
616		// last L3 digest has been created at block#64
617		// skewed digest covers:
618		// L2 digests at blocks: 80
619		// L1 digests at blocks: 84, 88
620		// regular blocks: 89, 90, 91
621		let mut input = (1u64..92u64).map(|b| (b, vec![])).collect::<Vec<_>>();
622		// changed at block#63 and covered by L3 digest at block#64
623		input[63 - 1].1.push(InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 63, key: vec![42] }, vec![0]));
624		input[64 - 1].1.push(InputPair::DigestIndex(DigestIndex { block: 64, key: vec![42] }, vec![63]));
625		// changed at block#79 and covered by L2 digest at block#80 + skewed digest at block#91
626		input[79 - 1].1.push(InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 79, key: vec![42] }, vec![1]));
627		input[80 - 1].1.push(InputPair::DigestIndex(DigestIndex { block: 80, key: vec![42] }, vec![79]));
628		input[91 - 1].1.push(InputPair::DigestIndex(DigestIndex { block: 91, key: vec![42] }, vec![80]));
629		let storage = InMemoryStorage::with_inputs(input, vec![]);
630
631		let drilldown_result = key_changes::<BlakeTwo256, u64>(
632			config_range,
633			&storage,
634			1,
635			&AnchorBlockId { hash: Default::default(), number: 91 },
636			100_000u64,
637			None,
638			&[42],
639		).and_then(Result::from_iter);
640		assert_eq!(drilldown_result, Ok(vec![(79, 1), (63, 0)]));
641	}
642}