Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified elf/celestia-range-elf-embedded
Binary file not shown.
Binary file modified elf/range-elf-bump
Binary file not shown.
Binary file modified elf/range-elf-embedded
Binary file not shown.
2 changes: 1 addition & 1 deletion utils/client/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ where
// Strip out all transactions that are not deposits.
attributes.transactions = attributes.transactions.map(|txs| {
txs.into_iter()
.filter(|tx| (!tx.is_empty() && tx[0] == OpTxType::Deposit as u8))
.filter(|tx| !tx.is_empty() && tx[0] == OpTxType::Deposit as u8)
.collect::<Vec<_>>()
});

Expand Down
5 changes: 5 additions & 0 deletions validity/src/prom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ pub enum ValidityGauge {
message = "Number of aggregation proof request errors"
)]
AggProofRequestErrorCount,
#[strum(
serialize = "succinct_agg_proof_validation_error_count",
message = "Number of aggregation proof validation errors"
)]
AggProofValidationErrorCount,
#[strum(
serialize = "succinct_relay_agg_proof_error_count",
message = "Number of relay aggregation proof errors"
Expand Down
131 changes: 130 additions & 1 deletion validity/src/proposer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,38 @@ where
.await?;

if let Some(unreq_agg_request) = unreq_agg_request {
return Ok(Some(unreq_agg_request));
// Fetch consecutive range proofs from the database associated with the aggregation
// proof request.
let range_proofs = self
.proof_requester
.db_client
.get_consecutive_complete_range_proofs(
unreq_agg_request.start_block,
unreq_agg_request.end_block,
&self.program_config.commitments,
self.requester_config.l1_chain_id,
self.requester_config.l2_chain_id,
)
.await?;

// Validate the aggregation proof request
match self.validate_aggregation_request(&range_proofs, &unreq_agg_request).await {
true => {
debug!(
"Aggregation request validated successfully: start_block={}, end_block={}",
unreq_agg_request.start_block, unreq_agg_request.end_block
);
return Ok(Some(unreq_agg_request));
}
false => {
debug!(
"Aggregation request validation failed, moving to range proofs: start_block={}, end_block={}",
unreq_agg_request.start_block, unreq_agg_request.end_block
);
ValidityGauge::AggProofValidationErrorCount.increment(1.0);
// Validation failed, continue to try fetching range proofs
}
}
}

let unreq_range_request = self
Expand All @@ -623,6 +654,104 @@ where
Ok(None)
}

/// Validates an aggregation proof request by checking that:
/// 1. There are no gaps between consecutive range proofs
/// 2. There are no duplicate/overlapping range proofs
/// 3. The range proofs cover the entire block range
pub async fn validate_aggregation_request(
&self,
range_proofs: &[OPSuccinctRequest],
agg_request: &OPSuccinctRequest,
) -> bool {
debug!(
"Validating aggregation proof request: start_block={}, end_block={}",
agg_request.start_block, agg_request.end_block
);

// Log all constituent range proofs
for (i, proof) in range_proofs.iter().enumerate() {
debug!(
"Range proof {}: start_block={}, end_block={}",
i, proof.start_block, proof.end_block
);
}

// If no range proofs found, validation fails
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if range_proofs.is_empty() {
warn!(
start_block = ?agg_request.start_block,
end_block = ?agg_request.end_block,
commitments = ?self.program_config.commitments,
"No consecutive span proof range found for request"
);
return false;
}

let first_range_proof_request =
range_proofs.first().expect("Range proofs should not be empty");

let last_range_proof_request =
range_proofs.last().expect("Range proofs should not be empty");

if first_range_proof_request.start_block != agg_request.start_block {
warn!(
expected_start_block = ?agg_request.start_block,
actual_start_block = ?first_range_proof_request.start_block,
commitments = ?self.program_config.commitments,
"Range proofs start block does not match aggregation request"
);

return false;
}

if last_range_proof_request.end_block != agg_request.end_block {
warn!(
expected_end_block = ?agg_request.end_block,
actual_end_block = ?last_range_proof_request.end_block,
commitments = ?self.program_config.commitments,
"Range proofs end block does not match aggregation request"
);
return false;
}

// Check for gaps and duplicates / overlaps between consecutive proofs
for i in 1..range_proofs.len() {
let prev_proof = &range_proofs[i - 1];
let curr_proof = &range_proofs[i];

// Check for gap
if prev_proof.end_block != curr_proof.start_block {
debug!(
"Gap detected: proof {} ends at {} but proof {} starts at {}",
i - 1,
prev_proof.end_block,
i,
curr_proof.start_block
);
return false;
}

// Check for overlap (duplicate blocks)
if prev_proof.end_block > curr_proof.start_block {
debug!(
"Overlap detected: proof {} ends at {} but proof {} starts at {}",
i - 1,
prev_proof.end_block,
i,
curr_proof.start_block
);
return false;
}
}

// All validation checks passed
debug!(
"Aggregation request validated successfully with {} consecutive range proofs",
range_proofs.len()
);
true
}

/// Relay all completed aggregation proofs to the contract.
#[tracing::instrument(name = "proposer.submit_agg_proofs", skip(self))]
async fn submit_agg_proofs(&self) -> Result<()> {
Expand Down
Loading