cfx_executor/stack/
frame_start.rsuse super::{
    super::context::OriginInfo, executable::make_executable, run_executable,
    FrameLocal, FrameStackAction, RuntimeRes,
};
use crate::{machine::Machine, state::State, substate::Substate};
use cfx_statedb::Result as DbResult;
use cfx_types::{Address, AddressSpaceUtil, AddressWithSpace, Space};
use cfx_vm_types::{
    ActionParams, ActionValue, CallType, CreateType, Env, Spec,
};
use primitives::{storage::STORAGE_LAYOUT_REGULAR_V0, StorageLayout};
pub struct FreshFrame<'a> {
    params: ActionParams,
    frame_local: FrameLocal<'a>,
}
impl<'a> FreshFrame<'a> {
    pub fn new(
        params: ActionParams, env: &'a Env, machine: &'a Machine,
        spec: &'a Spec, depth: usize, parent_static_flag: bool,
    ) -> Self {
        let is_create = params.create_type != CreateType::None;
        let create_address = is_create.then_some(params.code_address);
        trace!(
            "Executive::{:?}(params={:?}) self.env={:?}, parent_static={}",
            if is_create { "create" } else { "call" },
            params,
            env,
            parent_static_flag,
        );
        let static_flag =
            parent_static_flag || params.call_type == CallType::StaticCall;
        let substate = Substate::new();
        let origin = OriginInfo::from(¶ms);
        let frame_local = FrameLocal::new(
            params.space,
            env,
            machine,
            spec,
            depth,
            origin,
            substate,
            create_address,
            static_flag,
        );
        FreshFrame {
            frame_local,
            params,
        }
    }
    pub(super) fn init_and_exec(
        self, resources: &mut RuntimeRes<'a>,
    ) -> DbResult<FrameStackAction<'a>> {
        let FreshFrame {
            frame_local,
            params,
        } = self;
        let is_create = frame_local.create_address.is_some();
        if is_create {
            debug!(
                "CallCreateExecutiveKind::ExecCreate: contract_addr = {:?}",
                params.address
            );
            resources.tracer.record_create(¶ms);
        } else {
            resources.tracer.record_call(¶ms);
        }
        resources.state.checkpoint();
        let contract_address = frame_local.origin.recipient().clone();
        resources
            .callstack
            .push(contract_address.with_space(frame_local.space), is_create);
        let spec = &frame_local.spec;
        if is_create {
            transfer_exec_balance_and_init_contract(
                ¶ms,
                spec,
                resources.state,
                Some(STORAGE_LAYOUT_REGULAR_V0),
            )?
        } else {
            transfer_balance(¶ms, resources.state)?
        };
        let executable =
            make_executable(&frame_local, params, resources.tracer);
        run_executable(executable, frame_local, resources)
    }
}
fn transfer_balance(params: &ActionParams, state: &mut State) -> DbResult<()> {
    let sender = AddressWithSpace {
        address: params.sender,
        space: params.space,
    };
    let receiver = AddressWithSpace {
        address: params.address,
        space: params.space,
    };
    if let ActionValue::Transfer(val) = params.value {
        state.transfer_balance(&sender, &receiver, &val)?;
    }
    Ok(())
}
fn transfer_exec_balance_and_init_contract(
    params: &ActionParams, spec: &Spec, state: &mut State,
    storage_layout: Option<StorageLayout>,
) -> DbResult<()> {
    let sender = AddressWithSpace {
        address: params.sender,
        space: params.space,
    };
    let receiver = AddressWithSpace {
        address: params.address,
        space: params.space,
    };
    if let ActionValue::Transfer(val) = params.value {
        let prev_balance = state.balance(&receiver)?;
        state.sub_balance(&sender, &val)?;
        let admin = if params.space == Space::Native {
            params.original_sender
        } else {
            Address::zero()
        };
        state.new_contract_with_admin(
            &receiver,
            &admin,
            val.saturating_add(prev_balance),
            storage_layout,
            spec.cip107,
        )?;
    } else {
        unreachable!();
    }
    Ok(())
}