diff --git a/linera-sdk/mock_system_api.wit b/linera-sdk/mock_system_api.wit index 5158a3c59af4..d551876eabd9 100644 --- a/linera-sdk/mock_system_api.wit +++ b/linera-sdk/mock_system_api.wit @@ -14,9 +14,6 @@ enum log-level { error, } -mocked-load: func() -> list -mocked-store: func(value: list) -> bool - mocked-read-multi-values-bytes: func(keys: list>) -> list>> mocked-read-value-bytes: func(key: list) -> option> mocked-find-keys: func(prefix: list) -> list> diff --git a/linera-sdk/src/bin/linera-wasm-test-runner/mock_system_api.rs b/linera-sdk/src/bin/linera-wasm-test-runner/mock_system_api.rs index a29b535db14f..858e6883c5e3 100644 --- a/linera-sdk/src/bin/linera-wasm-test-runner/mock_system_api.rs +++ b/linera-sdk/src/bin/linera-wasm-test-runner/mock_system_api.rs @@ -369,30 +369,6 @@ pub fn add_to_linker(linker: &mut Linker) -> Result<()> { }) }, )?; - linker.func_wrap1_async( - "contract_system_api", - "load: func() -> list", - move |mut caller: Caller<'_, Resources>, return_offset: i32| { - Box::new(async move { - let function = get_function(&mut caller, "mocked-load: func() -> list").expect( - "Missing `mocked-load` function in the module. \ - Please ensure `linera_sdk::test::mock_application_state` was called", - ); - - let (result_offset,) = function - .typed::<(), (i32,), _>(&mut caller) - .expect("Incorrect `mocked-load` function signature") - .call_async(&mut caller, ()) - .await - .expect( - "Failed to call `mocked-load` function. \ - Please ensure `linera_sdk::test::mock_application_state` was called", - ); - - copy_memory_slices(&mut caller, result_offset, return_offset, 8); - }) - }, - )?; linker.func_wrap1_async( "service_system_api", @@ -604,36 +580,6 @@ pub fn add_to_linker(linker: &mut Linker) -> Result<()> { }) }, )?; - linker.func_wrap0_async( - "service_system_api", - "load::new: func() -> handle", - move |_: Caller<'_, Resources>| Box::new(async move { 0 }), - )?; - linker.func_wrap2_async( - "service_system_api", - "load::wait: func(self: handle) -> result, string>", - move |mut caller: Caller<'_, Resources>, _handle: i32, return_offset: i32| { - Box::new(async move { - let function = get_function(&mut caller, "mocked-load: func() -> list").expect( - "Missing `mocked-load` function in the module. \ - Please ensure `linera_sdk::test::mock_application_state` was called", - ); - - let (result_offset,) = function - .typed::<(), (i32,), _>(&mut caller) - .expect("Incorrect `mocked-load` function signature") - .call_async(&mut caller, ()) - .await - .expect( - "Failed to call `mocked-load` function. \ - Please ensure `linera_sdk::test::mock_application_state` was called", - ); - - store_in_memory(&mut caller, return_offset, 0_i32); - copy_memory_slices(&mut caller, result_offset, return_offset + 4, 8); - }) - }, - )?; linker.func_wrap15_async( "service_system_api", "try-query-application: func(\ @@ -1123,7 +1069,6 @@ pub fn add_to_linker(linker: &mut Linker) -> Result<()> { )?; let resource_names = [ - "load", "read-multi-values-bytes", "read-value-bytes", "find-keys", diff --git a/linera-sdk/src/contract/storage.rs b/linera-sdk/src/contract/storage.rs index 88264d04eca4..c4550892975e 100644 --- a/linera-sdk/src/contract/storage.rs +++ b/linera-sdk/src/contract/storage.rs @@ -8,11 +8,13 @@ //! contract type that implements [`Contract`]. use crate::{ - contract::system_api, views::ViewStorageContext, Contract, SimpleStateStorage, ViewStateStorage, + contract::system_api, + views::{AppStateStore, ViewStorageContext}, + Contract, SimpleStateStorage, ViewStateStorage, }; use async_trait::async_trait; use futures::TryFutureExt; -use linera_views::views::RootView; +use linera_views::{batch::Batch, common::KeyValueStore, views::RootView}; use serde::{de::DeserializeOwned, Serialize}; use std::future::Future; @@ -58,11 +60,29 @@ where Application: Contract + Default + DeserializeOwned + Serialize + Send + 'static, { async fn load() -> Application { - system_api::load().expect("Failed to lock contract state") + let maybe_bytes = AppStateStore + .read_value_bytes(&[]) + .await + .expect("Failed to read application state bytes"); + + if let Some(bytes) = maybe_bytes { + bcs::from_bytes(&bytes).expect("Failed to deserialize application state") + } else { + Application::default() + } } async fn store(state: Application) { - system_api::store(state).await; + let mut batch = Batch::new(); + + batch + .put_key_value(vec![], &state) + .expect("Failed to serialize application state"); + + AppStateStore + .write_batch(batch, &[]) + .await + .expect("Failed to store application state bytes"); } } diff --git a/linera-sdk/src/contract/system_api/mod.rs b/linera-sdk/src/contract/system_api/mod.rs index 7806abd05d4b..f30221752cd6 100644 --- a/linera-sdk/src/contract/system_api/mod.rs +++ b/linera-sdk/src/contract/system_api/mod.rs @@ -9,8 +9,7 @@ mod private; pub mod private; pub(crate) use self::private::{ - call_application, call_session, current_application_parameters, load, load_view, store, - store_view, + call_application, call_session, current_application_parameters, load_view, store_view, }; use super::contract_system_api as wit; use linera_base::{ diff --git a/linera-sdk/src/contract/system_api/private.rs b/linera-sdk/src/contract/system_api/private.rs index f6bbfd4e3185..8de3b2666eab 100644 --- a/linera-sdk/src/contract/system_api/private.rs +++ b/linera-sdk/src/contract/system_api/private.rs @@ -8,42 +8,12 @@ use super::super::contract_system_api as wit; use crate::views::ViewStorageContext; use linera_base::identifiers::{ApplicationId, SessionId}; use linera_views::views::{RootView, View}; -use serde::{de::DeserializeOwned, Serialize}; /// Retrieves the current application parameters. pub fn current_application_parameters() -> Vec { wit::application_parameters() } -/// Deserializes the application state or creates a new one if the `bytes` vector is empty. -fn deserialize_state(bytes: Vec) -> State -where - State: Default + DeserializeOwned, -{ - if bytes.is_empty() { - State::default() - } else { - bcs::from_bytes(&bytes).expect("Invalid application state") - } -} - -/// Loads the application state. -pub fn load() -> Option -where - State: Default + DeserializeOwned, -{ - let state_bytes = wit::load(); - Some(deserialize_state(state_bytes)) -} - -/// Saves the application state. -pub async fn store(state: State) -where - State: Serialize, -{ - wit::store(&bcs::to_bytes(&state).expect("State serialization failed")); -} - /// Loads the application state or create a new one if it doesn't exist. pub async fn load_view>() -> State { let context = ViewStorageContext::default(); diff --git a/linera-sdk/src/service/storage.rs b/linera-sdk/src/service/storage.rs index 14dc0edbb080..c084ee8490c0 100644 --- a/linera-sdk/src/service/storage.rs +++ b/linera-sdk/src/service/storage.rs @@ -9,11 +9,11 @@ use crate::{ service::{system_api, wit_types}, - views::ViewStorageContext, + views::{AppStateStore, ViewStorageContext}, Service, SimpleStateStorage, ViewStateStorage, }; use async_trait::async_trait; -use linera_views::views::RootView; +use linera_views::{common::KeyValueStore, views::RootView}; use serde::{de::DeserializeOwned, Serialize}; use std::sync::Arc; @@ -36,7 +36,18 @@ where context: wit_types::QueryContext, argument: Vec, ) -> Result, String> { - let application: Arc = Arc::new(system_api::load().await); + let maybe_bytes = AppStateStore + .read_value_bytes(&[]) + .await + .expect("Failed to read application state bytes"); + + let state = if let Some(bytes) = maybe_bytes { + bcs::from_bytes(&bytes).expect("Failed to deserialize application state") + } else { + Application::default() + }; + + let application: Arc = Arc::new(state); let argument: Application::Query = serde_json::from_slice(&argument).map_err(|e| e.to_string())?; let query_response = application diff --git a/linera-sdk/src/service/system_api/mod.rs b/linera-sdk/src/service/system_api/mod.rs index 96c732b8b037..95d62e05b825 100644 --- a/linera-sdk/src/service/system_api/mod.rs +++ b/linera-sdk/src/service/system_api/mod.rs @@ -8,9 +8,7 @@ mod private; #[cfg(any(test, feature = "test"))] pub mod private; -pub(crate) use self::private::{ - current_application_parameters, load, load_view, query_application, -}; +pub(crate) use self::private::{current_application_parameters, load_view, query_application}; use super::service_system_api as wit; use linera_base::{ data_types::{Amount, Timestamp}, diff --git a/linera-sdk/src/service/system_api/private.rs b/linera-sdk/src/service/system_api/private.rs index aec5fd3d74b9..303f50472b99 100644 --- a/linera-sdk/src/service/system_api/private.rs +++ b/linera-sdk/src/service/system_api/private.rs @@ -5,25 +5,9 @@ //! that shouldn't be used by applications directly. use super::super::service_system_api as wit; -use crate::{util::yield_once, views::ViewStorageContext}; +use crate::views::ViewStorageContext; use linera_base::identifiers::ApplicationId; use linera_views::views::View; -use serde::de::DeserializeOwned; - -/// Loads the application state, without locking it for writes. -pub async fn load() -> State -where - State: Default + DeserializeOwned, -{ - let promise = wit::Load::new(); - yield_once().await; - let bytes = promise.wait().expect("Failed to load application state"); - if bytes.is_empty() { - State::default() - } else { - bcs::from_bytes(&bytes).expect("Invalid application state") - } -} /// Helper function to load the service state or create a new one if it doesn't exist. pub async fn load_view>() -> State { diff --git a/linera-sdk/src/test/unit/mod.rs b/linera-sdk/src/test/unit/mod.rs index 5c9e56376c64..851b8b3de016 100644 --- a/linera-sdk/src/test/unit/mod.rs +++ b/linera-sdk/src/test/unit/mod.rs @@ -35,7 +35,6 @@ static mut MOCK_APPLICATION_PARAMETERS: Option> = None; static mut MOCK_SYSTEM_BALANCE: Option = None; static mut MOCK_SYSTEM_TIMESTAMP: Option = None; static mut MOCK_LOG_COLLECTOR: Vec<(log::Level, String)> = Vec::new(); -static mut MOCK_APPLICATION_STATE: Option> = None; static mut MOCK_KEY_VALUE_STORE: Option> = None; static mut MOCK_TRY_QUERY_APPLICATION: Option< Box) -> Result, String>>, @@ -74,11 +73,6 @@ pub fn log_messages() -> Vec<(log::Level, String)> { unsafe { MOCK_LOG_COLLECTOR.clone() } } -/// Sets the mocked application state. -pub fn mock_application_state(state: impl Into>>) { - unsafe { MOCK_APPLICATION_STATE = state.into() }; -} - /// Initializes and returns a view context for using as the mocked key-value store. pub fn mock_key_value_store() -> MemoryContext<()> { let store = linera_views::memory::create_memory_context(); @@ -151,23 +145,6 @@ impl wit::MockSystemApi for MockSystemApi { unsafe { MOCK_LOG_COLLECTOR.push((level.into(), message)) } } - fn mocked_load() -> Vec { - unsafe { MOCK_APPLICATION_STATE.clone() }.expect( - "Unexpected call to the `load` system API. \ - Please call `mock_application_state` first", - ) - } - - fn mocked_store(state: Vec) -> bool { - assert!( - unsafe { MOCK_APPLICATION_STATE.is_some() }, - "Unexpected call to `store_and_unlock` system API. \ - Please call `mock_application_state` first." - ); - unsafe { MOCK_APPLICATION_STATE = Some(state) }; - true - } - fn mocked_read_multi_values_bytes(keys: Vec>) -> Vec>> { unsafe { MOCK_KEY_VALUE_STORE.as_mut() } .expect( diff --git a/linera-sdk/src/views/mod.rs b/linera-sdk/src/views/mod.rs index 0b5e1c4ceb9f..04109f53ebe2 100644 --- a/linera-sdk/src/views/mod.rs +++ b/linera-sdk/src/views/mod.rs @@ -5,6 +5,7 @@ mod system_api; +pub(crate) use self::system_api::AppStateStore; pub use self::system_api::ViewStorageContext; pub use linera_views::{ self, diff --git a/linera-sdk/wasm-tests/src/lib.rs b/linera-sdk/wasm-tests/src/lib.rs index 4a8d3ed889e5..78f89d11e2a6 100644 --- a/linera-sdk/wasm-tests/src/lib.rs +++ b/linera-sdk/wasm-tests/src/lib.rs @@ -146,21 +146,6 @@ fn mock_service_log() { assert_eq!(test::log_messages(), expected); } -/// Test loading a mocked application state without locking it. -#[webassembly_test] -fn mock_load_blob_state() { - let state = vec![0, 1, 2, 3, 4, 5, 6]; - - test::mock_application_state( - bcs::to_bytes(&state).expect("Failed to serialize vector using BCS"), - ); - - assert_eq!( - service::system_api::private::load::>().blocking_wait(), - state - ); -} - /// A dummy view to test the key value store. #[derive(RootView)] struct DummyView {