revm_handler/
post_execution.rs1use crate::FrameResult;
2use context::journaled_state::account::JournaledAccountTr;
3use context_interface::{
4 cfg::GasParams,
5 journaled_state::JournalTr,
6 result::{ExecutionResult, HaltReason, HaltReasonTr, ResultGas},
7 Block, Cfg, ContextTr, Database, LocalContextTr, Transaction,
8};
9use interpreter::{Gas, InitialAndFloorGas, SuccessOrHalt};
10use primitives::{hardfork::SpecId, U256};
11
12pub fn build_result_gas(
14 _is_halt: bool,
15 gas: &Gas,
16 init_and_floor_gas: InitialAndFloorGas,
17) -> ResultGas {
18 let state_gas = gas
27 .state_gas_spent()
28 .saturating_add_unsigned(init_and_floor_gas.initial_state_gas)
29 .max(0) as u64;
30 let state_gas = state_gas.saturating_sub(init_and_floor_gas.state_refund);
31
32 ResultGas::default()
33 .with_total_gas_spent(
34 gas.limit()
35 .saturating_sub(gas.remaining())
36 .saturating_sub(gas.reservoir()),
37 )
38 .with_refunded(gas.refunded() as u64)
39 .with_floor_gas(init_and_floor_gas.floor_gas())
40 .with_state_gas_spent(state_gas)
41}
42
43pub const fn eip7623_check_gas_floor(gas: &mut Gas, init_and_floor_gas: InitialAndFloorGas) {
48 let gas_used_before_refund = gas.total_gas_spent().saturating_sub(gas.reservoir());
52 let gas_used_after_refund = gas_used_before_refund.saturating_sub(gas.refunded() as u64);
53 if gas_used_after_refund < init_and_floor_gas.floor_gas() {
54 gas.set_spent(init_and_floor_gas.floor_gas());
59 gas.set_reservoir(0);
60 gas.set_refund(0);
61 }
62}
63
64pub fn refund(gas_params: &GasParams, gas: &mut Gas, eip7702_refund: i64) {
66 gas.record_refund(eip7702_refund);
67 gas.set_final_refund(gas_params.max_refund_quotient());
68}
69
70#[inline]
72pub fn reimburse_caller<CTX: ContextTr>(
73 context: &mut CTX,
74 gas: &Gas,
75 additional_refund: U256,
76) -> Result<(), <CTX::Db as Database>::Error> {
77 if context.cfg().is_fee_charge_disabled() {
80 return Ok(());
81 }
82 let basefee = context.block().basefee() as u128;
83 let caller = context.tx().caller();
84 let effective_gas_price = context.tx().effective_gas_price(basefee);
85
86 let reimbursable = gas.remaining() + gas.reservoir() + gas.refunded() as u64;
89 context
90 .journal_mut()
91 .load_account_mut(caller)?
92 .incr_balance(
93 U256::from(effective_gas_price.saturating_mul(reimbursable as u128))
94 + additional_refund,
95 );
96
97 Ok(())
98}
99
100#[inline]
102pub fn reward_beneficiary<CTX: ContextTr>(
103 context: &mut CTX,
104 gas: &Gas,
105) -> Result<(), <CTX::Db as Database>::Error> {
106 if context.cfg().is_fee_charge_disabled() {
109 return Ok(());
110 }
111 let (block, tx, cfg, journal, _, _) = context.all_mut();
112 let basefee = block.basefee() as u128;
113 let effective_gas_price = tx.effective_gas_price(basefee);
114
115 let coinbase_gas_price = if cfg.spec().into().is_enabled_in(SpecId::LONDON) {
118 effective_gas_price.saturating_sub(basefee)
119 } else {
120 effective_gas_price
121 };
122
123 let effective_used = gas.used().saturating_sub(gas.reservoir());
126 journal
127 .load_account_mut(block.beneficiary())?
128 .incr_balance(U256::from(coinbase_gas_price * effective_used as u128));
129
130 Ok(())
131}
132
133pub fn output<CTX: ContextTr<Journal: JournalTr>, HALTREASON: HaltReasonTr>(
137 context: &mut CTX,
138 result: FrameResult,
141 result_gas: ResultGas,
142) -> ExecutionResult<HALTREASON> {
143 let output = result.output();
144 let instruction_result = result.into_interpreter_result();
145
146 let logs = context.journal_mut().take_logs();
148
149 match SuccessOrHalt::<HALTREASON>::from(instruction_result.result) {
150 SuccessOrHalt::Success(reason) => ExecutionResult::Success {
151 reason,
152 gas: result_gas,
153 logs,
154 output,
155 },
156 SuccessOrHalt::Revert => ExecutionResult::Revert {
157 gas: result_gas,
158 logs,
159 output: output.into_data(),
160 },
161 SuccessOrHalt::Halt(reason) => {
162 if matches!(
164 instruction_result.result,
165 interpreter::InstructionResult::PrecompileError
166 ) {
167 if let Some(message) = context.local_mut().take_precompile_error_context() {
168 return ExecutionResult::Halt {
169 reason: HALTREASON::from(HaltReason::PrecompileErrorWithContext(message)),
170 gas: result_gas,
171 logs,
172 };
173 }
174 }
175 ExecutionResult::Halt {
176 reason,
177 gas: result_gas,
178 logs,
179 }
180 }
181 flag @ (SuccessOrHalt::FatalExternalError | SuccessOrHalt::Internal(_)) => {
183 panic!(
184 "Encountered unexpected internal return flag: {flag:?} with instruction result: {instruction_result:?}"
185 )
186 }
187 }
188}