revm/handler/mainnet/
post_execution.rs

1use crate::{
2    interpreter::{Gas, SuccessOrHalt},
3    primitives::{
4        db::Database, EVMError, ExecutionResult, ResultAndState, Spec, SpecId, SpecId::LONDON, U256,
5    },
6    Context, FrameResult,
7};
8
9/// Mainnet end handle does not change the output.
10#[inline]
11pub fn end<EXT, DB: Database>(
12    _context: &mut Context<EXT, DB>,
13    evm_output: Result<ResultAndState, EVMError<DB::Error>>,
14) -> Result<ResultAndState, EVMError<DB::Error>> {
15    evm_output
16}
17
18/// Clear handle clears error and journal state.
19#[inline]
20pub fn clear<EXT, DB: Database>(context: &mut Context<EXT, DB>) {
21    // clear error and journaled state.
22    let _ = context.evm.take_error();
23    context.evm.inner.journaled_state.clear();
24}
25
26/// Reward beneficiary with gas fee.
27#[inline]
28pub fn reward_beneficiary<SPEC: Spec, EXT, DB: Database>(
29    context: &mut Context<EXT, DB>,
30    gas: &Gas,
31) -> Result<(), EVMError<DB::Error>> {
32    let beneficiary = context.evm.env.block.coinbase;
33    let effective_gas_price = context.evm.env.effective_gas_price();
34
35    // transfer fee to coinbase/beneficiary.
36    // EIP-1559 discard basefee for coinbase transfer. Basefee amount of gas is discarded.
37    let coinbase_gas_price = if SPEC::enabled(LONDON) {
38        effective_gas_price.saturating_sub(context.evm.env.block.basefee)
39    } else {
40        effective_gas_price
41    };
42
43    let coinbase_account = context
44        .evm
45        .inner
46        .journaled_state
47        .load_account(beneficiary, &mut context.evm.inner.db)?;
48
49    coinbase_account.data.mark_touch();
50    coinbase_account.data.info.balance = coinbase_account
51        .data
52        .info
53        .balance
54        .saturating_add(coinbase_gas_price * U256::from(gas.spent() - gas.refunded() as u64));
55
56    Ok(())
57}
58
59pub fn refund<SPEC: Spec, EXT, DB: Database>(
60    _context: &mut Context<EXT, DB>,
61    gas: &mut Gas,
62    eip7702_refund: i64,
63) {
64    gas.record_refund(eip7702_refund);
65
66    // Calculate gas refund for transaction.
67    // If spec is set to london, it will decrease the maximum refund amount to 5th part of
68    // gas spend. (Before london it was 2th part of gas spend)
69    gas.set_final_refund(SPEC::SPEC_ID.is_enabled_in(SpecId::LONDON));
70}
71
72#[inline]
73pub fn reimburse_caller<SPEC: Spec, EXT, DB: Database>(
74    context: &mut Context<EXT, DB>,
75    gas: &Gas,
76) -> Result<(), EVMError<DB::Error>> {
77    let caller = context.evm.env.tx.caller;
78    let effective_gas_price = context.evm.env.effective_gas_price();
79
80    // return balance of not spend gas.
81    let caller_account = context
82        .evm
83        .inner
84        .journaled_state
85        .load_account(caller, &mut context.evm.inner.db)?;
86
87    caller_account.data.info.balance =
88        caller_account.data.info.balance.saturating_add(
89            effective_gas_price * U256::from(gas.remaining() + gas.refunded() as u64),
90        );
91
92    Ok(())
93}
94
95/// Main return handle, returns the output of the transaction.
96#[inline]
97pub fn output<EXT, DB: Database>(
98    context: &mut Context<EXT, DB>,
99    result: FrameResult,
100) -> Result<ResultAndState, EVMError<DB::Error>> {
101    context.evm.take_error()?;
102    // used gas with refund calculated.
103    let gas_refunded = result.gas().refunded() as u64;
104    let final_gas_used = result.gas().spent() - gas_refunded;
105    let output = result.output();
106    let instruction_result = result.into_interpreter_result();
107
108    // reset journal and return present state.
109    let (state, logs) = context.evm.journaled_state.finalize();
110
111    let result = match instruction_result.result.into() {
112        SuccessOrHalt::Success(reason) => ExecutionResult::Success {
113            reason,
114            gas_used: final_gas_used,
115            gas_refunded,
116            logs,
117            output,
118        },
119        SuccessOrHalt::Revert => ExecutionResult::Revert {
120            gas_used: final_gas_used,
121            output: output.into_data(),
122        },
123        SuccessOrHalt::Halt(reason) => ExecutionResult::Halt {
124            reason,
125            gas_used: final_gas_used,
126        },
127        // Only two internal return flags.
128        flag @ (SuccessOrHalt::FatalExternalError | SuccessOrHalt::Internal(_)) => {
129            panic!(
130                "Encountered unexpected internal return flag: {:?} with instruction result: {:?}",
131                flag, instruction_result
132            )
133        }
134    };
135
136    Ok(ResultAndState { result, state })
137}