Skip to content

Commit

Permalink
Merge pull request #598 from radixdlt/architecture/cleanup-invocation…
Browse files Browse the repository at this point in the history
…-modules

Architecture: Cleanup invocation modules
  • Loading branch information
iamyulong authored Nov 21, 2022
2 parents a93fbb3 + b4dd1a1 commit 2ef218f
Show file tree
Hide file tree
Showing 10 changed files with 318 additions and 224 deletions.
2 changes: 1 addition & 1 deletion radix-engine/src/engine/actor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,10 @@ impl fmt::Debug for ResolvedMethod {
pub enum ExecutionMode {
Kernel,
Globalize,
MoveDownstream,
MoveUpstream,
Deref,
ScryptoInterpreter,
NodeMoveModule,
AuthModule,
Application,
DropNode,
Expand Down
4 changes: 2 additions & 2 deletions radix-engine/src/engine/errors.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::engine::node_move_module::NodeMoveError;
use crate::engine::{ExecutionMode, LockFlags, REActor};
use radix_engine_interface::api::types::{
GlobalAddress, LockHandle, NativeMethod, RENodeId, ScryptoFunctionIdent, ScryptoMethodIdent,
Expand Down Expand Up @@ -120,8 +121,6 @@ pub enum KernelError {
offset: SubstateOffset,
flags: LockFlags,
},
CantMoveDownstream(RENodeId),
CantMoveUpstream(RENodeId),
}

#[derive(Debug, Clone, PartialEq, Eq)]
Expand Down Expand Up @@ -158,6 +157,7 @@ pub enum InterpreterError {
#[derive(Debug, Clone, PartialEq, Eq)]
#[scrypto(TypeId, Encode, Decode)]
pub enum ModuleError {
NodeMoveError(NodeMoveError),
AuthError(AuthError),
CostingError(CostingError),
ExecutionTraceError(ExecutionTraceError),
Expand Down
231 changes: 68 additions & 163 deletions radix-engine/src/engine/kernel.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use radix_engine_interface::api::api::{EngineApi, SysInvokableNative};
use radix_engine_interface::api::types::{
AuthZoneOffset, BucketOffset, ComponentOffset, GlobalAddress, GlobalOffset, Level, LockHandle,
PackageOffset, ProofOffset, RENodeId, ScryptoFunctionIdent, ScryptoPackage, ScryptoReceiver,
SubstateId, SubstateOffset, VaultId, WorktopOffset,
AuthZoneOffset, ComponentOffset, GlobalAddress, GlobalOffset, Level, LockHandle, PackageOffset,
ProofOffset, RENodeId, ScryptoFunctionIdent, ScryptoPackage, ScryptoReceiver, SubstateId,
SubstateOffset, VaultId, WorktopOffset,
};
use radix_engine_interface::crypto::Hash;
use radix_engine_interface::data::*;
Expand All @@ -15,6 +15,7 @@ use transaction::errors::IdAllocationError;
use transaction::model::AuthZoneParams;
use transaction::validation::*;

use crate::engine::node_move_module::NodeMoveModule;
use crate::engine::system_api::Invokable;
use crate::engine::system_api::LockInfo;
use crate::engine::*;
Expand Down Expand Up @@ -334,108 +335,6 @@ where
}
}

pub fn prepare_move_downstream(
&mut self,
node_id: RENodeId,
to: &REActor,
) -> Result<(), RuntimeError> {
self.execute_in_mode(ExecutionMode::MoveDownstream, |system_api| match node_id {
RENodeId::Bucket(..) => {
let handle = system_api.lock_substate(
node_id,
SubstateOffset::Bucket(BucketOffset::Bucket),
LockFlags::read_only(),
)?;
let substate_ref = system_api.get_ref(handle)?;
let bucket = substate_ref.bucket();
let locked = bucket.is_locked();
system_api.drop_lock(handle)?;
if locked {
Err(RuntimeError::KernelError(KernelError::CantMoveDownstream(
node_id,
)))
} else {
Ok(())
}
}
RENodeId::Proof(..) => {
let from = system_api.get_actor();

if from.is_scrypto_or_transaction() || to.is_scrypto_or_transaction() {
let handle = system_api.lock_substate(
node_id,
SubstateOffset::Proof(ProofOffset::Proof),
LockFlags::MUTABLE,
)?;
let mut substate_ref_mut = system_api.get_ref_mut(handle)?;
let proof = substate_ref_mut.proof();

let rtn = if proof.is_restricted() {
Err(RuntimeError::KernelError(KernelError::CantMoveDownstream(
node_id,
)))
} else {
proof.change_to_restricted();
Ok(())
};

system_api.drop_lock(handle)?;

rtn
} else {
Ok(())
}
}
RENodeId::Component(..) => Ok(()),
RENodeId::AuthZoneStack(..)
| RENodeId::ResourceManager(..)
| RENodeId::KeyValueStore(..)
| RENodeId::NonFungibleStore(..)
| RENodeId::Vault(..)
| RENodeId::Package(..)
| RENodeId::Worktop
| RENodeId::EpochManager(..)
| RENodeId::Global(..) => Err(RuntimeError::KernelError(
KernelError::CantMoveDownstream(node_id),
)),
})
}

pub fn prepare_move_upstream(&mut self, node_id: RENodeId) -> Result<(), RuntimeError> {
self.execute_in_mode(ExecutionMode::MoveDownstream, |system_api| match node_id {
RENodeId::Bucket(..) => {
let handle = system_api.lock_substate(
node_id,
SubstateOffset::Bucket(BucketOffset::Bucket),
LockFlags::read_only(),
)?;
let substate_ref = system_api.get_ref(handle)?;
let bucket = substate_ref.bucket();
let locked = bucket.is_locked();
system_api.drop_lock(handle)?;
if locked {
Err(RuntimeError::KernelError(KernelError::CantMoveUpstream(
node_id,
)))
} else {
Ok(())
}
}
RENodeId::Proof(..) | RENodeId::Component(..) | RENodeId::Vault(..) => Ok(()),

RENodeId::AuthZoneStack(..)
| RENodeId::ResourceManager(..)
| RENodeId::KeyValueStore(..)
| RENodeId::NonFungibleStore(..)
| RENodeId::Package(..)
| RENodeId::Worktop
| RENodeId::EpochManager(..)
| RENodeId::Global(..) => Err(RuntimeError::KernelError(
KernelError::CantMoveUpstream(node_id),
)),
})
}

fn drop_node_internal(&mut self, node_id: RENodeId) -> Result<HeapRENode, RuntimeError> {
self.execute_in_mode::<_, _, RuntimeError>(ExecutionMode::DropNode, |system_api| {
match node_id {
Expand Down Expand Up @@ -536,82 +435,88 @@ where
None
};

let new_refed_nodes = self.execute_in_mode(ExecutionMode::AuthModule, |system_api| {
AuthModule::on_before_frame_start(&actor, &executor, system_api).map_err(|e| match e {
InvokeError::Error(e) => RuntimeError::ModuleError(e.into()),
InvokeError::Downstream(runtime_error) => runtime_error,
})
// Filter
self.execute_in_mode(ExecutionMode::AuthModule, |system_api| {
AuthModule::on_before_frame_start(&actor, &executor, system_api)
})?;

// TODO: Do this in a better way by allowing module to execute in next call frame
call_frame_update.node_refs_to_copy.extend(new_refed_nodes);

for node_id in &call_frame_update.nodes_to_move {
self.prepare_move_downstream(*node_id, &actor)?;
// New Call Frame pre-processing
{
// TODO: Abstract these away
self.execute_in_mode(ExecutionMode::AuthModule, |system_api| {
AuthModule::on_call_frame_enter(&mut call_frame_update, &actor, system_api)
})?;
self.execute_in_mode(ExecutionMode::NodeMoveModule, |system_api| {
NodeMoveModule::on_call_frame_enter(&mut call_frame_update, &actor, system_api)
})?;
for m in &mut self.modules {
m.pre_execute_invocation(
&actor,
executor.args(),
&mut self.current_frame,
&mut self.heap,
&mut self.track,
)
.map_err(RuntimeError::ModuleError)?;
}
}

for m in &mut self.modules {
m.pre_execute_invocation(
&actor,
executor.args(),
// Call Frame Push
{
let frame = CallFrame::new_child_from_parent(
&mut self.current_frame,
&mut self.heap,
&mut self.track,
)
.map_err(RuntimeError::ModuleError)?;
actor,
call_frame_update,
)?;
let parent = mem::replace(&mut self.current_frame, frame);
self.prev_frame_stack.push(parent);
}

// Call Frame Push
let frame =
CallFrame::new_child_from_parent(&mut self.current_frame, actor, call_frame_update)?;

let parent = mem::replace(&mut self.current_frame, frame);
self.prev_frame_stack.push(parent);

// Execute
let (output, update) = self.execute_in_mode(ExecutionMode::Application, |system_api| {
executor.execute(system_api)
})?;

for m in &mut self.modules {
m.post_execute_invocation(
&update,
&mut self.current_frame,
&mut self.heap,
&mut self.track,
)
.map_err(RuntimeError::ModuleError)?;
}

// Process return data
let mut parent = self.prev_frame_stack.pop().unwrap();

for node_id in &update.nodes_to_move {
self.prepare_move_upstream(*node_id)?;
}
// Call Frame post-processing
{
// Auto drop locks
self.current_frame
.drop_all_locks(&mut self.heap, &mut self.track)?;

CallFrame::update_upstream(&mut self.current_frame, &mut parent, update)?;
for m in &mut self.modules {
m.post_execute_invocation(
&update,
&mut self.current_frame,
&mut self.heap,
&mut self.track,
)
.map_err(RuntimeError::ModuleError)?;
}

// Auto drop locks
self.current_frame
.drop_all_locks(&mut self.heap, &mut self.track)?;
// TODO: Abstract these away
self.execute_in_mode(ExecutionMode::NodeMoveModule, |system_api| {
NodeMoveModule::on_call_frame_exit(&update, system_api)
})?;
self.execute_in_mode(ExecutionMode::AuthModule, |system_api| {
AuthModule::on_call_frame_exit(system_api)
})?;

self.execute_in_mode(ExecutionMode::AuthModule, |system_api| {
AuthModule::on_frame_end(system_api).map_err(|e| match e {
InvokeError::Error(e) => RuntimeError::ModuleError(e.into()),
InvokeError::Downstream(runtime_error) => runtime_error,
})
})?;
// Auto-drop locks again in case module forgot to drop
self.current_frame
.drop_all_locks(&mut self.heap, &mut self.track)?;
}

// Auto-drop locks again in case module forgot to drop
self.current_frame
.drop_all_locks(&mut self.heap, &mut self.track)?;
// Call Frame Pop
{
let mut parent = self.prev_frame_stack.pop().unwrap();
CallFrame::update_upstream(&mut self.current_frame, &mut parent, update)?;

// drop proofs and check resource leak
self.drop_nodes_in_frame()?;
// drop proofs and check resource leak
self.drop_nodes_in_frame()?;

// Restore previous frame
self.current_frame = parent;
// Restore previous frame
self.current_frame = parent;
}

if let Some(derefed_lock) = derefed_lock {
self.current_frame
Expand Down
Loading

0 comments on commit 2ef218f

Please sign in to comment.