Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Iteration over all keys with the specified prefix
  • Loading branch information
pepyakin committed Jul 3, 2018
commit 85079b4bd83d6550797499a7e894557a4887f040
8 changes: 8 additions & 0 deletions substrate/state-machine/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ pub trait Backend: TryIntoTrieBackend {
/// Get keyed storage associated with specific address, or None if there is nothing associated.
fn storage(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error>;

/// Retrieve all entries keys of which start with the given prefix and
/// call `f` for each of those keys.
fn for_keys_with_prefix<F: FnMut(&[u8])>(&self, prefix: &[u8], f: F);

/// Calculate the storage root, with given delta over what is already stored in
/// the backend, and produce a "transaction" that can be used to commit.
fn storage_root<I>(&self, delta: I) -> ([u8; 32], Self::Transaction)
Expand Down Expand Up @@ -105,6 +109,10 @@ impl Backend for InMemory {
Ok(self.inner.get(key).map(Clone::clone))
}

fn for_keys_with_prefix<F: FnMut(&[u8])>(&self, prefix: &[u8], f: F) {
self.inner.keys().filter(|key| key.starts_with(prefix)).map(|k| &**k).for_each(f);
}

fn storage_root<I>(&self, delta: I) -> ([u8; 32], Self::Transaction)
where I: IntoIterator<Item=(Vec<u8>, Option<Vec<u8>>)>
{
Expand Down
9 changes: 4 additions & 5 deletions substrate/state-machine/src/ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,12 +112,11 @@ impl<'a, B: 'a> Externalities for Ext<'a, B>
self.overlay.set_storage(key, value);
}

fn remove_prefix(&mut self, prefix: &[u8]) {
fn clear_prefix(&mut self, prefix: &[u8]) {
self.mark_dirty();



// TODO: iterate over a key range.
self.backend.for_keys_with_prefix(prefix, |key| {
self.overlay.set_storage(key.to_vec(), None);
});
}

fn chain_id(&self) -> u64 {
Expand Down
3 changes: 2 additions & 1 deletion substrate/state-machine/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,8 @@ pub trait Externalities {
self.place_storage(key.to_vec(), None);
}

fn remove_prefix(&mut self, prefix: &[u8]);
/// Clear storage entries which keys are start with the given prefix.
fn clear_prefix(&mut self, prefix: &[u8]);

/// Set or clear a storage entry (`key`) of current contract being called (effective immediately).
fn place_storage(&mut self, key: Vec<u8>, value: Option<Vec<u8>>);
Expand Down
6 changes: 5 additions & 1 deletion substrate/state-machine/src/proving_backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ impl Backend for ProvingBackend {
.get_with(key, &mut *proof_recorder).map(|x| x.map(|val| val.to_vec())).map_err(map_e)
}

fn for_keys_with_prefix<F: FnMut(&[u8])>(&self, prefix: &[u8], f: F) {
self.backend.for_keys_with_prefix(prefix, f)
}

fn pairs(&self) -> Vec<(Vec<u8>, Vec<u8>)> {
self.backend.pairs()
}
Expand Down Expand Up @@ -134,7 +138,7 @@ mod tests {
let proving_backend = test_proving();
assert_eq!(trie_backend.storage(b"key").unwrap(), proving_backend.storage(b"key").unwrap());
assert_eq!(trie_backend.pairs(), proving_backend.pairs());

let (trie_root, mut trie_mdb) = trie_backend.storage_root(::std::iter::empty());
let (proving_root, mut proving_mdb) = proving_backend.storage_root(::std::iter::empty());
assert_eq!(trie_root, proving_root);
Expand Down
2 changes: 1 addition & 1 deletion substrate/state-machine/src/testing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ impl Externalities for TestExternalities {
}
}

fn remove_prefix(&mut self, prefix: &[u8]) {
fn clear_prefix(&mut self, prefix: &[u8]) {
self.retain(|key, _|
!key.starts_with(prefix)
)
Expand Down
31 changes: 31 additions & 0 deletions substrate/state-machine/src/trie_backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,37 @@ impl Backend for TrieBackend {
.get(key).map(|x| x.map(|val| val.to_vec())).map_err(map_e)
}

fn for_keys_with_prefix<F: FnMut(&[u8])>(&self, prefix: &[u8], mut f: F) {
let mut read_overlay = MemoryDB::default();
let eph = Ephemeral {
storage: &self.storage,
overlay: &mut read_overlay,
};

let mut iter = move || -> Result<(), Box<TrieError>> {
let trie = TrieDB::new(&eph, &self.root)?;
let mut iter = trie.iter()?;

iter.seek(prefix)?;

for x in iter {
let (key, _) = x?;

if !key.starts_with(prefix) {
break;
}

f(&key);
}

Ok(())
};

if let Err(e) = iter() {
debug!(target: "trie", "Error while iterating by prefix: {}", e);
}
}

fn pairs(&self) -> Vec<(Vec<u8>, Vec<u8>)> {
let mut read_overlay = MemoryDB::default();
let eph = Ephemeral {
Expand Down