Skip to main content

linera_sdk/views/
system_api.rs

1// Copyright (c) Zefchain Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4//! Functions and types to interface with the system API available to application views.
5
6#[cfg(with_testing)]
7use std::sync::Arc;
8
9use linera_base::ensure;
10use linera_views::{
11    batch::Batch,
12    store::{ReadableKeyValueStore, WithError, WritableKeyValueStore},
13};
14use thiserror::Error;
15
16#[cfg(with_testing)]
17use super::mock_key_value_store::MockKeyValueStore;
18use crate::{
19    contract::wit::{
20        base_runtime_api::{self as contract_wit},
21        contract_runtime_api::{self, WriteOperation},
22    },
23    service::wit::base_runtime_api as service_wit,
24};
25
26/// We need to have a maximum key size that handles all possible underlying
27/// sizes. The tightest historical constraint was a key length of 1024.
28/// That key length is decreased by 4 due to the use of a value splitting.
29/// Then the [`KeyValueStore`] needs to handle some base key and so we
30/// reduce to 900. Depending on the size, the error can occur in `system_api`
31/// or in the `KeyValueStoreView`.
32const MAX_KEY_SIZE: usize = 900;
33
34/// A type to interface with the key value storage provided to applications.
35#[derive(Clone)]
36pub struct KeyValueStore {
37    wit_api: WitInterface,
38}
39
40#[cfg_attr(with_testing, allow(dead_code))]
41impl KeyValueStore {
42    /// Returns a [`KeyValueStore`] that uses the contract WIT interface.
43    pub(crate) fn for_contracts() -> Self {
44        KeyValueStore {
45            wit_api: WitInterface::Contract,
46        }
47    }
48
49    /// Returns a [`KeyValueStore`] that uses the service WIT interface.
50    pub(crate) fn for_services() -> Self {
51        KeyValueStore {
52            wit_api: WitInterface::Service,
53        }
54    }
55
56    /// Returns a new [`KeyValueStore`] that just keeps the storage contents in memory.
57    #[cfg(with_testing)]
58    pub fn mock() -> Self {
59        KeyValueStore {
60            wit_api: WitInterface::Mock {
61                store: Arc::new(MockKeyValueStore::default()),
62                read_only: true,
63            },
64        }
65    }
66
67    /// Returns a mocked [`KeyValueStore`] that shares the memory storage with this instance but
68    /// allows write operations.
69    #[cfg(with_testing)]
70    pub fn to_mut(&self) -> Self {
71        let WitInterface::Mock { store, .. } = &self.wit_api else {
72            panic!("Real `KeyValueStore` should not be used in unit tests");
73        };
74
75        KeyValueStore {
76            wit_api: WitInterface::Mock {
77                store: store.clone(),
78                read_only: false,
79            },
80        }
81    }
82}
83
84impl WithError for KeyValueStore {
85    type Error = KeyValueStoreError;
86}
87
88/// The error type for [`KeyValueStore`] operations.
89#[derive(Error, Debug)]
90pub enum KeyValueStoreError {
91    /// Key too long
92    #[error("Key too long")]
93    KeyTooLong,
94
95    /// BCS serialization error.
96    #[error(transparent)]
97    BcsError(#[from] bcs::Error),
98}
99
100impl linera_views::store::KeyValueStoreError for KeyValueStoreError {
101    const BACKEND: &'static str = "key_value_store";
102}
103
104impl ReadableKeyValueStore for KeyValueStore {
105    // The KeyValueStore of the system_api does not have limits
106    // on the size of its values.
107    const MAX_KEY_SIZE: usize = MAX_KEY_SIZE;
108
109    fn root_key(&self) -> Result<Vec<u8>, KeyValueStoreError> {
110        Ok(Vec::new())
111    }
112
113    async fn contains_key(&self, key: &[u8]) -> Result<bool, KeyValueStoreError> {
114        ensure!(
115            key.len() <= Self::MAX_KEY_SIZE,
116            KeyValueStoreError::KeyTooLong
117        );
118        let promise = self.wit_api.contains_key_new(key);
119        Ok(self.wit_api.contains_key_wait(promise))
120    }
121
122    async fn contains_keys(&self, keys: &[Vec<u8>]) -> Result<Vec<bool>, KeyValueStoreError> {
123        for key in keys {
124            ensure!(
125                key.len() <= Self::MAX_KEY_SIZE,
126                KeyValueStoreError::KeyTooLong
127            );
128        }
129        let promise = self.wit_api.contains_keys_new(keys);
130        Ok(self.wit_api.contains_keys_wait(promise))
131    }
132
133    async fn read_multi_values_bytes(
134        &self,
135        keys: &[Vec<u8>],
136    ) -> Result<Vec<Option<Vec<u8>>>, KeyValueStoreError> {
137        for key in keys {
138            ensure!(
139                key.len() <= Self::MAX_KEY_SIZE,
140                KeyValueStoreError::KeyTooLong
141            );
142        }
143        let promise = self.wit_api.read_multi_values_bytes_new(keys);
144        Ok(self.wit_api.read_multi_values_bytes_wait(promise))
145    }
146
147    async fn read_value_bytes(&self, key: &[u8]) -> Result<Option<Vec<u8>>, KeyValueStoreError> {
148        ensure!(
149            key.len() <= Self::MAX_KEY_SIZE,
150            KeyValueStoreError::KeyTooLong
151        );
152        let promise = self.wit_api.read_value_bytes_new(key);
153        Ok(self.wit_api.read_value_bytes_wait(promise))
154    }
155
156    async fn find_keys_by_prefix(
157        &self,
158        key_prefix: &[u8],
159    ) -> Result<Vec<Vec<u8>>, KeyValueStoreError> {
160        ensure!(
161            key_prefix.len() <= Self::MAX_KEY_SIZE,
162            KeyValueStoreError::KeyTooLong
163        );
164        let promise = self.wit_api.find_keys_new(key_prefix);
165        Ok(self.wit_api.find_keys_wait(promise))
166    }
167
168    async fn find_key_values_by_prefix(
169        &self,
170        key_prefix: &[u8],
171    ) -> Result<Vec<(Vec<u8>, Vec<u8>)>, KeyValueStoreError> {
172        ensure!(
173            key_prefix.len() <= Self::MAX_KEY_SIZE,
174            KeyValueStoreError::KeyTooLong
175        );
176        let promise = self.wit_api.find_key_values_new(key_prefix);
177        Ok(self.wit_api.find_key_values_wait(promise))
178    }
179}
180
181impl WritableKeyValueStore for KeyValueStore {
182    const MAX_VALUE_SIZE: usize = usize::MAX;
183
184    async fn write_batch(&self, batch: Batch) -> Result<(), KeyValueStoreError> {
185        self.wit_api.write_batch(batch);
186        Ok(())
187    }
188
189    async fn clear_journal(&self) -> Result<(), KeyValueStoreError> {
190        Ok(())
191    }
192}
193
194/// Which system API should be used to interface with the storage.
195#[derive(Clone)]
196#[cfg_attr(with_testing, allow(dead_code))]
197enum WitInterface {
198    /// The contract system API.
199    Contract,
200    /// The service system API.
201    Service,
202    #[cfg(with_testing)]
203    /// A mock system API.
204    Mock {
205        store: Arc<MockKeyValueStore>,
206        read_only: bool,
207    },
208}
209
210impl WitInterface {
211    /// Creates a promise for testing if a key exist in the key-value store
212    fn contains_key_new(&self, key: &[u8]) -> u32 {
213        match self {
214            WitInterface::Contract => contract_wit::contains_key_new(key),
215            WitInterface::Service => service_wit::contains_key_new(key),
216            #[cfg(with_testing)]
217            WitInterface::Mock { store, .. } => store.contains_key_new(key),
218        }
219    }
220
221    /// Resolves a promise for testing if a key exist in the key-value store
222    fn contains_key_wait(&self, promise: u32) -> bool {
223        match self {
224            WitInterface::Contract => contract_wit::contains_key_wait(promise),
225            WitInterface::Service => service_wit::contains_key_wait(promise),
226            #[cfg(with_testing)]
227            WitInterface::Mock { store, .. } => store.contains_key_wait(promise),
228        }
229    }
230
231    /// Creates a promise for testing if multiple keys exist in the key-value store
232    fn contains_keys_new(&self, keys: &[Vec<u8>]) -> u32 {
233        match self {
234            WitInterface::Contract => contract_wit::contains_keys_new(keys),
235            WitInterface::Service => service_wit::contains_keys_new(keys),
236            #[cfg(with_testing)]
237            WitInterface::Mock { store, .. } => store.contains_keys_new(keys),
238        }
239    }
240
241    /// Resolves a promise for testing if multiple keys exist in the key-value store
242    fn contains_keys_wait(&self, promise: u32) -> Vec<bool> {
243        match self {
244            WitInterface::Contract => contract_wit::contains_keys_wait(promise),
245            WitInterface::Service => service_wit::contains_keys_wait(promise),
246            #[cfg(with_testing)]
247            WitInterface::Mock { store, .. } => store.contains_keys_wait(promise),
248        }
249    }
250
251    /// Creates a promise for reading multiple keys in the key-value store
252    fn read_multi_values_bytes_new(&self, keys: &[Vec<u8>]) -> u32 {
253        match self {
254            WitInterface::Contract => contract_wit::read_multi_values_bytes_new(keys),
255            WitInterface::Service => service_wit::read_multi_values_bytes_new(keys),
256            #[cfg(with_testing)]
257            WitInterface::Mock { store, .. } => store.read_multi_values_bytes_new(keys),
258        }
259    }
260
261    /// Resolves a promise for reading multiple keys in the key-value store
262    fn read_multi_values_bytes_wait(&self, promise: u32) -> Vec<Option<Vec<u8>>> {
263        match self {
264            WitInterface::Contract => contract_wit::read_multi_values_bytes_wait(promise),
265            WitInterface::Service => service_wit::read_multi_values_bytes_wait(promise),
266            #[cfg(with_testing)]
267            WitInterface::Mock { store, .. } => store.read_multi_values_bytes_wait(promise),
268        }
269    }
270
271    /// Creates a promise for reading a key in the key-value store
272    fn read_value_bytes_new(&self, key: &[u8]) -> u32 {
273        match self {
274            WitInterface::Contract => contract_wit::read_value_bytes_new(key),
275            WitInterface::Service => service_wit::read_value_bytes_new(key),
276            #[cfg(with_testing)]
277            WitInterface::Mock { store, .. } => store.read_value_bytes_new(key),
278        }
279    }
280
281    /// Resolves a promise for reading a key in the key-value store
282    fn read_value_bytes_wait(&self, promise: u32) -> Option<Vec<u8>> {
283        match self {
284            WitInterface::Contract => contract_wit::read_value_bytes_wait(promise),
285            WitInterface::Service => service_wit::read_value_bytes_wait(promise),
286            #[cfg(with_testing)]
287            WitInterface::Mock { store, .. } => store.read_value_bytes_wait(promise),
288        }
289    }
290
291    /// Creates a promise for finding keys having a specified prefix in the key-value store
292    fn find_keys_new(&self, key_prefix: &[u8]) -> u32 {
293        match self {
294            WitInterface::Contract => contract_wit::find_keys_new(key_prefix),
295            WitInterface::Service => service_wit::find_keys_new(key_prefix),
296            #[cfg(with_testing)]
297            WitInterface::Mock { store, .. } => store.find_keys_new(key_prefix),
298        }
299    }
300
301    /// Resolves a promise for finding keys having a specified prefix in the key-value store
302    fn find_keys_wait(&self, promise: u32) -> Vec<Vec<u8>> {
303        match self {
304            WitInterface::Contract => contract_wit::find_keys_wait(promise),
305            WitInterface::Service => service_wit::find_keys_wait(promise),
306            #[cfg(with_testing)]
307            WitInterface::Mock { store, .. } => store.find_keys_wait(promise),
308        }
309    }
310
311    /// Creates a promise for finding the key/values having a specified prefix in the key-value store
312    fn find_key_values_new(&self, key_prefix: &[u8]) -> u32 {
313        match self {
314            WitInterface::Contract => contract_wit::find_key_values_new(key_prefix),
315            WitInterface::Service => service_wit::find_key_values_new(key_prefix),
316            #[cfg(with_testing)]
317            WitInterface::Mock { store, .. } => store.find_key_values_new(key_prefix),
318        }
319    }
320
321    /// Resolves a promise for finding the key/values having a specified prefix in the key-value store
322    fn find_key_values_wait(&self, promise: u32) -> Vec<(Vec<u8>, Vec<u8>)> {
323        match self {
324            WitInterface::Contract => contract_wit::find_key_values_wait(promise),
325            WitInterface::Service => service_wit::find_key_values_wait(promise),
326            #[cfg(with_testing)]
327            WitInterface::Mock { store, .. } => store.find_key_values_wait(promise),
328        }
329    }
330
331    /// Calls the `write_batch` WIT function.
332    fn write_batch(&self, batch: Batch) {
333        match self {
334            WitInterface::Contract => {
335                let batch_operations = batch
336                    .operations
337                    .into_iter()
338                    .map(WriteOperation::from)
339                    .collect::<Vec<_>>();
340
341                contract_runtime_api::write_batch(&batch_operations);
342            }
343            WitInterface::Service => panic!("Attempt to modify storage from a service"),
344            #[cfg(with_testing)]
345            WitInterface::Mock {
346                store,
347                read_only: false,
348            } => {
349                store.write_batch(batch);
350            }
351            #[cfg(with_testing)]
352            WitInterface::Mock {
353                read_only: true, ..
354            } => {
355                panic!("Attempt to modify storage from a service")
356            }
357        }
358    }
359}
360
361/// Implementation of [`linera_views::context::Context`] to be used for data storage
362/// by Linera applications.
363pub type ViewStorageContext = linera_views::context::ViewContext<(), KeyValueStore>;
364
365#[cfg(all(test, not(target_arch = "wasm32")))]
366mod tests {
367    use super::*;
368
369    #[tokio::test]
370    async fn test_key_value_store_mock() -> anyhow::Result<()> {
371        // Create a mock key-value store for testing
372        let store = KeyValueStore::mock();
373        let mock_store = store.to_mut();
374
375        // Check if key exists
376        let is_key_existing = mock_store.contains_key(b"foo").await?;
377        assert!(!is_key_existing);
378
379        // Check if keys exist
380        let is_keys_existing = mock_store
381            .contains_keys(&[b"foo".to_vec(), b"bar".to_vec()])
382            .await?;
383        assert!(!is_keys_existing[0]);
384        assert!(!is_keys_existing[1]);
385
386        // Read and write values
387        let mut batch = Batch::new();
388        batch.put_key_value(b"foo".to_vec(), &32_u128)?;
389        batch.put_key_value(b"bar".to_vec(), &42_u128)?;
390        mock_store.write_batch(batch).await?;
391
392        let is_key_existing = mock_store.contains_key(b"foo").await?;
393        assert!(is_key_existing);
394
395        let value = mock_store.read_value(b"foo").await?;
396        assert_eq!(value, Some(32_u128));
397
398        let value = mock_store.read_value(b"bar").await?;
399        assert_eq!(value, Some(42_u128));
400
401        Ok(())
402    }
403}