Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
4c526a0
start with implementation
JereSalo Mar 31, 2025
64965fe
add validium option to cli
JereSalo Mar 31, 2025
bf26fdf
add some things for validium to work
JereSalo Mar 31, 2025
f3c2e0f
make progress
JereSalo Mar 31, 2025
0e60588
nits
JereSalo Mar 31, 2025
b32f1f7
clippy lint and change comment
JereSalo Mar 31, 2025
85fd749
move state_diff call into if
JereSalo Apr 9, 2025
37e106d
remove validium wrong checks
JereSalo Apr 9, 2025
a9b8a9e
change l2 CI to test validium mode too
JereSalo Apr 9, 2025
63be86c
merge main
JereSalo Apr 11, 2025
a1cfadd
restore file from main
JereSalo Apr 11, 2025
1fad6a9
update sequencer configs with validium attribute and update integrati…
JereSalo Apr 11, 2025
e5d06c3
Merge branch 'main' into l2/add_validium_mode
JereSalo Apr 11, 2025
fefaf04
Merge branch 'main' of github.com:lambdaclass/ethrex into l2/add_vali…
ilitteri Apr 21, 2025
5718c72
Unify steps
ilitteri Apr 21, 2025
698e31d
Merge branch 'main' into l2/add_validium_mode
ilitteri Apr 22, 2025
06a31c1
Fix CI
ilitteri Apr 23, 2025
73d044d
Update .github/workflows/pr-main_l2.yaml
ilitteri Apr 23, 2025
501d964
Merge branch 'main' of github.com:lambdaclass/ethrex into l2/add_vali…
ilitteri Apr 24, 2025
c686fd1
Merge leftover
ilitteri Apr 24, 2025
ddddca3
Reject uncommitted blocks in Validium mode
ilitteri Apr 24, 2025
4a1fede
Add TODOs
ilitteri Apr 24, 2025
62df9bc
Update .github/workflows/pr-main_l2.yaml
ilitteri Apr 24, 2025
232c71d
Update .github/workflows/pr-main_l2.yaml
ilitteri Apr 24, 2025
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: 2 additions & 0 deletions crates/l2/configs/sequencer_config_example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ l1_private_key = "0x385c546456b6a603a1cfcaa9ec9494ba4832da08dd6bcf4de9a71e4a01b7
interval_ms = 5000
# 1 Gwei
arbitrary_base_blob_gas_price = 1000000000
# If set to true, initializes the committer in validium mode
validium = false

[prover_server]
# set it to 0.0.0.0 to allow connections from other machines
Expand Down
59 changes: 48 additions & 11 deletions crates/l2/contracts/deployer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -350,13 +350,14 @@ async fn deploy_contracts(
Color::Cyan,
);

let (on_chain_proposer_deployment_tx_hash, on_chain_proposer_address) = deploy_contract(
deployer,
deployer_private_key,
eth_client,
&contracts_path.join("solc_out/OnChainProposer.bin"),
)
.await?;
let (on_chain_proposer_deployment_tx_hash, on_chain_proposer_address) =
deploy_on_chain_proposer(
deployer,
deployer_private_key,
eth_client,
&contracts_path.join("solc_out/OnChainProposer.bin"),
)
.await?;

let msg = format!(
"OnChainProposer:\n\tDeployed at address {}\n\tWith tx hash {}",
Expand Down Expand Up @@ -438,12 +439,10 @@ async fn deploy_contract(
contract_path: &Path,
) -> Result<(H256, Address), DeployError> {
let init_code = hex::decode(std::fs::read_to_string(contract_path).map_err(|err| {
DeployError::DecodingError(format!("Failed to read on_chain_proposer_init_code: {err}"))
DeployError::DecodingError(format!("Failed to read contract init code: {err}"))
})?)
.map_err(|err| {
DeployError::DecodingError(format!(
"Failed to decode on_chain_proposer_init_code: {err}"
))
DeployError::DecodingError(format!("Failed to decode contract init code: {err}"))
})?
.into();

Expand All @@ -455,6 +454,44 @@ async fn deploy_contract(
Ok((deploy_tx_hash, contract_address))
}

async fn deploy_on_chain_proposer(
deployer: Address,
deployer_private_key: SecretKey,
eth_client: &EthClient,
contract_path: &Path,
) -> Result<(H256, Address), DeployError> {
let mut init_code = hex::decode(std::fs::read_to_string(contract_path).map_err(|err| {
DeployError::DecodingError(format!("Failed to read on_chain_proposer_init_code: {err}"))
})?)
.map_err(|err| {
DeployError::DecodingError(format!(
"Failed to decode on_chain_proposer_init_code: {err}"
))
})?;

let validium: bool = read_env_var("COMMITTER_VALIDIUM")?
.trim()
.parse()
.map_err(|err| DeployError::ParseError(format!("Malformed COMMITTER_VALIDIUM: {err}")))?;

let validium_value = if validium { 1u8 } else { 0u8 };
let encoded_validium = vec![0; 31]
.into_iter()
.chain(std::iter::once(validium_value));
init_code.extend(encoded_validium);

let (deploy_tx_hash, contract_address) = create2_deploy(
deployer,
deployer_private_key,
&init_code.into(),
eth_client,
)
.await
.map_err(DeployError::from)?;

Ok((deploy_tx_hash, contract_address))
}

async fn deploy_bridge(
deployer: Address,
deployer_private_key: SecretKey,
Expand Down
59 changes: 39 additions & 20 deletions crates/l2/contracts/src/l1/OnChainProposer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,16 @@ contract OnChainProposer is IOnChainProposer, ReentrancyGuard {
/// @dev Used only in dev mode.
address public constant DEV_MODE = address(0xAA);

/// @notice Indicates whether the contract operates in validium mode.
/// @dev This value is immutable and can only be set during contract deployment.
bool public immutable VALIDIUM;

/// @notice Constructor to initialize the immutable validium value.
/// @param _validium A boolean indicating if the contract operates in validium mode.
constructor(bool _validium) {
VALIDIUM = _validium;
}

modifier onlySequencer() {
require(
authorizedSequencerAddresses[msg.sender],
Expand Down Expand Up @@ -145,10 +155,12 @@ contract OnChainProposer is IOnChainProposer, ReentrancyGuard {
blockNumber == lastCommittedBlock + 1,
"OnChainProposer: blockNumber is not the immediate successor of lastCommittedBlock"
);
require(
blockCommitments[blockNumber].commitmentHash == bytes32(0),
"OnChainProposer: block already committed"
);
if (!VALIDIUM) {
require(
blockCommitments[blockNumber].commitmentHash == bytes32(0),
"OnChainProposer: block already committed"
);
}
// Check if commitment is equivalent to blob's KZG commitment.

if (depositLogs != bytes32(0)) {
Expand All @@ -165,12 +177,15 @@ contract OnChainProposer is IOnChainProposer, ReentrancyGuard {
withdrawalsLogsMerkleRoot
);
}
blockCommitments[blockNumber] = BlockCommitmentInfo(
if (!VALIDIUM) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, this event should still be emitted in valiidum mode

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

blockCommitments[blockNumber] = BlockCommitmentInfo(
commitment,
depositLogs
);
);
emit BlockCommitted(commitment);
}

lastCommittedBlock = blockNumber;
emit BlockCommitted(commitment);
}

/// @inheritdoc IOnChainProposer
Expand Down Expand Up @@ -201,10 +216,12 @@ contract OnChainProposer is IOnChainProposer, ReentrancyGuard {
"OnChainProposer: block already verified"
);

require(
blockCommitments[blockNumber].commitmentHash != bytes32(0),
"OnChainProposer: block not committed"
);
if (!VALIDIUM) {
require(
blockCommitments[blockNumber].commitmentHash != bytes32(0),
"OnChainProposer: block not committed"
);
}

if (PICOVERIFIER != DEV_MODE) {
// If the verification fails, it will revert.
Expand Down Expand Up @@ -234,16 +251,18 @@ contract OnChainProposer is IOnChainProposer, ReentrancyGuard {
}

lastVerifiedBlock = blockNumber;
// The first 2 bytes are the number of deposits.
uint16 deposits_amount = uint16(
bytes2(blockCommitments[blockNumber].depositLogs)
);
if (deposits_amount > 0) {
ICommonBridge(BRIDGE).removeDepositLogs(deposits_amount);
}

// Remove previous block commitment as it is no longer needed.
delete blockCommitments[blockNumber - 1];
if (!VALIDIUM) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also here, this should still happen in validium mode

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok! I wasn't sure of that if statement but at moment I thought about not doing it in validium because the commitment that we have is zero. Thanks for pointing it out.
37e106d

// The first 2 bytes are the number of deposits.
uint16 deposits_amount = uint16(
bytes2(blockCommitments[blockNumber].depositLogs)
);
if (deposits_amount > 0) {
ICommonBridge(BRIDGE).removeDepositLogs(deposits_amount);
}
// Remove previous block commitment as it is no longer needed.
delete blockCommitments[blockNumber - 1];
}

emit BlockVerified(blockNumber);
}
Expand Down
109 changes: 72 additions & 37 deletions crates/l2/sequencer/l1_committer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::{
utils::config::{committer::CommitterConfig, errors::ConfigError, eth::EthConfig},
};

use bytes::Bytes;
use ethrex_common::{
types::{
blobs_bundle, fake_exponential_checked, BlobsBundle, BlobsBundleError, Block,
Expand Down Expand Up @@ -39,6 +40,7 @@ pub struct Committer {
interval_ms: u64,
arbitrary_base_blob_gas_price: u64,
execution_cache: Arc<ExecutionCache>,
validium: bool,
}

pub async fn start_l1_committer(
Expand Down Expand Up @@ -70,6 +72,7 @@ impl Committer {
interval_ms: committer_config.interval_ms,
arbitrary_base_blob_gas_price: committer_config.arbitrary_base_blob_gas_price,
execution_cache,
validium: committer_config.validium,
}
}

Expand Down Expand Up @@ -159,7 +162,11 @@ impl Committer {
&account_updates,
)?;

let blobs_bundle = self.generate_blobs_bundle(&state_diff)?;
let blobs_bundle = if !self.validium {
self.generate_blobs_bundle(&state_diff)?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The call to prepare_state_diff can be moved inside the if case since there's no point in computing said state diff in validium mode (at least for now)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's right, I missed that one.
Fixed here

} else {
BlobsBundle::default()
};

let head_block_hash = block_to_commit.hash();
match self
Expand Down Expand Up @@ -356,33 +363,28 @@ impl Committer {
) -> Result<H256, CommitterError> {
info!("Sending commitment for block {block_number}");

let blob_versioned_hashes = blobs_bundle.generate_versioned_hashes();
let commitment_bytes: Bytes = if !self.validium {
let blob_versioned_hashes = blobs_bundle.generate_versioned_hashes();
blob_versioned_hashes
.first()
.ok_or(BlobsBundleError::BlobBundleEmptyError)
.map_err(CommitterError::from)?
.as_fixed_bytes()
.to_vec()
.into()
} else {
Bytes::from(vec![0; 32]) // Validium doesn't need to send commitment.
};

let calldata_values = vec![
Value::Uint(U256::from(block_number)),
Value::FixedBytes(
blob_versioned_hashes
.first()
.ok_or(BlobsBundleError::BlobBundleEmptyError)
.map_err(CommitterError::from)?
.as_fixed_bytes()
.to_vec()
.into(),
),
Value::FixedBytes(commitment_bytes),
Value::FixedBytes(withdrawal_logs_merkle_root.0.to_vec().into()),
Value::FixedBytes(deposit_logs_hash.0.to_vec().into()),
];

let calldata = encode_calldata(COMMIT_FUNCTION_SIGNATURE, &calldata_values)?;

let le_bytes = estimate_blob_gas(
&self.eth_client,
self.arbitrary_base_blob_gas_price,
20, // 20% of headroom
)
.await?
.to_le_bytes();

let gas_price_per_blob = U256::from_little_endian(&le_bytes);
let gas_price = self
.eth_client
.get_gas_price_with_extra(20)
Expand All @@ -392,25 +394,58 @@ impl Committer {
CommitterError::InternalError("Failed to convert gas_price to a u64".to_owned())
})?;

let wrapped_tx = self
.eth_client
.build_eip4844_transaction(
self.on_chain_proposer_address,
self.l1_address,
calldata.into(),
Overrides {
from: Some(self.l1_address),
gas_price_per_blob: Some(gas_price_per_blob),
max_fee_per_gas: Some(gas_price),
max_priority_fee_per_gas: Some(gas_price),
..Default::default()
},
blobs_bundle,
// Validium: EIP1559 Transaction.
// Rollup: EIP4844 Transaction -> For on-chain Data Availability.
let mut tx = if !self.validium {
let le_bytes = estimate_blob_gas(
&self.eth_client,
self.arbitrary_base_blob_gas_price,
20, // 20% of headroom
)
.await
.map_err(CommitterError::from)?;
.await?
.to_le_bytes();

let gas_price_per_blob = U256::from_little_endian(&le_bytes);

let wrapped_tx = self
.eth_client
.build_eip4844_transaction(
self.on_chain_proposer_address,
self.l1_address,
calldata.into(),
Overrides {
from: Some(self.l1_address),
gas_price_per_blob: Some(gas_price_per_blob),
max_fee_per_gas: Some(gas_price),
max_priority_fee_per_gas: Some(gas_price),
..Default::default()
},
blobs_bundle,
)
.await
.map_err(CommitterError::from)?;

WrappedTransaction::EIP4844(wrapped_tx)
} else {
let wrapped_tx = self
.eth_client
.build_eip1559_transaction(
self.on_chain_proposer_address,
self.l1_address,
calldata.into(),
Overrides {
from: Some(self.l1_address),
max_fee_per_gas: Some(gas_price),
max_priority_fee_per_gas: Some(gas_price),
..Default::default()
},
)
.await
.map_err(CommitterError::from)?;

WrappedTransaction::EIP1559(wrapped_tx)
};

let mut tx = WrappedTransaction::EIP4844(wrapped_tx);
self.eth_client
.set_gas_for_wrapped_tx(&mut tx, self.l1_address)
.await?;
Expand Down
1 change: 1 addition & 0 deletions crates/l2/utils/config/committer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ pub struct CommitterConfig {
pub l1_private_key: SecretKey,
pub interval_ms: u64,
pub arbitrary_base_blob_gas_price: u64,
pub validium: bool,
}

impl CommitterConfig {
Expand Down
3 changes: 3 additions & 0 deletions crates/l2/utils/config/toml_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ struct Committer {
l1_private_key: String,
interval_ms: u64,
arbitrary_base_blob_gas_price: u64,
validium: bool,
}

impl Committer {
Expand All @@ -143,12 +144,14 @@ impl Committer {
{prefix}_L1_PRIVATE_KEY={}
{prefix}_INTERVAL_MS={}
{prefix}_ARBITRARY_BASE_BLOB_GAS_PRICE={}
{prefix}_VALIDIUM={}
",
self.on_chain_proposer_address,
self.l1_address,
self.l1_private_key,
self.interval_ms,
self.arbitrary_base_blob_gas_price,
self.validium,
)
}
}
Expand Down