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

Upgradeable batch proof method id lists in light client circuit #1630

Merged
merged 29 commits into from
Dec 25, 2024
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
4e04def
Add DaDataLightClient::BatchProverMethodId transaction
kpp Dec 19, 2024
4ba8ca9
Rename BatchProverMethodId -> BatchProofMethodId
kpp Dec 24, 2024
fd18cbd
Merge branch 'nightly' into kpp/light_client_method_msg
kpp Dec 24, 2024
134f499
Take METHOD_ID_UPGRADE_AUTHORITY from env
kpp Dec 24, 2024
d76156e
Merge branch 'nightly' into kpp/light_client_method_msg
eyusufatik Dec 24, 2024
9004b5f
implement method id upgrades for light client circuit
eyusufatik Dec 24, 2024
c727cd6
Lint
yaziciahmet Dec 24, 2024
14e32bc
Rename DaData to DaTxRequest
yaziciahmet Dec 25, 2024
86d3511
Implemented batch proof method id tx sending
yaziciahmet Dec 25, 2024
f18b011
Use type0 for method id tx
yaziciahmet Dec 25, 2024
3def078
Merge branch 'nightly' into kpp/light_client_method_msg
yaziciahmet Dec 25, 2024
04a43d3
Improve error handling in lcp circuit
yaziciahmet Dec 25, 2024
89494d3
Make method id tx data readable from guest
yaziciahmet Dec 25, 2024
9935337
Added e2e test
yaziciahmet Dec 25, 2024
434df7c
Make testcase default
yaziciahmet Dec 25, 2024
ae6634b
Test one more da block to ensure same method ids are being used
yaziciahmet Dec 25, 2024
71a7e33
Lint
yaziciahmet Dec 25, 2024
0703908
Remove print
yaziciahmet Dec 25, 2024
530770e
Lint
yaziciahmet Dec 25, 2024
92642c0
Fix test
yaziciahmet Dec 25, 2024
341f51d
Separate batch proof method id tx as type 2
yaziciahmet Dec 25, 2024
18e1c56
fix method id tx comments and rename field
eyusufatik Dec 25, 2024
0ca4387
update method id append test in bitcoin-e2e with different method id
eyusufatik Dec 25, 2024
d02cfa2
Add method id tx to crate tests
yaziciahmet Dec 25, 2024
7dc7ce8
Merge branch 'nightly' into kpp/light_client_method_msg
yaziciahmet Dec 25, 2024
88b7beb
Rename da tests
yaziciahmet Dec 25, 2024
cc0eb10
Fix verifier test
yaziciahmet Dec 25, 2024
62c6781
Fix bitcoin verifier test
yaziciahmet Dec 25, 2024
267b23b
Remove TODO comment
yaziciahmet Dec 25, 2024
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
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ byteorder = { version = "1.5.0", default-features = false }
bytes = { version = "1.2.1", default-features = false }
chrono = { version = "0.4.37", default-features = false }
clap = { version = "4.4.10", features = ["derive"] }
const-hex = "1.12"
crypto-bigint = { version = "0.5.5" }
digest = { version = "0.10.6", default-features = false, features = ["alloc"] }
derive_more = { version = "0.99.11", default-features = false }
Expand Down
4 changes: 2 additions & 2 deletions bin/citrea/src/rollup/bitcoin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use sov_modules_api::{Address, SpecId, Zkvm};
use sov_modules_rollup_blueprint::RollupBlueprint;
use sov_prover_storage_manager::{ProverStorageManager, SnapshotManager};
use sov_rollup_interface::da::DaVerifier;
use sov_rollup_interface::services::da::SenderWithNotifier;
use sov_rollup_interface::services::da::TxRequestWithNotifier;
use sov_state::ProverStorage;
use sov_stf_runner::ProverGuestRunConfig;
use tokio::sync::broadcast;
Expand Down Expand Up @@ -118,7 +118,7 @@ impl RollupBlueprint for BitcoinRollup {
require_wallet_check: bool,
task_manager: &mut TaskManager<()>,
) -> Result<Arc<Self::DaService>, anyhow::Error> {
let (tx, rx) = unbounded_channel::<SenderWithNotifier<TxidWrapper>>();
let (tx, rx) = unbounded_channel::<TxRequestWithNotifier<TxidWrapper>>();

let bitcoin_service = if require_wallet_check {
BitcoinService::new_with_wallet_check(
Expand Down
4 changes: 2 additions & 2 deletions bin/citrea/tests/bitcoin_e2e/batch_prover_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use citrea_e2e::traits::NodeT;
use citrea_e2e::Result;
use citrea_primitives::{TO_BATCH_PROOF_PREFIX, TO_LIGHT_CLIENT_PREFIX};
use sov_ledger_rpc::LedgerRpcClient;
use sov_rollup_interface::da::{DaData, SequencerCommitment};
use sov_rollup_interface::da::{DaTxRequest, SequencerCommitment};
use sov_rollup_interface::rpc::VerifiedBatchProofResponse;
use tokio::time::sleep;

Expand Down Expand Up @@ -273,7 +273,7 @@ impl TestCase for SkipPreprovenCommitmentsTest {
// Send the same commitment that was already proven.
bitcoin_da_service
.send_transaction_with_fee_rate(
DaData::SequencerCommitment(commitments.first().unwrap().clone()),
DaTxRequest::SequencerCommitment(commitments.first().unwrap().clone()),
1,
)
.await
Expand Down
252 changes: 251 additions & 1 deletion bin/citrea/tests/bitcoin_e2e/light_client_test.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
use std::sync::Arc;
use std::time::Duration;

use alloy_primitives::U64;
use async_trait::async_trait;
use bitcoin_da::service::FINALITY_DEPTH;
use bitcoin_da::service::{BitcoinService, BitcoinServiceConfig, FINALITY_DEPTH};
use bitcoin_da::spec::RollupParams;
use citrea_batch_prover::rpc::BatchProverRpcClient;
use citrea_batch_prover::GroupCommitments;
use citrea_common::tasks::manager::TaskManager;
use citrea_e2e::config::{
BatchProverConfig, LightClientProverConfig, SequencerConfig, SequencerMempoolConfig,
TestCaseConfig,
};
use citrea_e2e::framework::TestFramework;
use citrea_e2e::node::NodeKind;
use citrea_e2e::test_case::{TestCase, TestCaseRunner};
use citrea_e2e::Result;
use citrea_light_client_prover::rpc::LightClientProverRpcClient;
use citrea_primitives::{TO_BATCH_PROOF_PREFIX, TO_LIGHT_CLIENT_PREFIX};
use sov_ledger_rpc::LedgerRpcClient;
use sov_rollup_interface::da::{BatchProofMethodId, DaTxRequest};

use super::batch_prover_test::wait_for_zkproofs;
use super::get_citrea_path;
Expand Down Expand Up @@ -433,3 +439,247 @@ async fn test_light_client_proving_multiple_proofs() -> Result<()> {
.run()
.await
}

#[derive(Default)]
struct LightClientBatchProofMethodIdUpdateTest {
task_manager: TaskManager<()>,
}

#[async_trait]
impl TestCase for LightClientBatchProofMethodIdUpdateTest {
fn test_config() -> TestCaseConfig {
TestCaseConfig {
with_sequencer: true,
with_batch_prover: true,
with_light_client_prover: true,
..Default::default()
}
}

fn sequencer_config() -> SequencerConfig {
SequencerConfig {
min_soft_confirmations_per_commitment: 2,
da_update_interval_ms: 500,
..Default::default()
}
}

fn batch_prover_config() -> BatchProverConfig {
BatchProverConfig {
enable_recovery: false,
..Default::default()
}
}

fn light_client_prover_config() -> LightClientProverConfig {
LightClientProverConfig {
enable_recovery: false,
initial_da_height: 171,
..Default::default()
}
}

async fn cleanup(&self) -> Result<()> {
self.task_manager.abort().await;
Ok(())
}

async fn run_test(&mut self, f: &mut TestFramework) -> Result<()> {
let da = f.bitcoin_nodes.get(0).unwrap();
let sequencer = f.sequencer.as_ref().unwrap();
let batch_prover = f.batch_prover.as_ref().unwrap();
let light_client_prover = f.light_client_prover.as_ref().unwrap();

let da_config = &da.config;
let bitcoin_da_service_config = BitcoinServiceConfig {
node_url: format!(
"http://127.0.0.1:{}/wallet/{}",
da_config.rpc_port,
NodeKind::Bitcoin
),
node_username: da_config.rpc_user.clone(),
node_password: da_config.rpc_password.clone(),
network: bitcoin::Network::Regtest,
da_private_key: Some(
// This is a random private key matching guest's METHOD_ID_UPGRADE_AUTHORITY
"79122E48DF1A002FB6584B2E94D0D50F95037416C82DAF280F21CD67D17D9077".to_string(),
),
tx_backup_dir: Self::test_config()
.dir
.join("tx_backup_dir")
.display()
.to_string(),
monitoring: Default::default(),
mempool_space_url: None,
};
let (tx, rx) = tokio::sync::mpsc::unbounded_channel();

let bitcoin_da_service = Arc::new(
BitcoinService::new_with_wallet_check(
bitcoin_da_service_config,
RollupParams {
to_light_client_prefix: TO_LIGHT_CLIENT_PREFIX.to_vec(),
to_batch_proof_prefix: TO_BATCH_PROOF_PREFIX.to_vec(),
},
tx,
)
.await
.unwrap(),
);

self.task_manager
.spawn(|tk| bitcoin_da_service.clone().run_da_queue(rx, tk));

let min_soft_confirmations_per_commitment =
sequencer.min_soft_confirmations_per_commitment();

// publish min_soft_confirmations_per_commitment confirmations
for _ in 0..min_soft_confirmations_per_commitment {
sequencer.client.send_publish_batch_request().await?;
}
sequencer
.wait_for_l2_height(min_soft_confirmations_per_commitment, None)
.await?;

// Wait for commitment tx to be submitted to DA
da.wait_mempool_len(2, Some(TEN_MINS)).await?;

// Finalize the DA block which contains the commitment tx
da.generate(FINALITY_DEPTH).await?;

let commitment_l1_height = da.get_finalized_height().await?;

// Wait for batch prover to generate proof for commitment
batch_prover
.wait_for_l1_height(commitment_l1_height, Some(TEN_MINS))
.await
.unwrap();

// Assert that commitment is queryable
let commitments = batch_prover
.client
.http_client()
.get_sequencer_commitments_on_slot_by_number(U64::from(commitment_l1_height))
.await
.unwrap()
.unwrap();
assert_eq!(commitments.len(), 1);

// Ensure that batch proof is submitted to DA
da.wait_mempool_len(2, Some(TEN_MINS)).await?;

// Finalize the DA block which contains the batch proof tx
da.generate(FINALITY_DEPTH).await?;

let batch_proof_l1_height = da.get_finalized_height().await?;

// Wait for light client prover to process batch proofs.
light_client_prover
.wait_for_l1_height(batch_proof_l1_height, Some(TEN_MINS))
.await
.unwrap();

// Expect light client prover to have generated light client proof
let lcp = light_client_prover
.client
.http_client()
.get_light_client_proof_by_l1_height(batch_proof_l1_height)
.await?;
let lcp_output = lcp.unwrap().light_client_proof_output;
// Verify the current batch proof method ids
assert_eq!(
lcp_output.batch_proof_method_ids,
vec![(0, citrea_risc0_batch_proof::BATCH_PROOF_BITCOIN_ID)],
);

// Send BatchProofMethodId transaction to da
let new_batch_proof_method_id = [1u32; 8];
bitcoin_da_service
.send_transaction_with_fee_rate(
DaTxRequest::BatchProofMethodId(BatchProofMethodId {
method_id: new_batch_proof_method_id,
activation_l2_height: 100,
}),
1,
)
.await
.unwrap();

// Ensure that method id tx is submitted to DA
da.wait_mempool_len(2, Some(TEN_MINS)).await?;

// Finalize the DA block which contains the method id tx
da.generate(FINALITY_DEPTH).await?;

let method_id_l1_height = da.get_finalized_height().await?;

// Wait for light client prover to process method id update
light_client_prover
.wait_for_l1_height(method_id_l1_height, Some(TEN_MINS))
.await
.unwrap();

// Assert that 1 l1 block before method id tx, still has the same batch proof method ids
let lcp = light_client_prover
.client
.http_client()
.get_light_client_proof_by_l1_height(method_id_l1_height - 1)
.await?;
let lcp_output = lcp.unwrap().light_client_proof_output;
// Verify the current batch proof method ids
assert_eq!(
lcp_output.batch_proof_method_ids,
vec![(0, citrea_risc0_batch_proof::BATCH_PROOF_BITCOIN_ID)],
);

// Assert that method ids are updated
let lcp = light_client_prover
.client
.http_client()
.get_light_client_proof_by_l1_height(method_id_l1_height)
.await?;
let lcp_output = lcp.unwrap().light_client_proof_output;
// Verify the current batch proof method ids
assert_eq!(
lcp_output.batch_proof_method_ids,
vec![
(0, citrea_risc0_batch_proof::BATCH_PROOF_BITCOIN_ID),
(100, new_batch_proof_method_id)
],
);

// Generate one more empty l1 block
da.generate(1).await?;

// Wait for light client to process it
light_client_prover
.wait_for_l1_height(method_id_l1_height + 1, None)
.await
.unwrap();

// Verify that previously updated method ids are being used
let lcp = light_client_prover
.client
.http_client()
.get_light_client_proof_by_l1_height(method_id_l1_height + 1)
.await?;
let lcp_output = lcp.unwrap().light_client_proof_output;
assert_eq!(
lcp_output.batch_proof_method_ids,
vec![
(0, citrea_risc0_batch_proof::BATCH_PROOF_BITCOIN_ID),
(100, new_batch_proof_method_id)
],
);

Ok(())
}
}

#[tokio::test]
async fn test_light_client_batch_proof_method_id_update() -> Result<()> {
TestCaseRunner::new(LightClientBatchProofMethodIdUpdateTest::default())
.set_citrea_path(get_citrea_path())
.run()
.await
}
8 changes: 4 additions & 4 deletions bin/citrea/tests/bitcoin_e2e/sequencer_commitments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use citrea_primitives::TO_BATCH_PROOF_PREFIX;
use rs_merkle::algorithms::Sha256;
use rs_merkle::MerkleTree;
use sov_ledger_rpc::LedgerRpcClient;
use sov_rollup_interface::da::{BlobReaderTrait, DaData};
use sov_rollup_interface::da::{BlobReaderTrait, DaTxRequest};
use sov_rollup_interface::rpc::SequencerCommitmentResponse;
use tokio::time::sleep;

Expand Down Expand Up @@ -309,11 +309,11 @@ impl SequencerSendCommitmentsToDaTest {

let data = BlobReaderTrait::full_data(&mut blob);

let commitment = DaData::try_from_slice(data).unwrap();
let commitment = DaTxRequest::try_from_slice(data).unwrap();

matches!(commitment, DaData::SequencerCommitment(_));
matches!(commitment, DaTxRequest::SequencerCommitment(_));

let DaData::SequencerCommitment(commitment) = commitment else {
let DaTxRequest::SequencerCommitment(commitment) = commitment else {
panic!("Expected SequencerCommitment, got {:?}", commitment);
};

Expand Down
8 changes: 4 additions & 4 deletions bin/citrea/tests/test_helpers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use sov_mock_da::{MockAddress, MockBlock, MockDaConfig, MockDaService};
use sov_modules_api::default_signature::private_key::DefaultPrivateKey;
use sov_modules_api::PrivateKey;
use sov_modules_rollup_blueprint::RollupBlueprint as _;
use sov_rollup_interface::da::{BlobReaderTrait, DaData, SequencerCommitment};
use sov_rollup_interface::da::{BlobReaderTrait, DaTxRequest, SequencerCommitment};
use sov_rollup_interface::services::da::{DaService, SlotData};
use sov_rollup_interface::zk::Proof;
use sov_rollup_interface::Network;
Expand Down Expand Up @@ -362,10 +362,10 @@ fn extract_da_data(
.extract_relevant_blobs(&block)
.into_iter()
.for_each(|mut tx| {
let data = DaData::try_from_slice(tx.full_data());
if let Ok(DaData::SequencerCommitment(seq_com)) = data {
let data = DaTxRequest::try_from_slice(tx.full_data());
if let Ok(DaTxRequest::SequencerCommitment(seq_com)) = data {
sequencer_commitments.push(seq_com);
} else if let Ok(DaData::ZKProof(proof)) = data {
} else if let Ok(DaTxRequest::ZKProof(proof)) = data {
zk_proofs.push(proof);
} else {
tracing::warn!(
Expand Down
Loading
Loading