Skip to content

Commit

Permalink
feat(protocol): operator fee
Browse files Browse the repository at this point in the history
  • Loading branch information
yuwen01 authored and refcell committed Dec 3, 2024
1 parent 985c1b5 commit 0a31806
Show file tree
Hide file tree
Showing 12 changed files with 275 additions and 5 deletions.
3 changes: 3 additions & 0 deletions crates/genesis/src/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ pub struct HardForkConfiguration {
pub granite_time: Option<u64>,
/// Holocene hardfork activation time
pub holocene_time: Option<u64>,
/// Isthmus hardfork activation time
pub isthmus_time: Option<u64>,
}

/// Defines core blockchain settings per block.
Expand Down Expand Up @@ -215,6 +217,7 @@ impl ChainConfig {
fjord_time: self.hardfork_configuration.fjord_time,
granite_time: self.hardfork_configuration.granite_time,
holocene_time: self.hardfork_configuration.holocene_time,
isthmus_time: self.hardfork_configuration.isthmus_time,
batch_inbox_address: self.batch_inbox_addr,
deposit_contract_address: self
.addresses
Expand Down
31 changes: 30 additions & 1 deletion crates/genesis/src/rollup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,11 @@ pub struct RollupConfig {
/// otherwise.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub holocene_time: Option<u64>,
/// `isthmus_time` sets the activation time for the Isthmus network upgrade.
/// Active if `isthmus_time` != None && L2 block timestamp >= Some(isthmus_time), inactive
/// otherwise.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub isthmus_time: Option<u64>,
/// `batch_inbox_address` is the L1 address that batches are sent to.
pub batch_inbox_address: Address,
/// `deposit_contract_address` is the L1 address that deposits are sent to.
Expand Down Expand Up @@ -144,6 +149,7 @@ impl<'a> arbitrary::Arbitrary<'a> for RollupConfig {
fjord_time: Option::<u64>::arbitrary(u)?,
granite_time: Option::<u64>::arbitrary(u)?,
holocene_time: Option::<u64>::arbitrary(u)?,
isthmus_time: Option::<u64>::arbitrary(u)?,
batch_inbox_address: Address::arbitrary(u)?,
deposit_contract_address: Address::arbitrary(u)?,
l1_system_config_address: Address::arbitrary(u)?,
Expand Down Expand Up @@ -177,6 +183,7 @@ impl Default for RollupConfig {
fjord_time: None,
granite_time: None,
holocene_time: None,
isthmus_time: None,
batch_inbox_address: Address::ZERO,
deposit_contract_address: Address::ZERO,
l1_system_config_address: Address::ZERO,
Expand Down Expand Up @@ -221,7 +228,12 @@ impl RollupConfig {

/// Returns true if Holocene is active at the given timestamp.
pub fn is_holocene_active(&self, timestamp: u64) -> bool {
self.holocene_time.map_or(false, |t| timestamp >= t)
self.holocene_time.map_or(false, |t| timestamp >= t) || self.is_isthmus_active(timestamp)
}

/// Returns true if Isthmus is active at the given timestamp.
pub fn is_isthmus_active(&self, timestamp: u64) -> bool {
self.isthmus_time.map_or(false, |t| timestamp >= t)
}

/// Returns true if a DA Challenge proxy Address is provided in the rollup config and the
Expand Down Expand Up @@ -266,6 +278,7 @@ impl RollupConfig {
fjord_time: self.fjord_time,
granite_time: self.granite_time,
holocene_time: self.holocene_time,
isthmus_time: self.isthmus_time,
}
}

Expand Down Expand Up @@ -395,6 +408,22 @@ mod tests {
assert!(!config.is_holocene_active(9));
}

#[test]
fn test_isthmus_active() {
let mut config = RollupConfig::default();
assert!(!config.is_isthmus_active(0));
config.isthmus_time = Some(10);
assert!(config.is_regolith_active(10));
assert!(config.is_canyon_active(10));
assert!(config.is_delta_active(10));
assert!(config.is_ecotone_active(10));
assert!(config.is_fjord_active(10));
assert!(config.is_granite_active(10));
assert!(config.is_holocene_active(10));
assert!(config.is_isthmus_active(10));
assert!(!config.is_isthmus_active(9));
}

#[test]
fn test_alt_da_enabled() {
let mut config = RollupConfig::default();
Expand Down
6 changes: 6 additions & 0 deletions crates/protocol/src/info/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ pub enum BlockInfoError {
/// Failed to parse the EIP-1559 elasticity parameter.
#[error("Failed to parse the EIP-1559 elasticity parameter")]
Eip1559Elasticity,
/// Failed to parse the Operator Fee Scalar.
#[error("Failed to parse the Operator fee scalar parameter")]
OperatorFeeScalar,
/// Failed to parse the Operator Fee Constant.
#[error("Failed to parse the Operator fee constant parameter")]
OperatorFeeConstant,
}

/// An error decoding an L1 block info transaction.
Expand Down
137 changes: 137 additions & 0 deletions crates/protocol/src/info/isthmus.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
//! Isthmus L1 Block Info transaction types.
use alloc::{format, string::ToString, vec::Vec};
use alloy_primitives::{Address, Bytes, B256, U256};

use crate::DecodeError;

/// Represents the fields within an Isthnus L1 block info transaction.
///
/// Holocene Binary Format
/// +---------+--------------------------+
/// | Bytes | Field |
/// +---------+--------------------------+
/// | 4 | Function signature |
/// | 4 | BaseFeeScalar |
/// | 4 | BlobBaseFeeScalar |
/// | 8 | SequenceNumber |
/// | 8 | Timestamp |
/// | 8 | L1BlockNumber |
/// | 32 | BaseFee |
/// | 32 | BlobBaseFee |
/// | 32 | BlockHash |
/// | 32 | BatcherHash |
/// | 4 | OperatorFeeScalar |
/// | 8 | OperatorFeeConstant |
/// +---------+--------------------------+
#[derive(Debug, Clone, Hash, Eq, PartialEq, Default, Copy)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct L1BlockInfoIsthmus {
/// The current L1 origin block number
pub number: u64,
/// The current L1 origin block's timestamp
pub time: u64,
/// The current L1 origin block's basefee
pub base_fee: u64,
/// The current L1 origin block's hash
pub block_hash: B256,
/// The current sequence number
pub sequence_number: u64,
/// The address of the batch submitter
pub batcher_address: Address,
/// The current blob base fee on L1
pub blob_base_fee: u128,
/// The fee scalar for L1 blobspace data
pub blob_base_fee_scalar: u32,
/// The fee scalar for L1 data
pub base_fee_scalar: u32,
/// The operator fee scalar
pub operator_fee_scalar: u32,
/// The operator fee constant
pub operator_fee_constant: u64,
}

impl L1BlockInfoIsthmus {
/// The type byte identifier for the L1 scalar format in Isthmus.
pub const L1_SCALAR: u8 = 2;

/// The length of an L1 info transaction in Isthmus.
pub const L1_INFO_TX_LEN: usize = 4 + 32 * 5 + 4 + 8;

/// The 4 byte selector of "setL1BlockValuesIsthmus()"
pub const L1_INFO_TX_SELECTOR: [u8; 4] = [0x09, 0x89, 0x99, 0xbe];

/// Encodes the [L1BlockInfoIsthmus] object into Ethereum transaction calldata.
pub fn encode_calldata(&self) -> Bytes {
let mut buf = Vec::with_capacity(Self::L1_INFO_TX_LEN);
buf.extend_from_slice(Self::L1_INFO_TX_SELECTOR.as_ref());
buf.extend_from_slice(self.base_fee_scalar.to_be_bytes().as_ref());
buf.extend_from_slice(self.blob_base_fee_scalar.to_be_bytes().as_ref());
buf.extend_from_slice(self.sequence_number.to_be_bytes().as_ref());
buf.extend_from_slice(self.time.to_be_bytes().as_ref());
buf.extend_from_slice(self.number.to_be_bytes().as_ref());
buf.extend_from_slice(U256::from(self.base_fee).to_be_bytes::<32>().as_ref());
buf.extend_from_slice(U256::from(self.blob_base_fee).to_be_bytes::<32>().as_ref());
buf.extend_from_slice(self.block_hash.as_ref());
buf.extend_from_slice(self.batcher_address.into_word().as_ref());
buf.extend_from_slice(self.operator_fee_scalar.to_be_bytes().as_ref());
buf.extend_from_slice(self.operator_fee_constant.to_be_bytes().as_ref());
buf.into()
}

/// Decodes the [L1BlockInfoIsthmus] object from ethereum transaction calldata.
pub fn decode_calldata(r: &[u8]) -> Result<Self, DecodeError> {
if r.len() != Self::L1_INFO_TX_LEN {
return Err(DecodeError::InvalidLength(format!(
"Invalid calldata length for Isthmus L1 info transaction, expected {}, got {}",
Self::L1_INFO_TX_LEN,
r.len()
)));
}
let base_fee_scalar = u32::from_be_bytes(r[4..8].try_into().map_err(|_| {
DecodeError::ParseError("Conversion error for base fee scalar".to_string())
})?);
let blob_base_fee_scalar = u32::from_be_bytes(r[8..12].try_into().map_err(|_| {
DecodeError::ParseError("Conversion error for blob base fee scalar".to_string())
})?);
let sequence_number = u64::from_be_bytes(r[12..20].try_into().map_err(|_| {
DecodeError::ParseError("Conversion error for sequence number".to_string())
})?);
let time =
u64::from_be_bytes(r[20..28].try_into().map_err(|_| {
DecodeError::ParseError("Conversion error for timestamp".to_string())
})?);
let number = u64::from_be_bytes(r[28..36].try_into().map_err(|_| {
DecodeError::ParseError("Conversion error for L1 block number".to_string())
})?);
let base_fee =
u64::from_be_bytes(r[60..68].try_into().map_err(|_| {
DecodeError::ParseError("Conversion error for base fee".to_string())
})?);
let blob_base_fee = u128::from_be_bytes(r[84..100].try_into().map_err(|_| {
DecodeError::ParseError("Conversion error for blob base fee".to_string())
})?);
let block_hash = B256::from_slice(r[100..132].as_ref());
let batcher_address = Address::from_slice(r[144..164].as_ref());
let operator_fee_scalar = u32::from_be_bytes(r[164..168].try_into().map_err(|_| {
DecodeError::ParseError("Conversion error for operator fee scalar".to_string())
})?);
let operator_fee_constant = u64::from_be_bytes(r[168..176].try_into().map_err(|_| {
DecodeError::ParseError("Conversion error for operator fee constant".to_string())
})?);

Ok(Self {
number,
time,
base_fee,
block_hash,
sequence_number,
batcher_address,
blob_base_fee,
blob_base_fee_scalar,
base_fee_scalar,
operator_fee_scalar,
operator_fee_constant,
})
}
}
3 changes: 3 additions & 0 deletions crates/protocol/src/info/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,8 @@ pub use bedrock::L1BlockInfoBedrock;
mod ecotone;
pub use ecotone::L1BlockInfoEcotone;

mod isthmus;
pub use isthmus::L1BlockInfoIsthmus;

mod errors;
pub use errors::{BlockInfoError, DecodeError};
Loading

0 comments on commit 0a31806

Please sign in to comment.