use crate::{
execution::UserAction,
execution_state_actor::{ExecutionStateSender, Request},
resources::ResourceController,
util::{ReceiverExt, UnboundedSenderExt},
ApplicationCallOutcome, BaseRuntime, CallOutcome, CalleeContext, ContractRuntime,
ExecutionError, ExecutionOutcome, ServiceRuntime, SessionId, UserApplicationDescription,
UserApplicationId, UserContractCode, UserContractInstance, UserServiceInstance,
};
use custom_debug_derive::Debug;
use linera_base::{
data_types::{Amount, ArithmeticError, Timestamp},
ensure,
identifiers::{ChainId, Owner},
};
use linera_views::batch::Batch;
use oneshot::Receiver;
use std::{
collections::{hash_map, BTreeMap, HashMap, HashSet},
sync::{Arc, Mutex},
};
#[cfg(test)]
#[path = "unit_tests/runtime_tests.rs"]
mod tests;
#[derive(Debug)]
pub struct SyncRuntime<UserInstance>(Arc<Mutex<SyncRuntimeInternal<UserInstance>>>);
pub type ContractSyncRuntime = SyncRuntime<UserContractInstance>;
pub type ServiceSyncRuntime = SyncRuntime<UserServiceInstance>;
#[derive(Debug)]
pub struct SyncRuntimeInternal<UserInstance> {
chain_id: ChainId,
execution_state_sender: ExecutionStateSender,
loaded_applications: HashMap<UserApplicationId, LoadedApplication<UserInstance>>,
call_stack: Vec<ApplicationStatus>,
active_applications: HashSet<UserApplicationId>,
execution_outcomes: Vec<ExecutionOutcome>,
session_manager: SessionManager,
simple_user_states: BTreeMap<UserApplicationId, SimpleUserState>,
view_user_states: BTreeMap<UserApplicationId, ViewUserState>,
resource_controller: ResourceController,
}
#[derive(Debug, Clone)]
struct ApplicationStatus {
id: UserApplicationId,
parameters: Vec<u8>,
signer: Option<Owner>,
}
#[derive(Debug)]
struct LoadedApplication<Instance> {
instance: Arc<Mutex<Instance>>,
parameters: Vec<u8>,
}
impl<Instance> LoadedApplication<Instance> {
fn new(instance: Instance, description: UserApplicationDescription) -> Self {
LoadedApplication {
instance: Arc::new(Mutex::new(instance)),
parameters: description.parameters,
}
}
}
impl<Instance> Clone for LoadedApplication<Instance> {
fn clone(&self) -> Self {
LoadedApplication {
instance: self.instance.clone(),
parameters: self.parameters.clone(),
}
}
}
#[derive(Debug, Default)]
struct SessionManager {
counters: BTreeMap<UserApplicationId, u64>,
states: BTreeMap<SessionId, SessionState>,
}
#[derive(Debug)]
enum Promise<T> {
Ready(T),
Pending(Receiver<T>),
}
impl<T> Promise<T> {
fn force(&mut self) -> Result<(), ExecutionError> {
if let Promise::Pending(receiver) = self {
let value = receiver
.recv_ref()
.map_err(|oneshot::RecvError| ExecutionError::MissingRuntimeResponse)?;
*self = Promise::Ready(value);
}
Ok(())
}
fn read(self) -> Result<T, ExecutionError> {
match self {
Promise::Pending(receiver) => {
let value = receiver.recv_response()?;
Ok(value)
}
Promise::Ready(value) => Ok(value),
}
}
}
#[derive(Debug, Default)]
struct SimpleUserState {
pending_query: Option<Receiver<Vec<u8>>>,
}
#[derive(Debug, Default)]
struct QueryManager<T> {
pending_queries: BTreeMap<u32, Promise<T>>,
query_count: u32,
active_query_count: u32,
}
impl<T> QueryManager<T> {
fn register(&mut self, receiver: Receiver<T>) -> Result<u32, ExecutionError> {
let id = self.query_count;
self.pending_queries.insert(id, Promise::Pending(receiver));
self.query_count = self
.query_count
.checked_add(1)
.ok_or(ArithmeticError::Overflow)?;
self.active_query_count = self
.active_query_count
.checked_add(1)
.ok_or(ArithmeticError::Overflow)?;
Ok(id)
}
fn wait(&mut self, id: u32) -> Result<T, ExecutionError> {
let promise = self
.pending_queries
.remove(&id)
.ok_or(ExecutionError::InvalidPromise)?;
let value = promise.read()?;
self.active_query_count -= 1;
Ok(value)
}
fn force_all(&mut self) -> Result<(), ExecutionError> {
for promise in self.pending_queries.values_mut() {
promise.force()?;
}
Ok(())
}
}
type Keys = Vec<Vec<u8>>;
type Value = Vec<u8>;
type KeyValues = Vec<(Vec<u8>, Vec<u8>)>;
#[derive(Debug, Default)]
struct ViewUserState {
contains_key_queries: QueryManager<bool>,
read_value_queries: QueryManager<Option<Value>>,
read_multi_values_queries: QueryManager<Vec<Option<Value>>>,
find_keys_queries: QueryManager<Keys>,
find_key_values_queries: QueryManager<KeyValues>,
}
impl ViewUserState {
fn force_all_pending_queries(&mut self) -> Result<(), ExecutionError> {
self.contains_key_queries.force_all()?;
self.read_value_queries.force_all()?;
self.read_multi_values_queries.force_all()?;
self.find_keys_queries.force_all()?;
self.find_key_values_queries.force_all()?;
Ok(())
}
}
#[derive(Debug)]
struct SessionState {
owner: UserApplicationId,
locked: bool,
data: Vec<u8>,
}
impl<UserInstance> SyncRuntimeInternal<UserInstance> {
fn new(
chain_id: ChainId,
execution_state_sender: ExecutionStateSender,
resource_controller: ResourceController,
) -> Self {
Self {
chain_id,
execution_state_sender,
loaded_applications: HashMap::new(),
call_stack: Vec::new(),
active_applications: HashSet::new(),
execution_outcomes: Vec::default(),
session_manager: SessionManager::default(),
simple_user_states: BTreeMap::default(),
view_user_states: BTreeMap::default(),
resource_controller,
}
}
fn current_application(&mut self) -> &ApplicationStatus {
self.call_stack
.last()
.expect("Call stack is unexpectedly empty")
}
fn push_application(&mut self, status: ApplicationStatus) {
self.active_applications.insert(status.id);
self.call_stack.push(status);
}
fn pop_application(&mut self) -> ApplicationStatus {
let status = self
.call_stack
.pop()
.expect("Can't remove application from empty call stack");
assert!(self.active_applications.remove(&status.id));
status
}
fn check_for_reentrancy(
&mut self,
application_id: UserApplicationId,
) -> Result<(), ExecutionError> {
ensure!(
!self.active_applications.contains(&application_id),
ExecutionError::ReentrantCall(application_id)
);
Ok(())
}
}
impl SyncRuntimeInternal<UserContractInstance> {
fn load_contract(
&mut self,
id: UserApplicationId,
) -> Result<(UserContractCode, UserApplicationDescription), ExecutionError> {
self.execution_state_sender
.send_request(|callback| Request::LoadContract { id, callback })?
.recv_response()
}
fn load_contract_instance(
&mut self,
this: Arc<Mutex<Self>>,
id: UserApplicationId,
) -> Result<LoadedApplication<UserContractInstance>, ExecutionError> {
match self.loaded_applications.entry(id) {
hash_map::Entry::Vacant(entry) => {
let (code, description) = self
.execution_state_sender
.send_request(|callback| Request::LoadContract { id, callback })?
.recv_response()?;
let instance = code.instantiate(SyncRuntime(this))?;
Ok(entry
.insert(LoadedApplication::new(instance, description))
.clone())
}
hash_map::Entry::Occupied(entry) => Ok(entry.get().clone()),
}
}
fn prepare_for_call(
&mut self,
this: Arc<Mutex<Self>>,
authenticated: bool,
callee_id: UserApplicationId,
forwarded_sessions: &[SessionId],
) -> Result<(Arc<Mutex<UserContractInstance>>, CalleeContext), ExecutionError> {
self.check_for_reentrancy(callee_id)?;
let application = self.load_contract_instance(this, callee_id)?;
let caller = self.current_application();
let caller_id = caller.id;
let caller_signer = caller.signer;
self.forward_sessions(forwarded_sessions, caller_id, callee_id)?;
let authenticated_signer = match caller_signer {
Some(signer) if authenticated => Some(signer),
_ => None,
};
let authenticated_caller_id = authenticated.then_some(caller_id);
let callee_context = CalleeContext {
chain_id: self.chain_id,
authenticated_signer,
authenticated_caller_id,
};
self.push_application(ApplicationStatus {
id: callee_id,
parameters: application.parameters,
signer: authenticated_signer,
});
Ok((application.instance, callee_context))
}
fn finish_call(
&mut self,
raw_outcome: ApplicationCallOutcome,
) -> Result<CallOutcome, ExecutionError> {
let ApplicationStatus {
id: callee_id,
signer,
..
} = self.pop_application();
self.execution_outcomes.push(ExecutionOutcome::User(
callee_id,
raw_outcome
.execution_outcome
.with_authenticated_signer(signer),
));
let caller_id = self.application_id()?;
let sessions = self.make_sessions(raw_outcome.create_sessions, callee_id, caller_id);
let outcome = CallOutcome {
value: raw_outcome.value,
sessions,
};
Ok(outcome)
}
fn forward_sessions(
&mut self,
session_ids: &[SessionId],
from_id: UserApplicationId,
to_id: UserApplicationId,
) -> Result<(), ExecutionError> {
let states = &mut self.session_manager.states;
for id in session_ids {
let state = states
.get_mut(id)
.ok_or(ExecutionError::InvalidSession(*id))?;
ensure!(
state.owner == from_id,
ExecutionError::invalid_session_owner(*id, from_id, state.owner,)
);
state.owner = to_id;
}
Ok(())
}
fn make_sessions(
&mut self,
new_sessions: Vec<Vec<u8>>,
creator_id: UserApplicationId,
receiver_id: UserApplicationId,
) -> Vec<SessionId> {
let manager = &mut self.session_manager;
let states = &mut manager.states;
let counter = manager.counters.entry(creator_id).or_default();
let mut session_ids = Vec::new();
for data in new_sessions {
let id = SessionId {
application_id: creator_id,
index: *counter,
};
*counter += 1;
session_ids.push(id);
let state = SessionState {
owner: receiver_id,
locked: false,
data,
};
states.insert(id, state);
}
session_ids
}
fn try_load_session(
&mut self,
session_id: SessionId,
application_id: UserApplicationId,
) -> Result<Vec<u8>, ExecutionError> {
let state = self
.session_manager
.states
.get_mut(&session_id)
.ok_or(ExecutionError::InvalidSession(session_id))?;
ensure!(!state.locked, ExecutionError::SessionIsInUse(session_id));
ensure!(
state.owner == application_id,
ExecutionError::invalid_session_owner(session_id, application_id, state.owner,)
);
state.locked = true;
Ok(state.data.clone())
}
fn try_save_session(
&mut self,
session_id: SessionId,
application_id: UserApplicationId,
data: Vec<u8>,
) -> Result<(), ExecutionError> {
let state = self
.session_manager
.states
.get_mut(&session_id)
.ok_or(ExecutionError::InvalidSession(session_id))?;
ensure!(
state.locked,
ExecutionError::SessionStateNotLocked(session_id)
);
ensure!(
state.owner == application_id,
ExecutionError::invalid_session_owner(session_id, application_id, state.owner,)
);
state.data = data;
state.locked = false;
Ok(())
}
fn try_close_session(
&mut self,
session_id: SessionId,
application_id: UserApplicationId,
) -> Result<(), ExecutionError> {
let state = self
.session_manager
.states
.get(&session_id)
.ok_or(ExecutionError::InvalidSession(session_id))?;
ensure!(
state.locked,
ExecutionError::SessionStateNotLocked(session_id)
);
ensure!(
state.owner == application_id,
ExecutionError::invalid_session_owner(session_id, application_id, state.owner,)
);
self.session_manager
.states
.remove(&session_id)
.ok_or(ExecutionError::InvalidSession(session_id))?;
Ok(())
}
}
impl SyncRuntimeInternal<UserServiceInstance> {
fn load_service_instance(
&mut self,
this: Arc<Mutex<Self>>,
id: UserApplicationId,
) -> Result<LoadedApplication<UserServiceInstance>, ExecutionError> {
match self.loaded_applications.entry(id) {
hash_map::Entry::Vacant(entry) => {
let (code, description) = self
.execution_state_sender
.send_request(|callback| Request::LoadService { id, callback })?
.recv_response()?;
let instance = code.instantiate(SyncRuntime(this))?;
Ok(entry
.insert(LoadedApplication::new(instance, description))
.clone())
}
hash_map::Entry::Occupied(entry) => Ok(entry.get().clone()),
}
}
}
impl<UserInstance> SyncRuntime<UserInstance> {
fn new(runtime: SyncRuntimeInternal<UserInstance>) -> Self {
SyncRuntime(Arc::new(Mutex::new(runtime)))
}
fn into_inner(self) -> Option<SyncRuntimeInternal<UserInstance>> {
let runtime = Arc::into_inner(self.0)?
.into_inner()
.expect("thread should not have panicked");
Some(runtime)
}
fn inner(&mut self) -> std::sync::MutexGuard<'_, SyncRuntimeInternal<UserInstance>> {
self.0
.try_lock()
.expect("Synchronous runtimes run on a single execution thread")
}
}
impl<UserInstance> BaseRuntime for SyncRuntime<UserInstance> {
type Read = <SyncRuntimeInternal<UserInstance> as BaseRuntime>::Read;
type ReadValueBytes = <SyncRuntimeInternal<UserInstance> as BaseRuntime>::ReadValueBytes;
type ContainsKey = <SyncRuntimeInternal<UserInstance> as BaseRuntime>::ContainsKey;
type ReadMultiValuesBytes =
<SyncRuntimeInternal<UserInstance> as BaseRuntime>::ReadMultiValuesBytes;
type FindKeysByPrefix = <SyncRuntimeInternal<UserInstance> as BaseRuntime>::FindKeysByPrefix;
type FindKeyValuesByPrefix =
<SyncRuntimeInternal<UserInstance> as BaseRuntime>::FindKeyValuesByPrefix;
fn chain_id(&mut self) -> Result<ChainId, ExecutionError> {
self.inner().chain_id()
}
fn application_id(&mut self) -> Result<UserApplicationId, ExecutionError> {
self.inner().application_id()
}
fn application_parameters(&mut self) -> Result<Vec<u8>, ExecutionError> {
self.inner().application_parameters()
}
fn read_system_balance(&mut self) -> Result<Amount, ExecutionError> {
self.inner().read_system_balance()
}
fn read_system_timestamp(&mut self) -> Result<Timestamp, ExecutionError> {
self.inner().read_system_timestamp()
}
fn write_batch(&mut self, batch: Batch) -> Result<(), ExecutionError> {
self.inner().write_batch(batch)
}
fn contains_key_new(&mut self, key: Vec<u8>) -> Result<Self::ContainsKey, ExecutionError> {
self.inner().contains_key_new(key)
}
fn contains_key_wait(&mut self, promise: &Self::ContainsKey) -> Result<bool, ExecutionError> {
self.inner().contains_key_wait(promise)
}
fn read_multi_values_bytes_new(
&mut self,
keys: Vec<Vec<u8>>,
) -> Result<Self::ReadMultiValuesBytes, ExecutionError> {
self.inner().read_multi_values_bytes_new(keys)
}
fn read_multi_values_bytes_wait(
&mut self,
promise: &Self::ReadMultiValuesBytes,
) -> Result<Vec<Option<Vec<u8>>>, ExecutionError> {
self.inner().read_multi_values_bytes_wait(promise)
}
fn read_value_bytes_new(
&mut self,
key: Vec<u8>,
) -> Result<Self::ReadValueBytes, ExecutionError> {
self.inner().read_value_bytes_new(key)
}
fn read_value_bytes_wait(
&mut self,
promise: &Self::ReadValueBytes,
) -> Result<Option<Vec<u8>>, ExecutionError> {
self.inner().read_value_bytes_wait(promise)
}
fn find_keys_by_prefix_new(
&mut self,
key_prefix: Vec<u8>,
) -> Result<Self::FindKeysByPrefix, ExecutionError> {
self.inner().find_keys_by_prefix_new(key_prefix)
}
fn find_keys_by_prefix_wait(
&mut self,
promise: &Self::FindKeysByPrefix,
) -> Result<Vec<Vec<u8>>, ExecutionError> {
self.inner().find_keys_by_prefix_wait(promise)
}
fn find_key_values_by_prefix_new(
&mut self,
key_prefix: Vec<u8>,
) -> Result<Self::FindKeyValuesByPrefix, ExecutionError> {
self.inner().find_key_values_by_prefix_new(key_prefix)
}
fn find_key_values_by_prefix_wait(
&mut self,
promise: &Self::FindKeyValuesByPrefix,
) -> Result<Vec<(Vec<u8>, Vec<u8>)>, ExecutionError> {
self.inner().find_key_values_by_prefix_wait(promise)
}
}
impl<UserInstance> BaseRuntime for SyncRuntimeInternal<UserInstance> {
type Read = ();
type ReadValueBytes = u32;
type ContainsKey = u32;
type ReadMultiValuesBytes = u32;
type FindKeysByPrefix = u32;
type FindKeyValuesByPrefix = u32;
fn chain_id(&mut self) -> Result<ChainId, ExecutionError> {
Ok(self.chain_id)
}
fn application_id(&mut self) -> Result<UserApplicationId, ExecutionError> {
Ok(self.current_application().id)
}
fn application_parameters(&mut self) -> Result<Vec<u8>, ExecutionError> {
Ok(self.current_application().parameters.clone())
}
fn read_system_balance(&mut self) -> Result<Amount, ExecutionError> {
self.execution_state_sender
.send_request(|callback| Request::SystemBalance { callback })?
.recv_response()
}
fn read_system_timestamp(&mut self) -> Result<Timestamp, ExecutionError> {
self.execution_state_sender
.send_request(|callback| Request::SystemTimestamp { callback })?
.recv_response()
}
fn write_batch(&mut self, batch: Batch) -> Result<(), ExecutionError> {
let id = self.application_id()?;
let state = self.view_user_states.entry(id).or_default();
state.force_all_pending_queries()?;
self.resource_controller.track_write_operations(
batch
.num_operations()
.try_into()
.map_err(|_| ExecutionError::from(ArithmeticError::Overflow))?,
)?;
self.resource_controller
.track_bytes_written(batch.size() as u64)?;
self.execution_state_sender
.send_request(|callback| Request::WriteBatch {
id,
batch,
callback,
})?
.recv_response()?;
Ok(())
}
fn contains_key_new(&mut self, key: Vec<u8>) -> Result<Self::ContainsKey, ExecutionError> {
let id = self.application_id()?;
let state = self.view_user_states.entry(id).or_default();
self.resource_controller.track_read_operations(1)?;
let receiver = self
.execution_state_sender
.send_request(move |callback| Request::ContainsKey { id, key, callback })?;
state.contains_key_queries.register(receiver)
}
fn contains_key_wait(&mut self, promise: &Self::ContainsKey) -> Result<bool, ExecutionError> {
let id = self.application_id()?;
let state = self.view_user_states.entry(id).or_default();
let value = state.contains_key_queries.wait(*promise)?;
Ok(value)
}
fn read_multi_values_bytes_new(
&mut self,
keys: Vec<Vec<u8>>,
) -> Result<Self::ReadMultiValuesBytes, ExecutionError> {
let id = self.application_id()?;
let state = self.view_user_states.entry(id).or_default();
self.resource_controller.track_read_operations(1)?;
let receiver = self
.execution_state_sender
.send_request(move |callback| Request::ReadMultiValuesBytes { id, keys, callback })?;
state.read_multi_values_queries.register(receiver)
}
fn read_multi_values_bytes_wait(
&mut self,
promise: &Self::ReadMultiValuesBytes,
) -> Result<Vec<Option<Vec<u8>>>, ExecutionError> {
let id = self.application_id()?;
let state = self.view_user_states.entry(id).or_default();
let values = state.read_multi_values_queries.wait(*promise)?;
for value in &values {
if let Some(value) = &value {
self.resource_controller
.track_bytes_read(value.len() as u64)?;
}
}
Ok(values)
}
fn read_value_bytes_new(
&mut self,
key: Vec<u8>,
) -> Result<Self::ReadValueBytes, ExecutionError> {
let id = self.application_id()?;
let state = self.view_user_states.entry(id).or_default();
self.resource_controller.track_read_operations(1)?;
let receiver = self
.execution_state_sender
.send_request(move |callback| Request::ReadValueBytes { id, key, callback })?;
state.read_value_queries.register(receiver)
}
fn read_value_bytes_wait(
&mut self,
promise: &Self::ReadValueBytes,
) -> Result<Option<Vec<u8>>, ExecutionError> {
let id = self.application_id()?;
let state = self.view_user_states.entry(id).or_default();
let value = state.read_value_queries.wait(*promise)?;
if let Some(value) = &value {
self.resource_controller
.track_bytes_read(value.len() as u64)?;
}
Ok(value)
}
fn find_keys_by_prefix_new(
&mut self,
key_prefix: Vec<u8>,
) -> Result<Self::FindKeysByPrefix, ExecutionError> {
let id = self.application_id()?;
let state = self.view_user_states.entry(id).or_default();
self.resource_controller.track_read_operations(1)?;
let receiver = self.execution_state_sender.send_request(move |callback| {
Request::FindKeysByPrefix {
id,
key_prefix,
callback,
}
})?;
state.find_keys_queries.register(receiver)
}
fn find_keys_by_prefix_wait(
&mut self,
promise: &Self::FindKeysByPrefix,
) -> Result<Vec<Vec<u8>>, ExecutionError> {
let id = self.application_id()?;
let state = self.view_user_states.entry(id).or_default();
let keys = state.find_keys_queries.wait(*promise)?;
let mut read_size = 0;
for key in &keys {
read_size += key.len();
}
self.resource_controller
.track_bytes_read(read_size as u64)?;
Ok(keys)
}
fn find_key_values_by_prefix_new(
&mut self,
key_prefix: Vec<u8>,
) -> Result<Self::FindKeyValuesByPrefix, ExecutionError> {
let id = self.application_id()?;
let state = self.view_user_states.entry(id).or_default();
self.resource_controller.track_read_operations(1)?;
let receiver = self.execution_state_sender.send_request(move |callback| {
Request::FindKeyValuesByPrefix {
id,
key_prefix,
callback,
}
})?;
state.find_key_values_queries.register(receiver)
}
fn find_key_values_by_prefix_wait(
&mut self,
promise: &Self::FindKeyValuesByPrefix,
) -> Result<Vec<(Vec<u8>, Vec<u8>)>, ExecutionError> {
let id = self.application_id()?;
let state = self.view_user_states.entry(id).or_default();
let key_values = state.find_key_values_queries.wait(*promise)?;
let mut read_size = 0;
for (key, value) in &key_values {
read_size += key.len() + value.len();
}
self.resource_controller
.track_bytes_read(read_size as u64)?;
Ok(key_values)
}
}
impl<UserInstance> Clone for SyncRuntime<UserInstance> {
fn clone(&self) -> Self {
SyncRuntime(self.0.clone())
}
}
impl ContractSyncRuntime {
pub(crate) fn run_action(
execution_state_sender: ExecutionStateSender,
application_id: UserApplicationId,
chain_id: ChainId,
resource_controller: ResourceController,
action: UserAction,
) -> Result<(Vec<ExecutionOutcome>, ResourceController), ExecutionError> {
let mut runtime =
SyncRuntimeInternal::new(chain_id, execution_state_sender, resource_controller);
let (code, description) = runtime.load_contract(application_id)?;
let signer = action.signer();
runtime.push_application(ApplicationStatus {
id: application_id,
parameters: description.parameters,
signer,
});
let mut runtime = ContractSyncRuntime::new(runtime);
let execution_result = {
let mut code = code.instantiate(runtime.clone())?;
match action {
UserAction::Initialize(context, argument) => code.initialize(context, argument),
UserAction::Operation(context, operation) => {
code.execute_operation(context, operation)
}
UserAction::Message(context, message) => code.execute_message(context, message),
}
};
runtime.inner().loaded_applications.clear();
let mut runtime = runtime
.into_inner()
.expect("Runtime clones should have been freed by now");
let execution_outcome = execution_result?;
assert_eq!(runtime.call_stack.len(), 1);
assert_eq!(runtime.call_stack[0].id, application_id);
assert_eq!(runtime.active_applications.len(), 1);
assert!(runtime.active_applications.contains(&application_id));
if let Some(session_id) = runtime.session_manager.states.keys().next() {
return Err(ExecutionError::SessionWasNotClosed(*session_id));
}
runtime.execution_outcomes.push(ExecutionOutcome::User(
application_id,
execution_outcome.with_authenticated_signer(signer),
));
Ok((runtime.execution_outcomes, runtime.resource_controller))
}
}
impl ContractRuntime for ContractSyncRuntime {
fn remaining_fuel(&mut self) -> Result<u64, ExecutionError> {
Ok(self.inner().resource_controller.remaining_fuel())
}
fn set_remaining_fuel(&mut self, remaining_fuel: u64) -> Result<(), ExecutionError> {
let mut this = self.inner();
let previous_fuel = this.resource_controller.remaining_fuel();
assert!(previous_fuel >= remaining_fuel);
this.resource_controller
.track_fuel(previous_fuel - remaining_fuel)
}
fn try_call_application(
&mut self,
authenticated: bool,
callee_id: UserApplicationId,
argument: Vec<u8>,
forwarded_sessions: Vec<SessionId>,
) -> Result<CallOutcome, ExecutionError> {
let cloned_self = self.clone().0;
let (contract, callee_context) = self.inner().prepare_for_call(
cloned_self,
authenticated,
callee_id,
&forwarded_sessions,
)?;
let raw_outcome = contract
.try_lock()
.expect("Applications should not have reentrant calls")
.handle_application_call(callee_context, argument, forwarded_sessions)?;
self.inner().finish_call(raw_outcome)
}
fn try_call_session(
&mut self,
authenticated: bool,
session_id: SessionId,
argument: Vec<u8>,
forwarded_sessions: Vec<SessionId>,
) -> Result<CallOutcome, ExecutionError> {
let callee_id = session_id.application_id;
let (contract, callee_context, session_state) = {
let cloned_self = self.clone().0;
let mut this = self.inner();
let caller_id = this.application_id()?;
let session_state = this.try_load_session(session_id, caller_id)?;
let (contract, callee_context) =
this.prepare_for_call(cloned_self, authenticated, callee_id, &forwarded_sessions)?;
Ok::<_, ExecutionError>((contract, callee_context, session_state))
}?;
let (raw_outcome, session_state) = contract
.try_lock()
.expect("Applications should not have reentrant calls")
.handle_session_call(callee_context, session_state, argument, forwarded_sessions)?;
{
let mut this = self.inner();
let outcome = this.finish_call(raw_outcome.inner)?;
let caller_id = this.application_id()?;
if raw_outcome.close_session {
this.try_close_session(session_id, caller_id)?;
} else {
this.try_save_session(session_id, caller_id, session_state)?;
}
Ok(outcome)
}
}
}
impl ServiceSyncRuntime {
pub(crate) fn run_query(
execution_state_sender: ExecutionStateSender,
application_id: UserApplicationId,
context: crate::QueryContext,
query: Vec<u8>,
) -> Result<Vec<u8>, ExecutionError> {
let runtime_internal = SyncRuntimeInternal::new(
context.chain_id,
execution_state_sender,
ResourceController::default(),
);
let mut runtime = ServiceSyncRuntime::new(runtime_internal);
let result = runtime.try_query_application(application_id, query);
runtime.inner().loaded_applications.clear();
result
}
}
impl ServiceRuntime for ServiceSyncRuntime {
fn try_query_application(
&mut self,
queried_id: UserApplicationId,
argument: Vec<u8>,
) -> Result<Vec<u8>, ExecutionError> {
let (query_context, service) = {
let cloned_self = self.clone().0;
let mut this = self.inner();
let application = this.load_service_instance(cloned_self, queried_id)?;
let query_context = crate::QueryContext {
chain_id: this.chain_id,
};
this.push_application(ApplicationStatus {
id: queried_id,
parameters: application.parameters,
signer: None,
});
(query_context, application.instance)
};
let response = service
.try_lock()
.expect("Applications should not have reentrant calls")
.handle_query(query_context, argument)?;
self.inner().pop_application();
Ok(response)
}
}