inkpad_cli/
store.rs

1//! Storage implementation
2use crate::Result;
3use inkpad_executor::Memory;
4use inkpad_runtime::Runtime;
5use inkpad_std::BTreeMap;
6use inkpad_support::{
7    traits::{self, Cache, Frame},
8    types::{Metadata, State},
9};
10use etc::{Etc, FileSystem, Meta};
11use parity_scale_codec::{Decode, Encode};
12use sled::{Db, Tree};
13use std::{cell::RefCell, fs, path::PathBuf, process, rc::Rc};
14
15const RUNTIME_CACHE: &str = "RUNTIME_CACHE";
16const PREVIOUS_STATE: &str = "PREVIOUS_STATE";
17type HostState = BTreeMap<[u8; 32], BTreeMap<Vec<u8>, Vec<u8>>>;
18
19/// A inkpad storage implementation using sled
20#[derive(Clone)]
21pub struct Storage {
22    pub db: Db,
23    cache: Tree,
24    frame: Vec<Rc<RefCell<State<Memory>>>>,
25    state: HostState,
26}
27
28impl traits::Storage for Storage {
29    fn set(&mut self, key: Vec<u8>, value: Vec<u8>) -> Option<Vec<u8>> {
30        self.cache.insert(key, value).ok()?.map(|v| v.to_vec())
31    }
32
33    fn remove(&mut self, key: &[u8]) -> Option<Vec<u8>> {
34        self.cache.remove(key).ok()?.map(|v| v.to_vec())
35    }
36
37    fn get(&self, key: &[u8]) -> Option<Vec<u8>> {
38        self.cache.get(key).ok()?.map(|v| v.to_vec())
39    }
40}
41
42impl Cache<Memory> for Storage {
43    fn frame(&self) -> &Vec<Rc<RefCell<State<Memory>>>> {
44        &self.frame
45    }
46
47    fn frame_mut(&mut self) -> &mut Vec<Rc<RefCell<State<Memory>>>> {
48        &mut self.frame
49    }
50
51    fn memory(&self) -> Option<Memory> {
52        Some(self.frame.last()?.borrow().memory.clone())
53    }
54
55    /// Flush data
56    fn flush(&mut self) -> Option<()> {
57        for state in self.frame.iter() {
58            let state = state.borrow().clone();
59            self.state.insert(state.hash, state.state);
60        }
61
62        let mut data = if let Some(state) = self.db.get(PREVIOUS_STATE).ok()? {
63            HostState::decode(&mut state.as_ref()).ok()?
64        } else {
65            BTreeMap::new()
66        };
67
68        data.append(&mut self.state.clone());
69        self.db.insert(PREVIOUS_STATE, data.encode()).ok()?;
70        self.db.flush().ok()?;
71        Some(())
72    }
73}
74
75impl Frame<Memory> for Storage {}
76
77impl Storage {
78    fn quit() {
79        println!(
80            "The following required arguments were not provided: \n\t\t\
81             <*.contract | name | code-hash>"
82        );
83        process::exit(1);
84    }
85
86    /// New storage
87    pub fn new() -> crate::Result<Self> {
88        let etc = Etc::new(&dirs::home_dir().ok_or("Could not find home dir")?)?;
89        let db = sled::open(etc.open(".inkpad/contracts")?.real_path()?)?;
90        let cache = db.open_tree(RUNTIME_CACHE)?;
91
92        Ok(Self {
93            db,
94            cache,
95            frame: Vec::new(),
96            state: BTreeMap::new(),
97        })
98    }
99
100    fn load(&mut self, rt: &mut Runtime) -> Result<()> {
101        let previous = self.db.get(PREVIOUS_STATE)?;
102        if previous.is_none() {
103            return Ok(());
104        }
105
106        for (code_hash, map) in
107            HostState::decode(&mut previous.ok_or("Get previous data failed")?.as_ref())?
108                .into_iter()
109        {
110            log::debug!("load contract: 0x{}", hex::encode(code_hash));
111            rt.sandbox.prepare(code_hash)?;
112            rt.sandbox
113                .cache
114                .borrow_mut()
115                .frame_mut()
116                .last_mut()
117                .ok_or("Could not get last frame")?
118                .borrow_mut()
119                .state = map;
120        }
121
122        let mut cache = rt.sandbox.cache.borrow_mut();
123        let first = cache
124            .frame()
125            .first()
126            .ok_or("No frame in current runtime")?
127            .clone();
128        cache.frame_mut().push(first);
129        Ok(())
130    }
131
132    /// Contract instance
133    ///
134    /// * From path of `*.contract`
135    /// * From name of `*.contract`
136    /// * From code_hash of `*.contract`
137    pub fn rt(&mut self, contract: &str) -> crate::Result<Runtime> {
138        let if_path = PathBuf::from(contract);
139        let cache = self.clone();
140        let mut runtime = if if_path.exists() {
141            // init from source
142            let source = fs::read(contract)?;
143            let r = Runtime::from_contract(&source, cache, Some(inkpad_ri::Instance))?;
144            self.db.insert(
145                r.cache
146                    .borrow()
147                    .active()
148                    .ok_or(inkpad_executor::Error::CodeNotFound)?,
149                r.metadata.encode(),
150            )?;
151            r
152        } else if let Ok(Some(contract)) = if contract.is_empty() {
153            // init from recent
154            let mut recent = None;
155            for c in self.db.iter() {
156                let (k, v) = c?;
157                if k.len() == 32 {
158                    recent = Some(Ok(Some(v)));
159                    break;
160                }
161            }
162
163            if let Some(r) = recent {
164                r
165            } else {
166                return Err(crate::Error::ParseContractFailed(
167                    "Get recent contract failed".to_string(),
168                ));
169            }
170        } else {
171            self.db.get(contract.as_bytes())
172        } {
173            Runtime::from_metadata(
174                Metadata::decode(&mut contract.as_ref())?,
175                cache,
176                Some(inkpad_ri::Instance),
177            )?
178        } else {
179            Self::quit();
180
181            // NOTE:
182            //
183            // Unreachable error
184            return Err(crate::Error::ParseContractFailed(contract.to_string()));
185        };
186
187        // load previous data
188        self.load(&mut runtime)?;
189
190        // flush data
191        self.flush().ok_or("Flush data failed")?;
192
193        // returns rt
194        Ok(runtime)
195    }
196}