From f92e95a76550c0995d693e9ed191c081d7f70d6f Mon Sep 17 00:00:00 2001 From: Filippo Costa Date: Thu, 2 Dec 2021 16:50:34 +0100 Subject: [PATCH] Improve API initialization pattern --- crates/runtime-ffi/src/api.rs | 151 ++++++++++++-------------- crates/runtime-ffi/src/config.rs | 36 ------ crates/runtime-ffi/src/lib.rs | 1 - crates/runtime-ffi/tests/api_tests.rs | 17 ++- 4 files changed, 75 insertions(+), 130 deletions(-) delete mode 100644 crates/runtime-ffi/src/config.rs diff --git a/crates/runtime-ffi/src/api.rs b/crates/runtime-ffi/src/api.rs index c346ac212..f4b3801a5 100644 --- a/crates/runtime-ffi/src/api.rs +++ b/crates/runtime-ffi/src/api.rs @@ -1,58 +1,32 @@ /// SVM C-API methods to access the runtime. use lazy_static::lazy_static; use log::{debug, error}; -use svm_state::GlobalState; +use std::sync::Mutex; use std::ffi::c_void; use std::panic::UnwindSafe; -use std::path::PathBuf; use std::slice; use svm_codec::Codec; use svm_runtime::{PriceResolverRegistry, Runtime, ValidateError}; +use svm_state::GlobalState; use svm_types::{Address, BytesPrimitive, Context, Envelope, Layer, State, TemplateAddr}; -use crate::config::Config; use crate::resource_tracker::ResourceTracker; use crate::svm_result_t; lazy_static! { static ref RUNTIME_TRACKER: ResourceTracker = ResourceTracker::default(); + static ref INITIALIZED: Mutex = Mutex::new(false); } type RuntimePtr = *mut c_void; -fn new_runtime() -> Runtime { - let config = Config::get(); - let imports = ("sm".to_string(), wasmer::Exports::new()); - let global_state = if let Some(db_path) = config.db_path { - GlobalState::new(db_path.as_os_str().to_str().unwrap()) - } else { - GlobalState::in_memory() - }; - - Runtime::new( - imports, - global_state, - PriceResolverRegistry::default(), - None, - ) -} - -/// Initializes the configuration options for all newly allocates SVM runtimes. +/// Initializes the SVM library. #[must_use] #[no_mangle] -pub unsafe extern "C" fn svm_init(in_memory: bool, path: *const u8, path_len: u32) -> svm_result_t { - Config::set(Config { - db_path: if in_memory { - None - } else { - let slice = std::slice::from_raw_parts(path, path_len as usize); - let s = std::str::from_utf8(slice).expect("Invalid UTF-8"); - Some(PathBuf::from(s.to_string())) - }, - }); - +pub extern "C" fn svm_init() -> svm_result_t { + *INITIALIZED.lock().unwrap() = true; svm_result_t::OK } @@ -60,43 +34,59 @@ pub unsafe extern "C" fn svm_init(in_memory: bool, path: *const u8, path_len: u3 #[no_mangle] pub unsafe extern "C" fn svm_free_result(_result: svm_result_t) {} -/// -/// Start of the Public C-API -/// -/// * Each method is annotated with `#[no_mangle]` -/// * Each method has `unsafe extern "C"` before `fn` -/// +/// Start of the public C API. /// See `build.rs` for using `cbindgen` to generate `svm.h` /// +/// Creates a new SVM runtime instance. The database for this runtime will be +/// located by `path` and `path_len`. In case `path` is `NULL`, the runtime will +/// not be persisted and will live entirely in-memory. /// -/// Creates a new SVM Runtime instance backed-by an in-memory KV. -/// -/// Returns it the created Runtime via the `runtime` parameter. +/// The pointer to the runtime is written to `runtime_ptr`. /// /// # Examples /// /// ```rust /// use svm_runtime_ffi::*; /// +/// svm_init().unwrap(); +/// /// let mut runtime = std::ptr::null_mut(); /// -/// unsafe { svm_init(true, std::ptr::null(), 0); } -/// let res = unsafe { svm_runtime_create(&mut runtime) }; +/// let res = unsafe { svm_runtime_create(&mut runtime, std::ptr::null(), 0) }; /// assert!(res.is_ok()); /// ``` /// #[must_use] #[no_mangle] -pub unsafe extern "C" fn svm_runtime_create(runtime_ptr: *mut RuntimePtr) -> svm_result_t { +pub unsafe extern "C" fn svm_runtime_create( + runtime_ptr: *mut RuntimePtr, + path: *const u8, + path_len: u32, +) -> svm_result_t { catch_unwind_or_fail(|| { - if !Config::is_ready() { + let mut initialized = INITIALIZED.lock().unwrap(); + if !*initialized { return svm_result_t::new_error(b"`svm_init` not called beforehand."); } + *initialized = true; - *runtime_ptr = RUNTIME_TRACKER.alloc(new_runtime()); - + let imports = ("sm".to_string(), wasmer::Exports::new()); + let global_state = if path.is_null() { + GlobalState::in_memory() + } else { + let db_path = std::slice::from_raw_parts(path, path_len as usize); + GlobalState::new(std::str::from_utf8(db_path).expect("Invalid UTF-8 path.")) + }; + + let runtime = Runtime::new( + imports, + global_state, + PriceResolverRegistry::default(), + None, + ); + + *runtime_ptr = RUNTIME_TRACKER.alloc(runtime); debug!("`svm_runtime_create` end"); - svm_result_t::OK }) } @@ -108,11 +98,11 @@ pub unsafe extern "C" fn svm_runtime_create(runtime_ptr: *mut RuntimePtr) -> svm /// ```rust /// use svm_runtime_ffi::*; /// -/// let mut runtime = std::ptr::null_mut(); +/// svm_init().unwrap(); /// -/// unsafe { svm_init(true, std::ptr::null(), 0); } +/// let mut runtime = std::ptr::null_mut(); /// -/// let res = unsafe { svm_runtime_create(&mut runtime) }; +/// let res = unsafe { svm_runtime_create(&mut runtime, std::ptr::null(), 0) }; /// assert!(res.is_ok()); /// /// // Destroys the Runtime @@ -131,8 +121,8 @@ pub extern "C" fn svm_runtime_destroy(runtime: RuntimePtr) -> svm_result_t { /// Returns the number of currently allocated runtimes. #[no_mangle] -pub unsafe extern "C" fn svm_runtimes_count(count: *mut u64) { - *count = RUNTIME_TRACKER.count(); +pub extern "C" fn svm_runtimes_count() -> u64 { + RUNTIME_TRACKER.count() } /// Validates syntactically a binary `Deploy Template` transaction. @@ -146,11 +136,11 @@ pub unsafe extern "C" fn svm_runtimes_count(count: *mut u64) { /// ```rust /// use svm_runtime_ffi::*; /// -/// let mut runtime = std::ptr::null_mut(); +/// svm_init().unwrap(); /// -/// unsafe { svm_init(true, std::ptr::null(), 0); } +/// let mut runtime = std::ptr::null_mut(); /// -/// let res = unsafe { svm_runtime_create(&mut runtime) }; +/// let res = unsafe { svm_runtime_create(&mut runtime, std::ptr::null(), 0) }; /// assert!(res.is_ok()); /// /// let message = b"message data..."; @@ -184,11 +174,12 @@ pub unsafe extern "C" fn svm_validate_deploy( /// ```rust /// use svm_runtime_ffi::*; /// -/// let mut runtime = std::ptr::null_mut(); +/// svm_init().unwrap(); /// -/// unsafe { svm_init(true, std::ptr::null(), 0); } +/// let mut runtime = std::ptr::null_mut(); /// -/// let res = unsafe { svm_runtime_create(&mut runtime) }; +/// svm_init().unwrap(); +/// let res = unsafe { svm_runtime_create(&mut runtime, std::ptr::null(), 0) }; /// assert!(res.is_ok()); /// /// let message = b"message data..."; @@ -218,11 +209,10 @@ pub unsafe extern "C" fn svm_validate_spawn( /// ```rust /// use svm_runtime_ffi::*; /// -/// let mut runtime = std::ptr::null_mut(); +/// svm_init().unwrap(); /// -/// unsafe { svm_init(true, std::ptr::null(), 0); } -/// -/// let res = unsafe { svm_runtime_create(&mut runtime) }; +/// let mut runtime = std::ptr::null_mut(); +/// let res = unsafe { svm_runtime_create(&mut runtime, std::ptr::null(), 0) }; /// assert!(res.is_ok()); /// /// let message = b"message data..."; @@ -252,11 +242,10 @@ pub unsafe extern "C" fn svm_validate_call( /// ```rust /// use svm_runtime_ffi::*; /// -/// let mut runtime = std::ptr::null_mut(); -/// -/// unsafe { svm_init(true, std::ptr::null(), 0); } +/// svm_init().unwrap(); /// -/// let res = unsafe { svm_runtime_create(&mut runtime) }; +/// let mut runtime = std::ptr::null_mut(); +/// let res = unsafe { svm_runtime_create(&mut runtime, std::ptr::null(), 0) }; /// assert!(res.is_ok()); /// /// let envelope = b"envelope data..."; @@ -300,11 +289,10 @@ pub unsafe extern "C" fn svm_deploy( /// ```rust /// use svm_runtime_ffi::*; /// -/// let mut runtime = std::ptr::null_mut(); -/// -/// unsafe { svm_init(true, std::ptr::null(), 0); } +/// svm_init().unwrap(); /// -/// let res = unsafe { svm_runtime_create(&mut runtime) }; +/// let mut runtime = std::ptr::null_mut(); +/// let res = unsafe { svm_runtime_create(&mut runtime, std::ptr::null(), 0) }; /// assert!(res.is_ok()); /// /// let envelope = b"envelope data..."; @@ -352,11 +340,10 @@ pub unsafe extern "C" fn svm_spawn( /// ```rust /// use svm_runtime_ffi::*; /// -/// let mut runtime = std::ptr::null_mut(); -/// -/// unsafe { svm_init(true, std::ptr::null(), 0); } +/// svm_init().unwrap(); /// -/// let res = unsafe { svm_runtime_create(&mut runtime) }; +/// let mut runtime = std::ptr::null_mut(); +/// let res = unsafe { svm_runtime_create(&mut runtime, std::ptr::null(), 0) }; /// assert!(res.is_ok()); /// /// let envelope = b"envelope data..."; @@ -401,11 +388,10 @@ pub unsafe extern "C" fn svm_verify( /// ```rust /// use svm_runtime_ffi::*; /// -/// let mut runtime = std::ptr::null_mut(); -/// -/// unsafe { svm_init(true, std::ptr::null(), 0); } +/// svm_init().unwrap(); /// -/// let res = unsafe { svm_runtime_create(&mut runtime) }; +/// let mut runtime = std::ptr::null_mut(); +/// let res = unsafe { svm_runtime_create(&mut runtime, std::ptr::null(), 0) }; /// assert!(res.is_ok()); /// /// let envelope = b"envelope data..."; @@ -450,11 +436,10 @@ pub unsafe extern "C" fn svm_call( /// ```rust /// use svm_runtime_ffi::*; /// -/// let mut runtime = std::ptr::null_mut(); +/// svm_init().unwrap(); /// -/// unsafe { svm_init(true, std::ptr::null(), 0); } -/// -/// let res = unsafe { svm_runtime_create(&mut runtime) }; +/// let mut runtime = std::ptr::null_mut(); +/// let res = unsafe { svm_runtime_create(&mut runtime, std::ptr::null(), 0) }; /// assert!(res.is_ok()); /// /// let res = unsafe { svm_uncommitted_changes(runtime) }; diff --git a/crates/runtime-ffi/src/config.rs b/crates/runtime-ffi/src/config.rs deleted file mode 100644 index 64de5140b..000000000 --- a/crates/runtime-ffi/src/config.rs +++ /dev/null @@ -1,36 +0,0 @@ -use lazy_static::lazy_static; - -use std::path::PathBuf; -use std::sync::Mutex; - -lazy_static! { - static ref CONFIG: Mutex> = Mutex::default(); -} - -#[derive(Debug, Clone)] -pub struct Config { - pub db_path: Option, -} - -impl Config { - /// Initializes the global [`Config`] instance. - pub fn set(config: Config) { - *CONFIG.lock().unwrap() = Some(config); - } - - /// Returns `true` if and only if the global [`Config`] instance has been - /// initialized via [`Config::set`]. - pub fn is_ready() -> bool { - CONFIG.lock().unwrap().is_some() - } - - /// Fetches the global [`Config`] instance. - /// - /// # Panics - /// - /// Panics if the global [`Config`] hasn't been initialized with - /// [`Config::set`]. - pub fn get() -> Config { - CONFIG.lock().unwrap().as_ref().unwrap().clone() - } -} diff --git a/crates/runtime-ffi/src/lib.rs b/crates/runtime-ffi/src/lib.rs index 497ccd1a6..79f20ddb4 100644 --- a/crates/runtime-ffi/src/lib.rs +++ b/crates/runtime-ffi/src/lib.rs @@ -11,7 +11,6 @@ #![feature(try_trait_v2)] mod api; -mod config; mod resource_tracker; mod result; diff --git a/crates/runtime-ffi/tests/api_tests.rs b/crates/runtime-ffi/tests/api_tests.rs index eaa3699fb..74a6e4615 100644 --- a/crates/runtime-ffi/tests/api_tests.rs +++ b/crates/runtime-ffi/tests/api_tests.rs @@ -32,13 +32,13 @@ fn call_message(target: &Address, func_name: &str, calldata: &[u8]) -> Vec { #[test] fn svm_runtime_success() { + svm_init().unwrap(); unsafe { - svm_init(true, std::ptr::null(), 0).unwrap(); - // 1) `Init Runtime` let mut runtime = std::ptr::null_mut(); + api::svm_runtime_create(&mut runtime, std::ptr::null(), 0).unwrap(); - let res = api::svm_runtime_create(&mut runtime); + let res = api::svm_runtime_create(&mut runtime, std::ptr::null(), 0); assert!(res.is_ok()); // 2) `Deploy Template` @@ -131,14 +131,11 @@ fn svm_runtime_success() { #[test] fn svm_runtime_failure() { + svm_init().unwrap(); unsafe { - svm_init(true, std::ptr::null(), 0).unwrap(); - // 1) `Init Runtime` let mut runtime = std::ptr::null_mut(); - - let res = api::svm_runtime_create(&mut runtime); - assert!(res.is_ok()); + api::svm_runtime_create(&mut runtime, std::ptr::null(), 0).unwrap(); // 2) `Deploy Template` let deploy_msg = deploy_message( @@ -217,14 +214,14 @@ fn svm_runtime_failure() { #[test] fn svm_transfer_success() { + api::svm_init().unwrap(); unsafe { let src_addr = Address::repeat(0xAB); let dst_addr = Address::repeat(0xCD); let mut runtime = std::ptr::null_mut(); - api::svm_init(true, std::ptr::null(), 0).unwrap(); - api::svm_runtime_create(&mut runtime).unwrap(); + api::svm_runtime_create(&mut runtime, std::ptr::null(), 0).unwrap(); api::svm_create_account(runtime, src_addr.as_slice().as_ptr(), 1000, 0, 0).unwrap(); api::svm_create_account(runtime, dst_addr.as_slice().as_ptr(), 0, 0, 0).unwrap(); api::svm_transfer(