cfx_executor/stack/
frame_start.rs1use super::{
2 super::context::OriginInfo, executable::make_executable, run_executable,
3 FrameLocal, FrameStackAction, RuntimeRes,
4};
5use crate::{machine::Machine, state::State, substate::Substate};
6
7use cfx_statedb::Result as DbResult;
8use cfx_types::{Address, AddressSpaceUtil, AddressWithSpace, Space};
9use cfx_vm_types::{
10 ActionParams, ActionValue, CallType, CreateType, Env, Spec,
11};
12use primitives::{storage::STORAGE_LAYOUT_REGULAR_V0, StorageLayout};
13
14pub struct FreshFrame<'a> {
17 params: ActionParams,
19
20 frame_local: FrameLocal<'a>,
22}
23
24impl<'a> FreshFrame<'a> {
25 pub fn new(
26 params: ActionParams, env: &'a Env, machine: &'a Machine,
27 spec: &'a Spec, depth: usize, parent_static_flag: bool,
28 ) -> Self {
29 let is_create = params.create_type != CreateType::None;
30 let create_address = is_create.then_some(params.code_address);
31 trace!(
32 "Executive::{:?}(params={:?}) self.env={:?}, parent_static={}",
33 if is_create { "create" } else { "call" },
34 params,
35 env,
36 parent_static_flag,
37 );
38
39 let static_flag =
40 parent_static_flag || params.call_type == CallType::StaticCall;
41
42 let substate = Substate::new();
43 let origin = OriginInfo::from(¶ms);
44
45 let frame_local = FrameLocal::new(
46 params.space,
47 env,
48 machine,
49 spec,
50 depth,
51 origin,
52 substate,
53 create_address,
54 static_flag,
55 );
56 FreshFrame {
57 frame_local,
58 params,
59 }
60 }
61
62 pub(super) fn init_and_exec(
65 self, resources: &mut RuntimeRes<'a>,
66 ) -> DbResult<FrameStackAction<'a>> {
67 let FreshFrame {
68 frame_local,
69 params,
70 } = self;
71 let is_create = frame_local.create_address.is_some();
72
73 if is_create {
74 debug!(
75 "CallCreateExecutiveKind::ExecCreate: contract_addr = {:?}",
76 params.address
77 );
78 resources.tracer.record_create(¶ms);
79 } else {
80 resources.tracer.record_call(¶ms);
81 }
82
83 resources.state.checkpoint();
86
87 let contract_address = frame_local.origin.recipient().clone();
88 resources
89 .callstack
90 .push(contract_address.with_space(frame_local.space), is_create);
91
92 let spec = &frame_local.spec;
94 if is_create {
95 transfer_exec_balance_and_init_contract(
96 ¶ms,
97 spec,
98 resources.state,
99 Some(STORAGE_LAYOUT_REGULAR_V0),
100 )?
101 } else {
102 transfer_balance(¶ms, resources.state)?
103 };
104
105 let executable =
106 make_executable(&frame_local, params, resources.tracer);
107 run_executable(executable, frame_local, resources)
108 }
109}
110
111fn transfer_balance(params: &ActionParams, state: &mut State) -> DbResult<()> {
112 let sender = AddressWithSpace {
113 address: params.sender,
114 space: params.space,
115 };
116 let receiver = AddressWithSpace {
117 address: params.address,
118 space: params.space,
119 };
120 if let ActionValue::Transfer(val) = params.value {
121 state.transfer_balance(&sender, &receiver, &val)?;
122 }
123
124 Ok(())
125}
126
127fn transfer_exec_balance_and_init_contract(
128 params: &ActionParams, spec: &Spec, state: &mut State,
129 storage_layout: Option<StorageLayout>,
130) -> DbResult<()> {
131 let sender = AddressWithSpace {
132 address: params.sender,
133 space: params.space,
134 };
135 let receiver = AddressWithSpace {
136 address: params.address,
137 space: params.space,
138 };
139 if let ActionValue::Transfer(val) = params.value {
140 let prev_balance = state.balance(&receiver)?;
143 state.sub_balance(&sender, &val)?;
144 let admin = if params.space == Space::Native {
145 params.original_sender
146 } else {
147 Address::zero()
148 };
149 state.new_contract_with_admin(
150 &receiver,
151 &admin,
152 val.saturating_add(prev_balance),
153 storage_layout,
154 spec.cip107,
155 )?;
156 } else {
157 unreachable!();
160 }
161
162 Ok(())
163}