revm_handler/
post_execution.rs

1use super::frame_data::FrameResult;
2use context::JournalOutput;
3use context_interface::ContextTr;
4use context_interface::{
5    journaled_state::JournalTr,
6    result::{ExecutionResult, HaltReasonTr, ResultAndState},
7    Block, Cfg, Database, Transaction,
8};
9use interpreter::{Gas, InitialAndFloorGas, SuccessOrHalt};
10use primitives::{hardfork::SpecId, U256};
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
30pub fn reimburse_caller<CTX: ContextTr>(
31    context: &mut CTX,
32    gas: &mut Gas,
33) -> Result<(), <CTX::Db as Database>::Error> {
34    let basefee = context.block().basefee() as u128;
35    let caller = context.tx().caller();
36    let effective_gas_price = context.tx().effective_gas_price(basefee);
37
38    // Return balance of not spend gas.
39    let caller_account = context.journal().load_account(caller)?;
40
41    let reimbursed =
42        effective_gas_price.saturating_mul((gas.remaining() + gas.refunded() as u64) as u128);
43    caller_account.data.info.balance = caller_account
44        .data
45        .info
46        .balance
47        .saturating_add(U256::from(reimbursed));
48
49    Ok(())
50}
51
52pub fn reward_beneficiary<CTX: ContextTr>(
53    context: &mut CTX,
54    gas: &mut Gas,
55) -> Result<(), <CTX::Db as Database>::Error> {
56    let block = context.block();
57    let tx = context.tx();
58    let beneficiary = block.beneficiary();
59    let basefee = block.basefee() as u128;
60    let effective_gas_price = 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    let coinbase_account = context.journal().load_account(beneficiary)?;
71
72    coinbase_account.data.mark_touch();
73    coinbase_account.data.info.balance =
74        coinbase_account
75            .data
76            .info
77            .balance
78            .saturating_add(U256::from(
79                coinbase_gas_price * (gas.spent() - gas.refunded() as u64) as u128,
80            ));
81
82    Ok(())
83}
84
85/// Calculate last gas spent and transform internal reason to external.
86///
87/// TODO make Journal FinalOutput more generic.
88pub fn output<
89    CTX: ContextTr<Journal: JournalTr<FinalOutput = JournalOutput>>,
90    HALTREASON: HaltReasonTr,
91>(
92    context: &mut CTX,
93    // TODO, make this more generic and nice.
94    // FrameResult should be a generic that returns gas and interpreter result.
95    result: FrameResult,
96) -> ResultAndState<HALTREASON> {
97    // Used gas with refund calculated.
98    let gas_refunded = result.gas().refunded() as u64;
99    let final_gas_used = result.gas().spent() - gas_refunded;
100    let output = result.output();
101    let instruction_result = result.into_interpreter_result();
102
103    // Reset journal and return present state.
104    let JournalOutput { state, logs } = context.journal().finalize();
105
106    let result = match SuccessOrHalt::<HALTREASON>::from(instruction_result.result) {
107        SuccessOrHalt::Success(reason) => ExecutionResult::Success {
108            reason,
109            gas_used: final_gas_used,
110            gas_refunded,
111            logs,
112            output,
113        },
114        SuccessOrHalt::Revert => ExecutionResult::Revert {
115            gas_used: final_gas_used,
116            output: output.into_data(),
117        },
118        SuccessOrHalt::Halt(reason) => ExecutionResult::Halt {
119            reason,
120            gas_used: final_gas_used,
121        },
122        // Only two internal return flags.
123        flag @ (SuccessOrHalt::FatalExternalError | SuccessOrHalt::Internal(_)) => {
124            panic!(
125                "Encountered unexpected internal return flag: {:?} with instruction result: {:?}",
126                flag, instruction_result
127            )
128        }
129    };
130
131    ResultAndState { result, state }
132}