revm_handler/
post_execution.rs

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