cfx_executor/stack/
executable.rs1use super::{FrameLocal, Resumable};
2use crate::{
3 builtin::BuiltinExec, context::Context, executive_observer::TracerTrait,
4 internal_contract::InternalContractExec,
5};
6use cfx_statedb::Result as DbResult;
7use cfx_types::{AddressSpaceUtil, U256};
8use cfx_vm_interpreter::{FinalizationResult, Finalize};
9use cfx_vm_types::{
10 self as vm, separate_out_db_error, ActionParams, Exec, GasLeft, ReturnData,
11 TrapError, TrapResult,
12};
13
14pub trait Executable: Send {
26 fn execute(
27 self: Box<Self>, context: Context,
28 ) -> DbResult<ExecutableOutcome>;
29}
30
31pub enum ExecutableOutcome {
36 Return(vm::Result<FinalizationResult>),
38 Invoke(ActionParams, Box<dyn Resumable>),
41}
42use ExecutableOutcome::*;
43
44pub fn make_executable<'a>(
48 frame_local: &FrameLocal<'a>, params: ActionParams,
49 tracer: &mut dyn TracerTrait,
50) -> Box<dyn 'a + Executable> {
51 let is_create = frame_local.create_address.is_some();
52 let code_address = params.code_address.with_space(params.space);
53 let internal_contract_map = frame_local.machine.internal_contracts();
54
55 if let Some(builtin) = frame_local.machine.builtin(
57 &code_address,
58 frame_local.env.number,
59 frame_local.env.epoch_height,
60 ) {
61 trace!("CallBuiltin");
62 return Box::new(BuiltinExec { builtin, params });
63 }
64
65 if let Some(internal) =
66 internal_contract_map.contract(&code_address, &frame_local.spec)
67 {
68 trace!(
69 "CallInternalContract: address={:?} data={:?}",
70 code_address,
71 params.data
72 );
73 return Box::new(InternalContractExec { internal, params });
74 }
75
76 if is_create || params.code.is_some() {
77 trace!("CallCreate");
78
79 tracer.initialize_interp(params.gas.clone());
81
82 let factory = frame_local.machine.vm_factory_ref();
83 Box::new(factory.create(params, frame_local.spec, frame_local.depth))
84 } else {
85 trace!("Transfer");
86 Box::new(NoopExec { gas: params.gas })
87 }
88}
89
90impl Executable for Box<dyn Exec> {
91 fn execute(
92 self: Box<Self>, mut context: Context,
93 ) -> DbResult<ExecutableOutcome> {
94 Ok(match self.exec(&mut context) {
95 TrapResult::Return(result) => {
96 let result = separate_out_db_error(result)?;
97 if matches!(result, Ok(GasLeft::Known(_))) {
102 context.insert_create_address_to_substate();
103 }
104 Return(result.finalize(context))
105 }
106 TrapResult::SubCallCreate(TrapError::Call(params, resume)) => {
107 Invoke(params, Box::new(resume))
108 }
109 TrapResult::SubCallCreate(TrapError::Create(params, resume)) => {
110 Invoke(params, Box::new(resume))
111 }
112 })
113 }
114}
115
116pub struct NoopExec {
117 pub gas: U256,
118}
119
120impl Executable for NoopExec {
121 fn execute(self: Box<Self>, _: Context) -> DbResult<ExecutableOutcome> {
122 let result = FinalizationResult {
123 gas_left: self.gas,
124 apply_state: true,
125 return_data: ReturnData::empty(),
126 };
127 Ok(Return(Ok(result)))
128 }
129}