Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(protocol): SystemConfig Conversion Utility #135

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/protocol/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ pub use frame::{
};

mod utils;
pub use utils::starts_with_2718_deposit;
pub use utils::{starts_with_2718_deposit, to_system_config, OpBlockConversionError};

mod channel;
pub use channel::{
Expand Down
104 changes: 104 additions & 0 deletions crates/protocol/src/utils.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
//! Utility methods used by protocol types.

use crate::{
block_info::DecodeError, L1BlockInfoBedrock, L1BlockInfoEcotone, L1BlockInfoHolocene,
L1BlockInfoTx,
};
use alloy_primitives::B256;
use op_alloy_consensus::{OpBlock, OpTxEnvelope};
use op_alloy_genesis::{RollupConfig, SystemConfig};

/// Returns if the given `value` is a deposit transaction.
pub fn starts_with_2718_deposit<B>(value: &B) -> bool
where
Expand All @@ -8,6 +16,102 @@ where
value.as_ref().first() == Some(&0x7E)
}

/// An error encountered during [OpBlock] conversion.
#[derive(Debug, derive_more::Display)]
pub enum OpBlockConversionError {
/// Invalid genesis hash.
#[display("Invalid genesis hash. Expected {_0}, got {_1}")]
InvalidGenesisHash(B256, B256),
/// Invalid transaction type.
#[display("First payload transaction has unexpected type: {_0}")]
InvalidTxType(u8),
/// L1 Info error
#[display("Failed to decode L1 info: {_0}")]
L1InfoError(DecodeError),
/// Missing system config in genesis block.
#[display("Missing system config in genesis block")]
MissingSystemConfigGenesis,
/// Empty transactions.
#[display("Empty transactions in payload. Block hash: {_0}")]
EmptyTransactions(B256),
}

impl core::error::Error for OpBlockConversionError {
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
match self {
Self::L1InfoError(err) => Some(err),
_ => None,
}
}
}

impl From<DecodeError> for OpBlockConversionError {
fn from(e: DecodeError) -> Self {
Self::L1InfoError(e)
}
}

/// Converts the [OpBlock] to a partial [SystemConfig].
pub fn to_system_config(
block: &OpBlock,
rollup_config: &RollupConfig,
) -> Result<SystemConfig, OpBlockConversionError> {
if block.header.number == rollup_config.genesis.l2.number {
if block.header.hash_slow() != rollup_config.genesis.l2.hash {
return Err(OpBlockConversionError::InvalidGenesisHash(
rollup_config.genesis.l2.hash,
block.header.hash_slow(),
));
}
return rollup_config
.genesis
.system_config
.ok_or(OpBlockConversionError::MissingSystemConfigGenesis);
}

if block.body.transactions.is_empty() {
return Err(OpBlockConversionError::EmptyTransactions(block.header.hash_slow()));
}
let OpTxEnvelope::Deposit(ref tx) = block.body.transactions[0] else {
return Err(OpBlockConversionError::InvalidTxType(
block.body.transactions[0].tx_type() as u8
));
};

let l1_info = L1BlockInfoTx::decode_calldata(tx.input.as_ref())?;
let l1_fee_scalar = match l1_info {
L1BlockInfoTx::Bedrock(L1BlockInfoBedrock { l1_fee_scalar, .. }) => l1_fee_scalar,
L1BlockInfoTx::Ecotone(L1BlockInfoEcotone {
base_fee_scalar,
blob_base_fee_scalar,
..
})
| L1BlockInfoTx::Holocene(L1BlockInfoHolocene {
base_fee_scalar,
blob_base_fee_scalar,
..
}) => {
// Translate Ecotone values back into encoded scalar if needed.
// We do not know if it was derived from a v0 or v1 scalar,
// but v1 is fine, a 0 blob base fee has the same effect.
let mut buf = B256::ZERO;
buf[0] = 0x01;
buf[24..28].copy_from_slice(blob_base_fee_scalar.to_be_bytes().as_ref());
buf[28..32].copy_from_slice(base_fee_scalar.to_be_bytes().as_ref());
buf.into()
}
};

Ok(SystemConfig {
batcher_address: l1_info.batcher_address(),
overhead: l1_info.l1_fee_overhead(),
scalar: l1_fee_scalar,
gas_limit: block.header.gas_limit,
base_fee_scalar: None,
blob_base_fee_scalar: None,
})
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
Loading