mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-09 20:11:09 +00:00
Allow updating configuration of changes tries (#3201)
* DigestItem::ChangesTrieSignal * introduce changes_trie::State * introduce config activation block * ChangesTrieSignal::as_new_configuration * moved well_known_cache_keys to client * extracted DbChangesTrieStorage to separate file * change meaning of none in blockchain cache * changes trie config (FULL) cache draft * eliminating const ChangesTrieConfiguration * delay pruning * continue elimination * do not prune CT config from cache * removed redundant code * fix some TODOs * introduce ConfigurationRange * use Configuration range in build * build skewed digest * remove debug print * extracted surface iterator * key_changes works with skewed digests * fix client build * add test for NeverPrune * fix TODO * fixed some TODOs * more tests * fixing TODOs * fixed compilation * update runtime version * git rid of large tuple * too long lines * config_activation_block -> zero * obsolete TODO * removed unjustified expect * update TODOs with issue number * new CT pruning algorithm fixed cache + multiple blocks finalization track CT configuraiton on light clients support CT configuration change revert revert CT config test new CT pruning algorithm fixed cache + multiple blocks finalization track CT configuraiton on light clients support CT configuration change revert revert CT config test * BlockIdOrHeader isn't really required * removed debug leftovers + some docs * more docs * more post-merge fixes * more post-merge fixes * revertes some unnecessary changes * reverted unnecessary changes * fix compilation + unnecessary changes * (restart CI) * fix cache update when finalizing multiple blocks * fixed tests * collect_extrinsics -> set_collect_extrinsics * restore lost test * do not calculate block number twice * Update primitives/blockchain/src/error.rs Co-Authored-By: cheme <emericchevalier.pro@gmail.com> * map_err -> unwrap_or * document get_at Result * delete abandoned file * added weight for set_changes_trie_config * prefer_configs -> fail_if_disabled * Update client/api/src/backend.rs Co-Authored-By: cheme <emericchevalier.pro@gmail.com> * Update client/db/src/changes_tries_storage.rs Co-Authored-By: cheme <emericchevalier.pro@gmail.com> * CommitOperation+merge -> CommitOperations * fixed test compilation * merged two different CTRange structs * lost file * uggrade db from v0 to v1 (init CT cache + add column) * fix after merge Co-authored-by: cheme <emericchevalier.pro@gmail.com> Co-authored-by: Gavin Wood <github@gavwood.com>
This commit is contained in:
committed by
Gavin Wood
parent
45fbf09dac
commit
febf29390a
@@ -17,7 +17,7 @@
|
||||
use std::{sync::Arc, panic::UnwindSafe, result, cell::RefCell};
|
||||
use codec::{Encode, Decode};
|
||||
use sp_runtime::{
|
||||
generic::BlockId, traits::{Block as BlockT, HasherFor},
|
||||
generic::BlockId, traits::{Block as BlockT, HasherFor, NumberFor},
|
||||
};
|
||||
use sp_state_machine::{
|
||||
self, OverlayedChanges, Ext, ExecutionManager, StateMachine, ExecutionStrategy,
|
||||
@@ -80,7 +80,7 @@ where
|
||||
let state = self.backend.state_at(*id)?;
|
||||
let return_data = StateMachine::new(
|
||||
&state,
|
||||
self.backend.changes_trie_storage(),
|
||||
backend::changes_tries_state_at_block(id, self.backend.changes_trie_storage())?,
|
||||
&mut changes,
|
||||
&self.executor,
|
||||
method,
|
||||
@@ -132,6 +132,7 @@ where
|
||||
}
|
||||
|
||||
let mut state = self.backend.state_at(*at)?;
|
||||
let changes_trie_state = backend::changes_tries_state_at_block(at, self.backend.changes_trie_storage())?;
|
||||
|
||||
let mut storage_transaction_cache = storage_transaction_cache.map(|c| c.borrow_mut());
|
||||
|
||||
@@ -150,7 +151,7 @@ where
|
||||
|
||||
StateMachine::new(
|
||||
&backend,
|
||||
self.backend.changes_trie_storage(),
|
||||
changes_trie_state,
|
||||
&mut *changes.borrow_mut(),
|
||||
&self.executor,
|
||||
method,
|
||||
@@ -163,7 +164,7 @@ where
|
||||
}
|
||||
None => StateMachine::new(
|
||||
&state,
|
||||
self.backend.changes_trie_storage(),
|
||||
changes_trie_state,
|
||||
&mut *changes.borrow_mut(),
|
||||
&self.executor,
|
||||
method,
|
||||
@@ -183,13 +184,13 @@ where
|
||||
fn runtime_version(&self, id: &BlockId<Block>) -> sp_blockchain::Result<RuntimeVersion> {
|
||||
let mut overlay = OverlayedChanges::default();
|
||||
let state = self.backend.state_at(*id)?;
|
||||
let changes_trie_state = backend::changes_tries_state_at_block(id, self.backend.changes_trie_storage())?;
|
||||
let mut cache = StorageTransactionCache::<Block, B::State>::default();
|
||||
|
||||
let mut ext = Ext::new(
|
||||
&mut overlay,
|
||||
&mut cache,
|
||||
&state,
|
||||
self.backend.changes_trie_storage(),
|
||||
changes_trie_state,
|
||||
None,
|
||||
);
|
||||
let version = self.executor.runtime_version(&mut ext);
|
||||
@@ -207,7 +208,7 @@ where
|
||||
method: &str,
|
||||
call_data: &[u8]
|
||||
) -> Result<(Vec<u8>, StorageProof), sp_blockchain::Error> {
|
||||
sp_state_machine::prove_execution_on_trie_backend(
|
||||
sp_state_machine::prove_execution_on_trie_backend::<_, _, NumberFor<Block>, _>(
|
||||
trie_state,
|
||||
overlay,
|
||||
&self.executor,
|
||||
|
||||
+230
-76
@@ -66,6 +66,7 @@ pub use sc_client_api::{
|
||||
backend::{
|
||||
self, BlockImportOperation, PrunableStateChangesTrieStorage,
|
||||
ClientImportOperation, Finalizer, ImportSummary, NewBlockState,
|
||||
changes_tries_state_at_block,
|
||||
},
|
||||
client::{
|
||||
ImportNotifications, FinalityNotification, FinalityNotifications, BlockImportNotification,
|
||||
@@ -407,18 +408,26 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
|
||||
first: NumberFor<Block>,
|
||||
last: BlockId<Block>,
|
||||
) -> sp_blockchain::Result<Option<(NumberFor<Block>, BlockId<Block>)>> {
|
||||
let (config, storage) = match self.require_changes_trie().ok() {
|
||||
Some((config, storage)) => (config, storage),
|
||||
None => return Ok(None),
|
||||
};
|
||||
let last_num = self.backend.blockchain().expect_block_number_from_id(&last)?;
|
||||
if first > last_num {
|
||||
let last_number = self.backend.blockchain().expect_block_number_from_id(&last)?;
|
||||
let last_hash = self.backend.blockchain().expect_block_hash_from_id(&last)?;
|
||||
if first > last_number {
|
||||
return Err(sp_blockchain::Error::ChangesTrieAccessFailed("Invalid changes trie range".into()));
|
||||
}
|
||||
let finalized_number = self.backend.blockchain().info().finalized_number;
|
||||
let oldest = storage.oldest_changes_trie_block(&config, finalized_number);
|
||||
let first = ::std::cmp::max(first, oldest);
|
||||
Ok(Some((first, last)))
|
||||
|
||||
let (storage, configs) = match self.require_changes_trie(first, last_hash, false).ok() {
|
||||
Some((storage, configs)) => (storage, configs),
|
||||
None => return Ok(None),
|
||||
};
|
||||
|
||||
let first_available_changes_trie = configs.last().map(|config| config.0);
|
||||
match first_available_changes_trie {
|
||||
Some(first_available_changes_trie) => {
|
||||
let oldest_unpruned = storage.oldest_pruned_digest_range_end();
|
||||
let first = std::cmp::max(first_available_changes_trie, oldest_unpruned);
|
||||
Ok(Some((first, last)))
|
||||
},
|
||||
None => Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
/// Get pairs of (block, extrinsic) where key has been changed at given blocks range.
|
||||
@@ -432,30 +441,42 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
|
||||
storage_key: Option<&StorageKey>,
|
||||
key: &StorageKey
|
||||
) -> sp_blockchain::Result<Vec<(NumberFor<Block>, u32)>> {
|
||||
let (config, storage) = self.require_changes_trie()?;
|
||||
let last_number = self.backend.blockchain().expect_block_number_from_id(&last)?;
|
||||
let last_hash = self.backend.blockchain().expect_block_hash_from_id(&last)?;
|
||||
let (storage, configs) = self.require_changes_trie(first, last_hash, true)?;
|
||||
|
||||
// FIXME: remove this in https://github.com/paritytech/substrate/pull/3201
|
||||
let config_range = ChangesTrieConfigurationRange {
|
||||
config: &config,
|
||||
zero: Zero::zero(),
|
||||
end: None,
|
||||
};
|
||||
let mut result = Vec::new();
|
||||
let best_number = self.backend.blockchain().info().best_number;
|
||||
for (config_zero, config_end, config) in configs {
|
||||
let range_first = ::std::cmp::max(first, config_zero + One::one());
|
||||
let range_anchor = match config_end {
|
||||
Some((config_end_number, config_end_hash)) => if last_number > config_end_number {
|
||||
ChangesTrieAnchorBlockId { hash: config_end_hash, number: config_end_number }
|
||||
} else {
|
||||
ChangesTrieAnchorBlockId { hash: convert_hash(&last_hash), number: last_number }
|
||||
},
|
||||
None => ChangesTrieAnchorBlockId { hash: convert_hash(&last_hash), number: last_number },
|
||||
};
|
||||
|
||||
key_changes::<HasherFor<Block>, _>(
|
||||
config_range,
|
||||
&*storage,
|
||||
first,
|
||||
&ChangesTrieAnchorBlockId {
|
||||
hash: convert_hash(&last_hash),
|
||||
number: last_number,
|
||||
},
|
||||
self.backend.blockchain().info().best_number,
|
||||
storage_key.as_ref().map(|sk| sk.0.as_slice()),
|
||||
&key.0)
|
||||
.and_then(|r| r.map(|r| r.map(|(block, tx)| (block, tx))).collect::<Result<_, _>>())
|
||||
.map_err(|err| sp_blockchain::Error::ChangesTrieAccessFailed(err))
|
||||
let config_range = ChangesTrieConfigurationRange {
|
||||
config: &config,
|
||||
zero: config_zero.clone(),
|
||||
end: config_end.map(|(config_end_number, _)| config_end_number),
|
||||
};
|
||||
let result_range: Vec<(NumberFor<Block>, u32)> = key_changes::<HasherFor<Block>, _>(
|
||||
config_range,
|
||||
storage.storage(),
|
||||
range_first,
|
||||
&range_anchor,
|
||||
best_number,
|
||||
storage_key.as_ref().map(|x| &x.0[..]),
|
||||
&key.0)
|
||||
.and_then(|r| r.map(|r| r.map(|(block, tx)| (block, tx))).collect::<Result<_, _>>())
|
||||
.map_err(|err| sp_blockchain::Error::ChangesTrieAccessFailed(err))?;
|
||||
result.extend(result_range);
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
/// Get proof for computation of (block, extrinsic) pairs where key has been changed at given blocks range.
|
||||
@@ -550,11 +571,13 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
|
||||
}
|
||||
}
|
||||
|
||||
let (config, storage) = self.require_changes_trie()?;
|
||||
let first_number = self.backend.blockchain()
|
||||
.expect_block_number_from_id(&BlockId::Hash(first))?;
|
||||
let (storage, configs) = self.require_changes_trie(first_number, last, true)?;
|
||||
let min_number = self.backend.blockchain().expect_block_number_from_id(&BlockId::Hash(min))?;
|
||||
|
||||
let recording_storage = AccessedRootsRecorder::<Block> {
|
||||
storage,
|
||||
storage: storage.storage(),
|
||||
min: min_number,
|
||||
required_roots_proofs: Mutex::new(BTreeMap::new()),
|
||||
};
|
||||
@@ -564,31 +587,31 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
|
||||
self.backend.blockchain().expect_block_number_from_id(&BlockId::Hash(max))?,
|
||||
);
|
||||
|
||||
// FIXME: remove this in https://github.com/paritytech/substrate/pull/3201
|
||||
let config_range = ChangesTrieConfigurationRange {
|
||||
config: &config,
|
||||
zero: Zero::zero(),
|
||||
end: None,
|
||||
};
|
||||
|
||||
// fetch key changes proof
|
||||
let first_number = self.backend.blockchain()
|
||||
.expect_block_number_from_id(&BlockId::Hash(first))?;
|
||||
let last_number = self.backend.blockchain()
|
||||
.expect_block_number_from_id(&BlockId::Hash(last))?;
|
||||
let key_changes_proof = key_changes_proof::<HasherFor<Block>, _>(
|
||||
config_range,
|
||||
&recording_storage,
|
||||
first_number,
|
||||
&ChangesTrieAnchorBlockId {
|
||||
hash: convert_hash(&last),
|
||||
number: last_number,
|
||||
},
|
||||
max_number,
|
||||
storage_key.as_ref().map(|sk| sk.0.as_slice()),
|
||||
&key.0,
|
||||
)
|
||||
.map_err(|err| sp_blockchain::Error::from(sp_blockchain::Error::ChangesTrieAccessFailed(err)))?;
|
||||
let mut proof = Vec::new();
|
||||
for (config_zero, config_end, config) in configs {
|
||||
let last_number = self.backend.blockchain()
|
||||
.expect_block_number_from_id(&BlockId::Hash(last))?;
|
||||
let config_range = ChangesTrieConfigurationRange {
|
||||
config: &config,
|
||||
zero: config_zero,
|
||||
end: config_end.map(|(config_end_number, _)| config_end_number),
|
||||
};
|
||||
let proof_range = key_changes_proof::<HasherFor<Block>, _>(
|
||||
config_range,
|
||||
&recording_storage,
|
||||
first_number,
|
||||
&ChangesTrieAnchorBlockId {
|
||||
hash: convert_hash(&last),
|
||||
number: last_number,
|
||||
},
|
||||
max_number,
|
||||
storage_key.as_ref().map(|x| &x.0[..]),
|
||||
&key.0,
|
||||
)
|
||||
.map_err(|err| sp_blockchain::Error::ChangesTrieAccessFailed(err))?;
|
||||
proof.extend(proof_range);
|
||||
}
|
||||
|
||||
// now gather proofs for all changes tries roots that were touched during key_changes_proof
|
||||
// execution AND are unknown (i.e. replaced with CHT) to the requester
|
||||
@@ -597,7 +620,7 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
|
||||
|
||||
Ok(ChangesProof {
|
||||
max_block: max_number,
|
||||
proof: key_changes_proof,
|
||||
proof,
|
||||
roots: roots.into_iter().map(|(n, h)| (n, convert_hash(&h))).collect(),
|
||||
roots_proof,
|
||||
})
|
||||
@@ -650,14 +673,45 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
|
||||
Ok(proof)
|
||||
}
|
||||
|
||||
/// Returns changes trie configuration and storage or an error if it is not supported.
|
||||
fn require_changes_trie(&self) -> sp_blockchain::Result<(ChangesTrieConfiguration, &B::ChangesTrieStorage)> {
|
||||
let config = self.changes_trie_config()?;
|
||||
let storage = self.backend.changes_trie_storage();
|
||||
match (config, storage) {
|
||||
(Some(config), Some(storage)) => Ok((config, storage)),
|
||||
_ => Err(sp_blockchain::Error::ChangesTriesNotSupported.into()),
|
||||
/// Returns changes trie storage and all configurations that have been active in the range [first; last].
|
||||
///
|
||||
/// Configurations are returned in descending order (and obviously never overlap).
|
||||
/// If fail_if_disabled is false, returns maximal consequent configurations ranges, starting from last and
|
||||
/// stopping on either first, or when CT have been disabled.
|
||||
/// If fail_if_disabled is true, fails when there's a subrange where CT have been disabled
|
||||
/// inside first..last blocks range.
|
||||
fn require_changes_trie(
|
||||
&self,
|
||||
first: NumberFor<Block>,
|
||||
last: Block::Hash,
|
||||
fail_if_disabled: bool,
|
||||
) -> sp_blockchain::Result<(
|
||||
&dyn PrunableStateChangesTrieStorage<Block>,
|
||||
Vec<(NumberFor<Block>, Option<(NumberFor<Block>, Block::Hash)>, ChangesTrieConfiguration)>,
|
||||
)> {
|
||||
let storage = match self.backend.changes_trie_storage() {
|
||||
Some(storage) => storage,
|
||||
None => return Err(sp_blockchain::Error::ChangesTriesNotSupported),
|
||||
};
|
||||
|
||||
let mut configs = Vec::with_capacity(1);
|
||||
let mut current = last;
|
||||
loop {
|
||||
let config_range = storage.configuration_at(&BlockId::Hash(current))?;
|
||||
match config_range.config {
|
||||
Some(config) => configs.push((config_range.zero.0, config_range.end, config)),
|
||||
None if !fail_if_disabled => return Ok((storage, configs)),
|
||||
None => return Err(sp_blockchain::Error::ChangesTriesNotSupported),
|
||||
}
|
||||
|
||||
if config_range.zero.0 < first {
|
||||
break;
|
||||
}
|
||||
|
||||
current = *self.backend.blockchain().expect_header(BlockId::Hash(config_range.zero.1))?.parent_hash();
|
||||
}
|
||||
|
||||
Ok((storage, configs))
|
||||
}
|
||||
|
||||
/// Create a new block, built on the head of the chain.
|
||||
@@ -988,10 +1042,14 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
|
||||
)?;
|
||||
|
||||
let state = self.backend.state_at(at)?;
|
||||
let changes_trie_state = changes_tries_state_at_block(
|
||||
&at,
|
||||
self.backend.changes_trie_storage(),
|
||||
)?;
|
||||
|
||||
let gen_storage_changes = runtime_api.into_storage_changes(
|
||||
&state,
|
||||
self.backend.changes_trie_storage(),
|
||||
changes_trie_state.as_ref(),
|
||||
*parent_hash,
|
||||
);
|
||||
|
||||
@@ -1249,13 +1307,6 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
|
||||
Ok(uncles)
|
||||
}
|
||||
|
||||
fn changes_trie_config(&self) -> Result<Option<ChangesTrieConfiguration>, Error> {
|
||||
Ok(self.backend.state_at(BlockId::Number(self.backend.blockchain().info().best_number))?
|
||||
.storage(well_known_keys::CHANGES_TRIE_CONFIG)
|
||||
.map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))?
|
||||
.and_then(|c| Decode::decode(&mut &*c).ok()))
|
||||
}
|
||||
|
||||
/// Prepare in-memory header that is used in execution environment.
|
||||
fn prepare_environment_block(&self, parent: &BlockId<Block>) -> sp_blockchain::Result<Block::Header> {
|
||||
let parent_header = self.backend.blockchain().expect_header(*parent)?;
|
||||
@@ -1871,7 +1922,8 @@ pub(crate) mod tests {
|
||||
|
||||
// prepare client ang import blocks
|
||||
let mut local_roots = Vec::new();
|
||||
let mut remote_client = TestClientBuilder::new().set_support_changes_trie(true).build();
|
||||
let config = Some(ChangesTrieConfiguration::new(4, 2));
|
||||
let mut remote_client = TestClientBuilder::new().changes_trie_config(config).build();
|
||||
let mut nonces: HashMap<_, u64> = Default::default();
|
||||
for (i, block_transfers) in blocks_transfers.into_iter().enumerate() {
|
||||
let mut builder = remote_client.new_block(Default::default()).unwrap();
|
||||
@@ -2907,13 +2959,15 @@ pub(crate) mod tests {
|
||||
.unwrap().build().unwrap().block;
|
||||
client.import(BlockOrigin::Own, b2.clone()).unwrap();
|
||||
|
||||
// prepare B3 before we finalize A2, because otherwise we won't be able to
|
||||
// read changes trie configuration after A2 is finalized
|
||||
let b3 = client.new_block_at(&BlockId::Hash(b2.hash()), Default::default(), false)
|
||||
.unwrap().build().unwrap().block;
|
||||
|
||||
// we will finalize A2 which should make it impossible to import a new
|
||||
// B3 at the same height but that doesnt't include it
|
||||
ClientExt::finalize_block(&client, BlockId::Hash(a2.hash()), None).unwrap();
|
||||
|
||||
let b3 = client.new_block_at(&BlockId::Hash(b2.hash()), Default::default(), false)
|
||||
.unwrap().build().unwrap().block;
|
||||
|
||||
let import_err = client.import(BlockOrigin::Own, b3).err().unwrap();
|
||||
let expected_err = ConsensusError::ClientImport(
|
||||
sp_blockchain::Error::NotInFinalizedChain.to_string()
|
||||
@@ -3050,4 +3104,104 @@ pub(crate) mod tests {
|
||||
check_block_b1.parent_hash = H256::random();
|
||||
assert_eq!(client.check_block(check_block_b1.clone()).unwrap(), ImportResult::UnknownParent);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn imports_blocks_with_changes_tries_config_change() {
|
||||
// create client with initial 4^2 configuration
|
||||
let mut client = TestClientBuilder::with_default_backend()
|
||||
.changes_trie_config(Some(ChangesTrieConfiguration {
|
||||
digest_interval: 4,
|
||||
digest_levels: 2,
|
||||
})).build();
|
||||
|
||||
// ===================================================================
|
||||
// blocks 1,2,3,4,5,6,7,8,9,10 are empty
|
||||
// block 11 changes the key
|
||||
// block 12 is the L1 digest that covers this change
|
||||
// blocks 13,14,15,16,17,18,19,20,21,22 are empty
|
||||
// block 23 changes the configuration to 5^1 AND is skewed digest
|
||||
// ===================================================================
|
||||
// blocks 24,25 are changing the key
|
||||
// block 26 is empty
|
||||
// block 27 changes the key
|
||||
// block 28 is the L1 digest (NOT SKEWED!!!) that covers changes AND changes configuration to 3^1
|
||||
// ===================================================================
|
||||
// block 29 is empty
|
||||
// block 30 changes the key
|
||||
// block 31 is L1 digest that covers this change
|
||||
// ===================================================================
|
||||
(1..11).for_each(|number| {
|
||||
let block = client.new_block_at(&BlockId::Number(number - 1), Default::default(), false)
|
||||
.unwrap().build().unwrap().block;
|
||||
client.import(BlockOrigin::Own, block).unwrap();
|
||||
});
|
||||
(11..12).for_each(|number| {
|
||||
let mut block = client.new_block_at(&BlockId::Number(number - 1), Default::default(), false).unwrap();
|
||||
block.push_storage_change(vec![42], Some(number.to_le_bytes().to_vec())).unwrap();
|
||||
let block = block.build().unwrap().block;
|
||||
client.import(BlockOrigin::Own, block).unwrap();
|
||||
});
|
||||
(12..23).for_each(|number| {
|
||||
let block = client.new_block_at(&BlockId::Number(number - 1), Default::default(), false)
|
||||
.unwrap().build().unwrap().block;
|
||||
client.import(BlockOrigin::Own, block).unwrap();
|
||||
});
|
||||
(23..24).for_each(|number| {
|
||||
let mut block = client.new_block_at(&BlockId::Number(number - 1), Default::default(), false).unwrap();
|
||||
block.push_changes_trie_configuration_update(Some(ChangesTrieConfiguration {
|
||||
digest_interval: 5,
|
||||
digest_levels: 1,
|
||||
})).unwrap();
|
||||
let block = block.build().unwrap().block;
|
||||
client.import(BlockOrigin::Own, block).unwrap();
|
||||
});
|
||||
(24..26).for_each(|number| {
|
||||
let mut block = client.new_block_at(&BlockId::Number(number - 1), Default::default(), false).unwrap();
|
||||
block.push_storage_change(vec![42], Some(number.to_le_bytes().to_vec())).unwrap();
|
||||
let block = block.build().unwrap().block;
|
||||
client.import(BlockOrigin::Own, block).unwrap();
|
||||
});
|
||||
(26..27).for_each(|number| {
|
||||
let block = client.new_block_at(&BlockId::Number(number - 1), Default::default(), false)
|
||||
.unwrap().build().unwrap().block;
|
||||
client.import(BlockOrigin::Own, block).unwrap();
|
||||
});
|
||||
(27..28).for_each(|number| {
|
||||
let mut block = client.new_block_at(&BlockId::Number(number - 1), Default::default(), false).unwrap();
|
||||
block.push_storage_change(vec![42], Some(number.to_le_bytes().to_vec())).unwrap();
|
||||
let block = block.build().unwrap().block;
|
||||
client.import(BlockOrigin::Own, block).unwrap();
|
||||
});
|
||||
(28..29).for_each(|number| {
|
||||
let mut block = client.new_block_at(&BlockId::Number(number - 1), Default::default(), false).unwrap();
|
||||
block.push_changes_trie_configuration_update(Some(ChangesTrieConfiguration {
|
||||
digest_interval: 3,
|
||||
digest_levels: 1,
|
||||
})).unwrap();
|
||||
let block = block.build().unwrap().block;
|
||||
client.import(BlockOrigin::Own, block).unwrap();
|
||||
});
|
||||
(29..30).for_each(|number| {
|
||||
let block = client.new_block_at(&BlockId::Number(number - 1), Default::default(), false)
|
||||
.unwrap().build().unwrap().block;
|
||||
client.import(BlockOrigin::Own, block).unwrap();
|
||||
});
|
||||
(30..31).for_each(|number| {
|
||||
let mut block = client.new_block_at(&BlockId::Number(number - 1), Default::default(), false).unwrap();
|
||||
block.push_storage_change(vec![42], Some(number.to_le_bytes().to_vec())).unwrap();
|
||||
let block = block.build().unwrap().block;
|
||||
client.import(BlockOrigin::Own, block).unwrap();
|
||||
});
|
||||
(31..32).for_each(|number| {
|
||||
let block = client.new_block_at(&BlockId::Number(number - 1), Default::default(), false)
|
||||
.unwrap().build().unwrap().block;
|
||||
client.import(BlockOrigin::Own, block).unwrap();
|
||||
});
|
||||
|
||||
// now check that configuration cache works
|
||||
assert_eq!(
|
||||
client.key_changes(1, BlockId::Number(31), None, &StorageKey(vec![42])).unwrap(),
|
||||
vec![(30, 0), (27, 0), (25, 0), (24, 0), (11, 0)]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ mod tests {
|
||||
use codec::{Encode, Decode, Joiner};
|
||||
use sc_executor::native_executor_instance;
|
||||
use sp_state_machine::{
|
||||
StateMachine, OverlayedChanges, ExecutionStrategy, InMemoryChangesTrieStorage,
|
||||
StateMachine, OverlayedChanges, ExecutionStrategy,
|
||||
InMemoryBackend,
|
||||
};
|
||||
use substrate_test_runtime_client::{
|
||||
@@ -92,7 +92,7 @@ mod tests {
|
||||
|
||||
StateMachine::new(
|
||||
backend,
|
||||
Some(&InMemoryChangesTrieStorage::<_, u64>::new()),
|
||||
sp_state_machine::disabled_changes_trie_state::<_, u64>(),
|
||||
&mut overlay,
|
||||
&executor(),
|
||||
"Core_initialize_block",
|
||||
@@ -105,7 +105,7 @@ mod tests {
|
||||
for tx in transactions.iter() {
|
||||
StateMachine::new(
|
||||
backend,
|
||||
Some(&InMemoryChangesTrieStorage::<_, u64>::new()),
|
||||
sp_state_machine::disabled_changes_trie_state::<_, u64>(),
|
||||
&mut overlay,
|
||||
&executor(),
|
||||
"BlockBuilder_apply_extrinsic",
|
||||
@@ -118,7 +118,7 @@ mod tests {
|
||||
|
||||
let ret_data = StateMachine::new(
|
||||
backend,
|
||||
Some(&InMemoryChangesTrieStorage::<_, u64>::new()),
|
||||
sp_state_machine::disabled_changes_trie_state::<_, u64>(),
|
||||
&mut overlay,
|
||||
&executor(),
|
||||
"BlockBuilder_finalize_block",
|
||||
@@ -150,7 +150,7 @@ mod tests {
|
||||
#[test]
|
||||
fn construct_genesis_should_work_with_native() {
|
||||
let mut storage = GenesisConfig::new(
|
||||
false,
|
||||
None,
|
||||
vec![Sr25519Keyring::One.public().into(), Sr25519Keyring::Two.public().into()],
|
||||
vec![AccountKeyring::One.into(), AccountKeyring::Two.into()],
|
||||
1000,
|
||||
@@ -165,7 +165,7 @@ mod tests {
|
||||
let mut overlay = OverlayedChanges::default();
|
||||
let _ = StateMachine::new(
|
||||
&backend,
|
||||
Some(&InMemoryChangesTrieStorage::<_, u64>::new()),
|
||||
sp_state_machine::disabled_changes_trie_state::<_, u64>(),
|
||||
&mut overlay,
|
||||
&executor(),
|
||||
"Core_execute_block",
|
||||
@@ -178,7 +178,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn construct_genesis_should_work_with_wasm() {
|
||||
let mut storage = GenesisConfig::new(false,
|
||||
let mut storage = GenesisConfig::new(None,
|
||||
vec![Sr25519Keyring::One.public().into(), Sr25519Keyring::Two.public().into()],
|
||||
vec![AccountKeyring::One.into(), AccountKeyring::Two.into()],
|
||||
1000,
|
||||
@@ -193,7 +193,7 @@ mod tests {
|
||||
let mut overlay = OverlayedChanges::default();
|
||||
let _ = StateMachine::new(
|
||||
&backend,
|
||||
Some(&InMemoryChangesTrieStorage::<_, u64>::new()),
|
||||
sp_state_machine::disabled_changes_trie_state::<_, u64>(),
|
||||
&mut overlay,
|
||||
&executor(),
|
||||
"Core_execute_block",
|
||||
@@ -206,7 +206,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn construct_genesis_with_bad_transaction_should_panic() {
|
||||
let mut storage = GenesisConfig::new(false,
|
||||
let mut storage = GenesisConfig::new(None,
|
||||
vec![Sr25519Keyring::One.public().into(), Sr25519Keyring::Two.public().into()],
|
||||
vec![AccountKeyring::One.into(), AccountKeyring::Two.into()],
|
||||
68,
|
||||
@@ -221,7 +221,7 @@ mod tests {
|
||||
let mut overlay = OverlayedChanges::default();
|
||||
let r = StateMachine::new(
|
||||
&backend,
|
||||
Some(&InMemoryChangesTrieStorage::<_, u64>::new()),
|
||||
sp_state_machine::disabled_changes_trie_state::<_, u64>(),
|
||||
&mut overlay,
|
||||
&executor(),
|
||||
"Core_execute_block",
|
||||
|
||||
@@ -16,22 +16,17 @@
|
||||
|
||||
//! In memory client backend
|
||||
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use parking_lot::RwLock;
|
||||
use sp_core::{ChangesTrieConfiguration, storage::well_known_keys};
|
||||
use sp_core::storage::well_known_keys;
|
||||
use sp_core::offchain::storage::{
|
||||
InMemOffchainStorage as OffchainStorage
|
||||
};
|
||||
use sp_runtime::generic::{BlockId, DigestItem};
|
||||
use sp_runtime::generic::BlockId;
|
||||
use sp_runtime::traits::{Block as BlockT, Header as HeaderT, Zero, NumberFor, HasherFor};
|
||||
use sp_runtime::{Justification, Storage};
|
||||
use sp_state_machine::{
|
||||
InMemoryChangesTrieStorage, ChangesTrieAnchorBlockId, ChangesTrieTransaction,
|
||||
InMemoryBackend, Backend as StateBackend,
|
||||
};
|
||||
use hash_db::Prefix;
|
||||
use sp_trie::MemoryDB;
|
||||
use sp_state_machine::{ChangesTrieTransaction, InMemoryBackend, Backend as StateBackend};
|
||||
use sp_blockchain::{CachedHeaderMetadata, HeaderMetadata};
|
||||
|
||||
use sc_client_api::{
|
||||
@@ -466,7 +461,6 @@ pub struct BlockImportOperation<Block: BlockT> {
|
||||
pending_cache: HashMap<CacheKeyId, Vec<u8>>,
|
||||
old_state: InMemoryBackend<HasherFor<Block>>,
|
||||
new_state: Option<InMemoryBackend<HasherFor<Block>>>,
|
||||
changes_trie_update: Option<MemoryDB<HasherFor<Block>>>,
|
||||
aux: Vec<(Vec<u8>, Option<Vec<u8>>)>,
|
||||
finalized_blocks: Vec<(BlockId<Block>, Option<Justification>)>,
|
||||
set_head: Option<BlockId<Block>>,
|
||||
@@ -510,9 +504,8 @@ impl<Block: BlockT> backend::BlockImportOperation<Block> for BlockImportOperatio
|
||||
|
||||
fn update_changes_trie(
|
||||
&mut self,
|
||||
update: ChangesTrieTransaction<HasherFor<Block>, NumberFor<Block>>,
|
||||
_update: ChangesTrieTransaction<HasherFor<Block>, NumberFor<Block>>,
|
||||
) -> sp_blockchain::Result<()> {
|
||||
self.changes_trie_update = Some(update.0);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -569,7 +562,6 @@ impl<Block: BlockT> backend::BlockImportOperation<Block> for BlockImportOperatio
|
||||
/// > struct for testing purposes. Do **NOT** use in production.
|
||||
pub struct Backend<Block: BlockT> where Block::Hash: Ord {
|
||||
states: RwLock<HashMap<Block::Hash, InMemoryBackend<HasherFor<Block>>>>,
|
||||
changes_trie_storage: ChangesTrieStorage<Block>,
|
||||
blockchain: Blockchain<Block>,
|
||||
import_lock: RwLock<()>,
|
||||
}
|
||||
@@ -579,7 +571,6 @@ impl<Block: BlockT> Backend<Block> where Block::Hash: Ord {
|
||||
pub fn new() -> Self {
|
||||
Backend {
|
||||
states: RwLock::new(HashMap::new()),
|
||||
changes_trie_storage: ChangesTrieStorage(InMemoryChangesTrieStorage::new()),
|
||||
blockchain: Blockchain::new(),
|
||||
import_lock: Default::default(),
|
||||
}
|
||||
@@ -606,7 +597,6 @@ impl<Block: BlockT> backend::Backend<Block> for Backend<Block> where Block::Hash
|
||||
type BlockImportOperation = BlockImportOperation<Block>;
|
||||
type Blockchain = Blockchain<Block>;
|
||||
type State = InMemoryBackend<HasherFor<Block>>;
|
||||
type ChangesTrieStorage = ChangesTrieStorage<Block>;
|
||||
type OffchainStorage = OffchainStorage;
|
||||
|
||||
fn begin_operation(&self) -> sp_blockchain::Result<Self::BlockImportOperation> {
|
||||
@@ -616,7 +606,6 @@ impl<Block: BlockT> backend::Backend<Block> for Backend<Block> where Block::Hash
|
||||
pending_cache: Default::default(),
|
||||
old_state,
|
||||
new_state: None,
|
||||
changes_trie_update: None,
|
||||
aux: Default::default(),
|
||||
finalized_blocks: Default::default(),
|
||||
set_head: None,
|
||||
@@ -647,17 +636,6 @@ impl<Block: BlockT> backend::Backend<Block> for Backend<Block> where Block::Hash
|
||||
|
||||
self.states.write().insert(hash, operation.new_state.unwrap_or_else(|| old_state.clone()));
|
||||
|
||||
let maybe_changes_trie_root = header.digest().log(DigestItem::as_changes_trie_root).cloned();
|
||||
if let Some(changes_trie_root) = maybe_changes_trie_root {
|
||||
if let Some(changes_trie_update) = operation.changes_trie_update {
|
||||
self.changes_trie_storage.0.insert(
|
||||
*header.number(),
|
||||
changes_trie_root,
|
||||
changes_trie_update
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
self.blockchain.insert(hash, header, justification, body, pending_block.state)?;
|
||||
}
|
||||
|
||||
@@ -688,8 +666,8 @@ impl<Block: BlockT> backend::Backend<Block> for Backend<Block> where Block::Hash
|
||||
None
|
||||
}
|
||||
|
||||
fn changes_trie_storage(&self) -> Option<&Self::ChangesTrieStorage> {
|
||||
Some(&self.changes_trie_storage)
|
||||
fn changes_trie_storage(&self) -> Option<&dyn backend::PrunableStateChangesTrieStorage<Block>> {
|
||||
None
|
||||
}
|
||||
|
||||
fn offchain_storage(&self) -> Option<Self::OffchainStorage> {
|
||||
@@ -737,66 +715,6 @@ impl<Block: BlockT> backend::RemoteBackend<Block> for Backend<Block> where Block
|
||||
}
|
||||
}
|
||||
|
||||
/// Prunable in-memory changes trie storage.
|
||||
pub struct ChangesTrieStorage<Block: BlockT>(
|
||||
InMemoryChangesTrieStorage<HasherFor<Block>, NumberFor<Block>>
|
||||
);
|
||||
|
||||
impl<Block: BlockT> backend::PrunableStateChangesTrieStorage<Block> for ChangesTrieStorage<Block> {
|
||||
fn oldest_changes_trie_block(
|
||||
&self,
|
||||
_config: &ChangesTrieConfiguration,
|
||||
_best_finalized: NumberFor<Block>,
|
||||
) -> NumberFor<Block> {
|
||||
Zero::zero()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Block: BlockT> sp_state_machine::ChangesTrieRootsStorage<HasherFor<Block>, NumberFor<Block>> for
|
||||
ChangesTrieStorage<Block>
|
||||
{
|
||||
fn build_anchor(
|
||||
&self,
|
||||
_hash: Block::Hash,
|
||||
) -> Result<sp_state_machine::ChangesTrieAnchorBlockId<Block::Hash, NumberFor<Block>>, String> {
|
||||
Err("Dummy implementation".into())
|
||||
}
|
||||
|
||||
fn root(
|
||||
&self,
|
||||
_anchor: &ChangesTrieAnchorBlockId<Block::Hash, NumberFor<Block>>,
|
||||
_block: NumberFor<Block>,
|
||||
) -> Result<Option<Block::Hash>, String> {
|
||||
Err("Dummy implementation".into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<Block: BlockT> sp_state_machine::ChangesTrieStorage<HasherFor<Block>, NumberFor<Block>> for
|
||||
ChangesTrieStorage<Block>
|
||||
{
|
||||
fn as_roots_storage(&self)
|
||||
-> &dyn sp_state_machine::ChangesTrieRootsStorage<HasherFor<Block>, NumberFor<Block>>
|
||||
{
|
||||
self
|
||||
}
|
||||
|
||||
fn with_cached_changed_keys(
|
||||
&self,
|
||||
_root: &Block::Hash,
|
||||
_functor: &mut dyn FnMut(&HashMap<Option<Vec<u8>>, HashSet<Vec<u8>>>),
|
||||
) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn get(
|
||||
&self,
|
||||
key: &Block::Hash,
|
||||
prefix: Prefix,
|
||||
) -> Result<Option<sp_state_machine::DBValue>, String> {
|
||||
self.0.get(key, prefix)
|
||||
}
|
||||
}
|
||||
|
||||
/// Check that genesis storage is valid.
|
||||
pub fn check_genesis_storage(storage: &Storage) -> sp_blockchain::Result<()> {
|
||||
if storage.top.iter().any(|(k, _)| well_known_keys::is_child_storage_key(k)) {
|
||||
|
||||
@@ -21,19 +21,22 @@ use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use parking_lot::RwLock;
|
||||
|
||||
use sp_core::storage::{ChildInfo, OwnedChildInfo};
|
||||
use codec::{Decode, Encode};
|
||||
|
||||
use sp_core::ChangesTrieConfiguration;
|
||||
use sp_core::storage::{well_known_keys, ChildInfo, OwnedChildInfo};
|
||||
use sp_core::offchain::storage::InMemOffchainStorage;
|
||||
use sp_state_machine::{
|
||||
Backend as StateBackend, TrieBackend, InMemoryBackend, ChangesTrieTransaction
|
||||
};
|
||||
use sp_runtime::{generic::BlockId, Justification, Storage};
|
||||
use sp_runtime::traits::{Block as BlockT, NumberFor, Zero, Header, HasherFor};
|
||||
use crate::in_mem::{self, check_genesis_storage};
|
||||
use crate::in_mem::check_genesis_storage;
|
||||
use sp_blockchain::{Error as ClientError, Result as ClientResult};
|
||||
use sc_client_api::{
|
||||
backend::{
|
||||
AuxStore, Backend as ClientBackend, BlockImportOperation, RemoteBackend, NewBlockState,
|
||||
StorageCollection, ChildStorageCollection,
|
||||
StorageCollection, ChildStorageCollection, PrunableStateChangesTrieStorage,
|
||||
},
|
||||
blockchain::{
|
||||
HeaderBackend as BlockchainHeaderBackend, well_known_cache_keys,
|
||||
@@ -62,6 +65,7 @@ pub struct ImportOperation<Block: BlockT, S> {
|
||||
finalized_blocks: Vec<BlockId<Block>>,
|
||||
set_head: Option<BlockId<Block>>,
|
||||
storage_update: Option<InMemoryBackend<HasherFor<Block>>>,
|
||||
changes_trie_config_update: Option<Option<ChangesTrieConfiguration>>,
|
||||
_phantom: std::marker::PhantomData<S>,
|
||||
}
|
||||
|
||||
@@ -115,7 +119,6 @@ impl<S, Block> ClientBackend<Block> for Backend<S, HasherFor<Block>>
|
||||
type BlockImportOperation = ImportOperation<Block, S>;
|
||||
type Blockchain = Blockchain<S>;
|
||||
type State = GenesisOrUnavailableState<HasherFor<Block>>;
|
||||
type ChangesTrieStorage = in_mem::ChangesTrieStorage<Block>;
|
||||
type OffchainStorage = InMemOffchainStorage;
|
||||
|
||||
fn begin_operation(&self) -> ClientResult<Self::BlockImportOperation> {
|
||||
@@ -127,6 +130,7 @@ impl<S, Block> ClientBackend<Block> for Backend<S, HasherFor<Block>>
|
||||
finalized_blocks: Vec::new(),
|
||||
set_head: None,
|
||||
storage_update: None,
|
||||
changes_trie_config_update: None,
|
||||
_phantom: Default::default(),
|
||||
})
|
||||
}
|
||||
@@ -148,6 +152,9 @@ impl<S, Block> ClientBackend<Block> for Backend<S, HasherFor<Block>>
|
||||
|
||||
if let Some(header) = operation.header {
|
||||
let is_genesis_import = header.number().is_zero();
|
||||
if let Some(new_config) = operation.changes_trie_config_update {
|
||||
operation.cache.insert(well_known_cache_keys::CHANGES_TRIE_CONFIG, new_config.encode());
|
||||
}
|
||||
self.blockchain.storage().import_header(
|
||||
header,
|
||||
operation.cache,
|
||||
@@ -194,7 +201,7 @@ impl<S, Block> ClientBackend<Block> for Backend<S, HasherFor<Block>>
|
||||
self.blockchain.storage().usage_info()
|
||||
}
|
||||
|
||||
fn changes_trie_storage(&self) -> Option<&Self::ChangesTrieStorage> {
|
||||
fn changes_trie_storage(&self) -> Option<&dyn PrunableStateChangesTrieStorage<Block>> {
|
||||
None
|
||||
}
|
||||
|
||||
@@ -296,6 +303,13 @@ impl<S, Block> BlockImportOperation<Block> for ImportOperation<Block, S>
|
||||
fn reset_storage(&mut self, input: Storage) -> ClientResult<Block::Hash> {
|
||||
check_genesis_storage(&input)?;
|
||||
|
||||
// changes trie configuration
|
||||
let changes_trie_config = input.top.iter()
|
||||
.find(|(k, _)| &k[..] == well_known_keys::CHANGES_TRIE_CONFIG)
|
||||
.map(|(_, v)| Decode::decode(&mut &v[..])
|
||||
.expect("changes trie configuration is encoded properly at genesis"));
|
||||
self.changes_trie_config_update = Some(changes_trie_config);
|
||||
|
||||
// this is only called when genesis block is imported => shouldn't be performance bottleneck
|
||||
let mut storage: HashMap<Option<(Vec<u8>, OwnedChildInfo)>, _> = HashMap::new();
|
||||
storage.insert(None, input.top);
|
||||
|
||||
@@ -259,7 +259,7 @@ fn check_execution_proof_with_make_header<Header, E, H, MakeNextHeader: Fn(&Head
|
||||
let mut changes = OverlayedChanges::default();
|
||||
let trie_backend = create_proof_check_backend(root, remote_proof)?;
|
||||
let next_header = make_next_header(&request.header);
|
||||
execution_proof_check_on_trie_backend::<H, _>(
|
||||
execution_proof_check_on_trie_backend::<H, Header::Number, _>(
|
||||
&trie_backend,
|
||||
&mut changes,
|
||||
executor,
|
||||
@@ -268,7 +268,7 @@ fn check_execution_proof_with_make_header<Header, E, H, MakeNextHeader: Fn(&Head
|
||||
)?;
|
||||
|
||||
// execute method
|
||||
execution_proof_check_on_trie_backend::<H, _>(
|
||||
execution_proof_check_on_trie_backend::<H, Header::Number, _>(
|
||||
&trie_backend,
|
||||
&mut changes,
|
||||
executor,
|
||||
|
||||
@@ -25,12 +25,12 @@ use codec::{Decode, Encode};
|
||||
use sp_core::{convert_hash, traits::CodeExecutor};
|
||||
use sp_runtime::traits::{
|
||||
Block as BlockT, Header as HeaderT, Hash, HashFor, NumberFor,
|
||||
SimpleArithmetic, CheckedConversion, Zero,
|
||||
SimpleArithmetic, CheckedConversion,
|
||||
};
|
||||
use sp_state_machine::{
|
||||
ChangesTrieRootsStorage, ChangesTrieAnchorBlockId, ChangesTrieConfigurationRange,
|
||||
TrieBackend, read_proof_check, key_changes_proof_check, create_proof_check_backend_storage,
|
||||
read_child_proof_check,
|
||||
InMemoryChangesTrieStorage, TrieBackend, read_proof_check, key_changes_proof_check_with_db,
|
||||
create_proof_check_backend_storage, read_child_proof_check,
|
||||
};
|
||||
pub use sp_state_machine::StorageProof;
|
||||
use sp_blockchain::{Error as ClientError, Result as ClientResult};
|
||||
@@ -113,30 +113,34 @@ impl<E, H, B: BlockT, S: BlockchainStorage<B>> LightDataChecker<E, H, B, S> {
|
||||
)?;
|
||||
}
|
||||
|
||||
// FIXME: remove this in https://github.com/paritytech/substrate/pull/3201
|
||||
let changes_trie_config_range = ChangesTrieConfigurationRange {
|
||||
config: &request.changes_trie_config,
|
||||
zero: Zero::zero(),
|
||||
end: None,
|
||||
};
|
||||
|
||||
// and now check the key changes proof + get the changes
|
||||
key_changes_proof_check::<H, _>(
|
||||
changes_trie_config_range,
|
||||
&RootsStorage {
|
||||
roots: (request.tries_roots.0, &request.tries_roots.2),
|
||||
prev_roots: remote_roots,
|
||||
},
|
||||
remote_proof,
|
||||
request.first_block.0,
|
||||
&ChangesTrieAnchorBlockId {
|
||||
hash: convert_hash(&request.last_block.1),
|
||||
number: request.last_block.0,
|
||||
},
|
||||
remote_max_block,
|
||||
request.storage_key.as_ref().map(Vec::as_slice),
|
||||
&request.key)
|
||||
.map_err(|err| ClientError::ChangesTrieAccessFailed(err))
|
||||
let mut result = Vec::new();
|
||||
let proof_storage = InMemoryChangesTrieStorage::with_proof(remote_proof);
|
||||
for config_range in &request.changes_trie_configs {
|
||||
let result_range = key_changes_proof_check_with_db::<H, _>(
|
||||
ChangesTrieConfigurationRange {
|
||||
config: config_range.config.as_ref().ok_or(ClientError::ChangesTriesNotSupported)?,
|
||||
zero: config_range.zero.0,
|
||||
end: config_range.end.map(|(n, _)| n),
|
||||
},
|
||||
&RootsStorage {
|
||||
roots: (request.tries_roots.0, &request.tries_roots.2),
|
||||
prev_roots: &remote_roots,
|
||||
},
|
||||
&proof_storage,
|
||||
request.first_block.0,
|
||||
&ChangesTrieAnchorBlockId {
|
||||
hash: convert_hash(&request.last_block.1),
|
||||
number: request.last_block.0,
|
||||
},
|
||||
remote_max_block,
|
||||
request.storage_key.as_ref().map(Vec::as_slice),
|
||||
&request.key)
|
||||
.map_err(|err| ClientError::ChangesTrieAccessFailed(err))?;
|
||||
result.extend(result_range);
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
/// Check CHT-based proof for changes tries roots.
|
||||
@@ -284,7 +288,7 @@ impl<E, Block, H, S> FetchChecker<Block> for LightDataChecker<E, H, Block, S>
|
||||
/// A view of BTreeMap<Number, Hash> as a changes trie roots storage.
|
||||
struct RootsStorage<'a, Number: SimpleArithmetic, Hash: 'a> {
|
||||
roots: (Number, &'a [Hash]),
|
||||
prev_roots: BTreeMap<Number, Hash>,
|
||||
prev_roots: &'a BTreeMap<Number, Hash>,
|
||||
}
|
||||
|
||||
impl<'a, H, Number, Hash> ChangesTrieRootsStorage<H, Number> for RootsStorage<'a, Number, Hash>
|
||||
@@ -340,7 +344,7 @@ pub mod tests {
|
||||
use crate::in_mem::{Blockchain as InMemoryBlockchain};
|
||||
use crate::light::fetcher::{FetchChecker, LightDataChecker, RemoteHeaderRequest};
|
||||
use crate::light::blockchain::tests::{DummyStorage, DummyBlockchain};
|
||||
use sp_core::{blake2_256, Blake2Hasher, H256};
|
||||
use sp_core::{blake2_256, Blake2Hasher, ChangesTrieConfiguration, H256};
|
||||
use sp_core::storage::{well_known_keys, StorageKey, ChildInfo};
|
||||
use sp_runtime::generic::BlockId;
|
||||
use sp_state_machine::Backend;
|
||||
@@ -569,8 +573,13 @@ pub mod tests {
|
||||
|
||||
// check proof on local client
|
||||
let local_roots_range = local_roots.clone()[(begin - 1) as usize..].to_vec();
|
||||
let config = ChangesTrieConfiguration::new(4, 2);
|
||||
let request = RemoteChangesRequest::<Header> {
|
||||
changes_trie_config: runtime::changes_trie_config(),
|
||||
changes_trie_configs: vec![sp_core::ChangesTrieConfigurationRange {
|
||||
zero: (0, Default::default()),
|
||||
end: None,
|
||||
config: Some(config),
|
||||
}],
|
||||
first_block: (begin, begin_hash),
|
||||
last_block: (end, end_hash),
|
||||
max_block: (max, max_hash),
|
||||
@@ -624,8 +633,13 @@ pub mod tests {
|
||||
);
|
||||
|
||||
// check proof on local client
|
||||
let config = ChangesTrieConfiguration::new(4, 2);
|
||||
let request = RemoteChangesRequest::<Header> {
|
||||
changes_trie_config: runtime::changes_trie_config(),
|
||||
changes_trie_configs: vec![sp_core::ChangesTrieConfigurationRange {
|
||||
zero: (0, Default::default()),
|
||||
end: None,
|
||||
config: Some(config),
|
||||
}],
|
||||
first_block: (1, b1),
|
||||
last_block: (4, b4),
|
||||
max_block: (4, b4),
|
||||
@@ -665,8 +679,13 @@ pub mod tests {
|
||||
begin_hash, end_hash, begin_hash, max_hash, None, &key).unwrap();
|
||||
|
||||
let local_roots_range = local_roots.clone()[(begin - 1) as usize..].to_vec();
|
||||
let config = ChangesTrieConfiguration::new(4, 2);
|
||||
let request = RemoteChangesRequest::<Header> {
|
||||
changes_trie_config: runtime::changes_trie_config(),
|
||||
changes_trie_configs: vec![sp_core::ChangesTrieConfigurationRange {
|
||||
zero: (0, Default::default()),
|
||||
end: None,
|
||||
config: Some(config),
|
||||
}],
|
||||
first_block: (begin, begin_hash),
|
||||
last_block: (end, end_hash),
|
||||
max_block: (max, max_hash),
|
||||
|
||||
Reference in New Issue
Block a user