// Copyright 2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // Substrate is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . use std::collections::hash_map::{HashMap, Entry}; /// Offchain workers local storage. pub trait OffchainStorage: Clone + Send + Sync { /// Persist a value in storage under given key and prefix. fn set(&mut self, prefix: &[u8], key: &[u8], value: &[u8]); /// Retrieve a value from storage under given key and prefix. fn get(&self, prefix: &[u8], key: &[u8]) -> Option>; /// Replace the value in storage if given old_value matches the current one. /// /// Returns `true` if the value has been set and false otherwise. fn compare_and_set( &mut self, prefix: &[u8], key: &[u8], old_value: Option<&[u8]>, new_value: &[u8], ) -> bool; } /// In-memory storage for offchain workers. #[derive(Debug, Clone, Default)] pub struct InMemOffchainStorage { storage: HashMap, Vec>, } impl OffchainStorage for InMemOffchainStorage { 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> { let key: Vec = prefix.iter().chain(key).cloned().collect(); self.storage.get(&key).cloned() } fn compare_and_set( &mut self, prefix: &[u8], key: &[u8], old_value: Option<&[u8]>, new_value: &[u8], ) -> bool { let key = prefix.iter().chain(key).cloned().collect(); match self.storage.entry(key) { Entry::Vacant(entry) => if old_value.is_none() { entry.insert(new_value.to_vec()); true } else { false }, Entry::Occupied(ref mut entry) if Some(entry.get().as_slice()) == old_value => { entry.insert(new_value.to_vec()); true }, _ => false, } } }