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, code_hash) = if context.spec.cip175 {
274 context.state.code_with_hash_on_call(&address)?
276 } else {
277 (
278 context.state.code(&address)?,
279 context.state.code_hash(&address)?,
280 )
281 };
282
283 let next_params = ActionParams {
284 space: Space::Ethereum,
285 sender: mapped_sender.address,
286 address: address.address,
287 value: ActionValue::Transfer(value),
288 code_address: address.address,
289 original_sender: mapped_origin.address,
290 storage_owner: mapped_sender.address,
291 gas: call_gas,
292 gas_price: params.gas_price,
293 code,
294 code_hash,
295 data: Some(data.clone()),
296 call_type,
297 create_type: CreateType::None,
298 params_type: vm::ParamsType::Separate,
299 };
300
301 let mut wait_return_log = false;
302
303 if call_type == CallType::Call {
304 let nonce = context.state.nonce(&mapped_sender)?;
305 context.state.inc_nonce(&mapped_sender)?;
306 CallEvent::log(
307 &(mapped_sender.address.0, address.address.0),
308 &(value, nonce, data),
309 params,
310 context,
311 )?;
312 wait_return_log = true;
313 }
314
315 Ok((
316 next_params,
317 Box::new(Resume {
318 params: params.clone(),
319 gas_retained: reserved_gas,
320 wait_return_log,
321 }),
322 ))
323}
324
325pub fn create_to_evmcore(
326 init: Vec<u8>, salt: Option<H256>, params: &ActionParams, gas_left: U256,
327 context: &mut InternalRefContext,
328) -> vm::Result<(ActionParams, Box<dyn Resumable>)> {
329 if context.depth >= context.spec.max_depth {
330 internal_bail!("Exceed Depth");
331 }
332
333 let call_gas = gas_left / CROSS_SPACE_GAS_RATIO
334 + if params.value.value() > U256::zero() {
335 U256::from(context.spec.call_stipend)
336 } else {
337 U256::zero()
338 };
339 let reserved_gas = gas_left - gas_left / CROSS_SPACE_GAS_RATIO;
340
341 let mapped_sender = params.sender.evm_map();
342 let mapped_origin = params.original_sender.evm_map();
343
344 let value = params.value.value();
345 context.state.transfer_balance(
346 ¶ms.address.with_native_space(),
347 &mapped_sender,
348 &value,
349 )?;
350 context.state.add_total_evm_tokens(value);
351 context.tracer.trace_internal_transfer(
352 AddressPocket::Balance(params.address.with_native_space()),
353 AddressPocket::Balance(mapped_sender),
354 params.value.value(),
355 );
356
357 let (address_scheme, create_type) = match salt {
358 None => (
359 CreateContractAddressType::FromSenderNonce,
360 CreateType::CREATE,
361 ),
362 Some(salt) => (
363 CreateContractAddressType::FromSenderSaltAndCodeHash(salt),
364 CreateType::CREATE2,
365 ),
366 };
367 let (address_with_space, code_hash) = cal_contract_address_with_space(
368 address_scheme,
369 &mapped_sender,
370 &context.state.nonce(&mapped_sender)?,
371 &init,
372 );
373 let address = address_with_space.address;
374
375 let next_params = ActionParams {
376 space: Space::Ethereum,
377 code_address: address,
378 address,
379 sender: mapped_sender.address,
380 original_sender: mapped_origin.address,
381 storage_owner: Address::zero(),
382 gas: call_gas,
383 gas_price: params.gas_price,
384 value: ActionValue::Transfer(value),
385 code: Some(Arc::new(init.clone())),
386 code_hash,
387 data: None,
388 call_type: CallType::None,
389 create_type,
390 params_type: ParamsType::Embedded,
391 };
392
393 let nonce = context.state.nonce(&mapped_sender)?;
394 context.state.inc_nonce(&mapped_sender)?;
395 CreateEvent::log(
396 &(mapped_sender.address.0, address.0),
397 &(value, nonce, init),
398 params,
399 context,
400 )?;
401
402 Ok((
403 next_params,
404 Box::new(Resume {
405 params: params.clone(),
406 gas_retained: reserved_gas,
407 wait_return_log: true,
408 }),
409 ))
410}
411
412pub fn withdraw_from_evmcore(
413 sender: Address, value: U256, params: &ActionParams,
414 context: &mut InternalRefContext,
415) -> vm::Result<()> {
416 let mapped_address = sender.evm_map();
417 let balance = context.state.balance(&mapped_address)?;
418 if balance < value {
419 internal_bail!(
420 "Not enough balance for withdrawing from mapped address"
421 );
422 }
423 context.state.transfer_balance(
424 &mapped_address,
425 &sender.with_native_space(),
426 &value,
427 )?;
428 context.state.sub_total_evm_tokens(value);
429 context.tracer.trace_internal_transfer(
430 AddressPocket::Balance(mapped_address),
431 AddressPocket::Balance(sender.with_native_space()),
432 value,
433 );
434
435 let nonce = context.state.nonce(&mapped_address)?;
436 context.state.inc_nonce(&mapped_address)?;
437 WithdrawEvent::log(
438 &(mapped_address.address.0, sender),
439 &(value, nonce),
440 params,
441 context,
442 )?;
443
444 Ok(())
445}
446
447pub fn mapped_balance(
448 address: Address, context: &mut InternalRefContext,
449) -> vm::Result<U256> {
450 Ok(context.state.balance(&address.evm_map())?)
451}
452
453pub fn mapped_nonce(
454 address: Address, context: &mut InternalRefContext,
455) -> vm::Result<U256> {
456 Ok(context.state.nonce(&address.evm_map())?)
457}