oasis_runtime_sdk/storage/
host.rs

1use std::sync::Arc;
2
3use anyhow::{anyhow, Result};
4
5use crate::{
6    core::{
7        common::namespace::Namespace,
8        consensus::{state::roothash::ImmutableState as RoothashState, verifier::Verifier},
9        protocol::Protocol,
10        storage::mkvs,
11        types::HostStorageEndpoint,
12    },
13    storage,
14};
15
16/// A store for a specific state root that talks to the runtime host.
17pub struct HostStore {
18    tree: mkvs::Tree,
19}
20
21impl HostStore {
22    /// Create a new host store for the given host and root.
23    pub fn new(host: Arc<Protocol>, root: mkvs::Root) -> Self {
24        Self {
25            tree: new_mkvs_tree_for_root(host, root),
26        }
27    }
28
29    /// Create a new host store for the given host and root at the given round.
30    ///
31    /// The corresponding root hash is fetched by looking it up in consensus layer state, verified
32    /// by the passed verifier to be correct.
33    pub async fn new_for_round(
34        host: Arc<Protocol>,
35        consensus_verifier: &Arc<dyn Verifier>,
36        runtime_id: Namespace,
37        round: u64,
38    ) -> Result<Self> {
39        Ok(Self {
40            tree: new_mkvs_tree_for_round(
41                host,
42                consensus_verifier,
43                runtime_id,
44                round,
45                mkvs::RootType::State,
46            )
47            .await?,
48        })
49    }
50}
51
52impl storage::Store for HostStore {
53    fn get(&self, key: &[u8]) -> Option<Vec<u8>> {
54        self.tree.get(key).unwrap()
55    }
56
57    fn insert(&mut self, key: &[u8], value: &[u8]) {
58        self.tree.insert(key, value).unwrap();
59    }
60
61    fn remove(&mut self, key: &[u8]) {
62        self.tree.remove(key).unwrap();
63    }
64
65    fn iter(&self) -> Box<dyn mkvs::Iterator + '_> {
66        Box::new(self.tree.iter())
67    }
68
69    fn prefetch_prefixes(&mut self, prefixes: Vec<mkvs::Prefix>, limit: u16) {
70        self.tree.prefetch_prefixes(&prefixes, limit).unwrap();
71    }
72}
73
74/// Create a new MKVS tree for the given host and root.
75pub fn new_mkvs_tree_for_root(host: Arc<Protocol>, root: mkvs::Root) -> mkvs::Tree {
76    let read_syncer = mkvs::sync::HostReadSyncer::new(host, HostStorageEndpoint::Runtime);
77    mkvs::Tree::builder()
78        .with_capacity(10_000, 1024 * 1024)
79        .with_root(root)
80        .build(Box::new(read_syncer))
81}
82
83/// Create a new MKVS tree for the given host and runtime at the given round.
84///
85/// The corresponding root hash is fetched by looking it up in consensus layer state, verified
86/// by the passed verifier to be correct.
87pub async fn new_mkvs_tree_for_round(
88    host: Arc<Protocol>,
89    consensus_verifier: &Arc<dyn Verifier>,
90    runtime_id: Namespace,
91    round: u64,
92    root_type: mkvs::RootType,
93) -> Result<mkvs::Tree> {
94    // Fetch latest consensus layer state.
95    let state = consensus_verifier.latest_state().await?;
96    // Fetch latest roots for the given namespace.
97    let roots = tokio::task::spawn_blocking(move || {
98        let roothash = RoothashState::new(&state);
99        roothash.round_roots(runtime_id, round)
100    })
101    .await??
102    .ok_or(anyhow!("root not found"))?;
103
104    let root = mkvs::Root {
105        namespace: runtime_id,
106        version: round,
107        root_type,
108        hash: match root_type {
109            mkvs::RootType::State => roots.state_root,
110            mkvs::RootType::IO => roots.io_root,
111            _ => return Err(anyhow!("unsupported root type")),
112        },
113    };
114
115    Ok(new_mkvs_tree_for_root(host, root))
116}