revm_handler/execution.rs
1use context::{ContextTr, Database, JournalTr};
2use context_interface::{
3 journaled_state::{account::JournaledAccountTr, JournalCheckpoint, JournalLoadError},
4 Cfg, Transaction,
5};
6use interpreter::{
7 CallInput, CallInputs, CallScheme, CallValue, CreateInputs, CreateScheme, FrameInput,
8 GasTracker,
9};
10use primitives::TxKind;
11use state::Bytecode;
12use std::boxed::Box;
13
14/// Creates the first [`FrameInput`] from the transaction and the
15/// transaction-level `gas`, forwarding all remaining regular gas and the
16/// reservoir to the frame.
17///
18/// Under EIP-2780 this completes the runtime gas phase started at
19/// pre-execution (the authorization charges): the target is loaded once and
20/// its state-dependent charges are recorded on `gas`:
21///
22/// - A value transfer to a non-existent recipient grows the state by one
23/// account leaf and pays the new-account state gas. The charge stays
24/// deducted and only the decision travels on the frame inputs
25/// (`charged_new_account_state_gas`), so the handler refunds it at frame
26/// settle when no account leaf ends up created. Checked before the
27/// delegation resolution, matching the spec's `prepare_dispatch` order.
28/// - An EIP-7702 delegated recipient pays the delegation-target access
29/// following the standard EIP-2929 warm/cold model. The charge must be
30/// covered before the delegate is read, so an out-of-gas here leaves a cold
31/// delegate out of the EIP-7928 block access list.
32/// - A create transaction whose deployment target does not already exist pays
33/// the account-creation state gas (`charged_create_state_gas`), decided by
34/// the single read that also warms the target.
35///
36/// The recipient is evaluated after the authorizations were applied, so a
37/// recipient materialized or delegated by an authorization in this
38/// transaction is seen in its post-authorization state. A self-transfer
39/// recipient is the (non-empty) sender, so the new-account charge never fires
40/// for it, while a delegated sender still pays for resolving its delegation.
41///
42/// Returns `None` when the charges run out of gas: the transaction stays
43/// valid but must be included as an out-of-gas halt without entering
44/// execution ([`runtime_oog_unwind`]).
45#[inline]
46pub fn create_init_frame<CTX: ContextTr>(
47 ctx: &mut CTX,
48 gas: &mut GasTracker,
49) -> Result<Option<FrameInput>, <<CTX::Journal as JournalTr>::Database as Database>::Error> {
50 let is_eip2780 = ctx.cfg().is_amsterdam_eip2780_enabled();
51 let params = ctx.cfg().gas_params();
52 let new_account_state_gas = params.new_account_state_gas();
53 let create_state_gas = params.create_state_gas();
54 let warm_access_cost = params.warm_storage_read_cost();
55 let cold_account_additional_cost = params.cold_account_additional_cost();
56 let (tx, journal) = ctx.tx_journal_mut();
57 let input = tx.input().clone();
58
59 match tx.kind() {
60 TxKind::Call(target_address) => {
61 // Load the recipient once (its access was already charged at the
62 // cold rate at the intrinsic phase).
63 let account = &journal.load_account_with_code(target_address)?.info;
64 let recipient_is_empty = account.is_empty();
65 let delegated_address = account.code.as_ref().and_then(Bytecode::eip7702_address);
66 let mut known_bytecode = (
67 account.code_hash(),
68 account.code.clone().unwrap_or_default(),
69 );
70
71 let mut charged_new_account_state_gas = false;
72 if is_eip2780 && !tx.value().is_zero() && recipient_is_empty {
73 if !gas.record_state_cost(new_account_state_gas) {
74 return Ok(None);
75 }
76 charged_new_account_state_gas = true;
77 }
78
79 if let Some(delegated_address) = delegated_address {
80 if is_eip2780 {
81 // Charge the warm access upfront and the cold difference
82 // after the load. Charges made before an out-of-gas bail
83 // need no undo: the runtime out-of-gas path rebuilds the
84 // transaction-level gas.
85 if !gas.record_regular_cost(warm_access_cost) {
86 return Ok(None);
87 }
88 let skip_cold_load = gas.remaining() < cold_account_additional_cost;
89 let acc = match journal.load_account_info_skip_cold_load(
90 delegated_address,
91 true,
92 skip_cold_load,
93 ) {
94 Ok(acc) => acc,
95 Err(JournalLoadError::ColdLoadSkipped) => return Ok(None),
96 Err(JournalLoadError::DBError(e)) => return Err(e),
97 };
98
99 if acc.is_cold && !gas.record_regular_cost(cold_account_additional_cost) {
100 return Ok(None);
101 }
102 known_bytecode = (acc.code_hash(), acc.code.clone().unwrap_or_default());
103 } else {
104 let account = &journal.load_account_with_code(delegated_address)?.info;
105 known_bytecode = (
106 account.code_hash(),
107 account.code.clone().unwrap_or_default(),
108 );
109 }
110 }
111
112 Ok(Some(FrameInput::Call(Box::new(CallInputs {
113 input: CallInput::Bytes(input),
114 gas_limit: gas.remaining(),
115 target_address,
116 bytecode_address: target_address,
117 known_bytecode,
118 caller: tx.caller(),
119 value: CallValue::Transfer(tx.value()),
120 scheme: CallScheme::Call,
121 is_static: false,
122 return_memory_offset: 0..0,
123 reservoir: gas.reservoir(),
124 charged_new_account_state_gas,
125 }))))
126 }
127 TxKind::Create => {
128 let mut charged_create_state_gas = false;
129 if is_eip2780 {
130 // The tx nonce was validated against the caller's nonce, which
131 // a create transaction bumps only at frame creation — after
132 // this point.
133 let created_address = tx.caller().create(tx.nonce());
134 let target_is_empty = journal.load_account(created_address)?.info.is_empty();
135 if target_is_empty {
136 if !gas.record_state_cost(create_state_gas) {
137 return Ok(None);
138 }
139 charged_create_state_gas = true;
140 }
141 }
142 let mut inputs = CreateInputs::new(
143 tx.caller(),
144 CreateScheme::Create,
145 tx.value(),
146 input,
147 gas.remaining(),
148 gas.reservoir(),
149 );
150 inputs.set_charged_create_state_gas(charged_create_state_gas);
151 Ok(Some(FrameInput::Create(Box::new(inputs))))
152 }
153 }
154}
155
156/// Unwinds the EIP-2780 runtime gas phase after first-frame creation ran out
157/// of gas ([`create_init_frame`] returned `None`): reverts the phase's
158/// journal checkpoint — dropping all runtime state changes, including applied
159/// EIP-7702 delegations — and bumps the sender nonce of a create transaction,
160/// whose increment precedes message processing and survives the halt. (Calls
161/// bump it in `validate_against_state_and_deduct_caller`; creates at frame
162/// creation, which the runtime halt never reaches.)
163#[inline]
164pub fn runtime_oog_unwind<CTX: ContextTr>(
165 ctx: &mut CTX,
166 checkpoint: JournalCheckpoint,
167) -> Result<(), <<CTX::Journal as JournalTr>::Database as Database>::Error> {
168 let (tx, journal) = ctx.tx_journal_mut();
169 journal.checkpoint_revert(checkpoint);
170 if tx.kind().is_create() {
171 journal.load_account_mut(tx.caller())?.data.bump_nonce();
172 }
173 Ok(())
174}