1use crate::{
2 executive::gas_required_for,
3 executive_observer::AddressPocket,
4 internal_bail,
5 stack::{
6 Context, Executable, ExecutableOutcome, FrameResult, FrameReturn,
7 Resumable,
8 },
9};
10
11use cfx_parameters::block::CROSS_SPACE_GAS_RATIO;
12use cfx_statedb::Result as DbResult;
13use cfx_types::{
14 address_util::AddressUtil, cal_contract_address_with_space, Address,
15 AddressSpaceUtil, CreateContractAddressType, Space, H256, U256,
16};
17use cfx_vm_interpreter::Finalize;
18use cfx_vm_types::{
19 self as vm, ActionParams, ActionValue, CallType, Context as _, CreateType,
20 GasLeft, ParamsType, Spec,
21};
22use solidity_abi::ABIEncodable;
23use std::{marker::PhantomData, sync::Arc};
24
25use super::super::{
26 components::{InternalRefContext, InternalTrapResult, SolidityEventTrait},
27 contracts::cross_space::{
28 CallEvent, CreateEvent, ReturnEvent, WithdrawEvent,
29 },
30};
31
32pub fn create_gas(context: &InternalRefContext, code: &[u8]) -> DbResult<U256> {
33 let code_length = code.len();
34
35 let transaction_gas = gas_required_for(
36 true,
37 code,
38 None,
39 0,
40 &context.spec.to_consensus_spec(),
41 ) + context.spec.tx_gas as u64;
42
43 let create_gas = U256::from(context.spec.create_gas);
44
45 let address_mapping_gas = context.spec.sha3_gas * 2;
46
47 let create_log_gas = {
48 let log_data_length =
49 H256::len_bytes() * 4 + (code_length + 31) / 32 * 32;
50 context.spec.log_gas
51 + 3 * context.spec.log_topic_gas
52 + context.spec.log_data_gas * log_data_length
53 };
54
55 let return_log_gas = {
56 let log_data_length = H256::len_bytes();
57 context.spec.log_gas
58 + context.spec.log_topic_gas
59 + context.spec.log_data_gas * log_data_length
60 };
61
62 Ok(create_gas
63 + transaction_gas
64 + address_mapping_gas
65 + create_log_gas
66 + return_log_gas)
67}
68
69pub fn call_gas(
70 receiver: Address, params: &ActionParams, context: &InternalRefContext,
71 data: &[u8],
72) -> DbResult<U256> {
73 let data_length = data.len();
74
75 let transaction_gas = gas_required_for(
76 false,
77 data,
78 None,
79 0,
80 &context.spec.to_consensus_spec(),
81 ) + context.spec.tx_gas as u64;
82
83 let new_account = !context
84 .state
85 .exists_and_not_null(&receiver.with_evm_space())?;
86 let new_account_gas = if new_account {
87 context.spec.call_new_account_gas * context.spec.evm_gas_ratio
88 } else {
89 0
90 };
91
92 let transfer_gas = if params.value.value() > U256::zero() {
93 context.spec.call_value_transfer_gas
94 } else {
95 0
96 };
97
98 let call_gas =
99 U256::from(context.spec.call_gas) + new_account_gas + transfer_gas;
100
101 let address_mapping_gas = context.spec.sha3_gas * 2;
102
103 let call_log_gas = {
104 let log_data_length =
105 H256::len_bytes() * 4 + (data_length + 31) / 32 * 32;
106 context.spec.log_gas
107 + 3 * context.spec.log_topic_gas
108 + context.spec.log_data_gas * log_data_length
109 };
110
111 let return_log_gas = {
112 let log_data_length = H256::len_bytes();
113 context.spec.log_gas
114 + context.spec.log_topic_gas
115 + context.spec.log_data_gas * log_data_length
116 };
117
118 Ok(call_gas
119 + transaction_gas
120 + address_mapping_gas
121 + call_log_gas
122 + return_log_gas)
123}
124
125pub fn static_call_gas(spec: &Spec) -> U256 {
126 let call_gas = U256::from(spec.call_gas);
127 let address_mapping_gas = spec.sha3_gas * 2;
128
129 call_gas + address_mapping_gas
130}
131
132pub fn withdraw_gas(spec: &Spec) -> U256 {
133 let call_gas = U256::from(spec.call_value_transfer_gas);
134 let transaction_gas = spec.tx_gas;
135 let address_mapping_gas = spec.sha3_gas;
136 let log_gas = spec.log_gas
137 + spec.log_topic_gas * 3
138 + spec.log_data_gas * H256::len_bytes() * 2;
139
140 call_gas + transaction_gas + address_mapping_gas + log_gas
141}
142
143#[derive(Clone)]
144pub struct Resume {
145 pub params: ActionParams,
146 pub gas_retained: U256,
147 pub wait_return_log: bool,
148}
149
150impl Resumable for Resume {
151 fn resume(self: Box<Self>, result: FrameResult) -> Box<dyn Executable> {
152 let frame_return = match result {
153 Ok(r) => r,
154 Err(e) => {
155 return Box::new(PassResult {
156 params: self.params,
157 result: Err(e),
158 apply_state: false,
159 wait_return_log: self.wait_return_log,
160 });
161 }
162 };
163
164 let gas_left = self.gas_retained + frame_return.gas_left;
165 let apply_state = frame_return.apply_state;
166
167 let data = match frame_return {
168 FrameReturn {
169 apply_state: true,
170 create_address: Some(create_address),
171 ..
172 } => create_address.0.abi_encode().into(),
173 FrameReturn {
174 apply_state: true,
175 return_data,
176 create_address: None,
177 ..
178 } => return_data.to_vec().abi_encode().into(),
179 FrameReturn {
180 apply_state: false,
181 return_data,
182 ..
183 } => return_data,
184 };
185
186 Box::new(PassResult {
187 params: self.params,
188 apply_state,
189 result: Ok(GasLeft::NeedsReturn {
190 gas_left,
191 data,
192 apply_state,
193 }),
194 wait_return_log: self.wait_return_log,
195 })
196 }
197}
198
199pub struct PassResult {
200 params: ActionParams,
201 result: vm::Result<GasLeft>,
202 apply_state: bool,
203 wait_return_log: bool,
204}
205
206impl Executable for PassResult {
207 fn execute(
208 self: Box<Self>, mut context: Context,
209 ) -> DbResult<ExecutableOutcome> {
210 if self.wait_return_log {
211 ReturnEvent::log(
212 &(),
213 &self.apply_state,
214 &self.params,
215 &mut context.internal_ref(),
216 )
217 .expect("Must have no static flag");
218 }
219
220 let result = self
221 .result
222 .and_then(|r| r.charge_return_data_gas(context.spec()))
223 .finalize(context);
224 Ok(ExecutableOutcome::Return(result))
225 }
226}
227
228pub fn process_trap<T>(
229 result: vm::Result<(ActionParams, Box<dyn Resumable>)>,
230 _phantom: PhantomData<T>,
231) -> InternalTrapResult<T> {
232 match result {
233 Ok((p, r)) => InternalTrapResult::Invoke(p, r),
234 Err(err) => InternalTrapResult::Return(Err(err)),
235 }
236}
237
238pub fn call_to_evmcore(
239 receiver: Address, data: Vec<u8>, call_type: CallType,
240 params: &ActionParams, gas_left: U256, context: &mut InternalRefContext,
241) -> vm::Result<(ActionParams, Box<dyn Resumable>)> {
242 if context.depth >= context.spec.max_depth {
243 internal_bail!("Exceed Depth");
244 }
245
246 let value = params.value.value();
247
248 let call_gas = gas_left / CROSS_SPACE_GAS_RATIO
249 + if value > U256::zero() {
250 U256::from(context.spec.call_stipend)
251 } else {
252 U256::zero()
253 };
254 let reserved_gas = gas_left - gas_left / CROSS_SPACE_GAS_RATIO;
255
256 let mapped_sender = params.sender.evm_map();
257 let mapped_origin = params.original_sender.evm_map();
258
259 context.state.transfer_balance(
260 ¶ms.address.with_native_space(),
261 &mapped_sender,
262 &value,
263 )?;
264 context.state.add_total_evm_tokens(value);
265 context.tracer.trace_internal_transfer(
266 AddressPocket::Balance(params.address.with_native_space()),
267 AddressPocket::Balance(mapped_sender),
268 params.value.value(),
269 );
270
271 let address = receiver.with_evm_space();
272
273 let code = context.state.code(&address)?;
274 let code_hash = context.state.code_hash(&address)?;
275
276 let next_params = ActionParams {
277 space: Space::Ethereum,
278 sender: mapped_sender.address,
279 address: address.address,
280 value: ActionValue::Transfer(value),
281 code_address: address.address,
282 original_sender: mapped_origin.address,
283 storage_owner: mapped_sender.address,
284 gas: call_gas,
285 gas_price: params.gas_price,
286 code,
287 code_hash,
288 data: Some(data.clone()),
289 call_type,
290 create_type: CreateType::None,
291 params_type: vm::ParamsType::Separate,
292 };
293
294 let mut wait_return_log = false;
295
296 if call_type == CallType::Call {
297 let nonce = context.state.nonce(&mapped_sender)?;
298 context.state.inc_nonce(&mapped_sender)?;
299 CallEvent::log(
300 &(mapped_sender.address.0, address.address.0),
301 &(value, nonce, data),
302 params,
303 context,
304 )?;
305 wait_return_log = true;
306 }
307
308 Ok((
309 next_params,
310 Box::new(Resume {
311 params: params.clone(),
312 gas_retained: reserved_gas,
313 wait_return_log,
314 }),
315 ))
316}
317
318pub fn create_to_evmcore(
319 init: Vec<u8>, salt: Option<H256>, params: &ActionParams, gas_left: U256,
320 context: &mut InternalRefContext,
321) -> vm::Result<(ActionParams, Box<dyn Resumable>)> {
322 if context.depth >= context.spec.max_depth {
323 internal_bail!("Exceed Depth");
324 }
325
326 let call_gas = gas_left / CROSS_SPACE_GAS_RATIO
327 + if params.value.value() > U256::zero() {
328 U256::from(context.spec.call_stipend)
329 } else {
330 U256::zero()
331 };
332 let reserved_gas = gas_left - gas_left / CROSS_SPACE_GAS_RATIO;
333
334 let mapped_sender = params.sender.evm_map();
335 let mapped_origin = params.original_sender.evm_map();
336
337 let value = params.value.value();
338 context.state.transfer_balance(
339 ¶ms.address.with_native_space(),
340 &mapped_sender,
341 &value,
342 )?;
343 context.state.add_total_evm_tokens(value);
344 context.tracer.trace_internal_transfer(
345 AddressPocket::Balance(params.address.with_native_space()),
346 AddressPocket::Balance(mapped_sender),
347 params.value.value(),
348 );
349
350 let (address_scheme, create_type) = match salt {
351 None => (
352 CreateContractAddressType::FromSenderNonce,
353 CreateType::CREATE,
354 ),
355 Some(salt) => (
356 CreateContractAddressType::FromSenderSaltAndCodeHash(salt),
357 CreateType::CREATE2,
358 ),
359 };
360 let (address_with_space, code_hash) = cal_contract_address_with_space(
361 address_scheme,
362 &mapped_sender,
363 &context.state.nonce(&mapped_sender)?,
364 &init,
365 );
366 let address = address_with_space.address;
367
368 let next_params = ActionParams {
369 space: Space::Ethereum,
370 code_address: address,
371 address,
372 sender: mapped_sender.address,
373 original_sender: mapped_origin.address,
374 storage_owner: Address::zero(),
375 gas: call_gas,
376 gas_price: params.gas_price,
377 value: ActionValue::Transfer(value),
378 code: Some(Arc::new(init.clone())),
379 code_hash,
380 data: None,
381 call_type: CallType::None,
382 create_type,
383 params_type: ParamsType::Embedded,
384 };
385
386 let nonce = context.state.nonce(&mapped_sender)?;
387 context.state.inc_nonce(&mapped_sender)?;
388 CreateEvent::log(
389 &(mapped_sender.address.0, address.0),
390 &(value, nonce, init),
391 params,
392 context,
393 )?;
394
395 Ok((
396 next_params,
397 Box::new(Resume {
398 params: params.clone(),
399 gas_retained: reserved_gas,
400 wait_return_log: true,
401 }),
402 ))
403}
404
405pub fn withdraw_from_evmcore(
406 sender: Address, value: U256, params: &ActionParams,
407 context: &mut InternalRefContext,
408) -> vm::Result<()> {
409 let mapped_address = sender.evm_map();
410 let balance = context.state.balance(&mapped_address)?;
411 if balance < value {
412 internal_bail!(
413 "Not enough balance for withdrawing from mapped address"
414 );
415 }
416 context.state.transfer_balance(
417 &mapped_address,
418 &sender.with_native_space(),
419 &value,
420 )?;
421 context.state.sub_total_evm_tokens(value);
422 context.tracer.trace_internal_transfer(
423 AddressPocket::Balance(mapped_address),
424 AddressPocket::Balance(sender.with_native_space()),
425 value,
426 );
427
428 let nonce = context.state.nonce(&mapped_address)?;
429 context.state.inc_nonce(&mapped_address)?;
430 WithdrawEvent::log(
431 &(mapped_address.address.0, sender),
432 &(value, nonce),
433 params,
434 context,
435 )?;
436
437 Ok(())
438}
439
440pub fn mapped_balance(
441 address: Address, context: &mut InternalRefContext,
442) -> vm::Result<U256> {
443 Ok(context.state.balance(&address.evm_map())?)
444}
445
446pub fn mapped_nonce(
447 address: Address, context: &mut InternalRefContext,
448) -> vm::Result<U256> {
449 Ok(context.state.nonce(&address.evm_map())?)
450}