// Copyright 2017-2020 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see .
//! 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 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};
/// Return changes of given key at given blocks range.
/// `max` is the number of best known block.
/// Changes are returned in descending order (i.e. last block comes first).
pub fn key_changes<'a, H: Hasher, Number: BlockNumber>(
config: ConfigurationRange<'a, Number>,
storage: &'a dyn Storage,
begin: Number,
end: &'a AnchorBlockId,
max: Number,
storage_key: Option<&'a PrefixedStorageKey>,
key: &'a [u8],
) -> Result, String> {
// we can't query any roots before root
let max = ::std::cmp::min(max.clone(), end.number.clone());
Ok(DrilldownIterator {
essence: DrilldownIteratorEssence {
storage_key,
key,
roots_storage: storage.as_roots_storage(),
storage,
begin: begin.clone(),
end,
config: config.clone(),
surface: surface_iterator(
config,
max,
begin,
end.number.clone(),
)?,
extrinsics: Default::default(),
blocks: Default::default(),
_hasher: ::std::marker::PhantomData::::default(),
},
})
}
/// 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>(
config: ConfigurationRange<'a, Number>,
storage: &dyn Storage,
begin: Number,
end: &AnchorBlockId,
max: Number,
storage_key: Option<&PrefixedStorageKey>,
key: &[u8],
) -> Result>, String> where H::Out: Codec {
// we can't query any roots before root
let max = ::std::cmp::min(max.clone(), end.number.clone());
let mut iter = ProvingDrilldownIterator {
essence: DrilldownIteratorEssence {
storage_key,
key,
roots_storage: storage.as_roots_storage(),
storage,
begin: begin.clone(),
end,
config: config.clone(),
surface: surface_iterator(
config,
max,
begin,
end.number.clone(),
)?,
extrinsics: Default::default(),
blocks: Default::default(),
_hasher: ::std::marker::PhantomData::::default(),
},
proof_recorder: Default::default(),
};
// iterate to collect proof
while let Some(item) = iter.next() {
item?;
}
Ok(iter.extract_proof())
}
/// Check key changes proof and return changes of the key at given blocks range.
/// `max` is the number of best known block.
/// Changes are returned in descending order (i.e. last block comes first).
pub fn key_changes_proof_check<'a, H: Hasher, Number: BlockNumber>(
config: ConfigurationRange<'a, Number>,
roots_storage: &dyn RootsStorage,
proof: Vec>,
begin: Number,
end: &AnchorBlockId,
max: Number,
storage_key: Option<&PrefixedStorageKey>,
key: &[u8]
) -> Result, String> where H::Out: Encode {
key_changes_proof_check_with_db(
config,
roots_storage,
&InMemoryStorage::with_proof(proof),
begin,
end,
max,
storage_key,
key,
)
}
/// Similar to the `key_changes_proof_check` function, but works with prepared proof storage.
pub fn key_changes_proof_check_with_db<'a, H: Hasher, Number: BlockNumber>(
config: ConfigurationRange<'a, Number>,
roots_storage: &dyn RootsStorage,
proof_db: &InMemoryStorage,
begin: Number,
end: &AnchorBlockId,
max: Number,
storage_key: Option<&PrefixedStorageKey>,
key: &[u8]
) -> Result, String> where H::Out: Encode {
// we can't query any roots before root
let max = ::std::cmp::min(max.clone(), end.number.clone());
DrilldownIterator {
essence: DrilldownIteratorEssence {
storage_key,
key,
roots_storage,
storage: proof_db,
begin: begin.clone(),
end,
config: config.clone(),
surface: surface_iterator(
config,
max,
begin,
end.number.clone(),
)?,
extrinsics: Default::default(),
blocks: Default::default(),
_hasher: ::std::marker::PhantomData::::default(),
},
}.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,
{
storage_key: Option<&'a PrefixedStorageKey>,
key: &'a [u8],
roots_storage: &'a dyn RootsStorage,
storage: &'a dyn Storage,
begin: Number,
end: &'a AnchorBlockId,
config: ConfigurationRange<'a, Number>,
surface: SurfaceIterator<'a, Number>,
extrinsics: VecDeque<(Number, u32)>,
blocks: VecDeque<(Number, Option)>,
_hasher: ::std::marker::PhantomData,
}
impl<'a, H, Number> DrilldownIteratorEssence<'a, H, Number>
where
H: Hasher,
Number: BlockNumber,
H::Out: 'a,
{
pub fn next(&mut self, trie_reader: F) -> Option>
where
F: FnMut(&dyn Storage, H::Out, &[u8]) -> Result