cfx_executor/executive/
mod.rs1pub mod executed;
5pub mod execution_outcome;
6mod fresh_executive;
7mod pre_checked_executive;
8#[cfg(test)]
9mod tests;
10pub mod transact_options;
11
12use cfx_rpc_eth_types::BlockOverrides;
13use cfx_statedb::Result as DbResult;
14use cfx_types::{
15 address_util::AddressUtil, AddressSpaceUtil, AddressWithSpace, Space,
16 SpaceMap, H256, U256,
17};
18use cfx_vm_types::{ConsensusGasSpec, CreateContractAddress, Env, Spec};
19use primitives::{AccessList, SignedTransaction};
20
21use fresh_executive::FreshExecutive;
22use pre_checked_executive::PreCheckedExecutive;
23
24pub use executed::Executed;
25pub use execution_outcome::{
26 ExecutionError, ExecutionOutcome, ToRepackError, TxDropError,
27};
28pub use transact_options::{
29 ChargeCollateral, TransactOptions, TransactSettings,
30};
31
32use crate::{
33 executive_observer::ExecutiveObserver, machine::Machine, state::State,
34};
35
36pub struct ExecutiveContext<'a> {
38 state: &'a mut State,
39 env: &'a Env,
40 machine: &'a Machine,
41 spec: &'a Spec,
42}
43
44impl<'a> ExecutiveContext<'a> {
45 pub fn new(
46 state: &'a mut State, env: &'a Env, machine: &'a Machine,
47 spec: &'a Spec,
48 ) -> Self {
49 ExecutiveContext {
50 state,
51 env,
52 machine,
53 spec,
54 }
55 }
56
57 #[inline(never)]
58 pub fn transact<O: ExecutiveObserver>(
59 self, tx: &SignedTransaction, options: TransactOptions<O>,
60 ) -> DbResult<ExecutionOutcome> {
61 assert!(self.state.cache.get_mut().is_empty());
63
64 let fresh_exec = FreshExecutive::new(self, tx, options);
65
66 Ok(match fresh_exec.check_all()? {
67 Ok(executive) => executive.execute_transaction()?,
68 Err(execution_outcome) => execution_outcome,
69 })
70 }
71
72 pub fn apply_env_overrides(
73 env: &mut Env, block_override: Box<BlockOverrides>,
74 ) {
75 if let Some(number) = block_override.number {
76 env.number = number.as_u64();
77 }
78 if let Some(difficulty) = block_override.difficulty {
79 env.difficulty = difficulty;
80 }
81 if let Some(timestamp) = block_override.time {
82 env.timestamp = timestamp;
83 }
84 if let Some(gas_limit) = block_override.gas_limit {
85 env.gas_limit = U256::from(gas_limit);
86 }
87 if let Some(author) = block_override.coinbase {
88 env.author = author;
89 }
90 if let Some(_random) = block_override.random {
91 }
93 if let Some(base_fee) = block_override.base_fee {
94 env.base_gas_price = SpaceMap::new(base_fee, base_fee); }
96
97 if let Some(_block_hash) = &block_override.block_hash {
98 }
100 }
101}
102
103#[inline]
104pub fn gas_required_for(
105 is_create: bool, data: &[u8], access_list: Option<&AccessList>,
106 authorization_len: usize, spec: &ConsensusGasSpec,
107) -> u64 {
108 let init_gas = (if is_create {
109 spec.tx_create_gas
110 } else {
111 spec.tx_gas
112 }) as u64;
113
114 let byte_gas = |b: &u8| {
115 (match *b {
116 0 => spec.tx_data_zero_gas,
117 _ => spec.tx_data_non_zero_gas,
118 }) as u64
119 };
120 let data_gas: u64 = data.iter().map(byte_gas).sum();
121 let data_word = (data.len() as u64 + 31) / 32;
122
123 let initcode_gas = if spec.cip645.eip3860 && is_create {
125 data_word * spec.init_code_word_gas as u64
126 } else {
127 0
128 };
129
130 let access_gas: u64 = if let Some(acc) = access_list {
131 let address_gas =
132 acc.len() as u64 * spec.access_list_address_gas as u64;
133
134 let storage_key_num =
135 acc.iter().map(|e| e.storage_keys.len() as u64).sum::<u64>();
136 let storage_key_gas =
137 storage_key_num * spec.access_list_storage_key_gas as u64;
138
139 address_gas + storage_key_gas
140 } else {
141 0
142 };
143
144 let authorization_gas = spec.per_empty_account_cost as u64
145 * spec.evm_gas_ratio as u64
146 * authorization_len as u64;
147
148 init_gas + data_gas + access_gas + authorization_gas + initcode_gas
149}
150
151pub fn eip7623_required_gas(data: &[u8], spec: &ConsensusGasSpec) -> u64 {
152 if !spec.eip7623 {
153 return 0;
154 }
155
156 let byte_floor_gas = |b: &u8| {
157 (match *b {
158 0 => spec.tx_data_floor_zero_gas,
159 _ => spec.tx_data_floor_non_zero_gas,
160 }) as u64
161 };
162
163 spec.tx_gas as u64 + data.iter().map(byte_floor_gas).sum::<u64>()
164}
165
166pub fn contract_address(
167 address_scheme: CreateContractAddress, block_number: u64,
168 sender: &AddressWithSpace, nonce: &U256, code: &[u8],
169) -> (AddressWithSpace, H256) {
170 let (mut address, code_hash) = cfx_vm_types::contract_address(
171 address_scheme,
172 block_number,
173 &sender.address,
174 nonce,
175 code,
176 );
177 if sender.space == Space::Native {
178 address.set_contract_type_bits();
179 }
180 (address.with_space(sender.space), code_hash)
181}
182
183#[cfg(test)]
184pub mod test_util {
185 use crate::{
186 executive_observer::TracerTrait, stack::accrue_substate,
187 substate::Substate,
188 };
189 use cfx_statedb::Result as DbResult;
190 use cfx_vm_interpreter::FinalizationResult;
191 use cfx_vm_types::{self as vm, ActionParams};
192
193 use super::{pre_checked_executive::exec_vm, ExecutiveContext};
194
195 impl<'a> ExecutiveContext<'a> {
196 pub fn call_for_test(
197 &mut self, params: ActionParams, substate: &mut Substate,
198 tracer: &mut dyn TracerTrait,
199 ) -> DbResult<vm::Result<FinalizationResult>> {
200 let mut frame_result = exec_vm(self, params, tracer)?;
201 accrue_substate(substate, &mut frame_result);
202
203 Ok(frame_result.map(Into::into))
204 }
205 }
206}