1use alloy_primitives::{keccak256, Address, B256, U256};
4use alloy_rpc_types_eth::{
5 state::{AccountOverride, StateOverride},
6 BlockOverrides,
7};
8use reth_evm::TransactionEnv;
9use revm::{
10 context::BlockEnv,
11 database::{CacheDB, State},
12 state::{Account, AccountStatus, Bytecode, EvmStorageSlot},
13 Database, DatabaseCommit,
14};
15use std::{
16 cmp::min,
17 collections::{BTreeMap, HashMap},
18};
19
20use super::{EthApiError, EthResult, RpcInvalidTransactionError};
21
22pub fn caller_gas_allowance<DB>(db: &mut DB, env: &impl TransactionEnv) -> EthResult<u64>
32where
33 DB: Database,
34 EthApiError: From<<DB as Database>::Error>,
35{
36 let caller = db.basic(env.caller())?;
38 let balance = caller.map(|acc| acc.balance).unwrap_or_default();
40 let value = env.value();
42 let balance = balance
45 .checked_sub(env.value())
46 .ok_or_else(|| RpcInvalidTransactionError::InsufficientFunds { cost: value, balance })?;
47
48 Ok(balance
49 .checked_div(U256::from(env.gas_price()))
51 .unwrap_or_default()
53 .saturating_to())
54}
55
56#[derive(Debug)]
58pub struct CallFees {
59 pub max_priority_fee_per_gas: Option<U256>,
61 pub gas_price: U256,
68 pub max_fee_per_blob_gas: Option<U256>,
70}
71
72impl CallFees {
75 pub fn ensure_fees(
94 call_gas_price: Option<U256>,
95 call_max_fee: Option<U256>,
96 call_priority_fee: Option<U256>,
97 block_base_fee: U256,
98 blob_versioned_hashes: Option<&[B256]>,
99 max_fee_per_blob_gas: Option<U256>,
100 block_blob_fee: Option<U256>,
101 ) -> EthResult<Self> {
102 fn get_effective_gas_price(
105 max_fee_per_gas: Option<U256>,
106 max_priority_fee_per_gas: Option<U256>,
107 block_base_fee: U256,
108 ) -> EthResult<U256> {
109 match max_fee_per_gas {
110 Some(max_fee) => {
111 let max_priority_fee_per_gas = max_priority_fee_per_gas.unwrap_or(U256::ZERO);
112
113 if !(max_fee.is_zero() && max_priority_fee_per_gas.is_zero()) &&
115 max_fee < block_base_fee
116 {
117 return Err(RpcInvalidTransactionError::FeeCapTooLow.into())
119 }
120 if max_fee < max_priority_fee_per_gas {
121 return Err(
122 RpcInvalidTransactionError::TipAboveFeeCap.into(),
124 )
125 }
126 Ok(min(
128 max_fee,
129 block_base_fee.checked_add(max_priority_fee_per_gas).ok_or_else(|| {
130 EthApiError::from(RpcInvalidTransactionError::TipVeryHigh)
131 })?,
132 ))
133 }
134 None => Ok(block_base_fee
135 .checked_add(max_priority_fee_per_gas.unwrap_or(U256::ZERO))
136 .ok_or(EthApiError::from(RpcInvalidTransactionError::TipVeryHigh))?),
137 }
138 }
139
140 let has_blob_hashes =
141 blob_versioned_hashes.as_ref().map(|blobs| !blobs.is_empty()).unwrap_or(false);
142
143 match (call_gas_price, call_max_fee, call_priority_fee, max_fee_per_blob_gas) {
144 (gas_price, None, None, None) => {
145 let gas_price = gas_price.unwrap_or(U256::ZERO);
148 Ok(Self {
149 gas_price,
150 max_priority_fee_per_gas: None,
151 max_fee_per_blob_gas: has_blob_hashes.then_some(block_blob_fee).flatten(),
152 })
153 }
154 (None, max_fee_per_gas, max_priority_fee_per_gas, None) => {
155 let effective_gas_price = get_effective_gas_price(
157 max_fee_per_gas,
158 max_priority_fee_per_gas,
159 block_base_fee,
160 )?;
161 let max_fee_per_blob_gas = has_blob_hashes.then_some(block_blob_fee).flatten();
162
163 Ok(Self {
164 gas_price: effective_gas_price,
165 max_priority_fee_per_gas,
166 max_fee_per_blob_gas,
167 })
168 }
169 (None, max_fee_per_gas, max_priority_fee_per_gas, Some(max_fee_per_blob_gas)) => {
170 let effective_gas_price = get_effective_gas_price(
172 max_fee_per_gas,
173 max_priority_fee_per_gas,
174 block_base_fee,
175 )?;
176 if !has_blob_hashes {
178 return Err(RpcInvalidTransactionError::BlobTransactionMissingBlobHashes.into())
180 }
181
182 Ok(Self {
183 gas_price: effective_gas_price,
184 max_priority_fee_per_gas,
185 max_fee_per_blob_gas: Some(max_fee_per_blob_gas),
186 })
187 }
188 _ => {
189 Err(EthApiError::ConflictingFeeFieldsInRequest)
191 }
192 }
193 }
194}
195
196pub trait OverrideBlockHashes {
200 fn override_block_hashes(&mut self, block_hashes: BTreeMap<u64, B256>);
202}
203
204impl<DB> OverrideBlockHashes for CacheDB<DB> {
205 fn override_block_hashes(&mut self, block_hashes: BTreeMap<u64, B256>) {
206 self.cache
207 .block_hashes
208 .extend(block_hashes.into_iter().map(|(num, hash)| (U256::from(num), hash)))
209 }
210}
211
212impl<DB> OverrideBlockHashes for State<DB> {
213 fn override_block_hashes(&mut self, block_hashes: BTreeMap<u64, B256>) {
214 self.block_hashes.extend(block_hashes);
215 }
216}
217
218pub fn apply_block_overrides(
220 overrides: BlockOverrides,
221 db: &mut impl OverrideBlockHashes,
222 env: &mut BlockEnv,
223) {
224 let BlockOverrides {
225 number,
226 difficulty,
227 time,
228 gas_limit,
229 coinbase,
230 random,
231 base_fee,
232 block_hash,
233 } = overrides;
234
235 if let Some(block_hashes) = block_hash {
236 db.override_block_hashes(block_hashes);
238 }
239
240 if let Some(number) = number {
241 env.number = number.saturating_to();
242 }
243 if let Some(difficulty) = difficulty {
244 env.difficulty = difficulty;
245 }
246 if let Some(time) = time {
247 env.timestamp = time;
248 }
249 if let Some(gas_limit) = gas_limit {
250 env.gas_limit = gas_limit;
251 }
252 if let Some(coinbase) = coinbase {
253 env.beneficiary = coinbase;
254 }
255 if let Some(random) = random {
256 env.prevrandao = Some(random);
257 }
258 if let Some(base_fee) = base_fee {
259 env.basefee = base_fee.saturating_to();
260 }
261}
262
263pub fn apply_state_overrides<DB>(overrides: StateOverride, db: &mut DB) -> EthResult<()>
265where
266 DB: Database + DatabaseCommit,
267 EthApiError: From<DB::Error>,
268{
269 for (account, account_overrides) in overrides {
270 apply_account_override(account, account_overrides, db)?;
271 }
272 Ok(())
273}
274
275fn apply_account_override<DB>(
277 account: Address,
278 account_override: AccountOverride,
279 db: &mut DB,
280) -> EthResult<()>
281where
282 DB: Database + DatabaseCommit,
283 EthApiError: From<DB::Error>,
284{
285 let mut info = db.basic(account)?.unwrap_or_default();
286
287 if let Some(nonce) = account_override.nonce {
288 info.nonce = nonce;
289 }
290 if let Some(code) = account_override.code {
291 info.code_hash = keccak256(&code);
293 info.code = Some(
294 Bytecode::new_raw_checked(code)
295 .map_err(|err| EthApiError::InvalidBytecode(err.to_string()))?,
296 );
297 }
298 if let Some(balance) = account_override.balance {
299 info.balance = balance;
300 }
301
302 let mut acc =
304 revm::state::Account { info, status: AccountStatus::Touched, storage: HashMap::default() };
305
306 let storage_diff = match (account_override.state, account_override.state_diff) {
307 (Some(_), Some(_)) => return Err(EthApiError::BothStateAndStateDiffInOverride(account)),
308 (None, None) => None,
309 (Some(state), None) => {
313 db.commit(HashMap::from_iter([(
315 account,
316 Account {
317 status: AccountStatus::SelfDestructed | AccountStatus::Touched,
318 ..Default::default()
319 },
320 )]));
321 acc.mark_created();
323 Some(state)
324 }
325 (None, Some(state)) => Some(state),
326 };
327
328 if let Some(state) = storage_diff {
329 for (slot, value) in state {
330 acc.storage.insert(
331 slot.into(),
332 EvmStorageSlot {
333 original_value: (!value).into(),
335 present_value: value.into(),
336 is_cold: false,
337 },
338 );
339 }
340 }
341
342 db.commit(HashMap::from_iter([(account, acc)]));
343
344 Ok(())
345}
346
347#[cfg(test)]
348mod tests {
349 use super::*;
350 use alloy_consensus::constants::GWEI_TO_WEI;
351 use alloy_primitives::{address, bytes};
352 use reth_revm::db::EmptyDB;
353
354 #[test]
355 fn test_ensure_0_fallback() {
356 let CallFees { gas_price, .. } =
357 CallFees::ensure_fees(None, None, None, U256::from(99), None, None, Some(U256::ZERO))
358 .unwrap();
359 assert!(gas_price.is_zero());
360 }
361
362 #[test]
363 fn test_ensure_max_fee_0_exception() {
364 let CallFees { gas_price, .. } =
365 CallFees::ensure_fees(None, Some(U256::ZERO), None, U256::from(99), None, None, None)
366 .unwrap();
367 assert!(gas_price.is_zero());
368 }
369
370 #[test]
371 fn test_blob_fees() {
372 let CallFees { gas_price, max_fee_per_blob_gas, .. } =
373 CallFees::ensure_fees(None, None, None, U256::from(99), None, None, Some(U256::ZERO))
374 .unwrap();
375 assert!(gas_price.is_zero());
376 assert_eq!(max_fee_per_blob_gas, None);
377
378 let CallFees { gas_price, max_fee_per_blob_gas, .. } = CallFees::ensure_fees(
379 None,
380 None,
381 None,
382 U256::from(99),
383 Some(&[B256::from(U256::ZERO)]),
384 None,
385 Some(U256::from(99)),
386 )
387 .unwrap();
388 assert!(gas_price.is_zero());
389 assert_eq!(max_fee_per_blob_gas, Some(U256::from(99)));
390 }
391
392 #[test]
393 fn test_eip_1559_fees() {
394 let CallFees { gas_price, .. } = CallFees::ensure_fees(
395 None,
396 Some(U256::from(25 * GWEI_TO_WEI)),
397 Some(U256::from(15 * GWEI_TO_WEI)),
398 U256::from(15 * GWEI_TO_WEI),
399 None,
400 None,
401 Some(U256::ZERO),
402 )
403 .unwrap();
404 assert_eq!(gas_price, U256::from(25 * GWEI_TO_WEI));
405
406 let CallFees { gas_price, .. } = CallFees::ensure_fees(
407 None,
408 Some(U256::from(25 * GWEI_TO_WEI)),
409 Some(U256::from(5 * GWEI_TO_WEI)),
410 U256::from(15 * GWEI_TO_WEI),
411 None,
412 None,
413 Some(U256::ZERO),
414 )
415 .unwrap();
416 assert_eq!(gas_price, U256::from(20 * GWEI_TO_WEI));
417
418 let CallFees { gas_price, .. } = CallFees::ensure_fees(
419 None,
420 Some(U256::from(30 * GWEI_TO_WEI)),
421 Some(U256::from(30 * GWEI_TO_WEI)),
422 U256::from(15 * GWEI_TO_WEI),
423 None,
424 None,
425 Some(U256::ZERO),
426 )
427 .unwrap();
428 assert_eq!(gas_price, U256::from(30 * GWEI_TO_WEI));
429
430 let call_fees = CallFees::ensure_fees(
431 None,
432 Some(U256::from(30 * GWEI_TO_WEI)),
433 Some(U256::from(31 * GWEI_TO_WEI)),
434 U256::from(15 * GWEI_TO_WEI),
435 None,
436 None,
437 Some(U256::ZERO),
438 );
439 assert!(call_fees.is_err());
440
441 let call_fees = CallFees::ensure_fees(
442 None,
443 Some(U256::from(5 * GWEI_TO_WEI)),
444 Some(U256::from(GWEI_TO_WEI)),
445 U256::from(15 * GWEI_TO_WEI),
446 None,
447 None,
448 Some(U256::ZERO),
449 );
450 assert!(call_fees.is_err());
451
452 let call_fees = CallFees::ensure_fees(
453 None,
454 Some(U256::MAX),
455 Some(U256::MAX),
456 U256::from(5 * GWEI_TO_WEI),
457 None,
458 None,
459 Some(U256::ZERO),
460 );
461 assert!(call_fees.is_err());
462 }
463
464 #[test]
465 fn state_override_state() {
466 let code = bytes!(
467 "0x63d0e30db05f525f5f6004601c3473c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25af15f5260205ff3"
468 );
469 let to = address!("0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599");
470
471 let mut db = State::builder().with_database(CacheDB::new(EmptyDB::new())).build();
472
473 let acc_override = AccountOverride::default().with_code(code.clone());
474 apply_account_override(to, acc_override, &mut db).unwrap();
475
476 let account = db.basic(to).unwrap().unwrap();
477 assert!(account.code.is_some());
478 assert_eq!(account.code_hash, keccak256(&code));
479 }
480
481 #[test]
482 fn state_override_cache_db() {
483 let code = bytes!(
484 "0x63d0e30db05f525f5f6004601c3473c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25af15f5260205ff3"
485 );
486 let to = address!("0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599");
487
488 let mut db = CacheDB::new(EmptyDB::new());
489
490 let acc_override = AccountOverride::default().with_code(code.clone());
491 apply_account_override(to, acc_override, &mut db).unwrap();
492
493 let account = db.basic(to).unwrap().unwrap();
494 assert!(account.code.is_some());
495 assert_eq!(account.code_hash, keccak256(&code));
496 }
497}