diff --git a/substrate/core/client/db/src/lib.rs b/substrate/core/client/db/src/lib.rs index e5837e7f3f394f37bf9ea92fa9f36ea9cc848c75..eb63f60e3ae8990f7ccedbfb4c4e81987eeecb63 100644 --- a/substrate/core/client/db/src/lib.rs +++ b/substrate/core/client/db/src/lib.rs @@ -122,6 +122,7 @@ mod columns { pub const BODY: Option<u32> = Some(5); pub const JUSTIFICATION: Option<u32> = Some(6); pub const CHANGES_TRIE: Option<u32> = Some(7); + pub const AUX: Option<u32> = Some(8); } struct PendingBlock<Block: BlockT> { @@ -739,6 +740,24 @@ impl<Block> client::backend::Backend<Block, Blake2Hasher> for Backend<Block> whe _ => Err(client::error::ErrorKind::UnknownBlock(format!("{:?}", block)).into()), } } + + fn insert_aux<'a, 'b: 'a, 'c: 'a, I: IntoIterator<Item=&'a (&'c [u8], &'c [u8])>, D: IntoIterator<Item=&'a &'b [u8]>> + (&self, insert: I, delete: D) -> Result<(), client::error::Error> + { + 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.storage.db.write(transaction).map_err(db_err)?; + Ok(()) + } + + fn get_aux(&self, key: &[u8]) -> Result<Option<Vec<u8>>, client::error::Error> { + Ok(self.storage.db.get(columns::AUX, key).map(|r| r.map(|v| v.to_vec())).map_err(db_err)?) + } } impl<Block> client::backend::LocalBackend<Block, Blake2Hasher> for Backend<Block> @@ -1144,4 +1163,14 @@ mod tests { let backend: Arc<Backend<test_client::runtime::Block>> = Arc::new(Backend::new_test(20, 20)); test_client::trait_tests::test_blockchain_query_by_number_gets_canonical(backend); } + + #[test] + fn test_aux() { + let backend: Backend<test_client::runtime::Block> = Backend::new_test(0, 0); + assert!(backend.get_aux(b"test").unwrap().is_none()); + backend.insert_aux(&[(&b"test"[..], &b"hello"[..])], &[]).unwrap(); + assert_eq!(b"hello", &backend.get_aux(b"test").unwrap().unwrap()[..]); + backend.insert_aux(&[], &[&b"test"[..]]).unwrap(); + assert!(backend.get_aux(b"test").unwrap().is_none()); + } } diff --git a/substrate/core/client/db/src/utils.rs b/substrate/core/client/db/src/utils.rs index 9065b3e620778117b84340624afa2fce821552dd..e7139467a194d3e5682b62e490b9f050316d4242 100644 --- a/substrate/core/client/db/src/utils.rs +++ b/substrate/core/client/db/src/utils.rs @@ -32,7 +32,7 @@ use DatabaseSettings; /// Number of columns in the db. Must be the same for both full && light dbs. /// Otherwise RocksDb will fail to open database && check its type. -pub const NUM_COLUMNS: u32 = 8; +pub const NUM_COLUMNS: u32 = 9; /// Meta column. The set of keys in the column is shared by full && light storages. pub const COLUMN_META: Option<u32> = Some(0); diff --git a/substrate/core/client/src/backend.rs b/substrate/core/client/src/backend.rs index 4a7f9ecc95c596dae767acce75140629085d2f85..59ad348aed015d8c9ba693c37936f69c98c30e8f 100644 --- a/substrate/core/client/src/backend.rs +++ b/substrate/core/client/src/backend.rs @@ -119,6 +119,10 @@ where /// Attempts to revert the chain by `n` blocks. Returns the number of blocks that were /// successfully reverted. fn revert(&self, n: NumberFor<Block>) -> error::Result<NumberFor<Block>>; + /// Insert auxiliary data into key-value store. + fn insert_aux<'a, 'b: 'a, 'c: 'a, I: IntoIterator<Item=&'a(&'c [u8], &'c [u8])>, D: IntoIterator<Item=&'a &'b [u8]>>(&self, insert: I, delete: D) -> error::Result<()>; + /// Query auxiliary data from key-value store. + fn get_aux(&self, key: &[u8]) -> error::Result<Option<Vec<u8>>>; } /// Mark for all Backend implementations, that are making use of state data, stored locally. diff --git a/substrate/core/client/src/in_mem.rs b/substrate/core/client/src/in_mem.rs index 4f8c4fd1d331b4c34e419b8ab030cad88ee1674e..c938a6dbd357171ef4a4ad60eb4d76507ef1a177 100644 --- a/substrate/core/client/src/in_mem.rs +++ b/substrate/core/client/src/in_mem.rs @@ -417,6 +417,7 @@ where states: RwLock<HashMap<Block::Hash, InMemory<H>>>, changes_trie_storage: InMemoryChangesTrieStorage<H>, blockchain: Blockchain<Block>, + aux: RwLock<HashMap<Vec<u8>, Vec<u8>>>, } impl<Block, H> Backend<Block, H> @@ -432,6 +433,7 @@ where states: RwLock::new(HashMap::new()), changes_trie_storage: InMemoryChangesTrieStorage::new(), blockchain: Blockchain::new(), + aux: RwLock::new(HashMap::new()), } } } @@ -514,6 +516,21 @@ where fn revert(&self, _n: NumberFor<Block>) -> error::Result<NumberFor<Block>> { Ok(As::sa(0)) } + + fn insert_aux<'a, 'b: 'a, 'c: 'a, I: IntoIterator<Item=&'a (&'c [u8], &'c [u8])>, D: IntoIterator<Item=&'a &'b [u8]>>(&self, insert: I, delete: D) -> error::Result<()> { + let mut aux = self.aux.write(); + for (k, v) in insert { + aux.insert(k.to_vec(), v.to_vec()); + } + for k in delete { + aux.remove(*k); + } + Ok(()) + } + + fn get_aux(&self, key: &[u8]) -> error::Result<Option<Vec<u8>>> { + Ok(self.aux.read().get(key).cloned()) + } } impl<Block, H> backend::LocalBackend<Block, H> for Backend<Block, H> diff --git a/substrate/core/client/src/light/backend.rs b/substrate/core/client/src/light/backend.rs index 099351c652dec6aa90ad835e23bdd110e1f042d0..693314388a214df82d8523350cee9777d02608de 100644 --- a/substrate/core/client/src/light/backend.rs +++ b/substrate/core/client/src/light/backend.rs @@ -126,7 +126,15 @@ impl<S, F, Block, H> ClientBackend<Block, H> for Backend<S, F> where } fn revert(&self, _n: NumberFor<Block>) -> ClientResult<NumberFor<Block>> { - unimplemented!() + Err(ClientErrorKind::NotAvailableOnLightClient.into()) + } + + fn insert_aux<'a, 'b: 'a, 'c: 'a, I: IntoIterator<Item=&'a (&'c [u8], &'c [u8])>, D: IntoIterator<Item=&'a &'b [u8]>>(&self, _insert: I, _delete: D) -> ClientResult<()> { + Err(ClientErrorKind::NotAvailableOnLightClient.into()) + } + + fn get_aux(&self, _key: &[u8]) -> ClientResult<Option<Vec<u8>>> { + Err(ClientErrorKind::NotAvailableOnLightClient.into()) } }