use std::{
io::{Read, Write},
num::NonZeroUsize,
sync::Mutex,
};
use once_cell::sync::Lazy;
use oasis_runtime_sdk::{
core::common::crypto::hash::Hash,
state::CurrentState,
storage::{self, Store},
};
use crate::{state, types, Config, Error, Module, MODULE_NAME};
static CODE_CACHE: Lazy<Mutex<lru::LruCache<Hash, Vec<u8>>>> =
Lazy::new(|| Mutex::new(lru::LruCache::new(NonZeroUsize::new(128).unwrap())));
impl<Cfg: Config> Module<Cfg> {
pub fn load_code(code_info: &types::Code) -> Result<Vec<u8>, Error> {
let mut cache = CODE_CACHE.lock().unwrap();
if let Some(code) = cache.get(&code_info.hash) {
return Ok(code.clone());
}
let code = CurrentState::with_store(|store| {
let mut store = storage::PrefixStore::new(store, &MODULE_NAME);
let code_store = storage::PrefixStore::new(&mut store, &state::CODE);
code_store
.get(&code_info.id.to_storage_key())
.ok_or_else(|| Error::CodeNotFound(code_info.id.as_u64()))
})?;
let mut output = Vec::with_capacity(code.len());
let mut decoder = snap::read::FrameDecoder::new(code.as_slice());
decoder.read_to_end(&mut output).unwrap();
cache.put(code_info.hash, output.clone());
Ok(output)
}
pub fn store_code(code_info: &types::Code, code: &[u8]) -> Result<(), Error> {
let mut cache = CODE_CACHE.lock().unwrap();
if cache.contains(&code_info.hash) {
cache.put(code_info.hash, code.to_vec());
}
let mut output = Vec::with_capacity(code.len() << 3);
let mut encoder = snap::write::FrameEncoder::new(&mut output);
encoder.write_all(code).unwrap();
drop(encoder); CurrentState::with_store(|store| {
let mut store = storage::PrefixStore::new(store, &MODULE_NAME);
let mut code_store = storage::PrefixStore::new(&mut store, &state::CODE);
code_store.insert(&code_info.id.to_storage_key(), &output);
});
Ok(())
}
}