use crate::{
executive_observer::{AddressPocket, TracerTrait},
state::State,
substate::{cleanup_mode, Substate},
};
use cfx_vm_types::{self as vm, ActionParams, Spec};
use cfx_types::{
address_util::AddressUtil, Address, AddressSpaceUtil, AddressWithSpace,
Space,
};
use super::super::components::InternalRefContext;
fn available_admin_address(_spec: &Spec, address: &Address) -> bool {
address.is_user_account_address() || address.is_null_address()
}
pub fn suicide(
contract_address: &AddressWithSpace, refund_address: &AddressWithSpace,
state: &mut State, spec: &Spec, substate: &mut Substate,
tracer: &mut dyn TracerTrait,
) -> vm::Result<()> {
substate.suicides.insert(contract_address.clone());
let balance = state.balance(contract_address)?;
if refund_address == contract_address
|| (!spec.is_valid_address(&refund_address.address)
&& refund_address.space == Space::Native)
{
tracer.trace_internal_transfer(
AddressPocket::Balance(*contract_address),
AddressPocket::MintBurn,
balance,
);
state.sub_balance(
contract_address,
&balance,
&mut cleanup_mode(substate, spec),
)?;
state.sub_total_issued(balance);
if contract_address.space == Space::Ethereum {
state.sub_total_evm_tokens(balance);
}
} else {
trace!(target: "context", "Destroying {} -> {} (xfer: {})", contract_address.address, refund_address.address, balance);
tracer.trace_internal_transfer(
AddressPocket::Balance(*contract_address),
AddressPocket::Balance(*refund_address),
balance,
);
state.transfer_balance(
contract_address,
refund_address,
&balance,
cleanup_mode(substate, spec),
)?;
}
Ok(())
}
pub fn set_admin(
contract_address: Address, new_admin_address: Address,
params: &ActionParams, context: &mut InternalRefContext,
) -> vm::Result<()> {
let requester = ¶ms.sender;
debug!(
"set_admin requester {:?} contract {:?}, \
new_admin {:?}, contract_in_creation {:?}",
requester,
contract_address,
new_admin_address,
context.callstack.contract_in_creation(),
);
let clear_admin_in_create = context.callstack.contract_in_creation()
== Some(&contract_address.with_native_space())
&& new_admin_address.is_null_address();
if context.is_contract_address(&contract_address)?
&& context.state.exists(&contract_address.with_native_space())?
&& (context.state.admin(&contract_address)?.eq(requester)
|| clear_admin_in_create)
&& available_admin_address(&context.spec, &new_admin_address)
{
debug!("set_admin to {:?}", new_admin_address);
context
.state
.set_admin(&contract_address, &new_admin_address)?;
}
Ok(())
}
pub fn destroy(
contract_address: Address, params: &ActionParams, state: &mut State,
spec: &Spec, substate: &mut Substate, tracer: &mut dyn TracerTrait,
) -> vm::Result<()> {
debug!("contract_address={:?}", contract_address);
let requester = ¶ms.sender;
let admin = state.admin(&contract_address)?;
if admin == *requester {
suicide(
&contract_address.with_native_space(),
&admin.with_native_space(),
state,
spec,
substate,
tracer,
)
} else {
Ok(())
}
}