cfx_executor/internal_contract/impls/
admin.rs1use crate::{
6 executive_observer::{AddressPocket, TracerTrait},
7 stack::CallStackInfo,
8 state::State,
9 substate::Substate,
10};
11use cfx_vm_types::{self as vm, ActionParams, Spec};
12
13use cfx_types::{
14 address_util::AddressUtil, Address, AddressSpaceUtil, AddressWithSpace,
15 Space,
16};
17use vm::Env;
18
19use super::super::components::InternalRefContext;
20
21fn available_admin_address(_spec: &Spec, address: &Address) -> bool {
22 address.is_user_account_address() || address.is_null_address()
23}
24
25pub fn suicide(
33 contract_address: &AddressWithSpace, refund_address: &AddressWithSpace,
34 state: &mut State, spec: &Spec, substate: &mut Substate, env: &Env,
35 creating_contract: bool, tracer: &mut dyn TracerTrait,
36) -> vm::Result<()> {
37 let transaction_hash = env.transaction_hash;
40 let contract_create_in_same_tx = state
41 .created_at_transaction(contract_address, transaction_hash)?
42 || creating_contract;
43 let soft_suicide = spec.cip151 && !contract_create_in_same_tx;
44
45 let balance = state.balance(contract_address)?;
46
47 if !soft_suicide {
48 substate.suicides.insert(contract_address.clone());
49 }
50
51 if (refund_address == contract_address && !soft_suicide)
52 || (!spec.is_valid_address(&refund_address.address)
53 && refund_address.space == Space::Native)
54 {
55 tracer.trace_internal_transfer(
56 AddressPocket::Balance(*contract_address),
57 AddressPocket::MintBurn,
58 balance,
59 );
60 state.sub_balance(contract_address, &balance)?;
62 state.sub_total_issued(balance);
63 if contract_address.space == Space::Ethereum {
64 state.sub_total_evm_tokens(balance);
65 }
66 } else if refund_address != contract_address {
67 trace!(target: "context", "Destroying {} -> {} (xfer: {})", contract_address.address, refund_address.address, balance);
68 tracer.trace_internal_transfer(
69 AddressPocket::Balance(*contract_address),
70 AddressPocket::Balance(*refund_address),
71 balance,
72 );
73 tracer.selfdestruct(
74 contract_address.space,
75 &contract_address.address,
76 &refund_address.address,
77 balance,
78 );
79 state.transfer_balance(contract_address, refund_address, &balance)?;
80 }
81
82 Ok(())
83}
84
85pub fn set_admin(
89 contract_address: Address, new_admin_address: Address,
90 params: &ActionParams, context: &mut InternalRefContext,
91) -> vm::Result<()> {
92 let requester = ¶ms.sender;
93 debug!(
94 "set_admin requester {:?} contract {:?}, \
95 new_admin {:?}, admin_control_in_creation {:?}",
96 requester,
97 contract_address,
98 new_admin_address,
99 context.callstack.admin_control_in_creation(),
100 );
101
102 let clear_admin_in_create = context.callstack.admin_control_in_creation()
103 == Some(&contract_address.with_native_space())
104 && new_admin_address.is_null_address();
105
106 if context.is_contract_address(&contract_address)?
107 && context.state.exists(&contract_address.with_native_space())?
108 && (context.state.admin(&contract_address)?.eq(requester)
110 || clear_admin_in_create)
111 && available_admin_address(&context.spec, &new_admin_address)
113 {
114 debug!("set_admin to {:?}", new_admin_address);
115 context
117 .state
118 .set_admin(&contract_address, &new_admin_address)?;
119 }
120 Ok(())
121}
122
123pub fn destroy(
126 contract_address: Address, params: &ActionParams, state: &mut State,
127 spec: &Spec, substate: &mut Substate, env: &Env,
128 tracer: &mut dyn TracerTrait, callstack: &CallStackInfo,
129) -> vm::Result<()> {
130 debug!("contract_address={:?}", contract_address);
131
132 let requester = ¶ms.sender;
133 let admin = state.admin(&contract_address)?;
134 if admin == *requester {
135 suicide(
136 &contract_address.with_native_space(),
137 &admin.with_native_space(),
138 state,
139 spec,
140 substate,
141 env,
142 callstack.creating_contract(&contract_address.with_native_space()),
143 tracer,
144 )
145 } else {
146 Ok(())
147 }
148}