Skip to content

Commit

Permalink
Get light client circuit constants as arg
Browse files Browse the repository at this point in the history
  • Loading branch information
yaziciahmet committed Dec 18, 2024
1 parent 1fb4c64 commit 487c84a
Show file tree
Hide file tree
Showing 13 changed files with 185 additions and 112 deletions.
19 changes: 0 additions & 19 deletions bin/citrea/tests/bitcoin_e2e/light_client_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -321,16 +321,6 @@ impl TestCase for LightClientProvingTestMultipleProofs {
light_client_proof.light_client_proof_output.last_l2_height
);

// Should always be the same
assert_eq!(
light_client_proof2
.light_client_proof_output
.l2_genesis_state_root,
light_client_proof
.light_client_proof_output
.l2_genesis_state_root
);

assert!(light_client_proof2
.light_client_proof_output
.unchained_batch_proofs_info
Expand Down Expand Up @@ -417,15 +407,6 @@ impl TestCase for LightClientProvingTestMultipleProofs {
batch_proofs[0].proof_output.final_state_root
);

assert_eq!(
light_client_proof3
.light_client_proof_output
.l2_genesis_state_root,
light_client_proof
.light_client_proof_output
.l2_genesis_state_root
);

assert_ne!(
light_client_proof3.light_client_proof_output.last_l2_height,
light_client_proof.light_client_proof_output.last_l2_height
Expand Down
23 changes: 8 additions & 15 deletions crates/light-client-prover/src/circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ pub enum LightClientVerificationError {
pub fn run_circuit<DaV: DaVerifier, G: ZkvmGuest>(
da_verifier: DaV,
input: LightClientCircuitInput<DaV::Spec>,
l2_genesis_root: [u8; 32],
batch_proof_method_id: [u32; 8],
batch_prover_da_public_key: &[u8],
) -> Result<LightClientCircuitOutput<DaV::Spec>, LightClientVerificationError> {
// Extract previous light client proof output
let previous_light_client_proof_output =
Expand Down Expand Up @@ -55,21 +58,13 @@ pub fn run_circuit<DaV: DaVerifier, G: ZkvmGuest>(
// Mapping from initial state root to final state root and last L2 height
let mut initial_to_final = std::collections::BTreeMap::<[u8; 32], ([u8; 32], u64)>::new();

let (mut last_state_root, mut last_l2_height, l2_genesis_state_root) =
let (mut last_state_root, mut last_l2_height) =
previous_light_client_proof_output.as_ref().map_or_else(
|| {
let r = input
.l2_genesis_state_root
.expect("if no preious proof, genesis must exist");
(r, 0, r)
},
|prev_journal| {
(
prev_journal.state_root,
prev_journal.last_l2_height,
prev_journal.l2_genesis_state_root,
)
// if no previous proof, we start from genesis state root
(l2_genesis_root, 0)
},
|prev_journal| (prev_journal.state_root, prev_journal.last_l2_height),
);

// If we have a previous light client proof, check they can be chained
Expand All @@ -88,10 +83,9 @@ pub fn run_circuit<DaV: DaVerifier, G: ZkvmGuest>(
}
// TODO: Test for multiple assumptions to see if the env::verify function does automatic matching between the journal and the assumption or do we need to verify them in order?
// https://github.com/chainwayxyz/citrea/issues/1401
let batch_proof_method_id = input.batch_proof_method_id;
// Parse the batch proof da data
for blob in input.da_data {
if blob.sender().as_ref() == input.batch_prover_da_pub_key {
if blob.sender().as_ref() == batch_prover_da_public_key {
let data = DaDataLightClient::try_from_slice(blob.verified_data());

if let Ok(data) = data {
Expand Down Expand Up @@ -157,6 +151,5 @@ pub fn run_circuit<DaV: DaVerifier, G: ZkvmGuest>(
da_prev_11_timestamps: block_updates.prev_11_timestamps,
unchained_batch_proofs_info: unchained_outputs,
last_l2_height,
l2_genesis_state_root,
})
}
16 changes: 0 additions & 16 deletions crates/light-client-prover/src/da_block_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,6 @@ where
}
let previous_l1_height = l1_height - 1;
let mut light_client_proof_journal = None;
let mut l2_genesis_state_root = None;
let l2_last_height = match self
.ledger_db
.get_light_client_proof_data_by_l1_height(previous_l1_height)?
Expand All @@ -204,13 +203,6 @@ where
// 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 {
// TODO: Provide genesis state root here to the light client proof circuit input
l2_genesis_state_root = self
.sequencer_client
.get_l2_genesis_state_root()
.await?
.map(|v| v.as_slice().try_into().unwrap());

tracing::info!(
"No previous light client proof found for L1 block: {}",
previous_l1_height
Expand All @@ -231,10 +223,6 @@ where
"Could not determine the last L2 height for batch proof"
))?;
let current_fork = fork_from_block_number(l2_last_height);
let batch_proof_method_id = self
.batch_proof_code_commitments
.get(&current_fork.spec_id)
.expect("Fork should have a guest code attached");
let light_client_proof_code_commitment = self
.light_client_proof_code_commitments
.get(&current_fork.spec_id)
Expand All @@ -250,11 +238,8 @@ where
inclusion_proof,
completeness_proof,
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(),
light_client_proof_method_id: light_client_proof_code_commitment.clone().into(),
previous_light_client_proof_journal: light_client_proof_journal,
l2_genesis_state_root,
};

let proof = self
Expand All @@ -281,7 +266,6 @@ where
da_prev_11_timestamps: circuit_output.da_prev_11_timestamps,
unchained_batch_proofs_info: circuit_output.unchained_batch_proofs_info,
last_l2_height: circuit_output.last_l2_height,
l2_genesis_state_root: circuit_output.l2_genesis_state_root,
};

self.ledger_db.insert_light_client_proof_data_by_l1_height(
Expand Down
139 changes: 99 additions & 40 deletions crates/light-client-prover/src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,19 @@ fn test_light_client_circuit_valid_da_valid_data() {
da_data: vec![blob_1, blob_2],
inclusion_proof: [1u8; 32],
completeness_proof: (),
l2_genesis_state_root: Some([1u8; 32]),
batch_proof_method_id,
batch_prover_da_pub_key: [9; 32].to_vec(),
};

let output_1 = run_circuit::<_, MockZkGuest>(da_verifier.clone(), input).unwrap();
let l2_genesis_state_root = [1u8; 32];
let batch_prover_da_pub_key = [9; 32].to_vec();

let output_1 = run_circuit::<_, MockZkGuest>(
da_verifier.clone(),
input,
l2_genesis_state_root,
batch_proof_method_id,
&batch_prover_da_pub_key,
)
.unwrap();

// Check that the state transition actually happened
assert_eq!(output_1.state_root, [3; 32]);
Expand All @@ -52,12 +59,16 @@ fn test_light_client_circuit_valid_da_valid_data() {
light_client_proof_method_id,
inclusion_proof: [1u8; 32],
completeness_proof: (),
l2_genesis_state_root: None,
batch_proof_method_id,
batch_prover_da_pub_key: [9; 32].to_vec(),
};

let output_2 = run_circuit::<_, MockZkGuest>(da_verifier.clone(), input_2).unwrap();
let output_2 = run_circuit::<_, MockZkGuest>(
da_verifier.clone(),
input_2,
l2_genesis_state_root,
batch_proof_method_id,
&batch_prover_da_pub_key,
)
.unwrap();

// Check that the state transition actually happened
assert_eq!(output_2.state_root, [5; 32]);
Expand All @@ -68,6 +79,7 @@ fn test_light_client_circuit_valid_da_valid_data() {
#[test]
fn test_wrong_order_da_blocks_should_still_work() {
let light_client_proof_method_id = [1u32; 8];
let batch_proof_method_id = [1u32; 8];
let da_verifier = MockDaVerifier {};

let blob_1 = create_mock_blob([1u8; 32], [2u8; 32], 2, true);
Expand All @@ -82,12 +94,19 @@ fn test_wrong_order_da_blocks_should_still_work() {
da_data: vec![blob_2, blob_1],
inclusion_proof: [1u8; 32],
completeness_proof: (),
l2_genesis_state_root: Some([1u8; 32]),
batch_proof_method_id: light_client_proof_method_id,
batch_prover_da_pub_key: [9; 32].to_vec(),
};

let output_1 = run_circuit::<_, MockZkGuest>(da_verifier.clone(), input).unwrap();
let l2_genesis_state_root = [1u8; 32];
let batch_prover_da_pub_key = [9; 32].to_vec();

let output_1 = run_circuit::<_, MockZkGuest>(
da_verifier.clone(),
input,
l2_genesis_state_root,
batch_proof_method_id,
&batch_prover_da_pub_key,
)
.unwrap();

// Check that the state transition actually happened
assert_eq!(output_1.state_root, [3; 32]);
Expand All @@ -98,6 +117,7 @@ fn test_wrong_order_da_blocks_should_still_work() {
#[test]
fn create_unchainable_outputs_then_chain_them_on_next_block() {
let light_client_proof_method_id = [1u32; 8];
let batch_proof_method_id = [1u32; 8];
let da_verifier = MockDaVerifier {};

let block_header_1 = MockBlockHeader::from_height(1);
Expand All @@ -112,12 +132,19 @@ fn create_unchainable_outputs_then_chain_them_on_next_block() {
da_data: vec![blob_2, blob_1],
inclusion_proof: [1u8; 32],
completeness_proof: (),
l2_genesis_state_root: Some([1u8; 32]),
batch_proof_method_id: light_client_proof_method_id,
batch_prover_da_pub_key: [9; 32].to_vec(),
};

let output_1 = run_circuit::<_, MockZkGuest>(da_verifier.clone(), input).unwrap();
let l2_genesis_state_root = [1u8; 32];
let batch_prover_da_pub_key = [9; 32].to_vec();

let output_1 = run_circuit::<_, MockZkGuest>(
da_verifier.clone(),
input,
l2_genesis_state_root,
batch_proof_method_id,
&batch_prover_da_pub_key,
)
.unwrap();

// Check that the state transition has not happened because we are missing 1->2
assert_eq!(output_1.state_root, [1; 32]);
Expand Down Expand Up @@ -150,12 +177,16 @@ fn create_unchainable_outputs_then_chain_them_on_next_block() {
da_data: vec![blob_1],
inclusion_proof: [1u8; 32],
completeness_proof: (),
l2_genesis_state_root: None,
batch_proof_method_id: light_client_proof_method_id,
batch_prover_da_pub_key: [9; 32].to_vec(),
};

let output_2 = run_circuit::<_, MockZkGuest>(da_verifier, input_2).unwrap();
let output_2 = run_circuit::<_, MockZkGuest>(
da_verifier.clone(),
input_2,
l2_genesis_state_root,
batch_proof_method_id,
&batch_prover_da_pub_key,
)
.unwrap();

// Check that the state transition actually happened from 1-4 now

Expand All @@ -167,6 +198,7 @@ fn create_unchainable_outputs_then_chain_them_on_next_block() {
#[test]
fn test_header_chain_proof_height_and_hash() {
let light_client_proof_method_id = [1u32; 8];
let batch_proof_method_id = [1u32; 8];
let da_verifier = MockDaVerifier {};

let blob_1 = create_mock_blob([1u8; 32], [2u8; 32], 2, true);
Expand All @@ -181,12 +213,19 @@ fn test_header_chain_proof_height_and_hash() {
da_data: vec![blob_1, blob_2],
inclusion_proof: [1u8; 32],
completeness_proof: (),
l2_genesis_state_root: Some([1u8; 32]),
batch_proof_method_id: light_client_proof_method_id,
batch_prover_da_pub_key: [9; 32].to_vec(),
};

let output_1 = run_circuit::<_, MockZkGuest>(da_verifier.clone(), input).unwrap();
let l2_genesis_state_root = [1u8; 32];
let batch_prover_da_pub_key = [9; 32].to_vec();

let output_1 = run_circuit::<_, MockZkGuest>(
da_verifier.clone(),
input,
l2_genesis_state_root,
batch_proof_method_id,
&batch_prover_da_pub_key,
)
.unwrap();

// Check that the state transition actually happened
assert_eq!(output_1.state_root, [3; 32]);
Expand All @@ -208,13 +247,16 @@ fn test_header_chain_proof_height_and_hash() {
light_client_proof_method_id,
inclusion_proof: [1u8; 32],
completeness_proof: (),
l2_genesis_state_root: None,
batch_proof_method_id: light_client_proof_method_id,
batch_prover_da_pub_key: [9; 32].to_vec(),
};

// Header chain verification must fail because the l1 block 3 was given before l1 block 2
let res = run_circuit::<_, MockZkGuest>(da_verifier, input_2);
let res = run_circuit::<_, MockZkGuest>(
da_verifier,
input_2,
l2_genesis_state_root,
batch_proof_method_id,
&batch_prover_da_pub_key,
);
assert!(matches!(
res,
Err(LightClientVerificationError::HeaderChainVerificationFailed)
Expand All @@ -239,12 +281,19 @@ fn test_unverifiable_batch_proofs() {
da_data: vec![blob_1, blob_2],
inclusion_proof: [1u8; 32],
completeness_proof: (),
l2_genesis_state_root: Some([1u8; 32]),
batch_proof_method_id,
batch_prover_da_pub_key: [9; 32].to_vec(),
};

let output_1 = run_circuit::<_, MockZkGuest>(da_verifier.clone(), input).unwrap();
let l2_genesis_state_root = [1u8; 32];
let batch_prover_da_pub_key = [9; 32].to_vec();

let output_1 = run_circuit::<_, MockZkGuest>(
da_verifier.clone(),
input,
l2_genesis_state_root,
batch_proof_method_id,
&batch_prover_da_pub_key,
)
.unwrap();

// Check that the state transition actually happened but only for verified batch proof
// and assert the unverified is ignored, so it is not even in the unchained outputs
Expand Down Expand Up @@ -272,12 +321,19 @@ fn test_unverifiable_prev_light_client_proof() {
da_data: vec![blob_1, blob_2],
inclusion_proof: [1u8; 32],
completeness_proof: (),
l2_genesis_state_root: Some([1u8; 32]),
batch_proof_method_id,
batch_prover_da_pub_key: [9; 32].to_vec(),
};

let output_1 = run_circuit::<_, MockZkGuest>(da_verifier.clone(), input).unwrap();
let l2_genesis_state_root = [1u8; 32];
let batch_prover_da_pub_key = [9; 32].to_vec();

let output_1 = run_circuit::<_, MockZkGuest>(
da_verifier.clone(),
input,
l2_genesis_state_root,
batch_proof_method_id,
&batch_prover_da_pub_key,
)
.unwrap();

// Check that the state transition actually happened but only for verified batch proof
// and assert the unverified is ignored, so it is not even in the unchained outputs
Expand All @@ -297,12 +353,15 @@ fn test_unverifiable_prev_light_client_proof() {
light_client_proof_method_id,
inclusion_proof: [1u8; 32],
completeness_proof: (),
l2_genesis_state_root: None,
batch_proof_method_id: light_client_proof_method_id,
batch_prover_da_pub_key: [9; 32].to_vec(),
};

let res = run_circuit::<_, MockZkGuest>(da_verifier, input_2);
let res = run_circuit::<_, MockZkGuest>(
da_verifier,
input_2,
l2_genesis_state_root,
light_client_proof_method_id,
&batch_prover_da_pub_key,
);
assert!(matches!(
res,
Err(LightClientVerificationError::InvalidPreviousLightClientProof)
Expand Down
Loading

0 comments on commit 487c84a

Please sign in to comment.