From 81f90ed0a4995f1511ea8bde34bf7d5329a67bf0 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Thu, 13 Dec 2018 19:01:57 +0300 Subject: [PATCH] AuxStore on light clients (#1251) * implement AuxStore on light clients * Update core/client/db/src/light.rs Co-Authored-By: svyatonik * Update core/client/db/src/light.rs Co-Authored-By: svyatonik * Update core/client/db/src/light.rs Co-Authored-By: svyatonik --- substrate/core/client/db/src/light.rs | 51 ++++++++++++++++++- substrate/core/client/src/in_mem.rs | 34 +++++++++---- substrate/core/client/src/light/backend.rs | 12 ++--- substrate/core/client/src/light/blockchain.rs | 20 +++++++- 4 files changed, 99 insertions(+), 18 deletions(-) diff --git a/substrate/core/client/db/src/light.rs b/substrate/core/client/db/src/light.rs index 1efe3b749e..729519020c 100644 --- a/substrate/core/client/db/src/light.rs +++ b/substrate/core/client/db/src/light.rs @@ -21,7 +21,7 @@ use parking_lot::RwLock; use kvdb::{KeyValueDB, DBTransaction}; -use client::backend::NewBlockState; +use client::backend::{AuxStore, NewBlockState}; use client::blockchain::{BlockStatus, Cache as BlockchainCache, HeaderBackend as BlockchainHeaderBackend, Info as BlockchainInfo}; use client::{cht, LeafSet}; @@ -275,6 +275,31 @@ impl LightStorage { } } +impl AuxStore for LightStorage + where Block: BlockT, +{ + fn insert_aux< + 'a, + 'b: 'a, + 'c: 'a, + I: IntoIterator, + D: IntoIterator, + >(&self, insert: I, delete: D) -> ClientResult<()> { + let mut transaction = DBTransaction::new(); + for (k, v) in insert { + transaction.put(columns::AUX, k, v); + } + for k in delete { + transaction.delete(columns::AUX, k); + } + self.db.write(transaction).map_err(db_err) + } + + fn get_aux(&self, key: &[u8]) -> ClientResult>> { + self.db.get(columns::AUX, key).map(|r| r.map(|v| v.to_vec())).map_err(db_err) + } +} + impl LightBlockchainStorage for LightStorage where Block: BlockT, { @@ -864,4 +889,28 @@ pub(crate) mod tests { assert_eq!(db.info().unwrap().best_hash, hash0); assert_eq!(db.header(BlockId::Hash::(hash0)).unwrap().unwrap().hash(), hash0); } + + #[test] + fn aux_store_works() { + let db = LightStorage::::new_test(); + + // insert aux1 + aux2 using direct store access + db.insert_aux(&[(&[1][..], &[101][..]), (&[2][..], &[102][..])], ::std::iter::empty()).unwrap(); + + // check aux values + assert_eq!(db.get_aux(&[1]).unwrap(), Some(vec![101])); + assert_eq!(db.get_aux(&[2]).unwrap(), Some(vec![102])); + assert_eq!(db.get_aux(&[3]).unwrap(), None); + + // delete aux1 + insert aux3 using import operation + db.import_header(default_header(&Default::default(), 0), None, NewBlockState::Best, vec![ + (vec![3], Some(vec![103])), + (vec![1], None), + ]).unwrap(); + + // check aux values + assert_eq!(db.get_aux(&[1]).unwrap(), None); + assert_eq!(db.get_aux(&[2]).unwrap(), Some(vec![102])); + assert_eq!(db.get_aux(&[3]).unwrap(), Some(vec![103])); + } } diff --git a/substrate/core/client/src/in_mem.rs b/substrate/core/client/src/in_mem.rs index 224d070838..1bf50d715d 100644 --- a/substrate/core/client/src/in_mem.rs +++ b/substrate/core/client/src/in_mem.rs @@ -338,6 +338,29 @@ impl blockchain::Backend for Blockchain { } } +impl backend::AuxStore for Blockchain { + fn insert_aux< + 'a, + 'b: 'a, + 'c: 'a, + I: IntoIterator, + D: IntoIterator, + >(&self, insert: I, delete: D) -> error::Result<()> { + let mut storage = self.storage.write(); + for (k, v) in insert { + storage.aux.insert(k.to_vec(), v.to_vec()); + } + for k in delete { + storage.aux.remove(*k); + } + Ok(()) + } + + fn get_aux(&self, key: &[u8]) -> error::Result>> { + Ok(self.storage.read().aux.get(key).cloned()) + } +} + impl light::blockchain::Storage for Blockchain where Block::Hash: From<[u8; 32]>, @@ -511,18 +534,11 @@ where I: IntoIterator, D: IntoIterator, >(&self, insert: I, delete: D) -> error::Result<()> { - let mut storage = self.blockchain.storage.write(); - for (k, v) in insert { - storage.aux.insert(k.to_vec(), v.to_vec()); - } - for k in delete { - storage.aux.remove(*k); - } - Ok(()) + self.blockchain.insert_aux(insert, delete) } fn get_aux(&self, key: &[u8]) -> error::Result>> { - Ok(self.blockchain.storage.read().aux.get(key).cloned()) + self.blockchain.get_aux(key) } } diff --git a/substrate/core/client/src/light/backend.rs b/substrate/core/client/src/light/backend.rs index 44a918e8b5..185b7cfa06 100644 --- a/substrate/core/client/src/light/backend.rs +++ b/substrate/core/client/src/light/backend.rs @@ -27,7 +27,7 @@ use state_machine::{Backend as StateBackend, InMemoryChangesTrieStorage, TrieBac use runtime_primitives::traits::{Block as BlockT, NumberFor}; use in_mem; -use backend::{Backend as ClientBackend, BlockImportOperation, RemoteBackend, NewBlockState}; +use backend::{AuxStore, Backend as ClientBackend, BlockImportOperation, RemoteBackend, NewBlockState}; use blockchain::HeaderBackend as BlockchainHeaderBackend; use error::{Error as ClientError, ErrorKind as ClientErrorKind, Result as ClientResult}; use light::blockchain::{Blockchain, Storage as BlockchainStorage}; @@ -70,19 +70,19 @@ impl Backend { } } -impl ::backend::AuxStore for Backend { +impl AuxStore for Backend { fn insert_aux< 'a, 'b: 'a, 'c: 'a, I: IntoIterator, D: IntoIterator, - >(&self, _insert: I, _delete: D) -> ClientResult<()> { - Err(ClientErrorKind::NotAvailableOnLightClient.into()) + >(&self, insert: I, delete: D) -> ClientResult<()> { + self.blockchain.storage().insert_aux(insert, delete) } - fn get_aux(&self, _key: &[u8]) -> ClientResult>> { - Err(ClientErrorKind::NotAvailableOnLightClient.into()) + fn get_aux(&self, key: &[u8]) -> ClientResult>> { + self.blockchain.storage().get_aux(key) } } diff --git a/substrate/core/client/src/light/blockchain.rs b/substrate/core/client/src/light/blockchain.rs index 5996732c3f..ed75043164 100644 --- a/substrate/core/client/src/light/blockchain.rs +++ b/substrate/core/client/src/light/blockchain.rs @@ -25,7 +25,7 @@ use primitives::AuthorityId; use runtime_primitives::{Justification, generic::BlockId}; use runtime_primitives::traits::{Block as BlockT, Header as HeaderT,NumberFor, Zero}; -use backend::NewBlockState; +use backend::{AuxStore, NewBlockState}; use blockchain::{Backend as BlockchainBackend, BlockStatus, Cache as BlockchainCache, HeaderBackend as BlockchainHeaderBackend, Info as BlockchainInfo}; use cht; @@ -33,7 +33,7 @@ use error::{ErrorKind as ClientErrorKind, Result as ClientResult}; use light::fetcher::{Fetcher, RemoteHeaderRequest}; /// Light client blockchain storage. -pub trait Storage: BlockchainHeaderBackend { +pub trait Storage: AuxStore + BlockchainHeaderBackend { /// Store new header. Should refuse to revert any finalized blocks. /// /// Takes new authorities, the leaf state of the new block, and @@ -207,6 +207,22 @@ pub mod tests { } } + impl AuxStore for DummyStorage { + fn insert_aux< + 'a, + 'b: 'a, + 'c: 'a, + I: IntoIterator, + D: IntoIterator, + >(&self, _insert: I, _delete: D) -> ClientResult<()> { + Err(ClientErrorKind::Backend("Test error".into()).into()) + } + + fn get_aux(&self, _key: &[u8]) -> ClientResult>> { + Err(ClientErrorKind::Backend("Test error".into()).into()) + } + } + impl Storage for DummyStorage { fn import_header( &self,