use crate::RollupConfig;
use alloy_consensus::{Eip658Value, Receipt};
use alloy_primitives::{address, b256, Address, Log, B256, B64, U256, U64};
use alloy_sol_types::{sol, SolType};
pub const CONFIG_UPDATE_TOPIC: B256 =
b256!("1d2b0bda21d56b8bd12d4f94ebacffdfb35f5e226f84b461103bb8beab6353be");
pub const CONFIG_UPDATE_EVENT_VERSION_0: B256 = B256::ZERO;
#[derive(Debug, Copy, Clone, Default, Hash, Eq, PartialEq)]
#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
pub struct SystemConfig {
#[cfg_attr(feature = "serde", serde(rename = "batcherAddr"))]
pub batcher_address: Address,
pub overhead: U256,
pub scalar: U256,
pub gas_limit: u64,
pub base_fee_scalar: Option<u64>,
pub blob_base_fee_scalar: Option<u64>,
pub eip1559_denominator: Option<u32>,
pub eip1559_elasticity: Option<u32>,
}
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
#[repr(u64)]
pub enum SystemConfigUpdateType {
Batcher = 0,
GasConfig = 1,
GasLimit = 2,
UnsafeBlockSigner = 3,
Eip1559 = 4,
}
impl TryFrom<u64> for SystemConfigUpdateType {
type Error = SystemConfigUpdateError;
fn try_from(value: u64) -> Result<Self, Self::Error> {
match value {
0 => Ok(Self::Batcher),
1 => Ok(Self::GasConfig),
2 => Ok(Self::GasLimit),
3 => Ok(Self::UnsafeBlockSigner),
4 => Ok(Self::Eip1559),
_ => Err(SystemConfigUpdateError::LogProcessing(
LogProcessingError::InvalidSystemConfigUpdateType(value),
)),
}
}
}
impl SystemConfig {
pub fn update_with_receipts(
&mut self,
receipts: &[Receipt],
l1_system_config_address: Address,
ecotone_active: bool,
) -> Result<(), SystemConfigUpdateError> {
for receipt in receipts {
if Eip658Value::Eip658(false) == receipt.status {
continue;
}
receipt.logs.iter().try_for_each(|log| {
let topics = log.topics();
if log.address == l1_system_config_address
&& !topics.is_empty()
&& topics[0] == CONFIG_UPDATE_TOPIC
{
self.process_config_update_log(log, ecotone_active)?;
}
Ok(())
})?;
}
Ok(())
}
pub fn eip_1559_params(
&self,
rollup_config: &RollupConfig,
parent_timestamp: u64,
next_timestamp: u64,
) -> Option<B64> {
let is_holocene = rollup_config.is_holocene_active(next_timestamp);
if is_holocene && !rollup_config.is_holocene_active(parent_timestamp) {
Some(B64::ZERO)
} else {
is_holocene.then_some(B64::from_slice(
&[
self.eip1559_denominator.unwrap_or_default().to_be_bytes(),
self.eip1559_elasticity.unwrap_or_default().to_be_bytes(),
]
.concat(),
))
}
}
fn process_config_update_log(
&mut self,
log: &Log,
ecotone_active: bool,
) -> Result<SystemConfigUpdateType, SystemConfigUpdateError> {
if log.topics().len() < 3 {
return Err(SystemConfigUpdateError::LogProcessing(
LogProcessingError::InvalidTopicLen(log.topics().len()),
));
}
if log.topics()[0] != CONFIG_UPDATE_TOPIC {
return Err(SystemConfigUpdateError::LogProcessing(LogProcessingError::InvalidTopic));
}
let version = log.topics()[1];
if version != CONFIG_UPDATE_EVENT_VERSION_0 {
return Err(SystemConfigUpdateError::LogProcessing(
LogProcessingError::UnsupportedVersion(version),
));
}
let Ok(topic_bytes) = <&[u8; 8]>::try_from(&log.topics()[2].as_slice()[24..]) else {
return Err(SystemConfigUpdateError::LogProcessing(
LogProcessingError::UpdateTypeDecodingError,
));
};
let update_type = u64::from_be_bytes(*topic_bytes);
let log_data = log.data.data.as_ref();
match update_type.try_into()? {
SystemConfigUpdateType::Batcher => {
self.update_batcher_address(log_data).map_err(SystemConfigUpdateError::Batcher)
}
SystemConfigUpdateType::GasConfig => self
.update_gas_config(log_data, ecotone_active)
.map_err(SystemConfigUpdateError::GasConfig),
SystemConfigUpdateType::GasLimit => {
self.update_gas_limit(log_data).map_err(SystemConfigUpdateError::GasLimit)
}
SystemConfigUpdateType::Eip1559 => {
self.update_eip1559_params(log_data).map_err(SystemConfigUpdateError::Eip1559)
}
SystemConfigUpdateType::UnsafeBlockSigner => {
Ok(SystemConfigUpdateType::UnsafeBlockSigner)
}
}
}
fn update_batcher_address(
&mut self,
log_data: &[u8],
) -> Result<SystemConfigUpdateType, BatcherUpdateError> {
if log_data.len() != 96 {
return Err(BatcherUpdateError::InvalidDataLen(log_data.len()));
}
let Ok(pointer) = <sol!(uint64)>::abi_decode(&log_data[0..32], true) else {
return Err(BatcherUpdateError::PointerDecodingError);
};
if pointer != 32 {
return Err(BatcherUpdateError::InvalidDataPointer(pointer));
}
let Ok(length) = <sol!(uint64)>::abi_decode(&log_data[32..64], true) else {
return Err(BatcherUpdateError::LengthDecodingError);
};
if length != 32 {
return Err(BatcherUpdateError::InvalidDataLength(length));
}
let Ok(batcher_address) = <sol!(address)>::abi_decode(&log_data[64..], true) else {
return Err(BatcherUpdateError::BatcherAddressDecodingError);
};
self.batcher_address = batcher_address;
Ok(SystemConfigUpdateType::Batcher)
}
fn update_gas_config(
&mut self,
log_data: &[u8],
ecotone_active: bool,
) -> Result<SystemConfigUpdateType, GasConfigUpdateError> {
if log_data.len() != 128 {
return Err(GasConfigUpdateError::InvalidDataLen(log_data.len()));
}
let Ok(pointer) = <sol!(uint64)>::abi_decode(&log_data[0..32], true) else {
return Err(GasConfigUpdateError::PointerDecodingError);
};
if pointer != 32 {
return Err(GasConfigUpdateError::InvalidDataPointer(pointer));
}
let Ok(length) = <sol!(uint64)>::abi_decode(&log_data[32..64], true) else {
return Err(GasConfigUpdateError::LengthDecodingError);
};
if length != 64 {
return Err(GasConfigUpdateError::InvalidDataLength(length));
}
let Ok(overhead) = <sol!(uint256)>::abi_decode(&log_data[64..96], true) else {
return Err(GasConfigUpdateError::OverheadDecodingError);
};
let Ok(scalar) = <sol!(uint256)>::abi_decode(&log_data[96..], true) else {
return Err(GasConfigUpdateError::ScalarDecodingError);
};
if ecotone_active
&& RollupConfig::check_ecotone_l1_system_config_scalar(scalar.to_be_bytes()).is_err()
{
return Ok(SystemConfigUpdateType::GasConfig);
}
self.scalar = scalar;
self.overhead = if ecotone_active { U256::ZERO } else { overhead };
Ok(SystemConfigUpdateType::GasConfig)
}
fn update_gas_limit(
&mut self,
log_data: &[u8],
) -> Result<SystemConfigUpdateType, GasLimitUpdateError> {
if log_data.len() != 96 {
return Err(GasLimitUpdateError::InvalidDataLen(log_data.len()));
}
let Ok(pointer) = <sol!(uint64)>::abi_decode(&log_data[0..32], true) else {
return Err(GasLimitUpdateError::PointerDecodingError);
};
if pointer != 32 {
return Err(GasLimitUpdateError::InvalidDataPointer(pointer));
}
let Ok(length) = <sol!(uint64)>::abi_decode(&log_data[32..64], true) else {
return Err(GasLimitUpdateError::LengthDecodingError);
};
if length != 32 {
return Err(GasLimitUpdateError::InvalidDataLength(length));
}
let Ok(gas_limit) = <sol!(uint256)>::abi_decode(&log_data[64..], true) else {
return Err(GasLimitUpdateError::GasLimitDecodingError);
};
self.gas_limit = U64::from(gas_limit).saturating_to::<u64>();
Ok(SystemConfigUpdateType::GasLimit)
}
fn update_eip1559_params(
&mut self,
log_data: &[u8],
) -> Result<SystemConfigUpdateType, EIP1559UpdateError> {
if log_data.len() != 96 {
return Err(EIP1559UpdateError::InvalidDataLen(log_data.len()));
}
let Ok(pointer) = <sol!(uint64)>::abi_decode(&log_data[0..32], true) else {
return Err(EIP1559UpdateError::PointerDecodingError);
};
if pointer != 32 {
return Err(EIP1559UpdateError::InvalidDataPointer(pointer));
}
let Ok(length) = <sol!(uint64)>::abi_decode(&log_data[32..64], true) else {
return Err(EIP1559UpdateError::LengthDecodingError);
};
if length != 32 {
return Err(EIP1559UpdateError::InvalidDataLength(length));
}
let Ok(eip1559_params) = <sol!(uint64)>::abi_decode(&log_data[64..], true) else {
return Err(EIP1559UpdateError::EIP1559DecodingError);
};
self.eip1559_denominator = Some((eip1559_params >> 32) as u32);
self.eip1559_elasticity = Some(eip1559_params as u32);
Ok(SystemConfigUpdateType::Eip1559)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum SystemConfigUpdateError {
LogProcessing(LogProcessingError),
Batcher(BatcherUpdateError),
GasConfig(GasConfigUpdateError),
GasLimit(GasLimitUpdateError),
Eip1559(EIP1559UpdateError),
}
impl core::fmt::Display for SystemConfigUpdateError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::LogProcessing(err) => write!(f, "Log processing error: {}", err),
Self::Batcher(err) => write!(f, "Batcher update error: {}", err),
Self::GasConfig(err) => write!(f, "Gas config update error: {}", err),
Self::GasLimit(err) => write!(f, "Gas limit update error: {}", err),
Self::Eip1559(err) => write!(f, "EIP-1559 parameter update error: {}", err),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum LogProcessingError {
InvalidTopicLen(usize),
InvalidTopic,
UnsupportedVersion(B256),
UpdateTypeDecodingError,
InvalidSystemConfigUpdateType(u64),
}
impl core::fmt::Display for LogProcessingError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::InvalidTopicLen(len) => {
write!(f, "Invalid config update log: invalid topic length: {}", len)
}
Self::InvalidTopic => write!(f, "Invalid config update log: invalid topic"),
Self::UnsupportedVersion(version) => {
write!(f, "Invalid config update log: unsupported version: {}", version)
}
Self::UpdateTypeDecodingError => {
write!(f, "Failed to decode config update log: update type")
}
Self::InvalidSystemConfigUpdateType(value) => {
write!(f, "Invalid system config update type: {}", value)
}
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum BatcherUpdateError {
InvalidDataLen(usize),
PointerDecodingError,
InvalidDataPointer(u64),
LengthDecodingError,
InvalidDataLength(u64),
BatcherAddressDecodingError,
}
impl core::fmt::Display for BatcherUpdateError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::InvalidDataLen(len) => {
write!(f, "Invalid config update log: invalid data length: {}", len)
}
Self::PointerDecodingError => {
write!(f, "Failed to decode batcher update log: data pointer")
}
Self::InvalidDataPointer(pointer) => {
write!(f, "Invalid config update log: invalid data pointer: {}", pointer)
}
Self::LengthDecodingError => {
write!(f, "Failed to decode batcher update log: data length")
}
Self::InvalidDataLength(length) => {
write!(f, "Invalid config update log: invalid data length: {}", length)
}
Self::BatcherAddressDecodingError => {
write!(f, "Failed to decode batcher update log: batcher address")
}
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum GasConfigUpdateError {
InvalidDataLen(usize),
PointerDecodingError,
InvalidDataPointer(u64),
LengthDecodingError,
InvalidDataLength(u64),
OverheadDecodingError,
ScalarDecodingError,
}
impl core::fmt::Display for GasConfigUpdateError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::InvalidDataLen(len) => {
write!(f, "Invalid config update log: invalid data length: {}", len)
}
Self::PointerDecodingError => {
write!(f, "Failed to decode gas config update log: data pointer")
}
Self::InvalidDataPointer(pointer) => {
write!(f, "Invalid config update log: invalid data pointer: {}", pointer)
}
Self::LengthDecodingError => {
write!(f, "Failed to decode gas config update log: data length")
}
Self::InvalidDataLength(length) => {
write!(f, "Invalid config update log: invalid data length: {}", length)
}
Self::OverheadDecodingError => {
write!(f, "Failed to decode gas config update log: overhead")
}
Self::ScalarDecodingError => {
write!(f, "Failed to decode gas config update log: scalar")
}
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum GasLimitUpdateError {
InvalidDataLen(usize),
PointerDecodingError,
InvalidDataPointer(u64),
LengthDecodingError,
InvalidDataLength(u64),
GasLimitDecodingError,
}
impl core::fmt::Display for GasLimitUpdateError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::InvalidDataLen(len) => {
write!(f, "Invalid config update log: invalid data length: {}", len)
}
Self::PointerDecodingError => {
write!(f, "Failed to decode gas limit update log: data pointer")
}
Self::InvalidDataPointer(pointer) => {
write!(f, "Invalid config update log: invalid data pointer: {}", pointer)
}
Self::LengthDecodingError => {
write!(f, "Failed to decode gas limit update log: data length")
}
Self::InvalidDataLength(length) => {
write!(f, "Invalid config update log: invalid data length: {}", length)
}
Self::GasLimitDecodingError => {
write!(f, "Failed to decode gas limit update log: gas limit")
}
}
}
}
impl core::error::Error for GasLimitUpdateError {}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum EIP1559UpdateError {
InvalidDataLen(usize),
PointerDecodingError,
InvalidDataPointer(u64),
LengthDecodingError,
InvalidDataLength(u64),
EIP1559DecodingError,
}
impl core::fmt::Display for EIP1559UpdateError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::InvalidDataLen(len) => {
write!(f, "Invalid config update log: invalid data length: {}", len)
}
Self::PointerDecodingError => {
write!(f, "Failed to decode eip1559 parameter update log: data pointer")
}
Self::InvalidDataPointer(pointer) => {
write!(f, "Invalid config update log: invalid data pointer: {}", pointer)
}
Self::LengthDecodingError => {
write!(f, "Failed to decode eip1559 parameter update log: data length")
}
Self::InvalidDataLength(length) => {
write!(f, "Invalid config update log: invalid data length: {}", length)
}
Self::EIP1559DecodingError => {
write!(
f,
"Failed to decode eip1559 parameter update log: eip1559 parameters invalid"
)
}
}
}
}
impl core::error::Error for EIP1559UpdateError {}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SystemAccounts {
pub attributes_depositor: Address,
pub attributes_predeploy: Address,
pub fee_vault: Address,
}
impl Default for SystemAccounts {
fn default() -> Self {
Self {
attributes_depositor: address!("deaddeaddeaddeaddeaddeaddeaddeaddead0001"),
attributes_predeploy: address!("4200000000000000000000000000000000000015"),
fee_vault: address!("4200000000000000000000000000000000000011"),
}
}
}
#[cfg(test)]
mod test {
use super::*;
use alloc::vec;
use alloy_primitives::{b256, hex, LogData, B256};
use arbitrary::Arbitrary;
use rand::Rng;
#[test]
fn test_arbitrary_system_config() {
let mut bytes = [0u8; 1024];
rand::thread_rng().fill(bytes.as_mut_slice());
SystemConfig::arbitrary(&mut arbitrary::Unstructured::new(&bytes)).unwrap();
}
#[test]
fn test_eip_1559_params_from_system_config_none() {
let rollup_config = RollupConfig::default();
let sys_config = SystemConfig::default();
assert_eq!(sys_config.eip_1559_params(&rollup_config, 0, 0), None);
}
#[test]
fn test_eip_1559_params_from_system_config_some() {
let rollup_config = RollupConfig { holocene_time: Some(0), ..Default::default() };
let sys_config = SystemConfig {
eip1559_denominator: Some(1),
eip1559_elasticity: None,
..Default::default()
};
let expected = Some(B64::from_slice(&[1u32.to_be_bytes(), 0u32.to_be_bytes()].concat()));
assert_eq!(sys_config.eip_1559_params(&rollup_config, 0, 0), expected);
}
#[test]
fn test_eip_1559_params_from_system_config() {
let rollup_config = RollupConfig { holocene_time: Some(0), ..Default::default() };
let sys_config = SystemConfig {
eip1559_denominator: Some(1),
eip1559_elasticity: Some(2),
..Default::default()
};
let expected = Some(B64::from_slice(&[1u32.to_be_bytes(), 2u32.to_be_bytes()].concat()));
assert_eq!(sys_config.eip_1559_params(&rollup_config, 0, 0), expected);
}
#[test]
fn test_default_eip_1559_params_from_system_config() {
let rollup_config = RollupConfig { holocene_time: Some(0), ..Default::default() };
let sys_config = SystemConfig {
eip1559_denominator: None,
eip1559_elasticity: None,
..Default::default()
};
let expected = Some(B64::ZERO);
assert_eq!(sys_config.eip_1559_params(&rollup_config, 0, 0), expected);
}
#[test]
fn test_default_eip_1559_params_from_system_config_pre_holocene() {
let rollup_config = RollupConfig::default();
let sys_config = SystemConfig {
eip1559_denominator: Some(1),
eip1559_elasticity: Some(2),
..Default::default()
};
assert_eq!(sys_config.eip_1559_params(&rollup_config, 0, 0), None);
}
#[test]
fn test_default_eip_1559_params_first_block_holocene() {
let rollup_config = RollupConfig { holocene_time: Some(2), ..Default::default() };
let sys_config = SystemConfig {
eip1559_denominator: Some(1),
eip1559_elasticity: Some(2),
..Default::default()
};
assert_eq!(sys_config.eip_1559_params(&rollup_config, 0, 2), Some(B64::ZERO));
}
#[test]
#[cfg(feature = "serde")]
fn test_system_config_serde() {
let sc_str = r#"{
"batcherAddr": "0x6887246668a3b87F54DeB3b94Ba47a6f63F32985",
"overhead": "0x00000000000000000000000000000000000000000000000000000000000000bc",
"scalar": "0x00000000000000000000000000000000000000000000000000000000000a6fe0",
"gasLimit": 30000000
}"#;
let system_config: SystemConfig = serde_json::from_str(sc_str).unwrap();
assert_eq!(
system_config.batcher_address,
address!("6887246668a3b87F54DeB3b94Ba47a6f63F32985")
);
assert_eq!(system_config.overhead, U256::from(0xbc));
assert_eq!(system_config.scalar, U256::from(0xa6fe0));
assert_eq!(system_config.gas_limit, 30000000);
}
#[test]
fn test_system_config_update_with_receipts_unchanged() {
let mut system_config = SystemConfig::default();
let receipts = vec![];
let l1_system_config_address = Address::ZERO;
let ecotone_active = false;
system_config
.update_with_receipts(&receipts, l1_system_config_address, ecotone_active)
.unwrap();
assert_eq!(system_config, SystemConfig::default());
}
#[test]
fn test_system_config_update_with_receipts_batcher_address() {
const UPDATE_TYPE: B256 =
b256!("0000000000000000000000000000000000000000000000000000000000000000");
let mut system_config = SystemConfig::default();
let l1_system_config_address = Address::ZERO;
let ecotone_active = false;
let update_log = Log {
address: Address::ZERO,
data: LogData::new_unchecked(
vec![
CONFIG_UPDATE_TOPIC,
CONFIG_UPDATE_EVENT_VERSION_0,
UPDATE_TYPE,
],
hex!("00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000beef").into()
)
};
let receipt = Receipt {
logs: vec![update_log],
status: Eip658Value::Eip658(true),
cumulative_gas_used: 0u128,
};
system_config
.update_with_receipts(&[receipt], l1_system_config_address, ecotone_active)
.unwrap();
assert_eq!(
system_config.batcher_address,
address!("000000000000000000000000000000000000bEEF"),
);
}
#[test]
fn test_system_config_update_batcher_log() {
const UPDATE_TYPE: B256 =
b256!("0000000000000000000000000000000000000000000000000000000000000000");
let mut system_config = SystemConfig::default();
let update_log = Log {
address: Address::ZERO,
data: LogData::new_unchecked(
vec![
CONFIG_UPDATE_TOPIC,
CONFIG_UPDATE_EVENT_VERSION_0,
UPDATE_TYPE,
],
hex!("00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000beef").into()
)
};
system_config.process_config_update_log(&update_log, false).unwrap();
assert_eq!(
system_config.batcher_address,
address!("000000000000000000000000000000000000bEEF")
);
}
#[test]
fn test_system_config_update_gas_config_log() {
const UPDATE_TYPE: B256 =
b256!("0000000000000000000000000000000000000000000000000000000000000001");
let mut system_config = SystemConfig::default();
let update_log = Log {
address: Address::ZERO,
data: LogData::new_unchecked(
vec![
CONFIG_UPDATE_TOPIC,
CONFIG_UPDATE_EVENT_VERSION_0,
UPDATE_TYPE,
],
hex!("00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000babe000000000000000000000000000000000000000000000000000000000000beef").into()
)
};
system_config.process_config_update_log(&update_log, false).unwrap();
assert_eq!(system_config.overhead, U256::from(0xbabe));
assert_eq!(system_config.scalar, U256::from(0xbeef));
}
#[test]
fn test_system_config_update_gas_config_log_ecotone() {
const UPDATE_TYPE: B256 =
b256!("0000000000000000000000000000000000000000000000000000000000000001");
let mut system_config = SystemConfig::default();
let update_log = Log {
address: Address::ZERO,
data: LogData::new_unchecked(
vec![
CONFIG_UPDATE_TOPIC,
CONFIG_UPDATE_EVENT_VERSION_0,
UPDATE_TYPE,
],
hex!("00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000babe000000000000000000000000000000000000000000000000000000000000beef").into()
)
};
system_config.process_config_update_log(&update_log, true).unwrap();
assert_eq!(system_config.overhead, U256::from(0));
assert_eq!(system_config.scalar, U256::from(0xbeef));
}
#[test]
fn test_system_config_update_gas_limit_log() {
const UPDATE_TYPE: B256 =
b256!("0000000000000000000000000000000000000000000000000000000000000002");
let mut system_config = SystemConfig::default();
let update_log = Log {
address: Address::ZERO,
data: LogData::new_unchecked(
vec![
CONFIG_UPDATE_TOPIC,
CONFIG_UPDATE_EVENT_VERSION_0,
UPDATE_TYPE,
],
hex!("00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000beef").into()
)
};
system_config.process_config_update_log(&update_log, false).unwrap();
assert_eq!(system_config.gas_limit, 0xbeef_u64);
}
#[test]
fn test_system_config_update_eip1559_params_log() {
const UPDATE_TYPE: B256 =
b256!("0000000000000000000000000000000000000000000000000000000000000004");
let mut system_config = SystemConfig::default();
let update_log = Log {
address: Address::ZERO,
data: LogData::new_unchecked(
vec![
CONFIG_UPDATE_TOPIC,
CONFIG_UPDATE_EVENT_VERSION_0,
UPDATE_TYPE,
],
hex!("000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000babe0000beef").into()
)
};
system_config.process_config_update_log(&update_log, false).unwrap();
assert_eq!(system_config.eip1559_denominator, Some(0xbabe_u32));
assert_eq!(system_config.eip1559_elasticity, Some(0xbeef_u32));
}
}