Skip to content

Commit

Permalink
refactor: checkpoint proof to verify only the batch transition
Browse files Browse the repository at this point in the history
  • Loading branch information
prajwolrg committed Feb 4, 2025
1 parent a0d413d commit 8060379
Show file tree
Hide file tree
Showing 16 changed files with 211 additions and 248 deletions.
4 changes: 2 additions & 2 deletions bin/strata-client/src/rpc_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -587,7 +587,7 @@ impl<D: Database + Send + Sync + 'static> StrataApiServer for StrataRpcImpl<D> {
Ok(client_state
.l1_view()
.last_finalized_checkpoint()
.map(|checkpoint| checkpoint.batch_info.idx()))
.map(|checkpoint| checkpoint.batch_info.epoch()))
} else {
// get latest checkpoint index from db
let idx = self
Expand Down Expand Up @@ -803,7 +803,7 @@ impl StrataSequencerApiServer for SequencerServerImpl {
verify_proof(&checkpoint, &proof_receipt, self.params.rollup())
.map_err(|e| Error::InvalidProof(idx, e.to_string()))?;

entry.proof = proof_receipt;
entry.proof = proof_receipt.proof().clone();
entry.proving_status = CheckpointProvingStatus::ProofReady;

debug!(%idx, "Proof is pending, setting proof reaedy");
Expand Down
15 changes: 8 additions & 7 deletions crates/consensus-logic/src/csm/client_transition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ pub fn process_event(
&batch_checkpoint_with_commitment.batch_checkpoint;
L1Checkpoint::new(
batch_checkpoint.batch_info().clone(),
batch_checkpoint.batch_transition().clone(),
batch_checkpoint.bootstrap_state().clone(),
!batch_checkpoint.proof().is_empty(),
*height,
Expand Down Expand Up @@ -434,14 +435,14 @@ pub fn filter_verified_checkpoints(
} else {
last_finalized
}
.map(|x| (x.batch_info.idx() + 1, Some(&x.batch_info)))
.map(|x| (x.batch_info.epoch() + 1, Some(&x.batch_transition)))
.unwrap_or((0, None)); // expect the first checkpoint

let mut result_checkpoints = Vec::new();

for checkpoint in checkpoints {
let curr_idx = checkpoint.batch_checkpoint.batch_info().idx;
let proof_receipt: ProofReceipt = checkpoint.batch_checkpoint.clone().into_proof_receipt();
let curr_idx = checkpoint.batch_checkpoint.batch_info().epoch;
let proof_receipt: ProofReceipt = checkpoint.batch_checkpoint.get_proof_receipt();
if curr_idx != expected_idx {
warn!(%expected_idx, %curr_idx, "Received invalid checkpoint idx, ignoring.");
continue;
Expand All @@ -450,7 +451,7 @@ pub fn filter_verified_checkpoints(
&& verify_proof(&checkpoint.batch_checkpoint, &proof_receipt, params).is_ok()
{
result_checkpoints.push(checkpoint.clone());
last_valid_checkpoint = Some(checkpoint.batch_checkpoint.batch_info());
last_valid_checkpoint = Some(checkpoint.batch_checkpoint.batch_transition());
} else if expected_idx == 0 {
warn!(%expected_idx, "Received invalid checkpoint proof, ignoring.");
} else {
Expand All @@ -460,8 +461,8 @@ pub fn filter_verified_checkpoints(
let last_l2_tsn = last_valid_checkpoint
.expect("There should be a last_valid_checkpoint")
.l2_transition;
let l1_tsn = checkpoint.batch_checkpoint.batch_info().l1_transition;
let l2_tsn = checkpoint.batch_checkpoint.batch_info().l2_transition;
let l1_tsn = checkpoint.batch_checkpoint.batch_transition().l1_transition;
let l2_tsn = checkpoint.batch_checkpoint.batch_transition().l2_transition;

if l1_tsn.0 != last_l1_tsn.1 {
warn!(obtained = ?l1_tsn.0, expected = ?last_l1_tsn.1, "Received invalid checkpoint l1 transition, ignoring.");
Expand All @@ -473,7 +474,7 @@ pub fn filter_verified_checkpoints(
}
if verify_proof(&checkpoint.batch_checkpoint, &proof_receipt, params).is_ok() {
result_checkpoints.push(checkpoint.clone());
last_valid_checkpoint = Some(checkpoint.batch_checkpoint.batch_info());
last_valid_checkpoint = Some(checkpoint.batch_checkpoint.batch_transition());
} else {
warn!(%expected_idx, "Received invalid checkpoint proof, ignoring.");
continue;
Expand Down
10 changes: 6 additions & 4 deletions crates/consensus-logic/src/csm/worker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,13 +312,14 @@ fn apply_action<D: Database>(
SyncAction::WriteCheckpoints(_height, checkpoints) => {
for c in checkpoints.iter() {
let batch_ckp = &c.batch_checkpoint;
let idx = batch_ckp.batch_info().idx();
let idx = batch_ckp.batch_info().epoch();
let pstatus = CheckpointProvingStatus::ProofReady;
let cstatus = CheckpointConfStatus::Confirmed;
let entry = CheckpointEntry::new(
batch_ckp.batch_info().clone(),
batch_ckp.batch_transition().clone(),
batch_ckp.bootstrap_state().clone(),
batch_ckp.clone().into_proof_receipt(),
batch_ckp.proof().clone(),
pstatus,
cstatus,
Some(c.commitment.clone().into()),
Expand All @@ -332,13 +333,14 @@ fn apply_action<D: Database>(
SyncAction::FinalizeCheckpoints(_height, checkpoints) => {
for c in checkpoints.iter() {
let batch_ckp = &c.batch_checkpoint;
let idx = batch_ckp.batch_info().idx();
let idx = batch_ckp.batch_info().epoch();
let pstatus = CheckpointProvingStatus::ProofReady;
let cstatus = CheckpointConfStatus::Finalized;
let entry = CheckpointEntry::new(
batch_ckp.batch_info().clone(),
batch_ckp.batch_transition().clone(),
batch_ckp.bootstrap_state().clone(),
batch_ckp.clone().into_proof_receipt(),
batch_ckp.proof().clone(),
pstatus,
cstatus,
Some(c.commitment.clone().into()),
Expand Down
2 changes: 1 addition & 1 deletion crates/consensus-logic/src/duty/worker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ fn update_tracker(
let latest_finalized_batch = state
.l1_view()
.last_finalized_checkpoint()
.map(|x| x.batch_info.idx());
.map(|x| x.batch_info.epoch());

let tracker_update = types::StateUpdate::new(
block_idx,
Expand Down
4 changes: 2 additions & 2 deletions crates/consensus-logic/src/l1_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ pub fn verify_proof(
rollup_params: &RollupParams,
) -> ZkVmResult<()> {
let rollup_vk = rollup_params.rollup_vk;
let checkpoint_idx = checkpoint.batch_info().idx();
let checkpoint_idx = checkpoint.batch_info().epoch();
info!(%checkpoint_idx, "verifying proof");

// FIXME: we are accepting empty proofs for now (devnet) to reduce dependency on the prover
Expand All @@ -197,7 +197,7 @@ pub fn verify_proof(
return Ok(());
}

let expected_public_output = checkpoint.proof_output();
let expected_public_output = checkpoint.get_proof_output();
let actual_public_output: CheckpointProofOutput =
borsh::from_slice(proof_receipt.public_values().as_bytes())
.map_err(|e| ZkVmError::OutputExtractionError { source: e.into() })?;
Expand Down
33 changes: 25 additions & 8 deletions crates/db/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ use strata_primitives::{
buf::Buf32,
l1::payload::{L1Payload, PayloadIntent},
};
use strata_state::batch::{BatchCheckpoint, BatchInfo, BootstrapState, CommitmentInfo};
use zkaleido::ProofReceipt;
use strata_state::batch::{
BatchCheckpoint, BatchInfo, BatchTransition, BootstrapState, CommitmentInfo,
};
use zkaleido::Proof;

/// Represents an intent to publish to some DA, which will be bundled for efficiency.
#[derive(Debug, Clone, PartialEq, BorshSerialize, BorshDeserialize, Arbitrary)]
Expand Down Expand Up @@ -187,12 +189,15 @@ pub struct CheckpointEntry {
/// Info related to the batch
pub batch_info: BatchInfo,

/// Transition data for L1 and L2 states, which is verified by the proof.
pub batch_transition: BatchTransition,

/// Includes the initial and final hashed state of both the `L1StateTransition` and
/// `L2StateTransition` that happened in this batch
pub bootstrap: BootstrapState,

/// Proof with public values
pub proof: ProofReceipt,
/// Proof
pub proof: Proof,

/// Proving Status
pub proving_status: CheckpointProvingStatus,
Expand All @@ -207,15 +212,17 @@ pub struct CheckpointEntry {
impl CheckpointEntry {
pub fn new(
batch_info: BatchInfo,
batch_transition: BatchTransition,
bootstrap: BootstrapState,
proof: ProofReceipt,
proof: Proof,
proving_status: CheckpointProvingStatus,
confirmation_status: CheckpointConfStatus,
commitment: Option<CheckpointCommitment>,
) -> Self {
Self {
batch_info,
bootstrap,
batch_transition,
proof,
proving_status,
confirmation_status,
Expand All @@ -224,15 +231,25 @@ impl CheckpointEntry {
}

pub fn into_batch_checkpoint(self) -> BatchCheckpoint {
BatchCheckpoint::new(self.batch_info, self.bootstrap, self.proof.proof().clone())
BatchCheckpoint::new(
self.batch_info,
self.batch_transition,
self.bootstrap,
self.proof,
)
}

/// Creates a new instance for a freshly defined checkpoint.
pub fn new_pending_proof(info: BatchInfo, bootstrap: BootstrapState) -> Self {
pub fn new_pending_proof(
info: BatchInfo,
transition: BatchTransition,
bootstrap: BootstrapState,
) -> Self {
Self::new(
info,
transition,
bootstrap,
ProofReceipt::default(),
Proof::default(),
CheckpointProvingStatus::PendingProof,
CheckpointConfStatus::Pending,
None,
Expand Down
51 changes: 18 additions & 33 deletions crates/proof-impl/checkpoint/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use borsh::{BorshDeserialize, BorshSerialize};
use strata_primitives::{params::RollupParams, proof::RollupVerifyingKey};
use strata_proofimpl_cl_stf::L2BatchProofOutput;
use strata_proofimpl_l1_batch::L1BatchProofOutput;
use strata_state::batch::{BatchInfo, CheckpointProofOutput};
use strata_state::batch::{BatchTransition, CheckpointProofOutput};
use zkaleido::{ProofReceipt, ZkVmEnv};

pub mod prover;
Expand Down Expand Up @@ -38,65 +38,50 @@ pub fn process_checkpoint_proof(
);

// Create BatchInfo based on `l1_batch` and `l2_batch`
let mut batch_info = BatchInfo::new(
0,
let batch_transition = BatchTransition::new(
(
l1_batch_output.initial_snapshot.block_num,
l1_batch_output.final_snapshot.block_num,
l1_batch_output.initial_state_hash,
l1_batch_output.final_state_hash,
),
(
l2_batch_output.initial_snapshot.slot,
l2_batch_output.final_snapshot.slot,
),
(
l1_batch_output.initial_snapshot.hash,
l1_batch_output.final_snapshot.hash,
),
(
l2_batch_output.initial_snapshot.hash,
l2_batch_output.final_snapshot.hash,
),
l2_batch_output.final_snapshot.l2_blockid,
(
l1_batch_output.initial_snapshot.acc_pow,
l1_batch_output.final_snapshot.acc_pow,
l2_batch_output.initial_state_hash,
l2_batch_output.final_state_hash,
),
l1_batch_output.rollup_params_commitment,
);

let (bootstrap, opt_prev_output) = match l1_batch_output.prev_checkpoint.as_ref() {
// Genesis batch: initialize with initial bootstrap state
None => (batch_info.get_initial_bootstrap_state(), None),
None => (batch_transition.get_initial_bootstrap_state(), None),
Some(prev_checkpoint) => {
// Ensure sequential state transition
assert_eq!(
prev_checkpoint.batch_info().get_final_bootstrap_state(),
batch_info.get_initial_bootstrap_state()
prev_checkpoint
.batch_transition()
.get_final_bootstrap_state(),
batch_transition.get_initial_bootstrap_state()
);

assert_eq!(
prev_checkpoint.batch_info().rollup_params_commitment(),
batch_info.rollup_params_commitment()
prev_checkpoint
.batch_transition()
.rollup_params_commitment(),
batch_transition.rollup_params_commitment()
);

batch_info.idx = prev_checkpoint.batch_info().idx + 1;

// If there exist proof for the prev_batch, use the prev_batch bootstrap state, else set
// the current batch initial info as bootstrap
if prev_checkpoint.proof().is_empty() {
// No proof in previous checkpoint: use initial bootstrap state
(batch_info.get_initial_bootstrap_state(), None)
(batch_transition.get_initial_bootstrap_state(), None)
} else {
// Use previous checkpoint's bootstrap state and include previous proof
let bootstrap = prev_checkpoint.bootstrap_state().clone();
(
bootstrap,
Some(prev_checkpoint.clone().into_proof_receipt()),
)
(bootstrap, Some(prev_checkpoint.get_proof_receipt()))
}
}
};
let output = CheckpointProofOutput::new(batch_info, bootstrap);
let output = CheckpointProofOutput::new(batch_transition, bootstrap);
(output, opt_prev_output)
}

Expand Down
14 changes: 5 additions & 9 deletions crates/proof-impl/cl-agg/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,7 @@ pub fn process_cl_agg(zkvm: &impl ZkVmEnv, cl_stf_vk: &[u32; 8]) {
"At least one CL proof is required for aggregation"
);

let mut cl_proof_pp_start: L2BatchProofOutput = zkvm.read_verified_borsh(cl_stf_vk);
// `BatchInfo` has range which is inclusive. This makes it compatible and avoids off by 1 issue.
// TODO: Do this in a better way
cl_proof_pp_start.initial_snapshot.slot += 1;

let cl_proof_pp_start: L2BatchProofOutput = zkvm.read_verified_borsh(cl_stf_vk);
let mut cl_proof_pp_prev = cl_proof_pp_start.clone();
let mut acc_deposits = cl_proof_pp_start.deposits.clone();

Expand All @@ -36,8 +32,8 @@ pub fn process_cl_agg(zkvm: &impl ZkVmEnv, cl_stf_vk: &[u32; 8]) {
// proof of the batch
let public_params = L2BatchProofOutput {
deposits: acc_deposits,
initial_snapshot: cl_proof_pp_start.initial_snapshot,
final_snapshot: cl_proof_pp_prev.final_snapshot,
initial_state_hash: cl_proof_pp_start.initial_state_hash,
final_state_hash: cl_proof_pp_prev.final_state_hash,
rollup_params_commitment,
};

Expand All @@ -50,8 +46,8 @@ fn validate_proof_consistency(
next_proof_cs_snap: &L2BatchProofOutput,
) {
assert_eq!(
current_proof_cs_snap.final_snapshot.hash, // post-state root of the current proof
next_proof_cs_snap.initial_snapshot.hash, // initial state root of the next proof
current_proof_cs_snap.final_state_hash, // post-state root of the current proof
next_proof_cs_snap.initial_state_hash, // initial state root of the next proof
"State root mismatch between proofs"
);
}
Loading

0 comments on commit 8060379

Please sign in to comment.