Persistent Local Storage for offchain workers. (#2894)

* WiP.

* Implement offchain storage APIs.

* Change compare_and_set to return bool.

* Add offchain http test.

* Fix tests.

* Bump spec version.

* Fix warnings and test.

* Fix compilation.

* Remove unused code.

* Introduce Local (fork-aware) and Persistent storage.

* Fix borked merge.

* Prevent warning on depreacated client.backend

* Fix long lines.

* Clean up dependencies.

* Update core/primitives/src/offchain.rs

Co-Authored-By: André Silva <andre.beat@gmail.com>

* Update core/primitives/src/offchain.rs

Co-Authored-By: André Silva <andre.beat@gmail.com>
This commit is contained in:
Tomasz Drwięga
2019-07-02 20:11:06 +02:00
committed by Gavin Wood
parent 24aa882ebc
commit 2217c1e9a1
26 changed files with 726 additions and 118 deletions
+61
View File
@@ -593,6 +593,7 @@ where
type Blockchain = Blockchain<Block>;
type State = InMemory<H>;
type ChangesTrieStorage = ChangesTrieStorage<Block, H>;
type OffchainStorage = OffchainStorage;
fn begin_operation(&self) -> error::Result<Self::BlockImportOperation> {
let old_state = self.state_at(BlockId::Hash(Default::default()))?;
@@ -669,6 +670,10 @@ where
Some(&self.changes_trie_storage)
}
fn offchain_storage(&self) -> Option<Self::OffchainStorage> {
None
}
fn state_at(&self, block: BlockId<Block>) -> error::Result<Self::State> {
match block {
BlockId::Hash(h) if h == Default::default() => {
@@ -768,8 +773,46 @@ pub fn check_genesis_storage(top: &StorageOverlay, children: &ChildrenStorageOve
Ok(())
}
/// In-memory storage for offchain workers.
#[derive(Debug, Clone, Default)]
pub struct OffchainStorage {
storage: HashMap<Vec<u8>, Vec<u8>>,
}
impl backend::OffchainStorage for OffchainStorage {
fn set(&mut self, prefix: &[u8], key: &[u8], value: &[u8]) {
let key = prefix.iter().chain(key).cloned().collect();
self.storage.insert(key, value.to_vec());
}
fn get(&self, prefix: &[u8], key: &[u8]) -> Option<Vec<u8>> {
let key: Vec<u8> = prefix.iter().chain(key).cloned().collect();
self.storage.get(&key).cloned()
}
fn compare_and_set(
&mut self,
prefix: &[u8],
key: &[u8],
old_value: &[u8],
new_value: &[u8],
) -> bool {
let key = prefix.iter().chain(key).cloned().collect();
let mut set = false;
self.storage.entry(key).and_modify(|val| {
if val.as_slice() == old_value {
*val = new_value.to_vec();
set = true;
}
});
set
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::sync::Arc;
use test_client;
use primitives::Blake2Hasher;
@@ -789,4 +832,22 @@ mod tests {
test_client::trait_tests::test_blockchain_query_by_number_gets_canonical(backend);
}
#[test]
fn in_memory_offchain_storage() {
use crate::backend::OffchainStorage as _;
let mut storage = OffchainStorage::default();
assert_eq!(storage.get(b"A", b"B"), None);
assert_eq!(storage.get(b"B", b"A"), None);
storage.set(b"A", b"B", b"C");
assert_eq!(storage.get(b"A", b"B"), Some(b"C".to_vec()));
assert_eq!(storage.get(b"B", b"A"), None);
storage.compare_and_set(b"A", b"B", b"X", b"D");
assert_eq!(storage.get(b"A", b"B"), Some(b"C".to_vec()));
storage.compare_and_set(b"A", b"B", b"C", b"D");
assert_eq!(storage.get(b"A", b"B"), Some(b"D".to_vec()));
}
}