Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.

Commit 4eb8ffc

Browse files
committed
use changes tries in query_storage RPC
1 parent 942f998 commit 4eb8ffc

File tree

16 files changed

+461
-199
lines changed

16 files changed

+461
-199
lines changed

core/client/db/src/lib.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,21 @@ impl<Block: BlockT> DbChangesTrieStorage<Block> {
430430
}
431431
}
432432

433+
impl<Block: BlockT> client::backend::PrunableStateChangesTrieStorage<Blake2Hasher> for DbChangesTrieStorage<Block> {
434+
fn oldest_changes_trie_block(
435+
&self,
436+
config: &ChangesTrieConfiguration,
437+
best_finalized_block: u64
438+
) -> u64 {
439+
let min_blocks_to_keep = match self.min_blocks_to_keep {
440+
Some(min_blocks_to_keep) => min_blocks_to_keep,
441+
None => return 1,
442+
};
443+
444+
state_machine::oldest_non_pruned_changes_trie(config, min_blocks_to_keep, best_finalized_block)
445+
}
446+
}
447+
433448
impl<Block: BlockT> state_machine::ChangesTrieRootsStorage<Blake2Hasher> for DbChangesTrieStorage<Block> {
434449
fn root(&self, anchor: &state_machine::ChangesTrieAnchorBlockId<H256>, block: u64) -> Result<Option<H256>, String> {
435450
// check API requirement

core/client/src/backend.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
//! Substrate Client data backend
1818
1919
use error;
20-
use primitives::AuthorityId;
20+
use primitives::{AuthorityId, ChangesTrieConfiguration};
2121
use runtime_primitives::{generic::BlockId, Justification, StorageMap, ChildrenStorageMap};
2222
use runtime_primitives::traits::{Block as BlockT, NumberFor};
2323
use state_machine::backend::Backend as StateBackend;
@@ -98,7 +98,7 @@ where
9898
/// Associated state backend type.
9999
type State: StateBackend<H>;
100100
/// Changes trie storage.
101-
type ChangesTrieStorage: StateChangesTrieStorage<H>;
101+
type ChangesTrieStorage: PrunableStateChangesTrieStorage<H>;
102102

103103
/// Begin a new block insertion transaction with given parent block id.
104104
/// When constructing the genesis, this is called with all-zero hash.
@@ -123,6 +123,12 @@ where
123123
fn get_aux(&self, key: &[u8]) -> error::Result<Option<Vec<u8>>>;
124124
}
125125

126+
/// Changes trie storage that supports pruning.
127+
pub trait PrunableStateChangesTrieStorage<H: Hasher>: StateChangesTrieStorage<H> {
128+
/// Get number block of oldest, non-pruned changes trie.
129+
fn oldest_changes_trie_block(&self, config: &ChangesTrieConfiguration, best_finalized: u64) -> u64;
130+
}
131+
126132
/// Mark for all Backend implementations, that are making use of state data, stored locally.
127133
pub trait LocalBackend<Block, H>: Backend<Block, H>
128134
where

core/client/src/client.rs

Lines changed: 67 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,12 @@ use primitives::storage::well_known_keys;
3636
use codec::{Encode, Decode};
3737
use state_machine::{
3838
Backend as StateBackend, CodeExecutor,
39-
ExecutionStrategy, ExecutionManager, ChangesTrieAnchorBlockId,
40-
prove_read, key_changes, key_changes_proof, OverlayedChanges
39+
ExecutionStrategy, ExecutionManager, prove_read,
40+
key_changes, key_changes_proof,
41+
ChangesTrieAnchorBlockId, OverlayedChanges
4142
};
4243

43-
use backend::{self, BlockImportOperation};
44+
use backend::{self, BlockImportOperation, PrunableStateChangesTrieStorage};
4445
use blockchain::{self, Info as ChainInfo, Backend as ChainBackend, HeaderBackend as ChainHeaderBackend};
4546
use call_executor::{CallExecutor, LocalCallExecutor};
4647
use executor::{RuntimeVersion, RuntimeInfo};
@@ -336,33 +337,56 @@ impl<B, E, Block> Client<B, E, Block> where
336337
Ok((header, proof))
337338
}
338339

340+
/// Get longest range within [first; last] that is possible to use in `key_changes`
341+
/// and `key_changes_proof` calls.
342+
/// Range could be shortened from the beginning if some changes tries have been pruned.
343+
/// Returns None if changes trues are not supported.
344+
pub fn max_key_changes_range(
345+
&self,
346+
first: NumberFor<Block>,
347+
last: BlockId<Block>,
348+
) -> error::Result<Option<(NumberFor<Block>, BlockId<Block>)>> {
349+
let (config, storage) = match self.require_changes_trie().ok() {
350+
Some((config, storage)) => (config, storage),
351+
None => return Ok(None),
352+
};
353+
354+
let first = first.as_();
355+
let last_num = self.require_block_number_from_id(&last)?.as_();
356+
if first > last_num {
357+
return Err(error::ErrorKind::ChangesTrieAccessFailed("Invalid changes trie range".into()).into());
358+
}
359+
360+
let finalized_number = self.backend.blockchain().info()?.finalized_number;
361+
let oldest = storage.oldest_changes_trie_block(config, finalized_number.as_());
362+
let first = As::sa(::std::cmp::max(first, oldest));
363+
Ok(Some((first, last)))
364+
}
365+
339366
/// Get pairs of (block, extrinsic) where key has been changed at given blocks range.
340367
/// Works only for runtimes that are supporting changes tries.
368+
/// Changes are returned in descending order.
341369
pub fn key_changes(
342370
&self,
343-
first: Block::Hash,
344-
last: Block::Hash,
345-
key: &[u8]
371+
first: NumberFor<Block>,
372+
last: BlockId<Block>,
373+
key: &StorageKey,
346374
) -> error::Result<Vec<(NumberFor<Block>, u32)>> {
347-
let config = self.changes_trie_config.as_ref();
348-
let storage = self.backend.changes_trie_storage();
349-
let (config, storage) = match (config, storage) {
350-
(Some(config), Some(storage)) => (config, storage),
351-
_ => return Err(error::ErrorKind::ChangesTriesNotSupported.into()),
352-
};
353-
354-
key_changes::<_, Blake2Hasher>(
375+
let (config, storage) = self.require_changes_trie()?;
376+
let last_number = self.require_block_number_from_id(&last)?.as_();
377+
let last_hash = self.require_block_hash_from_id(&last)?;
378+
key_changes(
355379
config,
356-
storage,
357-
self.require_block_number_from_id(&BlockId::Hash(first))?.as_(),
380+
&*storage,
381+
first.as_(),
358382
&ChangesTrieAnchorBlockId {
359-
hash: convert_hash(&last),
360-
number: self.require_block_number_from_id(&BlockId::Hash(last))?.as_(),
383+
hash: convert_hash(&last_hash),
384+
number: last_number,
361385
},
362386
self.backend.blockchain().info()?.best_number.as_(),
363-
key)
387+
&key.0)
388+
.and_then(|r| r.map(|r| r.map(|(block, tx)| (As::sa(block), tx))).collect::<Result<_, _>>())
364389
.map_err(|err| error::ErrorKind::ChangesTrieAccessFailed(err).into())
365-
.map(|r| r.into_iter().map(|(b, e)| (As::sa(b), e)).collect())
366390
}
367391

368392
/// Get proof for computation of (block, extrinsic) pairs where key has been changed at given blocks range.
@@ -374,33 +398,37 @@ impl<B, E, Block> Client<B, E, Block> where
374398
first: Block::Hash,
375399
last: Block::Hash,
376400
max: Block::Hash,
377-
key: &[u8]
401+
key: &StorageKey,
378402
) -> error::Result<(NumberFor<Block>, Vec<Vec<u8>>)> {
379-
let config = self.changes_trie_config.as_ref();
380-
let storage = self.backend.changes_trie_storage();
381-
let (config, storage) = match (config, storage) {
382-
(Some(config), Some(storage)) => (config, storage),
383-
_ => return Err(error::ErrorKind::ChangesTriesNotSupported.into()),
384-
};
385-
403+
let (config, storage) = self.require_changes_trie()?;
386404
let max_number = ::std::cmp::min(
387405
self.backend.blockchain().info()?.best_number,
388406
self.require_block_number_from_id(&BlockId::Hash(max))?,
389407
);
390-
key_changes_proof::<_, Blake2Hasher>(
408+
key_changes_proof(
391409
config,
392-
storage,
410+
&*storage,
393411
self.require_block_number_from_id(&BlockId::Hash(first))?.as_(),
394412
&ChangesTrieAnchorBlockId {
395413
hash: convert_hash(&last),
396414
number: self.require_block_number_from_id(&BlockId::Hash(last))?.as_(),
397415
},
398416
max_number.as_(),
399-
key)
417+
&key.0)
400418
.map_err(|err| error::ErrorKind::ChangesTrieAccessFailed(err).into())
401419
.map(|proof| (max_number, proof))
402420
}
403421

422+
/// Returns changes trie configuration and storage or an error if it is not supported.
423+
fn require_changes_trie(&self) -> error::Result<(&ChangesTrieConfiguration, &B::ChangesTrieStorage)> {
424+
let config = self.changes_trie_config.as_ref();
425+
let storage = self.backend.changes_trie_storage();
426+
match (config, storage) {
427+
(Some(config), Some(storage)) => Ok((config, storage)),
428+
_ => Err(error::ErrorKind::ChangesTriesNotSupported.into()),
429+
}
430+
}
431+
404432
/// Create a new block, built on the head of the chain.
405433
pub fn new_block(&self) -> error::Result<block_builder::BlockBuilder<B, E, Block, Blake2Hasher>>
406434
where E: Clone
@@ -750,7 +778,13 @@ impl<B, E, Block> Client<B, E, Block> where
750778
}
751779
}
752780

753-
/// Convert an arbitrary block ID into a block hash.
781+
/// Convert an arbitrary block ID into a block number, returning error if the block is unknown.
782+
fn require_block_hash_from_id(&self, id: &BlockId<Block>) -> error::Result<Block::Hash> {
783+
self.block_hash_from_id(id)
784+
.and_then(|n| n.ok_or_else(|| error::ErrorKind::UnknownBlock(format!("{}", id)).into()))
785+
}
786+
787+
/// Convert an arbitrary block ID into a block number.
754788
pub fn block_number_from_id(&self, id: &BlockId<Block>) -> error::Result<Option<NumberFor<Block>>> {
755789
match *id {
756790
BlockId::Hash(_) => Ok(self.header(id)?.map(|h| h.number().clone())),
@@ -1586,9 +1620,7 @@ pub(crate) mod tests {
15861620
let (client, _, test_cases) = prepare_client_with_key_changes();
15871621

15881622
for (index, (begin, end, key, expected_result)) in test_cases.into_iter().enumerate() {
1589-
let begin = client.block_hash(begin).unwrap().unwrap();
1590-
let end = client.block_hash(end).unwrap().unwrap();
1591-
let actual_result = client.key_changes(begin, end, &key).unwrap();
1623+
let actual_result = client.key_changes(begin, BlockId::Number(end), &StorageKey(key)).unwrap();
15921624
match actual_result == expected_result {
15931625
true => (),
15941626
false => panic!(format!("Failed test {}: actual = {:?}, expected = {:?}",

core/client/src/in_mem.rs

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,14 @@ use parking_lot::RwLock;
2222
use error;
2323
use backend::{self, NewBlockState};
2424
use light;
25-
use primitives::{AuthorityId, storage::well_known_keys};
25+
use primitives::{AuthorityId, ChangesTrieConfiguration, storage::well_known_keys};
2626
use runtime_primitives::generic::BlockId;
2727
use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, Zero,
2828
NumberFor, As, Digest, DigestItem};
2929
use runtime_primitives::{Justification, StorageMap, ChildrenStorageMap};
3030
use blockchain::{self, BlockStatus, HeaderBackend};
3131
use state_machine::backend::{Backend as StateBackend, InMemory, Consolidate};
32-
use state_machine::InMemoryChangesTrieStorage;
32+
use state_machine::{self, InMemoryChangesTrieStorage, ChangesTrieAnchorBlockId};
3333
use hash_db::Hasher;
3434
use heapsize::HeapSizeOf;
3535
use leaves::LeafSet;
@@ -436,7 +436,7 @@ where
436436
H::Out: HeapSizeOf + Ord,
437437
{
438438
states: RwLock<HashMap<Block::Hash, InMemory<H>>>,
439-
changes_trie_storage: InMemoryChangesTrieStorage<H>,
439+
changes_trie_storage: ChangesTrieStorage<H>,
440440
blockchain: Blockchain<Block>,
441441
aux: RwLock<HashMap<Vec<u8>, Vec<u8>>>,
442442
}
@@ -451,7 +451,7 @@ where
451451
pub fn new() -> Backend<Block, H> {
452452
Backend {
453453
states: RwLock::new(HashMap::new()),
454-
changes_trie_storage: InMemoryChangesTrieStorage::new(),
454+
changes_trie_storage: ChangesTrieStorage(InMemoryChangesTrieStorage::new()),
455455
blockchain: Blockchain::new(),
456456
aux: RwLock::new(HashMap::new()),
457457
}
@@ -467,7 +467,7 @@ where
467467
type BlockImportOperation = BlockImportOperation<Block, H>;
468468
type Blockchain = Blockchain<Block>;
469469
type State = InMemory<H>;
470-
type ChangesTrieStorage = InMemoryChangesTrieStorage<H>;
470+
type ChangesTrieStorage = ChangesTrieStorage<H>;
471471

472472
fn begin_operation(&self, block: BlockId<Block>) -> error::Result<Self::BlockImportOperation> {
473473
let state = match block {
@@ -498,7 +498,7 @@ where
498498
if let Some(changes_trie_root) = changes_trie_root {
499499
if let Some(changes_trie_update) = operation.changes_trie_update {
500500
let changes_trie_root: H::Out = changes_trie_root.into();
501-
self.changes_trie_storage.insert(header.number().as_(), changes_trie_root, changes_trie_update);
501+
self.changes_trie_storage.0.insert(header.number().as_(), changes_trie_root, changes_trie_update);
502502
}
503503
}
504504

@@ -574,6 +574,27 @@ impl<Block: BlockT> blockchain::Cache<Block> for Cache<Block> {
574574
}
575575
}
576576

577+
/// Prunable in-memory changes trie storage.
578+
pub struct ChangesTrieStorage<H: Hasher>(InMemoryChangesTrieStorage<H>) where H::Out: HeapSizeOf;
579+
580+
impl<H: Hasher> backend::PrunableStateChangesTrieStorage<H> for ChangesTrieStorage<H> where H::Out: HeapSizeOf {
581+
fn oldest_changes_trie_block(&self, _config: &ChangesTrieConfiguration, _best_finalized: u64) -> u64 {
582+
0
583+
}
584+
}
585+
586+
impl<H: Hasher> state_machine::ChangesTrieRootsStorage<H> for ChangesTrieStorage<H> where H::Out: HeapSizeOf {
587+
fn root(&self, anchor: &ChangesTrieAnchorBlockId<H::Out>, block: u64) -> Result<Option<H::Out>, String> {
588+
self.0.root(anchor, block)
589+
}
590+
}
591+
592+
impl<H: Hasher> state_machine::ChangesTrieStorage<H> for ChangesTrieStorage<H> where H::Out: HeapSizeOf {
593+
fn get(&self, key: &H::Out) -> Result<Option<state_machine::DBValue>, String> {
594+
self.0.get(key)
595+
}
596+
}
597+
577598
/// Insert authorities entry into in-memory blockchain cache. Extracted as a separate function to use it in tests.
578599
pub fn cache_authorities_at<Block: BlockT>(
579600
blockchain: &Blockchain<Block>,

core/client/src/light/backend.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use parking_lot::RwLock;
2323

2424
use primitives::AuthorityId;
2525
use runtime_primitives::{generic::BlockId, Justification, StorageMap, ChildrenStorageMap};
26-
use state_machine::{Backend as StateBackend, InMemoryChangesTrieStorage, TrieBackend};
26+
use state_machine::{Backend as StateBackend, TrieBackend};
2727
use runtime_primitives::traits::{Block as BlockT, NumberFor};
2828

2929
use in_mem;
@@ -79,7 +79,7 @@ impl<S, F, Block, H> ClientBackend<Block, H> for Backend<S, F> where
7979
type BlockImportOperation = ImportOperation<Block, S, F>;
8080
type Blockchain = Blockchain<S, F>;
8181
type State = OnDemandState<Block, S, F>;
82-
type ChangesTrieStorage = InMemoryChangesTrieStorage<H>;
82+
type ChangesTrieStorage = in_mem::ChangesTrieStorage<H>;
8383

8484
fn begin_operation(&self, _block: BlockId<Block>) -> ClientResult<Self::BlockImportOperation> {
8585
Ok(ImportOperation {

core/client/src/light/fetcher.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ pub mod tests {
275275
use light::fetcher::{Fetcher, FetchChecker, LightDataChecker,
276276
RemoteCallRequest, RemoteHeaderRequest};
277277
use primitives::{Blake2Hasher};
278-
use primitives::storage::well_known_keys;
278+
use primitives::storage::{StorageKey, well_known_keys};
279279
use runtime_primitives::generic::BlockId;
280280
use state_machine::Backend;
281281
use super::*;
@@ -419,6 +419,7 @@ pub mod tests {
419419
let end_hash = remote_client.block_hash(end).unwrap().unwrap();
420420

421421
// 'fetch' changes proof from remote node
422+
let key = StorageKey(key);
422423
let (remote_max, remote_proof) = remote_client.key_changes_proof(
423424
begin_hash, end_hash, max_hash, &key
424425
).unwrap();
@@ -431,7 +432,7 @@ pub mod tests {
431432
last_block: (end, end_hash),
432433
max_block: (max, max_hash),
433434
tries_roots: local_roots_range,
434-
key: key,
435+
key: key.0,
435436
retry_count: None,
436437
};
437438
let local_result = local_checker.check_changes_proof(
@@ -460,6 +461,7 @@ pub mod tests {
460461
let end_hash = remote_client.block_hash(end).unwrap().unwrap();
461462

462463
// 'fetch' changes proof from remote node
464+
let key = StorageKey(key);
463465
let (remote_max, mut remote_proof) = remote_client.key_changes_proof(
464466
begin_hash, end_hash, max_hash, &key).unwrap();
465467
let local_roots_range = local_roots.clone()[(begin - 1) as usize..].to_vec();
@@ -469,7 +471,7 @@ pub mod tests {
469471
last_block: (end, end_hash),
470472
max_block: (max, max_hash),
471473
tries_roots: local_roots_range.clone(),
472-
key: key,
474+
key: key.0,
473475
retry_count: None,
474476
};
475477

core/network/src/chain.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, NumberFor};
2323
use runtime_primitives::generic::{BlockId};
2424
use consensus::{ImportBlock, ImportResult};
2525
use runtime_primitives::Justification;
26-
use primitives::{H256, Blake2Hasher, AuthorityId};
26+
use primitives::{H256, Blake2Hasher, AuthorityId, storage::StorageKey};
2727

2828
/// Local client abstraction for the network.
2929
pub trait Client<Block: BlockT>: Send + Sync {
@@ -64,7 +64,7 @@ pub trait Client<Block: BlockT>: Send + Sync {
6464
first: Block::Hash,
6565
last: Block::Hash,
6666
max: Block::Hash,
67-
key: &[u8]
67+
key: &StorageKey,
6868
) -> Result<(NumberFor<Block>, Vec<Vec<u8>>), Error>;
6969
}
7070

@@ -121,7 +121,7 @@ impl<B, E, Block> Client<Block> for SubstrateClient<B, E, Block> where
121121
first: Block::Hash,
122122
last: Block::Hash,
123123
max: Block::Hash,
124-
key: &[u8]
124+
key: &StorageKey
125125
) -> Result<(NumberFor<Block>, Vec<Vec<u8>>), Error> {
126126
(self as &SubstrateClient<B, E, Block>).key_changes_proof(first, last, max, key)
127127
}

0 commit comments

Comments
 (0)