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

chore(l2): forbid as conversions #1347

Merged
merged 19 commits into from
Dec 2, 2024
Merged
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/common/types/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ pub fn calculate_base_fee_per_blob_gas(parent_excess_blob_gas: u64) -> u64 {
}

// Defined in [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844)
fn fake_exponential(factor: u64, numerator: u64, denominator: u64) -> u64 {
pub fn fake_exponential(factor: u64, numerator: u64, denominator: u64) -> u64 {
let mut i = 1;
let mut output = 0;
let mut numerator_accum = factor * denominator;
Expand Down
12 changes: 12 additions & 0 deletions crates/common/types/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,18 @@ pub enum TxType {
Privileged = 0x7e,
}

impl From<TxType> for u8 {
fn from(val: TxType) -> Self {
match val {
TxType::Legacy => 0x00,
TxType::EIP2930 => 0x01,
TxType::EIP1559 => 0x02,
TxType::EIP4844 => 0x03,
TxType::Privileged => 0x7e,
}
}
}

pub trait Signable {
fn sign(&self, private_key: &SecretKey) -> Self
where
Expand Down
2 changes: 2 additions & 0 deletions crates/l2/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,5 @@ path = "./l2.rs"
unwrap_used = "deny"
expect_used = "deny"
indexing_slicing = "deny"
as_conversions = "deny"
unnecessary_cast = "warn"
2 changes: 2 additions & 0 deletions crates/l2/contracts/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,5 @@ path = "./deployer.rs"
unwrap_used = "deny"
expect_used = "deny"
indexing_slicing = "deny"
as_conversions = "deny"
unnecessary_cast = "warn"
4 changes: 4 additions & 0 deletions crates/l2/proposer/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ pub enum CommitterError {
InvalidWithdrawalTransaction,
#[error("Blob estimation failed: {0}")]
BlobEstimationError(#[from] BlobEstimationError),
#[error("length does not fit in u16")]
TryIntoError(#[from] std::num::TryFromIntError),
}

#[derive(Debug, thiserror::Error)]
Expand Down Expand Up @@ -131,4 +133,6 @@ pub enum StateDiffError {
BytecodeAndBytecodeHashSet,
#[error("Empty account diff")]
EmptyAccountDiff,
#[error("The length of the vector is too big to fit in u16: {0}")]
LengthTooBig(#[from] core::num::TryFromIntError),
}
37 changes: 22 additions & 15 deletions crates/l2/proposer/l1_committer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,16 @@ use crate::{
use bytes::Bytes;
use ethrex_core::{
types::{
blobs_bundle, BlobsBundle, Block, PrivilegedL2Transaction, PrivilegedTxType, Transaction,
TxKind, BLOB_BASE_FEE_UPDATE_FRACTION,
blobs_bundle, fake_exponential, BlobsBundle, Block, PrivilegedL2Transaction,
PrivilegedTxType, Transaction, TxKind, BLOB_BASE_FEE_UPDATE_FRACTION,
MIN_BASE_FEE_PER_BLOB_GAS,
},
Address, H256, U256,
};
use ethrex_storage::{error::StoreError, Store};
use ethrex_vm::{evm_state, execute_block, get_state_transitions};
use keccak_hash::keccak;
use secp256k1::SecretKey;
use std::f64::consts::E;
use std::{collections::HashMap, time::Duration};
use tokio::time::sleep;
use tracing::{error, info};
Expand Down Expand Up @@ -211,9 +211,13 @@ impl Committer {

pub fn get_deposit_hash(&self, deposit_hashes: Vec<H256>) -> Result<H256, CommitterError> {
if !deposit_hashes.is_empty() {
let deposit_hashes_len: u16 = deposit_hashes
.len()
.try_into()
.map_err(CommitterError::from)?;
Ok(H256::from_slice(
[
&(deposit_hashes.len() as u16).to_be_bytes(),
&deposit_hashes_len.to_be_bytes(),
keccak(
deposit_hashes
.iter()
Expand Down Expand Up @@ -270,7 +274,9 @@ impl Committer {
.clone()
.ok_or(CommitterError::FailedToRetrieveDataFromStorage)?
.nonce
- prev_nonce) as u16,
- prev_nonce)
.try_into()
.map_err(CommitterError::from)?,
storage: account_update.added_storage.clone().into_iter().collect(),
bytecode: account_update.code.clone(),
bytecode_hash: None,
Expand Down Expand Up @@ -347,7 +353,7 @@ impl Committer {
let le_bytes = estimate_blob_gas(
&self.eth_client,
self.arbitrary_base_blob_gas_price,
1.2, // 20% of headroom
20, // 20% of headroom
)
.await?
.to_le_bytes();
Expand Down Expand Up @@ -393,7 +399,7 @@ impl Committer {
/// # Parameters:
/// - `eth_client`: The Ethereum client used to fetch the latest block.
/// - `arbitrary_base_blob_gas_price`: The base gas price that serves as the minimum price for blob transactions.
/// - `headroom`: A multiplier (as a float) applied to the estimated gas price to provide a buffer against fluctuations.
/// - `headroom`: Percentage applied to the estimated gas price to provide a buffer against fluctuations.
///
/// # Formula:
/// The gas price is estimated using an exponential function based on the blob gas used in the latest block and the
Expand All @@ -404,7 +410,7 @@ impl Committer {
async fn estimate_blob_gas(
eth_client: &EthClient,
arbitrary_base_blob_gas_price: u64,
headroom: f64,
headroom: u64,
) -> Result<u64, CommitterError> {
let latest_block = eth_client
.get_block_by_number(BlockByNumber::Latest)
Expand Down Expand Up @@ -432,15 +438,16 @@ async fn estimate_blob_gas(
};

// If the blob's market is in high demand, the equation may give a really big number.
let exponent = (total_blob_gas as f64) / (BLOB_BASE_FEE_UPDATE_FRACTION as f64);
let blob_gas = match E.powf(exponent) {
result if result.is_finite() => result,
_ => return Err(BlobEstimationError::NonFiniteResult.into()),
};
let blob_gas = fake_exponential(
LeanSerra marked this conversation as resolved.
Show resolved Hide resolved
MIN_BASE_FEE_PER_BLOB_GAS,
total_blob_gas,
BLOB_BASE_FEE_UPDATE_FRACTION,
);

let gas_with_headroom = (blob_gas * (100 + headroom)) / 100;

// Check if we have an overflow when we take the headroom into account.
let gas_with_headroom = blob_gas * headroom;
let blob_gas = match arbitrary_base_blob_gas_price.checked_add(gas_with_headroom as u64) {
let blob_gas = match arbitrary_base_blob_gas_price.checked_add(gas_with_headroom) {
Some(gas) => gas,
None => return Err(BlobEstimationError::OverflowError.into()),
};
Expand Down
7 changes: 6 additions & 1 deletion crates/l2/proposer/prover_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,12 @@ impl ProverServer {
calldata.extend(journal_digest.as_bytes());

// extend with size of seal
calldata.extend(H256::from_low_u64_be(seal.len() as u64).as_bytes());
calldata.extend(
H256::from_low_u64_be(seal.len().try_into().map_err(|err| {
ProverServerError::Custom(format!("Seal length does not fit in u64: {}", err))
})?)
.as_bytes(),
);
// extend with seal
calldata.extend(seal);
// extend with zero padding
Expand Down
48 changes: 40 additions & 8 deletions crates/l2/proposer/state_diff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,32 @@ impl Default for StateDiff {
}
}

impl From<AccountStateDiffType> for u8 {
fn from(value: AccountStateDiffType) -> Self {
match value {
AccountStateDiffType::NewBalance => 1,
AccountStateDiffType::NonceDiff => 2,
AccountStateDiffType::Storage => 4,
AccountStateDiffType::Bytecode => 8,
AccountStateDiffType::BytecodeHash => 16,
}
}
}

impl StateDiff {
pub fn encode(&self) -> Result<Bytes, StateDiffError> {
if self.version != 1 {
return Err(StateDiffError::UnsupportedVersion(self.version));
}
let modified_accounts_len: u16 = self
.modified_accounts
.len()
.try_into()
.map_err(StateDiffError::from)?;

let mut encoded: Vec<u8> = Vec::new();
encoded.push(self.version);
encoded.extend((self.modified_accounts.len() as u16).to_be_bytes());
encoded.extend(modified_accounts_len.to_be_bytes());

for (address, diff) in &self.modified_accounts {
let (r#type, diff_encoded) = diff.encode()?;
Expand Down Expand Up @@ -119,20 +136,28 @@ impl AccountStateDiff {
let mut encoded: Vec<u8> = Vec::new();

if let Some(new_balance) = self.new_balance {
r#type += AccountStateDiffType::NewBalance as u8;
let r_type: u8 = AccountStateDiffType::NewBalance.into();
r#type += r_type;
let buf = &mut [0u8; 32];
new_balance.to_big_endian(buf);
encoded.extend_from_slice(buf);
}

if self.nonce_diff != 0 {
r#type += AccountStateDiffType::NonceDiff as u8;
let r_type: u8 = AccountStateDiffType::NonceDiff.into();
r#type += r_type;
encoded.extend(self.nonce_diff.to_be_bytes());
}

if !self.storage.is_empty() {
r#type += AccountStateDiffType::Storage as u8;
encoded.extend((self.storage.len() as u16).to_be_bytes());
let r_type: u8 = AccountStateDiffType::Storage.into();
let storage_len: u16 = self
.storage
.len()
.try_into()
.map_err(StateDiffError::from)?;
r#type += r_type;
encoded.extend(storage_len.to_be_bytes());
for (key, value) in &self.storage {
encoded.extend_from_slice(&key.0);
let buf = &mut [0u8; 32];
Expand All @@ -142,13 +167,20 @@ impl AccountStateDiff {
}

if let Some(bytecode) = &self.bytecode {
r#type += AccountStateDiffType::Bytecode as u8;
encoded.extend((bytecode.len() as u16).to_be_bytes());
let r_type: u8 = AccountStateDiffType::Bytecode.into();
let bytecode_len: u16 = self
.storage
.len()
.try_into()
.map_err(StateDiffError::from)?;
r#type += r_type;
encoded.extend(bytecode_len.to_be_bytes());
encoded.extend(bytecode);
}

if let Some(bytecode_hash) = &self.bytecode_hash {
r#type += AccountStateDiffType::BytecodeHash as u8;
let r_type: u8 = AccountStateDiffType::BytecodeHash.into();
r#type += r_type;
encoded.extend(&bytecode_hash.0);
}

Expand Down
2 changes: 2 additions & 0 deletions crates/l2/prover/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,5 @@ gpu = ["risc0-zkvm/cuda"]
unwrap_used = "deny"
expect_used = "deny"
indexing_slicing = "deny"
as_conversions = "deny"
unnecessary_cast = "warn"
2 changes: 2 additions & 0 deletions crates/l2/sdk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,5 @@ path = "src/sdk.rs"
unwrap_used = "deny"
expect_used = "deny"
indexing_slicing = "deny"
as_conversions = "deny"
unnecessary_cast = "warn"
9 changes: 7 additions & 2 deletions crates/l2/sdk/src/sdk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ pub async fn get_withdraw_merkle_proof(
Transaction::PrivilegedL2Transaction(privileged_l2_transaction) => {
privileged_l2_transaction
.get_withdrawal_hash()
.map(|withdrawal_hash| (i as u64, (withdrawal_hash)))
.map(|withdrawal_hash| (i, (withdrawal_hash)))
}
_ => unreachable!(),
})
Expand All @@ -283,5 +283,10 @@ pub async fn get_withdraw_merkle_proof(
"Failed to generate merkle proof, element is not on the tree".to_string(),
))?;

Ok((index, path))
Ok((
index
.try_into()
.map_err(|err| EthClientError::Custom(format!("index does not fit in u64: {}", err)))?,
path,
))
}
6 changes: 5 additions & 1 deletion crates/l2/utils/eth_client/eth_sender.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,11 @@ impl EthClient {
let encoded_from = deployer.encode_to_vec();
// FIXME: We'll probably need to use nonce - 1 since it was updated above.
let encoded_nonce = self.get_nonce(deployer).await?.encode_to_vec();
let mut encoded = vec![(0xc0 + encoded_from.len() + encoded_nonce.len()) as u8];
let mut encoded = vec![(0xc0 + encoded_from.len() + encoded_nonce.len())
.try_into()
.map_err(|err| {
EthClientError::Custom(format!("Failed to encode deployed_address {}", err))
})?];
encoded.extend(encoded_from.clone());
encoded.extend(encoded_nonce.clone());
let deployed_address = Address::from(keccak(encoded));
Expand Down
Loading
Loading