revm_handler/
post_execution.rs

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