Skip to content

Commit

Permalink
Verification of previous light client proof in light client circuit (#…
Browse files Browse the repository at this point in the history
…1418)

Co-authored-by: eyusufatik <[email protected]>
  • Loading branch information
ercecan and eyusufatik authored Nov 5, 2024
1 parent ce58cda commit df7519e
Show file tree
Hide file tree
Showing 33 changed files with 367 additions and 244 deletions.
21 changes: 10 additions & 11 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion bin/citrea/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down
2 changes: 1 addition & 1 deletion bin/citrea/tests/bitcoin_e2e/bitcoin_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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?;
Expand Down
12 changes: 6 additions & 6 deletions bin/citrea/tests/e2e/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand All @@ -203,15 +203,15 @@ 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();

let LastVerifiedProofResponse {
proof: last_proof,
height: proof_l1_height,
} = full_node_test_client
.ledger_get_last_verified_proof()
.ledger_get_last_verified_batch_proof()
.await
.unwrap();

Expand Down Expand Up @@ -289,21 +289,21 @@ 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();

let LastVerifiedProofResponse {
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);
Expand Down
8 changes: 4 additions & 4 deletions bin/citrea/tests/e2e/proving.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand All @@ -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);
Expand Down Expand Up @@ -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();

Expand All @@ -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);
Expand Down
22 changes: 15 additions & 7 deletions bin/citrea/tests/test_client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};

Expand Down Expand Up @@ -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<ProofResponse> {
pub(crate) async fn ledger_get_batch_proofs_by_slot_height(
&self,
height: u64,
) -> Vec<BatchProofResponse> {
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<Vec<VerifiedProofResponse>> {
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<LastVerifiedProofResponse> {
pub(crate) async fn ledger_get_last_verified_batch_proof(
&self,
) -> Option<LastVerifiedProofResponse> {
self.http_client
.request("ledger_getLastVerifiedProof", rpc_params![])
.request("ledger_getLastVerifiedBatchProof", rpc_params![])
.await
.ok()
}
Expand Down
2 changes: 1 addition & 1 deletion bin/citrea/tests/test_helpers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
17 changes: 10 additions & 7 deletions crates/batch-prover/src/proving.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -250,7 +250,7 @@ where

pub(crate) fn state_transition_already_proven<StateRoot, Witness, Da>(
state_transition: &StateTransitionData<StateRoot, Witness, Da::Spec>,
proofs: &Vec<StoredProof>,
proofs: &Vec<StoredBatchProof>,
) -> bool
where
Da: DaService,
Expand Down Expand Up @@ -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::<<Da as DaService>::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::<
<Da as DaService>::Spec,
StateTransition<<Da as DaService>::Spec, StateRoot>,
>(&proof)
.expect("Proof should be deserializable");

info!("Verifying proof!");

Expand Down Expand Up @@ -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,
Expand Down
9 changes: 6 additions & 3 deletions crates/fullnode/src/da_block_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -296,8 +296,11 @@ where
);
tracing::debug!("ZK proof: {:?}", proof);

let state_transition = Vm::extract_output::<<Da as DaService>::Spec, StateRoot>(&proof)
.expect("Proof should be deserializable");
let state_transition = Vm::extract_output::<
<Da as DaService>::Spec,
StateTransition<<Da as DaService>::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
{
Expand Down
24 changes: 20 additions & 4 deletions crates/light-client-prover/src/circuit.rs
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -17,6 +14,24 @@ pub fn run_circuit<DaV: DaVerifier, G: ZkvmGuest>(
) -> Result<LightClientCircuitOutput, LightClientVerificationError> {
let input: LightClientCircuitInput<DaV::Spec> = 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::<LightClientCircuitOutput>(
&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(
Expand Down Expand Up @@ -61,6 +76,7 @@ pub fn run_circuit<DaV: DaVerifier, G: ZkvmGuest>(

Ok(LightClientCircuitOutput {
state_root: [1; 32],
light_client_proof_method_id: input.light_client_proof_method_id,
})

// First
Expand Down
Loading

0 comments on commit df7519e

Please sign in to comment.