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