trevm/system/
eip4895.rs

1use crate::{helpers::Ctx, EvmExtUnchecked, EvmNeedsTx};
2use alloy::{
3    eips::eip4895::Withdrawal,
4    primitives::{map::HashMap, U256},
5};
6use revm::{context::result::EVMError, Database, DatabaseCommit, Inspector};
7
8impl<Db, Insp> EvmNeedsTx<Db, Insp>
9where
10    Db: Database + DatabaseCommit,
11    Insp: Inspector<Ctx<Db>>,
12{
13    /// Apply the withdrawals to the EVM state.
14    pub fn apply_withdrawals<'b>(
15        &mut self,
16        withdrawals: impl IntoIterator<Item = &'b Withdrawal>,
17    ) -> Result<(), EVMError<Db::Error>> {
18        // We need to apply the withdrawals by incrementing the balances of the
19        // respective accounts, then committing the changes to the database.
20        let mut changes = HashMap::default();
21
22        let increments = withdrawals
23            .into_iter()
24            .map(|withdrawal| (withdrawal.address, withdrawal.amount as u128))
25            .filter(|(_, amount)| *amount != 0);
26
27        for (address, amount) in increments {
28            let mut acct =
29                self.inner_mut_unchecked().account(address).map_err(EVMError::Database)?;
30            acct.info.balance = acct.info.balance.saturating_add(U256::from(amount));
31            acct.mark_touch();
32            changes.insert(address, acct);
33        }
34
35        self.commit_unchecked(changes);
36        Ok(())
37    }
38}
39
40#[cfg(test)]
41mod test {
42    use alloy::{
43        eips::eip4895::{Withdrawal, GWEI_TO_WEI},
44        primitives::{Address, U256},
45    };
46
47    use crate::{NoopBlock, NoopCfg};
48
49    const USER: Address = Address::with_last_byte(0x42);
50
51    const WITHDRAWALS: &[Withdrawal] =
52        &[Withdrawal { validator_index: 1, index: 1, address: USER, amount: 100 * GWEI_TO_WEI }];
53
54    #[test]
55    fn test_eip4895() {
56        let mut trevm = crate::test_utils::test_trevm().fill_cfg(&NoopCfg).fill_block(&NoopBlock);
57
58        assert_eq!(trevm.try_read_balance(USER).unwrap(), U256::ZERO);
59
60        trevm.apply_withdrawals(WITHDRAWALS).unwrap();
61
62        assert_eq!(trevm.try_read_balance(USER).unwrap(), U256::from(100 * GWEI_TO_WEI));
63    }
64}