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