revm_handler/
post_execution.rs

1use super::frame_data::FrameResult;
2use context_interface::ContextTr;
3use context_interface::{
4    journaled_state::JournalTr,
5    result::{ExecutionResult, HaltReasonTr},
6    Block, Cfg, Database, Transaction,
7};
8use interpreter::{Gas, InitialAndFloorGas, SuccessOrHalt};
9use primitives::{hardfork::SpecId, U256};
10use state::EvmState;
11
12pub fn eip7623_check_gas_floor(gas: &mut Gas, init_and_floor_gas: InitialAndFloorGas) {
13    // EIP-7623: Increase calldata cost
14    // spend at least a gas_floor amount of gas.
15    if gas.spent_sub_refunded() < init_and_floor_gas.floor_gas {
16        gas.set_spent(init_and_floor_gas.floor_gas);
17        // clear refund
18        gas.set_refund(0);
19    }
20}
21
22pub fn refund(spec: SpecId, gas: &mut Gas, eip7702_refund: i64) {
23    gas.record_refund(eip7702_refund);
24    // Calculate gas refund for transaction.
25    // If spec is set to london, it will decrease the maximum refund amount to 5th part of
26    // gas spend. (Before london it was 2th part of gas spend)
27    gas.set_final_refund(spec.is_enabled_in(SpecId::LONDON));
28}
29
30#[inline]
31pub fn reimburse_caller<CTX: ContextTr>(
32    context: &mut CTX,
33    gas: &mut Gas,
34    additional_refund: U256,
35) -> Result<(), <CTX::Db as Database>::Error> {
36    let basefee = context.block().basefee() as u128;
37    let caller = context.tx().caller();
38    let effective_gas_price = context.tx().effective_gas_price(basefee);
39
40    // Return balance of not spend gas.
41    context.journal_mut().balance_incr(
42        caller,
43        U256::from(
44            effective_gas_price.saturating_mul((gas.remaining() + gas.refunded() as u64) as u128),
45        ) + additional_refund,
46    )?;
47
48    Ok(())
49}
50
51#[inline]
52pub fn reward_beneficiary<CTX: ContextTr>(
53    context: &mut CTX,
54    gas: &mut Gas,
55) -> Result<(), <CTX::Db as Database>::Error> {
56    let beneficiary = context.block().beneficiary();
57    let basefee = context.block().basefee() as u128;
58    let effective_gas_price = context.tx().effective_gas_price(basefee);
59
60    // Transfer fee to coinbase/beneficiary.
61    // EIP-1559 discard basefee for coinbase transfer. Basefee amount of gas is discarded.
62    let coinbase_gas_price = if context.cfg().spec().into().is_enabled_in(SpecId::LONDON) {
63        effective_gas_price.saturating_sub(basefee)
64    } else {
65        effective_gas_price
66    };
67
68    // reward beneficiary
69    context.journal_mut().balance_incr(
70        beneficiary,
71        U256::from(coinbase_gas_price * (gas.spent() - gas.refunded() as u64) as u128),
72    )?;
73
74    Ok(())
75}
76
77/// Calculate last gas spent and transform internal reason to external.
78///
79/// TODO make Journal FinalOutput more generic.
80pub fn output<CTX: ContextTr<Journal: JournalTr<State = EvmState>>, HALTREASON: HaltReasonTr>(
81    context: &mut CTX,
82    // TODO, make this more generic and nice.
83    // FrameResult should be a generic that returns gas and interpreter result.
84    result: FrameResult,
85) -> ExecutionResult<HALTREASON> {
86    // Used gas with refund calculated.
87    let gas_refunded = result.gas().refunded() as u64;
88    let final_gas_used = result.gas().spent() - gas_refunded;
89    let output = result.output();
90    let instruction_result = result.into_interpreter_result();
91
92    // take logs from journal.
93    let logs = context.journal_mut().take_logs();
94
95    match SuccessOrHalt::<HALTREASON>::from(instruction_result.result) {
96        SuccessOrHalt::Success(reason) => ExecutionResult::Success {
97            reason,
98            gas_used: final_gas_used,
99            gas_refunded,
100            logs,
101            output,
102        },
103        SuccessOrHalt::Revert => ExecutionResult::Revert {
104            gas_used: final_gas_used,
105            output: output.into_data(),
106        },
107        SuccessOrHalt::Halt(reason) => ExecutionResult::Halt {
108            reason,
109            gas_used: final_gas_used,
110        },
111        // Only two internal return flags.
112        flag @ (SuccessOrHalt::FatalExternalError | SuccessOrHalt::Internal(_)) => {
113            panic!(
114                "Encountered unexpected internal return flag: {:?} with instruction result: {:?}",
115                flag, instruction_result
116            )
117        }
118    }
119}