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

Commit

Permalink
Runtime refactoring (#435)
Browse files Browse the repository at this point in the history
* Runtime - extracting code to `load_template`

* Runtime#spawn uses `create_account`

* Adding `GasTank`

* Using the term `gas_limit` only in the context of the `Envelope`

* Fixed a couple of tests

* GasTank#unwrap

* Returning back test assertions

* cargo doc fix

* Runtime#create_genesis_account (changes requested during PR review)
  • Loading branch information
YaronWittenstein authored Dec 13, 2021
1 parent a3147f6 commit 6edb73d
Show file tree
Hide file tree
Showing 20 changed files with 411 additions and 281 deletions.
8 changes: 8 additions & 0 deletions crates/codec/src/api/json/receipt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,14 @@ fn decode_error(ty: &'static str, err: &RuntimeError, logs: &[ReceiptLog]) -> Va
"func": func,
"message": msg,
}),
RuntimeError::FuncNotCtor {
template: template_addr,
func,
} => json!({
"err_type": "function-not-ctor",
"template_addr": TemplateAddrWrapper::from(*template_addr),
"func": func,
}),
RuntimeError::FuncNotAllowed {
target: account_addr,
template: template_addr,
Expand Down
30 changes: 26 additions & 4 deletions crates/codec/src/receipt/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@
//! | (20 bytes) | (20 bytes) | (String) | (UTF-8 String) |
//! +-------------------+------------------+------------+----------------+
//!
//! * Function Not Ctor
//! +-------------------+-------------------+----------------+
//! | Template Address | Function | Message |
//! | (20 bytes) | (String) | (UTF-8 String) |
//! +-------------------+-------------------+----------------+
//!
//! * Function Not Allowed
//! +-------------------+-------------------+------------+----------------+
//! | Template Address | Account Address | Function | Message |
Expand Down Expand Up @@ -128,6 +134,10 @@ impl Codec for RuntimeFailure {
func.encode(w);
encode_msg(&msg, w);
}
RuntimeError::FuncNotCtor { template, func } => {
template.encode(w);
func.encode(w);
}
RuntimeError::FuncNotAllowed {
target,
template,
Expand Down Expand Up @@ -164,8 +174,9 @@ impl Codec for RuntimeFailure {
4 => instantiation_error(cursor),
5 => func_not_found(cursor),
6 => func_failed(cursor),
7 => func_not_allowed(cursor),
8 => func_invalid_sig(cursor),
7 => func_not_ctor(cursor),
8 => func_not_allowed(cursor),
9 => func_invalid_sig(cursor),
_ => unreachable!(),
}
};
Expand Down Expand Up @@ -193,8 +204,9 @@ fn encode_err_type(err: &RuntimeError, w: &mut impl WriteExt) {
RuntimeError::InstantiationFailed { .. } => 4,
RuntimeError::FuncNotFound { .. } => 5,
RuntimeError::FuncFailed { .. } => 6,
RuntimeError::FuncNotAllowed { .. } => 7,
RuntimeError::FuncInvalidSignature { .. } => 8,
RuntimeError::FuncNotCtor { .. } => 7,
RuntimeError::FuncNotAllowed { .. } => 8,
RuntimeError::FuncInvalidSignature { .. } => 9,
};

w.write_byte(ty);
Expand Down Expand Up @@ -264,6 +276,16 @@ fn func_failed(cursor: &mut impl ReadExt) -> RuntimeError {
}
}

fn func_not_ctor(cursor: &mut impl ReadExt) -> RuntimeError {
let template_addr = TemplateAddr::decode(cursor).unwrap();
let func = String::decode(cursor).unwrap();

RuntimeError::FuncNotCtor {
template: template_addr,
func,
}
}

fn func_not_allowed(cursor: &mut impl ReadExt) -> RuntimeError {
let template_addr = TemplateAddr::decode(cursor).unwrap();
let account_addr = Address::decode(cursor).unwrap();
Expand Down
17 changes: 7 additions & 10 deletions crates/runtime-ffi/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use std::panic::UnwindSafe;
use std::slice;

use svm_codec::Codec;
use svm_runtime::{PriceResolverRegistry, Runtime, ValidateError};
use svm_runtime::{PriceResolverRegistry, Runtime, TemplatePriceCache, ValidateError};
use svm_state::GlobalState;
use svm_types::{Address, BytesPrimitive, Context, Envelope, Layer, State};

Expand Down Expand Up @@ -68,20 +68,17 @@ pub unsafe extern "C" fn svm_runtime_create(
}
*initialized = true;

let imports = ("sm".to_string(), wasmer::Exports::new());
// TODO: move both `GlobalState` and `TemplatePriceCache` to sit under `Env`.
// `Env` be a singleton living throughout the process' lifetime.
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,
);
let registry = PriceResolverRegistry::default();
let runtime = Runtime::new(global_state, TemplatePriceCache::new(registry));

*runtime_ptr = RUNTIME_TRACKER.alloc(runtime);
debug!("`svm_runtime_create` end");
Expand Down Expand Up @@ -545,7 +542,7 @@ pub unsafe extern "C" fn svm_get_account(
/// Creates an account at genesis with a given balance and nonce counter.
#[no_mangle]
#[must_use]
pub unsafe extern "C" fn svm_create_account(
pub unsafe extern "C" fn svm_create_genesis_account(
runtime_ptr: *mut c_void,
addr: *const u8,
balance: u64,
Expand All @@ -556,7 +553,7 @@ pub unsafe extern "C" fn svm_create_account(
let runtime = RUNTIME_TRACKER.get(runtime_ptr).unwrap();
let account_addr = Address::new(slice::from_raw_parts(addr, Address::N));
let counter = ((counter_upper_bits as u128) << 64) | (counter_lower_bits as u128);
runtime.create_account(&account_addr, "".to_string(), balance, counter)?;
runtime.create_genesis_account(&account_addr, "".to_string(), balance, counter)?;

svm_result_t::OK
})
Expand Down
4 changes: 2 additions & 2 deletions crates/runtime-ffi/tests/api_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,8 +222,8 @@ fn svm_transfer_success() {
let mut runtime = std::ptr::null_mut();

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_create_genesis_account(runtime, src_addr.as_slice().as_ptr(), 1000, 0, 0).unwrap();
api::svm_create_genesis_account(runtime, dst_addr.as_slice().as_ptr(), 0, 0, 0).unwrap();
api::svm_transfer(
runtime,
src_addr.as_slice().as_ptr(),
Expand Down
38 changes: 19 additions & 19 deletions crates/runtime/src/func_env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ impl FuncEnv {
context: &Context,
template_addr: TemplateAddr,
target_addr: Address,
mode: ProtectedMode,
mode: AccessMode,
) -> Self {
let inner = Inner::new(storage);

Expand All @@ -39,7 +39,7 @@ impl FuncEnv {
envelope: envelope.clone(),
context: context.clone(),
};
env.set_protected_mode(mode);
env.set_access_mode(mode);

env
}
Expand All @@ -52,11 +52,10 @@ impl FuncEnv {
context: &Context,
template_addr: TemplateAddr,
target_addr: Address,
mode: ProtectedMode,
mode: AccessMode,
) -> Self {
let env = Self::new(storage, envelope, context, template_addr, target_addr, mode);
env.borrow_mut().set_memory(memory);

env
}

Expand Down Expand Up @@ -86,14 +85,14 @@ impl FuncEnv {
.expect("Attempted write but RwLock is poisoned")
}

/// Sets the [`ProtectedMode`] and overrides the existing value.
pub fn set_protected_mode(&self, mode: ProtectedMode) {
/// Sets the [`AccessMode`] and overrides the existing value.
pub fn set_access_mode(&self, mode: AccessMode) {
let mut borrow = self.borrow_mut();
borrow.set_protected_mode(mode);
borrow.set_access_mode(mode);
}

/// Returns the current [`ProtectedMode`].
pub fn protected_mode(&self) -> ProtectedMode {
/// Returns the current [`AccessMode`].
pub fn access_mode(&self) -> AccessMode {
let borrow = self.borrow();
borrow.mode
}
Expand All @@ -118,17 +117,22 @@ pub struct Inner {
/// Pointer to `calldata`. Tuple stores `(offset, len)`.
calldata: Option<(usize, usize)>,

mode: ProtectedMode,
/// The current [`AccessMode`] of the running transaction.
mode: AccessMode,

/// Set of [`Address`] that have been part of at least once `Coins Transfer` during transaction execution.
touched_accounts: HashSet<Address>,
}

/// Denotes the capabilities allowed to the executing Account at a given point in time.
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum ProtectedMode {
pub enum AccessMode {
/// Access to [`AccountStorage`] is not allowed.
AccessDenied,

/// Only `Read Access` to [AccountStorage]'s `Immutable Storage` is allowed.
ImmutableOnly,

/// Full-Access to [`AccountStorage`] is allowed.
FullAccess,
}
Expand All @@ -146,7 +150,7 @@ impl Inner {
calldata: None,
returndata: None,
used_memory: 0,
mode: ProtectedMode::AccessDenied,
mode: AccessMode::AccessDenied,
touched_accounts,
}
}
Expand All @@ -160,19 +164,17 @@ impl Inner {
self.touched_accounts.clone()
}

pub fn set_protected_mode(&mut self, mode: ProtectedMode) {
pub fn set_access_mode(&mut self, mode: AccessMode) {
self.mode = mode;
}

pub fn storage(&self) -> &AccountStorage {
assert!(self.can_read());

&self.storage
}

pub fn storage_mut(&mut self) -> &mut AccountStorage {
assert!(self.can_write());

&mut self.storage
}

Expand Down Expand Up @@ -202,7 +204,6 @@ impl Inner {
);

debug_assert!(self.returndata.is_none());

self.returndata = Some((offset, len));
}

Expand All @@ -216,7 +217,6 @@ impl Inner {

pub fn memory(&self) -> &Memory {
debug_assert!(self.memory.is_some());

self.memory.as_ref().unwrap()
}

Expand All @@ -238,11 +238,11 @@ impl Inner {

#[inline]
fn can_read(&self) -> bool {
self.mode != ProtectedMode::AccessDenied
self.mode != AccessMode::AccessDenied
}

#[inline]
fn can_write(&self) -> bool {
matches!(self.mode, ProtectedMode::FullAccess)
matches!(self.mode, AccessMode::FullAccess)
}
}
4 changes: 2 additions & 2 deletions crates/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ pub mod testing;
pub mod vmcalls;

pub use error::ValidateError;
pub use func_env::{FuncEnv, ProtectedMode};
pub use func_env::{AccessMode, FuncEnv};
pub use price_registry::PriceResolverRegistry;
pub use runtime::{compute_account_addr, compute_template_addr, Runtime};
pub use runtime::{compute_account_addr, compute_template_addr, Runtime, TemplatePriceCache};
pub use wasm_store::new_store;
3 changes: 1 addition & 2 deletions crates/runtime/src/price_registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@ impl PriceResolverRegistry {
self.price_resolvers.insert(version, price_resolver);
}

/// Retrieves the [`PriceResolver`] associated with a certain SVM version
/// within `self`.
/// Retrieves the [`PriceResolver`] associated with a certain SVM version within `self`.
pub fn get(&self, version: u16) -> Option<Rc<dyn PriceResolver>> {
self.price_resolvers.get(&version).cloned()
}
Expand Down
12 changes: 7 additions & 5 deletions crates/runtime/src/runtime/call.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use svm_types::{Address, Context, Envelope, Gas, State, TemplateAddr};
use svm_types::{Address, Context, Envelope, State, TemplateAddr};

use crate::ProtectedMode;
use crate::AccessMode;

use super::gas_tank::GasTank;

/// Information regarding a Wasm function call.
#[doc(hidden)]
Expand All @@ -9,11 +11,11 @@ pub struct Call<'a> {
pub func_name: &'a str,
pub func_input: &'a [u8],
pub target: Address,
pub template: TemplateAddr,
pub template_addr: TemplateAddr,
pub state: &'a State,
pub gas_limit: Gas,
pub gas_left: GasTank,
pub within_spawn: bool,
pub context: &'a Context,
pub envelope: &'a Envelope,
pub protected_mode: ProtectedMode,
pub access_mode: AccessMode,
}
43 changes: 43 additions & 0 deletions crates/runtime/src/runtime/gas_tank.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use svm_types::Gas;

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum GasTank {
NonEmpty(u64),
Empty,
}

impl GasTank {
pub fn new(gas: Gas) -> Self {
let gas = gas.unwrap_or(std::u64::MAX);

if gas > 0 {
GasTank::NonEmpty(gas)
} else {
GasTank::Empty
}
}

pub fn is_empty(&self) -> bool {
matches!(self, Self::Empty)
}

pub fn consume(self, gas: u64) -> GasTank {
match self {
GasTank::Empty => GasTank::Empty,
GasTank::NonEmpty(left) => {
if left > gas {
GasTank::NonEmpty(left - gas)
} else {
GasTank::Empty
}
}
}
}

pub fn unwrap(self) -> u64 {
match self {
GasTank::Empty => 0,
GasTank::NonEmpty(gas) => gas,
}
}
}
4 changes: 4 additions & 0 deletions crates/runtime/src/runtime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@
mod call;
mod function;
mod outcome;
mod price_cache;
mod runtime;

mod gas_tank;

pub use call::Call;
pub use function::Function;
pub use outcome::Outcome;
pub use price_cache::TemplatePriceCache;
pub use runtime::{compute_account_addr, compute_template_addr, Runtime};
Loading

0 comments on commit 6edb73d

Please sign in to comment.