Skip to content
This repository has been archived by the owner on Aug 14, 2023. It is now read-only.

Commit

Permalink
Improve API initialization pattern
Browse files Browse the repository at this point in the history
  • Loading branch information
neysofu committed Dec 2, 2021
1 parent 61b3d70 commit f92e95a
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 130 deletions.
151 changes: 68 additions & 83 deletions crates/runtime-ffi/src/api.rs
Original file line number Diff line number Diff line change
@@ -1,102 +1,92 @@
/// 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<Runtime> = ResourceTracker::default();
static ref INITIALIZED: Mutex<bool> = 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
}

/// Frees the memory allocated within the given [`svm_result_t`].
#[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
})
}
Expand All @@ -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
Expand All @@ -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.
Expand All @@ -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...";
Expand Down Expand Up @@ -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...";
Expand Down Expand Up @@ -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...";
Expand Down Expand Up @@ -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...";
Expand Down Expand Up @@ -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...";
Expand Down Expand Up @@ -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...";
Expand Down Expand Up @@ -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...";
Expand Down Expand Up @@ -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) };
Expand Down
36 changes: 0 additions & 36 deletions crates/runtime-ffi/src/config.rs

This file was deleted.

1 change: 0 additions & 1 deletion crates/runtime-ffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
#![feature(try_trait_v2)]

mod api;
mod config;
mod resource_tracker;
mod result;

Expand Down
17 changes: 7 additions & 10 deletions crates/runtime-ffi/tests/api_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,13 @@ fn call_message(target: &Address, func_name: &str, calldata: &[u8]) -> Vec<u8> {

#[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`
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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(
Expand Down

0 comments on commit f92e95a

Please sign in to comment.