diff --git a/Cargo.lock b/Cargo.lock index 0c850f8b0..8050443d5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1829,7 +1829,7 @@ dependencies = [ [[package]] name = "citrea-e2e" version = "0.1.0" -source = "git+https://github.com/chainwayxyz/citrea-e2e?rev=bd8ece7#bd8ece76b5e57bef6efa55fcdd758c0f59e05833" +source = "git+https://github.com/chainwayxyz/citrea-e2e?rev=07914ec#07914ecfc5ce4ae0006faa4b359e086523e2513e" dependencies = [ "anyhow", "async-trait", @@ -1842,8 +1842,8 @@ dependencies = [ "rand 0.8.5", "serde", "serde_json", - "sov-ledger-rpc 0.5.0-rc.1 (git+https://github.com/chainwayxyz/citrea?rev=ab6b5dd)", - "sov-rollup-interface 0.5.0-rc.1 (git+https://github.com/chainwayxyz/citrea?rev=ab6b5dd)", + "sov-ledger-rpc 0.5.0-rc.1 (git+https://github.com/chainwayxyz/citrea?rev=a043984)", + "sov-rollup-interface 0.5.0-rc.1 (git+https://github.com/chainwayxyz/citrea?rev=a043984)", "tempfile", "tokio", "toml", @@ -5002,7 +5002,6 @@ dependencies = [ "parking_lot", "rand 0.8.5", "rayon", - "risc0-zkvm", "rs_merkle", "serde", "sha2", @@ -7323,11 +7322,11 @@ dependencies = [ [[package]] name = "sov-ledger-rpc" version = "0.5.0-rc.1" -source = "git+https://github.com/chainwayxyz/citrea?rev=ab6b5dd#ab6b5ddf0645f5b61486259845f1bdf62a22ded3" +source = "git+https://github.com/chainwayxyz/citrea?rev=a043984#a0439843a37801331279869a2eb57d985e2d296f" dependencies = [ "jsonrpsee", "serde", - "sov-rollup-interface 0.5.0-rc.1 (git+https://github.com/chainwayxyz/citrea?rev=ab6b5dd)", + "sov-rollup-interface 0.5.0-rc.1 (git+https://github.com/chainwayxyz/citrea?rev=a043984)", ] [[package]] @@ -7525,7 +7524,7 @@ dependencies = [ [[package]] name = "sov-rollup-interface" version = "0.5.0-rc.1" -source = "git+https://github.com/chainwayxyz/citrea?rev=ab6b5dd#ab6b5ddf0645f5b61486259845f1bdf62a22ded3" +source = "git+https://github.com/chainwayxyz/citrea?rev=a043984#a0439843a37801331279869a2eb57d985e2d296f" dependencies = [ "anyhow", "async-trait", @@ -7849,18 +7848,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.67" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3c6efbfc763e64eb85c11c25320f0737cb7364c4b6336db90aa9ebe27a0bbd" +checksum = "5d171f59dbaa811dbbb1aee1e73db92ec2b122911a48e1390dfe327a821ddede" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.67" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b607164372e89797d78b8e23a6d67d5d1038c1c65efd52e1389ef8b77caba2a6" +checksum = "b08be0f17bd307950653ce45db00cd31200d82b624b36e181337d9c7d92765b5" dependencies = [ "proc-macro2", "quote", diff --git a/bin/citrea/Cargo.toml b/bin/citrea/Cargo.toml index 903fc0c64..03a3a25b2 100644 --- a/bin/citrea/Cargo.toml +++ b/bin/citrea/Cargo.toml @@ -89,7 +89,7 @@ rustc_version_runtime = { workspace = true } # bitcoin-e2e dependencies bitcoin.workspace = true bitcoincore-rpc.workspace = true -citrea-e2e = { git = "https://github.com/chainwayxyz/citrea-e2e", rev = "bd8ece7" } +citrea-e2e = { git = "https://github.com/chainwayxyz/citrea-e2e", rev = "07914ec" } [build-dependencies] sp1-helper = { version = "3.0.0", default-features = false } diff --git a/bin/citrea/tests/bitcoin_e2e/bitcoin_test.rs b/bin/citrea/tests/bitcoin_e2e/bitcoin_test.rs index 024dee6e8..94f223887 100644 --- a/bin/citrea/tests/bitcoin_e2e/bitcoin_test.rs +++ b/bin/citrea/tests/bitcoin_e2e/bitcoin_test.rs @@ -43,7 +43,7 @@ impl TestCase for BasicSyncTest { // Sync both nodes f.bitcoin_nodes - .wait_for_sync(Duration::from_secs(30)) + .wait_for_sync(Some(Duration::from_secs(30))) .await?; let height0 = da0.get_block_count().await?; diff --git a/bin/citrea/tests/e2e/mod.rs b/bin/citrea/tests/e2e/mod.rs index 0f7d9bec8..0bec8150d 100644 --- a/bin/citrea/tests/e2e/mod.rs +++ b/bin/citrea/tests/e2e/mod.rs @@ -189,7 +189,7 @@ async fn test_all_flow() { assert_eq!(commitments_hash, commitments); let prover_proof = prover_node_test_client - .ledger_get_proofs_by_slot_height(3) + .ledger_get_batch_proofs_by_slot_height(3) .await[0] .clone(); @@ -203,7 +203,7 @@ async fn test_all_flow() { // So the full node should see the proof in block 5 wait_for_proof(&full_node_test_client, 4, Some(Duration::from_secs(120))).await; let full_node_proof = full_node_test_client - .ledger_get_verified_proofs_by_slot_height(4) + .ledger_get_verified_batch_proofs_by_slot_height(4) .await .unwrap(); @@ -211,7 +211,7 @@ async fn test_all_flow() { proof: last_proof, height: proof_l1_height, } = full_node_test_client - .ledger_get_last_verified_proof() + .ledger_get_last_verified_batch_proof() .await .unwrap(); @@ -289,13 +289,13 @@ async fn test_all_flow() { assert_eq!(commitments.len(), 1); let prover_proof_data = prover_node_test_client - .ledger_get_proofs_by_slot_height(5) + .ledger_get_batch_proofs_by_slot_height(5) .await[0] .clone(); wait_for_proof(&full_node_test_client, 6, Some(Duration::from_secs(120))).await; let full_node_proof_data = full_node_test_client - .ledger_get_verified_proofs_by_slot_height(6) + .ledger_get_verified_batch_proofs_by_slot_height(6) .await .unwrap(); @@ -303,7 +303,7 @@ async fn test_all_flow() { proof: last_proof, height: proof_l1_height, } = full_node_test_client - .ledger_get_last_verified_proof() + .ledger_get_last_verified_batch_proof() .await .unwrap(); assert_eq!(proof_l1_height, 6); diff --git a/bin/citrea/tests/e2e/proving.rs b/bin/citrea/tests/e2e/proving.rs index f935f9737..c7b5c93d2 100644 --- a/bin/citrea/tests/e2e/proving.rs +++ b/bin/citrea/tests/e2e/proving.rs @@ -141,7 +141,7 @@ async fn full_node_verify_proof_and_store() { assert_eq!(commitments_hash, commitments); let prover_proof = prover_node_test_client - .ledger_get_proofs_by_slot_height(3) + .ledger_get_batch_proofs_by_slot_height(3) .await[0] .clone(); @@ -160,7 +160,7 @@ async fn full_node_verify_proof_and_store() { // So the full node should see the proof in block 4 wait_for_proof(&full_node_test_client, 4, Some(Duration::from_secs(60))).await; let full_node_proof = full_node_test_client - .ledger_get_verified_proofs_by_slot_height(4) + .ledger_get_verified_batch_proofs_by_slot_height(4) .await .unwrap(); assert_eq!(prover_proof.proof, full_node_proof[0].proof); @@ -319,7 +319,7 @@ async fn test_prover_prove_rpc() { assert_eq!(commitments_hash, commitments); let prover_proof = prover_node_test_client - .ledger_get_proofs_by_slot_height(3) + .ledger_get_batch_proofs_by_slot_height(3) .await[0] .clone(); @@ -338,7 +338,7 @@ async fn test_prover_prove_rpc() { // So the full node should see the proof in block 4 wait_for_proof(&full_node_test_client, 4, Some(Duration::from_secs(60))).await; let full_node_proof = full_node_test_client - .ledger_get_verified_proofs_by_slot_height(4) + .ledger_get_verified_batch_proofs_by_slot_height(4) .await .unwrap(); assert_eq!(prover_proof.proof, full_node_proof[0].proof); diff --git a/bin/citrea/tests/test_client/mod.rs b/bin/citrea/tests/test_client/mod.rs index 426b3945c..c883499f9 100644 --- a/bin/citrea/tests/test_client/mod.rs +++ b/bin/citrea/tests/test_client/mod.rs @@ -20,7 +20,7 @@ use reth_rpc_types::trace::geth::{GethDebugTracingOptions, GethTrace}; use reth_rpc_types::RichBlock; use sequencer_client::GetSoftConfirmationResponse; use sov_rollup_interface::rpc::{ - LastVerifiedProofResponse, ProofResponse, SequencerCommitmentResponse, + BatchProofResponse, LastVerifiedProofResponse, SequencerCommitmentResponse, SoftConfirmationResponse, SoftConfirmationStatus, VerifiedProofResponse, }; @@ -533,26 +533,34 @@ impl TestClient { .map_err(|e| e.into()) } - pub(crate) async fn ledger_get_proofs_by_slot_height(&self, height: u64) -> Vec { + pub(crate) async fn ledger_get_batch_proofs_by_slot_height( + &self, + height: u64, + ) -> Vec { self.http_client - .request("ledger_getProofsBySlotHeight", rpc_params![height]) + .request("ledger_getBatchProofsBySlotHeight", rpc_params![height]) .await .unwrap() } - pub(crate) async fn ledger_get_verified_proofs_by_slot_height( + pub(crate) async fn ledger_get_verified_batch_proofs_by_slot_height( &self, height: u64, ) -> Option> { self.http_client - .request("ledger_getVerifiedProofsBySlotHeight", rpc_params![height]) + .request( + "ledger_getVerifiedBatchProofsBySlotHeight", + rpc_params![height], + ) .await .ok() } - pub(crate) async fn ledger_get_last_verified_proof(&self) -> Option { + pub(crate) async fn ledger_get_last_verified_batch_proof( + &self, + ) -> Option { self.http_client - .request("ledger_getLastVerifiedProof", rpc_params![]) + .request("ledger_getLastVerifiedBatchProof", rpc_params![]) .await .ok() } diff --git a/bin/citrea/tests/test_helpers/mod.rs b/bin/citrea/tests/test_helpers/mod.rs index 3476d7bcf..97c1ae266 100644 --- a/bin/citrea/tests/test_helpers/mod.rs +++ b/bin/citrea/tests/test_helpers/mod.rs @@ -308,7 +308,7 @@ pub async fn wait_for_proof(test_client: &TestClient, slot_height: u64, timeout: slot_height ); let proof = test_client - .ledger_get_verified_proofs_by_slot_height(slot_height) + .ledger_get_verified_batch_proofs_by_slot_height(slot_height) .await; if proof.is_some() { break; diff --git a/crates/batch-prover/src/proving.rs b/crates/batch-prover/src/proving.rs index 575192877..1bfd5efed 100644 --- a/crates/batch-prover/src/proving.rs +++ b/crates/batch-prover/src/proving.rs @@ -10,12 +10,12 @@ use citrea_common::utils::{check_l2_range_exists, filter_out_proven_commitments} use serde::de::DeserializeOwned; use serde::Serialize; use sov_db::ledger_db::BatchProverLedgerOps; -use sov_db::schema::types::{BatchNumber, StoredProof, StoredStateTransition}; +use sov_db::schema::types::{BatchNumber, StoredBatchProof, StoredStateTransition}; use sov_modules_api::{BlobReaderTrait, SlotData, SpecId, Zkvm}; use sov_rollup_interface::da::{BlockHeaderTrait, DaNamespace, DaSpec, SequencerCommitment}; use sov_rollup_interface::rpc::SoftConfirmationStatus; use sov_rollup_interface::services::da::DaService; -use sov_rollup_interface::zk::{Proof, StateTransitionData, ZkvmHost}; +use sov_rollup_interface::zk::{Proof, StateTransition, StateTransitionData, ZkvmHost}; use sov_stf_runner::ProverService; use tokio::sync::Mutex; use tracing::{debug, info}; @@ -250,7 +250,7 @@ where pub(crate) fn state_transition_already_proven( state_transition: &StateTransitionData, - proofs: &Vec, + proofs: &Vec, ) -> bool where Da: DaService, @@ -296,9 +296,12 @@ where let tx_id_u8 = tx_id.into(); // l1_height => (tx_id, proof, transition_data) - // save proof along with tx id to db, should be queriable by slot number or slot hash - let transition_data = Vm::extract_output::<::Spec, StateRoot>(&proof) - .expect("Proof should be deserializable"); + // save proof along with tx id to db, should be queryable by slot number or slot hash + let transition_data = Vm::extract_output::< + ::Spec, + StateTransition<::Spec, StateRoot>, + >(&proof) + .expect("Proof should be deserializable"); info!("Verifying proof!"); @@ -327,7 +330,7 @@ where .get_l1_height_of_l1_hash(slot_hash)? .expect("l1 height should exist"); - if let Err(e) = ledger_db.insert_proof_data_by_l1_height( + if let Err(e) = ledger_db.insert_batch_proof_data_by_l1_height( l1_height, tx_id_u8, proof, diff --git a/crates/fullnode/src/da_block_handler.rs b/crates/fullnode/src/da_block_handler.rs index c34e69876..dc371db8c 100644 --- a/crates/fullnode/src/da_block_handler.rs +++ b/crates/fullnode/src/da_block_handler.rs @@ -22,7 +22,7 @@ use sov_rollup_interface::da::{BlockHeaderTrait, SequencerCommitment}; use sov_rollup_interface::rpc::SoftConfirmationStatus; use sov_rollup_interface::services::da::{DaService, SlotData}; use sov_rollup_interface::spec::SpecId; -use sov_rollup_interface::zk::{Proof, ZkvmHost}; +use sov_rollup_interface::zk::{Proof, StateTransition, ZkvmHost}; use tokio::select; use tokio::sync::{mpsc, Mutex}; use tokio::time::{sleep, Duration}; @@ -296,8 +296,11 @@ where ); tracing::debug!("ZK proof: {:?}", proof); - let state_transition = Vm::extract_output::<::Spec, StateRoot>(&proof) - .expect("Proof should be deserializable"); + let state_transition = Vm::extract_output::< + ::Spec, + StateTransition<::Spec, StateRoot>, + >(&proof) + .expect("Proof should be deserializable"); if state_transition.sequencer_da_public_key != self.sequencer_da_pub_key || state_transition.sequencer_public_key != self.sequencer_pub_key { diff --git a/crates/light-client-prover/src/circuit.rs b/crates/light-client-prover/src/circuit.rs index e2048326c..89c95cde7 100644 --- a/crates/light-client-prover/src/circuit.rs +++ b/crates/light-client-prover/src/circuit.rs @@ -1,10 +1,7 @@ use borsh::BorshDeserialize; use sov_modules_api::BlobReaderTrait; use sov_rollup_interface::da::{DaDataLightClient, DaNamespace, DaVerifier}; -use sov_rollup_interface::zk::ZkvmGuest; - -use crate::input::LightClientCircuitInput; -use crate::output::LightClientCircuitOutput; +use sov_rollup_interface::zk::{LightClientCircuitInput, LightClientCircuitOutput, ZkvmGuest}; #[derive(Debug)] pub enum LightClientVerificationError { @@ -17,6 +14,24 @@ pub fn run_circuit( ) -> Result { let input: LightClientCircuitInput = guest.read_from_host(); + // Start by verifying the previous light client proof + // If this is the first light client proof, skip this step + if let Some(light_client_proof_journal) = input.light_client_proof_journal { + let deserialized_previous_light_client_proof_journal = + G::verify_and_extract_output::( + &light_client_proof_journal, + &input.light_client_proof_method_id.into(), + ) + .expect("Should have verified the light client proof"); + + // TODO: Once we implement light client method id by spec update this to do the right checks + // Assert that the output method id and the input method id are the same + assert_eq!( + input.light_client_proof_method_id, + deserialized_previous_light_client_proof_journal.light_client_proof_method_id + ); + } + // Verify data from da let _validity_condition = da_verifier .verify_transactions( @@ -61,6 +76,7 @@ pub fn run_circuit( Ok(LightClientCircuitOutput { state_root: [1; 32], + light_client_proof_method_id: input.light_client_proof_method_id, }) // First diff --git a/crates/light-client-prover/src/da_block_handler.rs b/crates/light-client-prover/src/da_block_handler.rs index 3957bc0dd..650eeea0e 100644 --- a/crates/light-client-prover/src/da_block_handler.rs +++ b/crates/light-client-prover/src/da_block_handler.rs @@ -5,13 +5,16 @@ use borsh::BorshDeserialize; use citrea_common::cache::L1BlockCache; use citrea_common::da::get_da_block_at_height; use citrea_common::LightClientProverConfig; +use sequencer_client::SequencerClient; use sov_db::ledger_db::{LightClientProverLedgerOps, SharedLedgerOps}; use sov_db::schema::types::SlotNumber; use sov_modules_api::{BlobReaderTrait, DaSpec, Zkvm}; use sov_rollup_interface::da::{BlockHeaderTrait, DaDataLightClient, DaNamespace}; use sov_rollup_interface::services::da::{DaService, SlotData}; use sov_rollup_interface::spec::SpecId; -use sov_rollup_interface::zk::ZkvmHost; +use sov_rollup_interface::zk::{ + LightClientCircuitInput, LightClientCircuitOutput, Proof, ZkvmHost, +}; use sov_stf_runner::ProverService; use tokio::select; use tokio::sync::{mpsc, Mutex}; @@ -19,9 +22,6 @@ use tokio::time::{sleep, Duration}; use tokio_util::sync::CancellationToken; use tracing::{error, info}; -use crate::input::LightClientCircuitInput; -use crate::output::LightClientCircuitOutput; - pub(crate) struct L1BlockHandler where Da: DaService, @@ -35,9 +35,10 @@ where da_service: Arc, batch_prover_da_pub_key: Vec, batch_proof_code_commitments_by_spec: HashMap, - _light_client_proof_code_commitment: Vm::CodeCommitment, + light_client_proof_code_commitment: Vm::CodeCommitment, l1_block_cache: Arc>>, queued_l1_blocks: VecDeque<::FilteredBlock>, + sequencer_client: Arc, } impl L1BlockHandler @@ -56,6 +57,7 @@ where batch_prover_da_pub_key: Vec, batch_proof_code_commitments_by_spec: HashMap, light_client_proof_code_commitment: Vm::CodeCommitment, + sequencer_client: Arc, ) -> Self { Self { _prover_config: prover_config, @@ -64,9 +66,10 @@ where da_service, batch_prover_da_pub_key, batch_proof_code_commitments_by_spec, - _light_client_proof_code_commitment: light_client_proof_code_commitment, + light_client_proof_code_commitment, l1_block_cache: Arc::new(Mutex::new(L1BlockCache::new())), queued_l1_blocks: VecDeque::new(), + sequencer_client, } } @@ -155,13 +158,13 @@ where .expect("Batch proof code commitment not found"); let mut assumptions = vec![]; - let mut journals = vec![]; + let mut batch_proof_journals = vec![]; for batch_proof in batch_proofs { if let DaDataLightClient::Complete(proof) = batch_proof { match Vm::verify(proof.as_slice(), batch_proof_method_id) { Ok(output) => { assumptions.push(proof); - journals.push(output); + batch_proof_journals.push(output); } Err(e) => { tracing::error!("Failed to verify batch proof: {:?}", e); @@ -170,6 +173,42 @@ where } } } + let previous_l1_height = l1_height - 1; + let mut light_client_proof_journal = None; + match self + .ledger_db + .get_light_client_proof_data_by_l1_height(previous_l1_height)? + { + Some(data) => { + let proof = data.proof; + let output = data.light_client_circuit_output; + assumptions.push(proof); + light_client_proof_journal = Some(borsh::to_vec(&output)?); + } + None => { + let initial_l1_height = self + .sequencer_client + .get_soft_confirmation::(1) + .await? + .unwrap() + .da_slot_height; + // If the prev block is the block before the first processed l1 block + // then we don't have a previous light client proof, so just give an info + if previous_l1_height == initial_l1_height { + tracing::info!( + "No previous light client proof found for L1 block: {}", + previous_l1_height + ); + } + // If not then we have a problem + else { + panic!( + "No previous light client proof found for L1 block: {}", + previous_l1_height + ); + } + } + } let circuit_input = LightClientCircuitInput { da_data, @@ -178,16 +217,28 @@ where da_block_header: l1_block.header().clone(), batch_prover_da_pub_key: self.batch_prover_da_pub_key.clone(), batch_proof_method_id: batch_proof_method_id.clone().into(), - batch_proof_journals: journals, + batch_proof_journals, + light_client_proof_method_id: self.light_client_proof_code_commitment.clone().into(), + + light_client_proof_journal, }; - let circuit_output = self.prove(circuit_input, assumptions).await?; + let proof = self.prove(circuit_input, assumptions).await?; + + let circuit_output = Vm::extract_output::(&proof) + .expect("Should deserialize valid proof"); tracing::info!( "Generated proof for L1 block: {l1_height} output={:?}", circuit_output ); + self.ledger_db.insert_light_client_proof_data_by_l1_height( + l1_height, + proof, + circuit_output, + )?; + self.ledger_db .set_last_scanned_l1_height(SlotNumber(l1_block.header().height())) .expect("Saving last scanned l1 height to ledger db"); @@ -226,7 +277,7 @@ where &self, circuit_input: LightClientCircuitInput<::Spec>, assumptions: Vec>, - ) -> Result { + ) -> Result { let prover_service = self.prover_service.as_ref(); prover_service @@ -235,11 +286,9 @@ where let proofs = self.prover_service.prove().await?; - // Light client always does proving one-by-one, so its ok to get the first element - self.prover_service - .extract_output(proofs) - .await - .map(|mut outputs| outputs.remove(0)) + assert_eq!(proofs.len(), 1); + + Ok(proofs[0].clone()) } } diff --git a/crates/light-client-prover/src/input.rs b/crates/light-client-prover/src/input.rs deleted file mode 100644 index 5be36f8ca..000000000 --- a/crates/light-client-prover/src/input.rs +++ /dev/null @@ -1,14 +0,0 @@ -use borsh::{BorshDeserialize, BorshSerialize}; -use sov_rollup_interface::da::DaSpec; - -#[derive(BorshDeserialize, BorshSerialize)] -pub struct LightClientCircuitInput { - pub da_data: Vec, - pub inclusion_proof: Da::InclusionMultiProof, - pub completeness_proof: Da::CompletenessProof, - pub da_block_header: Da::BlockHeader, - - pub batch_prover_da_pub_key: Vec, - pub batch_proof_method_id: [u32; 8], - pub batch_proof_journals: Vec>, -} diff --git a/crates/light-client-prover/src/lib.rs b/crates/light-client-prover/src/lib.rs index 5a88f394d..95241462f 100644 --- a/crates/light-client-prover/src/lib.rs +++ b/crates/light-client-prover/src/lib.rs @@ -1,7 +1,4 @@ pub mod circuit; -pub mod input; -pub mod output; - #[cfg(feature = "native")] pub mod da_block_handler; #[cfg(feature = "native")] diff --git a/crates/light-client-prover/src/output.rs b/crates/light-client-prover/src/output.rs deleted file mode 100644 index 8b5e353d0..000000000 --- a/crates/light-client-prover/src/output.rs +++ /dev/null @@ -1,6 +0,0 @@ -use borsh::{BorshDeserialize, BorshSerialize}; - -#[derive(Debug, Clone, BorshDeserialize, BorshSerialize)] -pub struct LightClientCircuitOutput { - pub state_root: [u8; 32], -} diff --git a/crates/light-client-prover/src/runner.rs b/crates/light-client-prover/src/runner.rs index 901b53e58..9ff13e182 100644 --- a/crates/light-client-prover/src/runner.rs +++ b/crates/light-client-prover/src/runner.rs @@ -189,6 +189,7 @@ where let batch_prover_da_pub_key = self.public_keys.prover_da_pub_key.clone(); let batch_proof_commitments_by_spec = self.batch_proof_commitments_by_spec.clone(); let light_client_proof_commitment = self.light_client_proof_commitment.clone(); + let sequencer_client = self.sequencer_client.clone(); self.task_manager.spawn(|cancellation_token| async move { let l1_block_handler = L1BlockHandler::::new( @@ -199,6 +200,7 @@ where batch_prover_da_pub_key, batch_proof_commitments_by_spec, light_client_proof_commitment, + Arc::new(sequencer_client), ); l1_block_handler .run(last_l1_height_scanned.0, cancellation_token) diff --git a/crates/prover-services/Cargo.toml b/crates/prover-services/Cargo.toml index 9c3b35dd5..9d935ff3d 100644 --- a/crates/prover-services/Cargo.toml +++ b/crates/prover-services/Cargo.toml @@ -31,7 +31,6 @@ num_cpus = { workspace = true } parking_lot = { workspace = true } rand = { workspace = true } rayon = { workspace = true } -risc0-zkvm = { workspace = true } rs_merkle = { workspace = true } serde = { workspace = true } tokio = { workspace = true } diff --git a/crates/prover-services/src/parallel/mod.rs b/crates/prover-services/src/parallel/mod.rs index a7fc1f3bd..7e7fd9893 100644 --- a/crates/prover-services/src/parallel/mod.rs +++ b/crates/prover-services/src/parallel/mod.rs @@ -2,9 +2,7 @@ use std::ops::DerefMut; use std::sync::Arc; use async_trait::async_trait; -use borsh::BorshDeserialize; use futures::future; -use risc0_zkvm::Receipt; use sov_db::ledger_db::LedgerDB; use sov_rollup_interface::da::DaData; use sov_rollup_interface::services::da::DaService; @@ -210,22 +208,6 @@ where Ok(self.prove_all(proof_queue).await) } - async fn extract_output( - &self, - proofs: Vec, - ) -> anyhow::Result> { - // Extract output - Ok(proofs - .into_iter() - .map(|proof| { - let receipt: Receipt = - bincode::deserialize(&proof).expect("bincode deserialize must not fail"); - let journal = receipt.journal; - T::try_from_slice(&journal.bytes).expect("Borsh deserialize must not fail") - }) - .collect()) - } - async fn submit_proofs( &self, proofs: Vec, diff --git a/crates/risc0/src/guest.rs b/crates/risc0/src/guest.rs index 46f832b26..544ef7913 100644 --- a/crates/risc0/src/guest.rs +++ b/crates/risc0/src/guest.rs @@ -48,14 +48,12 @@ impl Zkvm for Risc0Guest { Ok(journal.to_vec()) } - fn verify_and_extract_output( + fn verify_and_extract_output( journal: &[u8], code_commitment: &Self::CodeCommitment, - ) -> Result, Self::Error> { + ) -> Result { env::verify(code_commitment.0, journal) .expect("Guest side verification error should be Infallible"); - Ok(BorshDeserialize::deserialize( - &mut journal.to_vec().as_slice(), - )?) + Ok(T::deserialize(&mut journal.to_vec().as_slice())?) } } diff --git a/crates/risc0/src/host.rs b/crates/risc0/src/host.rs index eafc5c08f..1bdc289de 100644 --- a/crates/risc0/src/host.rs +++ b/crates/risc0/src/host.rs @@ -164,13 +164,13 @@ impl<'a> ZkvmHost for Risc0BonsaiHost<'a> { Ok(serialized_receipt) } - fn extract_output( + fn extract_output( proof: &Proof, - ) -> Result, Self::Error> { + ) -> Result { let receipt: Receipt = bincode::deserialize(proof)?; let journal = receipt.journal; - Ok(BorshDeserialize::try_from_slice(&journal.bytes)?) + Ok(T::try_from_slice(&journal.bytes)?) } fn recover_proving_sessions(&self) -> Result, anyhow::Error> { @@ -221,17 +221,15 @@ impl<'host> Zkvm for Risc0BonsaiHost<'host> { Ok(receipt.journal.bytes) } - fn verify_and_extract_output( + fn verify_and_extract_output( serialized_proof: &[u8], code_commitment: &Self::CodeCommitment, - ) -> Result, Self::Error> { + ) -> Result { let receipt: Receipt = bincode::deserialize(serialized_proof)?; #[allow(clippy::clone_on_copy)] receipt.verify(code_commitment.clone())?; - Ok(BorshDeserialize::deserialize( - &mut receipt.journal.bytes.as_slice(), - )?) + Ok(T::deserialize(&mut receipt.journal.bytes.as_slice())?) } } diff --git a/crates/sovereign-sdk/adapters/mock-zkvm/src/lib.rs b/crates/sovereign-sdk/adapters/mock-zkvm/src/lib.rs index e685c882a..c80278e1e 100644 --- a/crates/sovereign-sdk/adapters/mock-zkvm/src/lib.rs +++ b/crates/sovereign-sdk/adapters/mock-zkvm/src/lib.rs @@ -8,9 +8,7 @@ use std::sync::{Arc, Condvar, Mutex}; use anyhow::ensure; use borsh::{BorshDeserialize, BorshSerialize}; use serde::{Deserialize, Serialize}; -use sov_rollup_interface::da::BlockHeaderTrait; -use sov_rollup_interface::spec::SpecId; -use sov_rollup_interface::zk::{Matches, Proof, StateTransitionData, ValidityCondition}; +use sov_rollup_interface::zk::{Matches, Proof, ValidityCondition}; /// A mock commitment to a particular zkVM program. #[derive(Debug, Clone, PartialEq, Eq, BorshDeserialize, BorshSerialize, Serialize, Deserialize)] @@ -156,12 +154,12 @@ impl sov_rollup_interface::zk::Zkvm for MockZkv Ok(serialized_proof[33..].to_vec()) } - fn verify_and_extract_output( + fn verify_and_extract_output( serialized_proof: &[u8], code_commitment: &Self::CodeCommitment, - ) -> Result, Self::Error> { + ) -> Result { let output = Self::verify(serialized_proof, code_commitment)?; - Ok(BorshDeserialize::deserialize(&mut &*output)?) + Ok(T::deserialize(&mut &*output)?) } } @@ -193,26 +191,12 @@ impl sov_rollup_interface::zk::ZkvmHost Ok(self.committed_data.pop_front().unwrap_or_default()) } - fn extract_output( + fn extract_output( proof: &Proof, - ) -> Result, Self::Error> { + ) -> Result { let data: ProofInfo = bincode::deserialize(proof)?; - let st: StateTransitionData = - BorshDeserialize::deserialize(&mut &*data.hint)?; - - Ok(sov_rollup_interface::zk::StateTransition { - initial_state_root: st.initial_state_root, - final_state_root: st.final_state_root, - initial_batch_hash: st.initial_batch_hash, - validity_condition: data.validity_condition, - state_diff: Default::default(), - da_slot_hash: st.da_block_header_of_commitments.hash(), - sequencer_public_key: vec![], - sequencer_da_public_key: vec![], - sequencer_commitments_range: (0, 0), - last_active_spec_id: SpecId::Genesis, - preproven_commitments: vec![], - }) + + T::try_from_slice(&data.hint).map_err(Into::into) } fn recover_proving_sessions(&self) -> Result, anyhow::Error> { @@ -235,10 +219,10 @@ impl sov_rollup_interface::zk::Zkvm for MockZkGuest { unimplemented!() } - fn verify_and_extract_output( + fn verify_and_extract_output( _serialized_proof: &[u8], _code_commitment: &Self::CodeCommitment, - ) -> Result, Self::Error> { + ) -> Result { unimplemented!() } } diff --git a/crates/sovereign-sdk/full-node/db/sov-db/src/ledger_db/mod.rs b/crates/sovereign-sdk/full-node/db/sov-db/src/ledger_db/mod.rs index 816b33c39..0a03702a9 100644 --- a/crates/sovereign-sdk/full-node/db/sov-db/src/ledger_db/mod.rs +++ b/crates/sovereign-sdk/full-node/db/sov-db/src/ledger_db/mod.rs @@ -16,14 +16,16 @@ use crate::rocks_db_config::RocksdbConfig; use crate::schema::tables::TestTableNew; use crate::schema::tables::{ BatchByNumber, CommitmentsByNumber, ExecutedMigrations, L2GenesisStateRoot, L2RangeByL1Height, - L2Witness, LastPrunedBlock, LastSequencerCommitmentSent, LastStateDiff, MempoolTxs, - PendingProvingSessions, PendingSequencerCommitmentL2Range, ProofsBySlotNumber, - ProverLastScannedSlot, ProverStateDiffs, SlotByHash, SlotByNumber, SoftConfirmationByHash, - SoftConfirmationByNumber, SoftConfirmationStatus, VerifiedProofsBySlotNumber, LEDGER_TABLES, + L2Witness, LastPrunedBlock, LastSequencerCommitmentSent, LastStateDiff, + LightClientProofBySlotNumber, MempoolTxs, PendingProvingSessions, + PendingSequencerCommitmentL2Range, ProofsBySlotNumber, ProverLastScannedSlot, ProverStateDiffs, + SlotByHash, SlotByNumber, SoftConfirmationByHash, SoftConfirmationByNumber, + SoftConfirmationStatus, VerifiedBatchProofsBySlotNumber, LEDGER_TABLES, }; use crate::schema::types::{ - split_tx_for_storage, BatchNumber, L2HeightRange, SlotNumber, StoredProof, StoredSlot, - StoredSoftConfirmation, StoredStateTransition, StoredVerifiedProof, + split_tx_for_storage, BatchNumber, L2HeightRange, SlotNumber, StoredBatchProof, + StoredLightClientProof, StoredSlot, StoredSoftConfirmation, StoredStateTransition, + StoredVerifiedProof, }; /// Implementation of database migrator @@ -501,6 +503,31 @@ impl SharedLedgerOps for LedgerDB { } } +impl LightClientProverLedgerOps for LedgerDB { + fn insert_light_client_proof_data_by_l1_height( + &self, + l1_height: u64, + proof: Proof, + light_client_circuit_output: sov_rollup_interface::zk::LightClientCircuitOutput, + ) -> anyhow::Result<()> { + let data_to_store = StoredLightClientProof { + proof, + light_client_circuit_output, + }; + + self.db + .put::(&SlotNumber(l1_height), &data_to_store) + } + + fn get_light_client_proof_data_by_l1_height( + &self, + l1_height: u64, + ) -> anyhow::Result> { + self.db + .get::(&SlotNumber(l1_height)) + } +} + impl BatchProverLedgerOps for LedgerDB { /// Get the witness by L2 height #[instrument(level = "trace", skip_all, err)] @@ -519,14 +546,14 @@ impl BatchProverLedgerOps for LedgerDB { /// Stores proof related data on disk, accessible via l1 slot height #[instrument(level = "trace", skip(self, proof, state_transition), err, ret)] - fn insert_proof_data_by_l1_height( + fn insert_batch_proof_data_by_l1_height( &self, l1_height: u64, l1_tx_id: [u8; 32], proof: Proof, state_transition: StoredStateTransition, ) -> anyhow::Result<()> { - let data_to_store = StoredProof { + let data_to_store = StoredBatchProof { l1_tx_id, proof, state_transition, @@ -545,7 +572,10 @@ impl BatchProverLedgerOps for LedgerDB { } #[instrument(level = "trace", skip(self), err)] - fn get_proofs_by_l1_height(&self, l1_height: u64) -> anyhow::Result>> { + fn get_proofs_by_l1_height( + &self, + l1_height: u64, + ) -> anyhow::Result>> { self.db.get::(&SlotNumber(l1_height)) } @@ -599,8 +629,6 @@ impl BatchProverLedgerOps for LedgerDB { } } -impl LightClientProverLedgerOps for LedgerDB {} - impl ProvingServiceLedgerOps for LedgerDB { /// Gets all pending sessions and step numbers #[instrument(level = "trace", skip(self), err)] @@ -765,7 +793,7 @@ impl NodeLedgerOps for LedgerDB { ) -> anyhow::Result<()> { let verified_proofs = self .db - .get::(&SlotNumber(l1_height))?; + .get::(&SlotNumber(l1_height))?; match verified_proofs { Some(mut verified_proofs) => { @@ -774,8 +802,10 @@ impl NodeLedgerOps for LedgerDB { state_transition, }; verified_proofs.push(stored_verified_proof); - self.db - .put::(&SlotNumber(l1_height), &verified_proofs) + self.db.put::( + &SlotNumber(l1_height), + &verified_proofs, + ) } None => self.db.put( &SlotNumber(l1_height), diff --git a/crates/sovereign-sdk/full-node/db/sov-db/src/ledger_db/rpc.rs b/crates/sovereign-sdk/full-node/db/sov-db/src/ledger_db/rpc.rs index 0184dc936..0e86c657f 100644 --- a/crates/sovereign-sdk/full-node/db/sov-db/src/ledger_db/rpc.rs +++ b/crates/sovereign-sdk/full-node/db/sov-db/src/ledger_db/rpc.rs @@ -1,13 +1,13 @@ use serde::de::DeserializeOwned; use sov_rollup_interface::rpc::{ - sequencer_commitment_to_response, LastVerifiedProofResponse, LedgerRpcProvider, ProofResponse, - SequencerCommitmentResponse, SoftConfirmationIdentifier, SoftConfirmationResponse, - VerifiedProofResponse, + sequencer_commitment_to_response, BatchProofResponse, LastVerifiedProofResponse, + LedgerRpcProvider, SequencerCommitmentResponse, SoftConfirmationIdentifier, + SoftConfirmationResponse, VerifiedProofResponse, }; use crate::schema::tables::{ CommitmentsByNumber, ProofsBySlotNumber, SlotByHash, SoftConfirmationByHash, - SoftConfirmationByNumber, SoftConfirmationStatus, VerifiedProofsBySlotNumber, + SoftConfirmationByNumber, SoftConfirmationStatus, VerifiedBatchProofsBySlotNumber, }; use crate::schema::types::{BatchNumber, SlotNumber}; @@ -141,13 +141,16 @@ impl LedgerRpcProvider for LedgerDB { } } - fn get_proof_data_by_l1_height( + fn get_batch_proof_data_by_l1_height( &self, height: u64, - ) -> Result>, anyhow::Error> { + ) -> Result>, anyhow::Error> { match self.db.get::(&SlotNumber(height))? { Some(stored_proofs) => Ok(Some( - stored_proofs.into_iter().map(ProofResponse::from).collect(), + stored_proofs + .into_iter() + .map(BatchProofResponse::from) + .collect(), )), None => Ok(None), } @@ -159,7 +162,7 @@ impl LedgerRpcProvider for LedgerDB { ) -> Result>, anyhow::Error> { match self .db - .get::(&SlotNumber(height))? + .get::(&SlotNumber(height))? { Some(stored_proofs) => Ok(Some( stored_proofs @@ -171,8 +174,10 @@ impl LedgerRpcProvider for LedgerDB { } } - fn get_last_verified_proof(&self) -> Result, anyhow::Error> { - let mut iter = self.db.iter::()?; + fn get_last_verified_batch_proof( + &self, + ) -> Result, anyhow::Error> { + let mut iter = self.db.iter::()?; iter.seek_to_last(); match iter.next() { Some(Ok(item)) => Ok(Some(LastVerifiedProofResponse { diff --git a/crates/sovereign-sdk/full-node/db/sov-db/src/ledger_db/traits.rs b/crates/sovereign-sdk/full-node/db/sov-db/src/ledger_db/traits.rs index e72c7083c..2ceafa737 100644 --- a/crates/sovereign-sdk/full-node/db/sov-db/src/ledger_db/traits.rs +++ b/crates/sovereign-sdk/full-node/db/sov-db/src/ledger_db/traits.rs @@ -5,13 +5,13 @@ use serde::de::DeserializeOwned; use serde::Serialize; use sov_rollup_interface::da::{DaSpec, SequencerCommitment}; use sov_rollup_interface::stf::{SoftConfirmationReceipt, StateDiff}; -use sov_rollup_interface::zk::Proof; +use sov_rollup_interface::zk::{LightClientCircuitOutput, Proof}; use sov_schema_db::SchemaBatch; use super::ItemNumbers; use crate::schema::types::{ - BatchNumber, L2HeightRange, SlotNumber, StoredProof, StoredSlot, StoredSoftConfirmation, - StoredStateTransition, + BatchNumber, L2HeightRange, SlotNumber, StoredBatchProof, StoredLightClientProof, StoredSlot, + StoredSoftConfirmation, StoredStateTransition, }; /// Shared ledger operations @@ -162,7 +162,7 @@ pub trait BatchProverLedgerOps: SharedLedgerOps + Send + Sync { /// Stores proof related data on disk, accessible via l1 slot height /// Inserts proofs of state transitions of multiple ranges of sequencer commitments found in an l1 block - fn insert_proof_data_by_l1_height( + fn insert_batch_proof_data_by_l1_height( &self, l1_height: u64, l1_tx_id: [u8; 32], @@ -171,7 +171,7 @@ pub trait BatchProverLedgerOps: SharedLedgerOps + Send + Sync { ) -> Result<()>; /// Gets proofs by L1 height - fn get_proofs_by_l1_height(&self, l1_height: u64) -> Result>>; + fn get_proofs_by_l1_height(&self, l1_height: u64) -> Result>>; /// Set the witness by L2 height fn set_l2_witness(&self, l2_height: u64, witness: &Witness) -> Result<()>; @@ -187,7 +187,21 @@ pub trait BatchProverLedgerOps: SharedLedgerOps + Send + Sync { } /// Light client prover ledger operations -pub trait LightClientProverLedgerOps: SharedLedgerOps + Send + Sync {} +pub trait LightClientProverLedgerOps: SharedLedgerOps + Send + Sync { + /// Inserts light client proof data by L1 height + fn insert_light_client_proof_data_by_l1_height( + &self, + l1_height: u64, + proof: Proof, + light_client_proof_output: LightClientCircuitOutput, + ) -> Result<()>; + + /// Gets light client proof data by L1 height + fn get_light_client_proof_data_by_l1_height( + &self, + l1_height: u64, + ) -> Result>; +} /// Ledger operations for the prover service pub trait ProvingServiceLedgerOps: BatchProverLedgerOps + SharedLedgerOps + Send + Sync { diff --git a/crates/sovereign-sdk/full-node/db/sov-db/src/schema/tables.rs b/crates/sovereign-sdk/full-node/db/sov-db/src/schema/tables.rs index 7e0af2078..bce448cc9 100644 --- a/crates/sovereign-sdk/full-node/db/sov-db/src/schema/tables.rs +++ b/crates/sovereign-sdk/full-node/db/sov-db/src/schema/tables.rs @@ -36,7 +36,8 @@ use sov_schema_db::{CodecError, SeekKeyEncoder}; use super::types::{ AccessoryKey, AccessoryStateValue, BatchNumber, DbHash, JmtValue, L2HeightRange, SlotNumber, - StateKey, StoredBatch, StoredProof, StoredSlot, StoredSoftConfirmation, StoredVerifiedProof, + StateKey, StoredBatch, StoredBatchProof, StoredLightClientProof, StoredSlot, + StoredSoftConfirmation, StoredVerifiedProof, }; /// A list of all tables used by the StateDB. These tables store rollup state - meaning @@ -59,6 +60,7 @@ pub const LEDGER_TABLES: &[&str] = &[ L2Witness::table_name(), L2GenesisStateRoot::table_name(), LastStateDiff::table_name(), + LightClientProofBySlotNumber::table_name(), PendingSequencerCommitmentL2Range::table_name(), LastSequencerCommitmentSent::table_name(), ProverLastScannedSlot::table_name(), @@ -66,7 +68,7 @@ pub const LEDGER_TABLES: &[&str] = &[ SoftConfirmationStatus::table_name(), CommitmentsByNumber::table_name(), ProofsBySlotNumber::table_name(), - VerifiedProofsBySlotNumber::table_name(), + VerifiedBatchProofsBySlotNumber::table_name(), MempoolTxs::table_name(), PendingProvingSessions::table_name(), ProverStateDiffs::table_name(), @@ -306,14 +308,19 @@ define_table_without_codec!( (JmtNodes) NodeKey => Node ); +define_table_with_default_codec!( + /// Light client proof data by l1 height + (LightClientProofBySlotNumber) SlotNumber => StoredLightClientProof +); + define_table_with_default_codec!( /// Proof data on L1 slot - (ProofsBySlotNumber) SlotNumber => Vec + (ProofsBySlotNumber) SlotNumber => Vec ); define_table_with_default_codec!( /// Proof data on L1 slot verified by full node - (VerifiedProofsBySlotNumber) SlotNumber => Vec + (VerifiedBatchProofsBySlotNumber) SlotNumber => Vec ); define_table_with_seek_key_codec!( diff --git a/crates/sovereign-sdk/full-node/db/sov-db/src/schema/types.rs b/crates/sovereign-sdk/full-node/db/sov-db/src/schema/types.rs index 3ecd1ba7a..4db4e8f04 100644 --- a/crates/sovereign-sdk/full-node/db/sov-db/src/schema/types.rs +++ b/crates/sovereign-sdk/full-node/db/sov-db/src/schema/types.rs @@ -5,12 +5,12 @@ use borsh::{BorshDeserialize, BorshSerialize}; use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; use sov_rollup_interface::rpc::{ - HexTx, ProofResponse, SoftConfirmationResponse, StateTransitionRpcResponse, TxIdentifier, + BatchProofResponse, HexTx, SoftConfirmationResponse, StateTransitionRpcResponse, TxIdentifier, TxResponse, VerifiedProofResponse, }; use sov_rollup_interface::soft_confirmation::SignedSoftConfirmation; use sov_rollup_interface::stf::{Event, EventKey, TransactionReceipt}; -use sov_rollup_interface::zk::{CumulativeStateDiff, Proof}; +use sov_rollup_interface::zk::{CumulativeStateDiff, LightClientCircuitOutput, Proof}; /// A cheaply cloneable bytes abstraction for use within the trust boundary of the node /// (i.e. when interfacing with the database). Serializes and deserializes more efficiently, @@ -72,10 +72,18 @@ pub struct StoredSlot { /// The range of batches which occurred in this slot. pub batches: std::ops::Range, } +/// The on-disk format for a light client proof +#[derive(Debug, PartialEq, BorshDeserialize, BorshSerialize)] +pub struct StoredLightClientProof { + /// The proof + pub proof: Proof, + /// The light client circuit output + pub light_client_circuit_output: LightClientCircuitOutput, +} /// The on-disk format for a proof. Stores the tx id of the proof sent to da, proof data and state transition #[derive(Debug, PartialEq, BorshDeserialize, BorshSerialize)] -pub struct StoredProof { +pub struct StoredBatchProof { /// Tx id pub l1_tx_id: [u8; 32], /// Proof @@ -84,8 +92,8 @@ pub struct StoredProof { pub state_transition: StoredStateTransition, } -impl From for ProofResponse { - fn from(value: StoredProof) -> Self { +impl From for BatchProofResponse { + fn from(value: StoredBatchProof) -> Self { Self { l1_tx_id: value.l1_tx_id, proof: value.proof, diff --git a/crates/sovereign-sdk/full-node/sov-ledger-rpc/src/client.rs b/crates/sovereign-sdk/full-node/sov-ledger-rpc/src/client.rs index c388a0643..af2580092 100644 --- a/crates/sovereign-sdk/full-node/sov-ledger-rpc/src/client.rs +++ b/crates/sovereign-sdk/full-node/sov-ledger-rpc/src/client.rs @@ -5,8 +5,8 @@ use jsonrpsee::proc_macros::rpc; use sov_rollup_interface::rpc::{ - ProofResponse, SequencerCommitmentResponse, SoftConfirmationResponse, SoftConfirmationStatus, - VerifiedProofResponse, + BatchProofResponse, SequencerCommitmentResponse, SoftConfirmationResponse, + SoftConfirmationStatus, VerifiedProofResponse, }; use crate::HexHash; @@ -63,12 +63,18 @@ pub trait Rpc { ) -> RpcResult>>; /// Gets proof by slot height. - #[method(name = "getProofsBySlotHeight")] - async fn get_proofs_by_slot_height(&self, height: u64) -> RpcResult>; + #[method(name = "getBatchProofsBySlotHeight")] + async fn get_batch_proofs_by_slot_height( + &self, + height: u64, + ) -> RpcResult>; /// Gets proof by slot hash. - #[method(name = "getProofsBySlotHash")] - async fn get_proofs_by_slot_hash(&self, hash: [u8; 32]) -> RpcResult>; + #[method(name = "getBatchProofsBySlotHash")] + async fn get_batch_proofs_by_slot_hash( + &self, + hash: [u8; 32], + ) -> RpcResult>; /// Gets the height pf most recent committed soft confirmation. #[method(name = "getHeadSoftConfirmation")] @@ -79,13 +85,13 @@ pub trait Rpc { async fn get_head_soft_confirmation_height(&self) -> RpcResult; /// Gets verified proofs by slot height - #[method(name = "getVerifiedProofsBySlotHeight")] - async fn get_verified_proofs_by_slot_height( + #[method(name = "getVerifiedBatchProofsBySlotHeight")] + async fn get_verified_batch_proofs_by_slot_height( &self, height: u64, ) -> RpcResult>>; /// Gets last verified proog - #[method(name = "getLastVerifiedProof")] - async fn get_last_verified_proof(&self) -> RpcResult>; + #[method(name = "getLastVerifiedBatchProof")] + async fn get_last_verified_batch_proof(&self) -> RpcResult>; } diff --git a/crates/sovereign-sdk/full-node/sov-ledger-rpc/src/server.rs b/crates/sovereign-sdk/full-node/sov-ledger-rpc/src/server.rs index 5ee676974..d288ed5ba 100644 --- a/crates/sovereign-sdk/full-node/sov-ledger-rpc/src/server.rs +++ b/crates/sovereign-sdk/full-node/sov-ledger-rpc/src/server.rs @@ -90,30 +90,36 @@ where }, )?; - rpc.register_blocking_method("ledger_getProofsBySlotHeight", move |params, ledger, _| { - // Returns proof on DA slot with given height - let height: u64 = params.one()?; - ledger - .get_proof_data_by_l1_height(height) - .map_err(|e| to_jsonrpsee_error_object(LEDGER_RPC_ERROR, e)) - })?; + rpc.register_blocking_method( + "ledger_getBatchProofsBySlotHeight", + move |params, ledger, _| { + // Returns proof on DA slot with given height + let height: u64 = params.one()?; + ledger + .get_batch_proof_data_by_l1_height(height) + .map_err(|e| to_jsonrpsee_error_object(LEDGER_RPC_ERROR, e)) + }, + )?; - rpc.register_blocking_method("ledger_getProofsBySlotHash", move |params, ledger, _| { - // Returns proof on DA slot with given height - let hash: [u8; 32] = params.one()?; - let height = ledger - .get_slot_number_by_hash(hash) - .map_err(|e| to_jsonrpsee_error_object(LEDGER_RPC_ERROR, e))?; - match height { - Some(height) => ledger - .get_proof_data_by_l1_height(height) - .map_err(|e| to_jsonrpsee_error_object(LEDGER_RPC_ERROR, e)), - None => Ok(None), - } - })?; + rpc.register_blocking_method( + "ledger_getBatchProofsBySlotHash", + move |params, ledger, _| { + // Returns proof on DA slot with given height + let hash: [u8; 32] = params.one()?; + let height = ledger + .get_slot_number_by_hash(hash) + .map_err(|e| to_jsonrpsee_error_object(LEDGER_RPC_ERROR, e))?; + match height { + Some(height) => ledger + .get_batch_proof_data_by_l1_height(height) + .map_err(|e| to_jsonrpsee_error_object(LEDGER_RPC_ERROR, e)), + None => Ok(None), + } + }, + )?; rpc.register_blocking_method( - "ledger_getVerifiedProofsBySlotHeight", + "ledger_getVerifiedBatchProofsBySlotHeight", move |params, ledger, _| { // Returns proof on DA slot with given height let height: u64 = params.one()?; @@ -123,10 +129,10 @@ where }, )?; - rpc.register_blocking_method("ledger_getLastVerifiedProof", move |_, ledger, _| { + rpc.register_blocking_method("ledger_getLastVerifiedBatchProof", move |_, ledger, _| { // Returns latest proof data ledger - .get_last_verified_proof() + .get_last_verified_batch_proof() .map_err(|e| to_jsonrpsee_error_object(LEDGER_RPC_ERROR, e)) })?; diff --git a/crates/sovereign-sdk/full-node/sov-ledger-rpc/tests/empty_ledger.rs b/crates/sovereign-sdk/full-node/sov-ledger-rpc/tests/empty_ledger.rs index fcf0a893c..644f134b7 100644 --- a/crates/sovereign-sdk/full-node/sov-ledger-rpc/tests/empty_ledger.rs +++ b/crates/sovereign-sdk/full-node/sov-ledger-rpc/tests/empty_ledger.rs @@ -52,9 +52,12 @@ async fn getters_succeed() { .await .unwrap(); - rpc_client.get_proofs_by_slot_height(0).await.unwrap(); + rpc_client.get_batch_proofs_by_slot_height(0).await.unwrap(); - rpc_client.get_proofs_by_slot_hash([0; 32]).await.unwrap(); + rpc_client + .get_batch_proofs_by_slot_hash([0; 32]) + .await + .unwrap(); rpc_client .get_head_soft_confirmation_height() @@ -64,9 +67,9 @@ async fn getters_succeed() { rpc_client.get_head_soft_confirmation().await.unwrap(); rpc_client - .get_verified_proofs_by_slot_height(0) + .get_verified_batch_proofs_by_slot_height(0) .await .unwrap(); - rpc_client.get_last_verified_proof().await.unwrap(); + rpc_client.get_last_verified_batch_proof().await.unwrap(); } diff --git a/crates/sovereign-sdk/full-node/sov-stf-runner/src/prover_service/mod.rs b/crates/sovereign-sdk/full-node/sov-stf-runner/src/prover_service/mod.rs index 00a1f15f8..64341324a 100644 --- a/crates/sovereign-sdk/full-node/sov-stf-runner/src/prover_service/mod.rs +++ b/crates/sovereign-sdk/full-node/sov-stf-runner/src/prover_service/mod.rs @@ -1,5 +1,4 @@ use async_trait::async_trait; -use borsh::BorshDeserialize; use serde::{Deserialize, Serialize}; use sov_rollup_interface::services::da::DaService; use sov_rollup_interface::zk::Proof; @@ -98,12 +97,6 @@ pub trait ProverService { proofs: Vec, ) -> anyhow::Result::TransactionId, Proof)>>; - /// Extracts the journal output of the given proofs and borsh deserializes them. - async fn extract_output( - &self, - proofs: Vec, - ) -> anyhow::Result>; - /// Recover the ongoing sessions and submit them to DA. async fn recover_and_submit_proving_sessions( &self, diff --git a/crates/sovereign-sdk/rollup-interface/src/node/rpc/mod.rs b/crates/sovereign-sdk/rollup-interface/src/node/rpc/mod.rs index 6a181a0ee..28917ce27 100644 --- a/crates/sovereign-sdk/rollup-interface/src/node/rpc/mod.rs +++ b/crates/sovereign-sdk/rollup-interface/src/node/rpc/mod.rs @@ -209,7 +209,7 @@ pub struct SequencerCommitmentResponse { /// The rpc response of proof by l1 slot height #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct ProofResponse { +pub struct BatchProofResponse { /// l1 tx id of #[serde(with = "hex::serde")] pub l1_tx_id: [u8; 32], @@ -442,11 +442,11 @@ pub trait LedgerRpcProvider { height: u64, ) -> Result>, anyhow::Error>; - /// Get proof by l1 height - fn get_proof_data_by_l1_height( + /// Get batch proof by l1 height + fn get_batch_proof_data_by_l1_height( &self, height: u64, - ) -> Result>, anyhow::Error>; + ) -> Result>, anyhow::Error>; /// Get verified proof by l1 height fn get_verified_proof_data_by_l1_height( @@ -455,7 +455,9 @@ pub trait LedgerRpcProvider { ) -> Result>, anyhow::Error>; /// Get last verified proof - fn get_last_verified_proof(&self) -> Result, anyhow::Error>; + fn get_last_verified_batch_proof( + &self, + ) -> Result, anyhow::Error>; /// Get head soft confirmation fn get_head_soft_confirmation(&self) diff --git a/crates/sovereign-sdk/rollup-interface/src/state_machine/zk/mod.rs b/crates/sovereign-sdk/rollup-interface/src/state_machine/zk/mod.rs index d2eae2ada..be6d122f3 100644 --- a/crates/sovereign-sdk/rollup-interface/src/state_machine/zk/mod.rs +++ b/crates/sovereign-sdk/rollup-interface/src/state_machine/zk/mod.rs @@ -48,9 +48,7 @@ pub trait ZkvmHost: Zkvm + Clone { fn run(&mut self, with_proof: bool) -> Result; /// Extracts public input and receipt from the proof. - fn extract_output( - proof: &Proof, - ) -> Result, Self::Error>; + fn extract_output(proof: &Proof) -> Result; /// Host recovers pending proving sessions and returns proving results fn recover_proving_sessions(&self) -> Result, anyhow::Error>; @@ -87,10 +85,10 @@ pub trait Zkvm: Send + Sync { /// Same as [`verify`](Zkvm::verify), except that instead of returning the output /// as a serialized array, it returns a state transition structure. /// TODO: specify a deserializer for the output - fn verify_and_extract_output( + fn verify_and_extract_output( serialized_proof: &[u8], code_commitment: &Self::CodeCommitment, - ) -> Result, Self::Error>; + ) -> Result; } /// A trait which is accessible from within a zkVM program. @@ -212,3 +210,38 @@ pub struct StateTransitionData { /// The range is inclusive. pub sequencer_commitments_range: (u32, u32), } + +/// The output of light client proof +#[derive(Debug, Clone, BorshDeserialize, BorshSerialize, PartialEq)] +pub struct LightClientCircuitOutput { + /// State root of the node after the light client proof + pub state_root: [u8; 32], + /// The method id of the light client proof + /// This is used to compare the previous light client proof method id with the input (current) method id + pub light_client_proof_method_id: [u32; 8], +} + +/// The input of light client proof +#[derive(BorshDeserialize, BorshSerialize)] +pub struct LightClientCircuitInput { + /// The `crate::da::DaData` that are being processed as blobs. + pub da_data: Vec, + /// The inclusion proof for all DA data. + pub inclusion_proof: Da::InclusionMultiProof, + /// The completeness proof for all DA data. + pub completeness_proof: Da::CompletenessProof, + /// DA block header that the batch proofs were found in. + pub da_block_header: Da::BlockHeader, + + /// Public key of the batch prover + pub batch_prover_da_pub_key: Vec, + /// Batch proof method id + pub batch_proof_method_id: [u32; 8], + /// Batch proofs outputs + pub batch_proof_journals: Vec>, + /// Light client proof method id + pub light_client_proof_method_id: [u32; 8], + /// Light client proof output + /// Optional because the first light client proof doesn't have a previous proof + pub light_client_proof_journal: Option>, +} diff --git a/crates/sp1/src/guest.rs b/crates/sp1/src/guest.rs index 888d95ef0..235cb5ee6 100644 --- a/crates/sp1/src/guest.rs +++ b/crates/sp1/src/guest.rs @@ -30,10 +30,10 @@ impl Zkvm for SP1Guest { unimplemented!() } - fn verify_and_extract_output( + fn verify_and_extract_output( _serialized_proof: &[u8], _code_commitment: &Self::CodeCommitment, - ) -> Result, Self::Error> { + ) -> Result { unimplemented!() } } diff --git a/crates/sp1/src/host.rs b/crates/sp1/src/host.rs index a6e573240..c80ca88ee 100644 --- a/crates/sp1/src/host.rs +++ b/crates/sp1/src/host.rs @@ -133,9 +133,9 @@ impl ZkvmHost for SP1Host { } } - fn extract_output( + fn extract_output( proof: &Proof, - ) -> Result, Self::Error> { + ) -> Result { let public_values = match proof { Proof::PublicInput(data) => { let public_values: SP1PublicValues = bincode::deserialize(data)?; @@ -194,17 +194,15 @@ impl Zkvm for SP1Host { Ok(proof.public_values.to_vec()) } - fn verify_and_extract_output( + fn verify_and_extract_output( serialized_proof: &[u8], code_commitment: &Self::CodeCommitment, - ) -> Result, Self::Error> { + ) -> Result { let proof: SP1ProofWithPublicValues = bincode::deserialize(serialized_proof)?; CLIENT.verify(&proof, &code_commitment.0)?; - Ok(BorshDeserialize::try_from_slice( - proof.public_values.as_slice(), - )?) + Ok(T::try_from_slice(proof.public_values.as_slice())?) } }