use super::{checked_insert_code, execute_system_tx};
use crate::{helpers::Ctx, system::SystemTx, EvmNeedsTx};
use alloy::{
eips::eip7251::CONSOLIDATION_REQUEST_PREDEPLOY_CODE,
primitives::{Address, Bytes},
};
use revm::{
context::result::EVMError, primitives::hardfork::SpecId, Database, DatabaseCommit, Inspector,
};
pub use alloy::eips::eip7251::CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS;
pub const CONSOLIDATION_REQUEST_BYTES: usize = 20 + 48 + 48;
impl SystemTx {
pub const fn eip7251() -> Self {
Self::eip7251_with_target(CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS)
}
pub const fn eip7251_with_target(target: Address) -> Self {
Self::new(target, Bytes::new())
}
pub const fn eip7251_with_target_and_caller(target: Address, caller: Address) -> Self {
Self::new_with_caller(target, Bytes::new(), caller)
}
}
impl<Db, Insp> EvmNeedsTx<Db, Insp>
where
Db: Database + DatabaseCommit,
Insp: Inspector<Ctx<Db>>,
{
pub fn apply_eip7251(&mut self) -> Result<Bytes, EVMError<Db::Error>> {
if self.spec_id() < SpecId::PRAGUE {
return Ok(Bytes::new());
}
checked_insert_code(
self.inner_mut_unchecked(),
CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS,
&CONSOLIDATION_REQUEST_PREDEPLOY_CODE,
)?;
let res = execute_system_tx(self.inner_mut_unchecked(), &SystemTx::eip7251())?;
let Some(output) = res.output() else {
panic!("execution halted during consolidation request system contract execution")
};
Ok(output.clone())
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::{NoopBlock, NoopCfg, Tx};
use alloy::{
consensus::constants::ETH_TO_WEI,
primitives::{fixed_bytes, FixedBytes, TxKind, U256},
};
use revm::context::TxEnv;
const WITHDRAWAL_ADDR: Address = Address::with_last_byte(0x42);
const VALIDATOR_PUBKEY: FixedBytes<48> = fixed_bytes!("111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
const TARGET_VALIDATOR_PUBKEY: FixedBytes<48> = fixed_bytes!("111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
struct ConsolidationTx;
impl Tx for ConsolidationTx {
fn fill_tx_env(&self, tx_env: &mut TxEnv) {
let input: Bytes =
[&VALIDATOR_PUBKEY[..], &TARGET_VALIDATOR_PUBKEY[..]].concat().into();
tx_env.caller = WITHDRAWAL_ADDR;
tx_env.data = input;
tx_env.kind = TxKind::Call(CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS);
tx_env.value = U256::from(1);
}
}
#[test]
fn test_eip7251() {
let mut trevm = crate::test_utils::test_trevm().fill_cfg(&NoopCfg).fill_block(&NoopBlock);
trevm.apply_eip7251().unwrap();
trevm.test_increase_balance(WITHDRAWAL_ADDR, U256::from(100 * ETH_TO_WEI));
let mut trevm = trevm.run_tx(&ConsolidationTx).unwrap().accept_state();
let requests = trevm.apply_eip7251().unwrap();
assert_eq!(&requests[..20], WITHDRAWAL_ADDR.as_slice());
assert_eq!(&requests[20..68], VALIDATOR_PUBKEY.as_slice());
assert_eq!(&requests[68..], TARGET_VALIDATOR_PUBKEY.as_slice());
}
}