use crate::{attempt, Status, StatusCode};
use ckb_types::{packed, prelude::*};
use std::collections::HashSet;
pub struct CompactBlockVerifier {}
impl CompactBlockVerifier {
pub(crate) fn verify(block: &packed::CompactBlock) -> Status {
attempt!(PrefilledVerifier::verify(block));
attempt!(ShortIdsVerifier::verify(block));
Status::ok()
}
}
pub struct PrefilledVerifier {}
impl PrefilledVerifier {
pub(crate) fn verify(block: &packed::CompactBlock) -> Status {
let prefilled_transactions = &block.prefilled_transactions();
let short_ids = &block.short_ids();
let txs_len = prefilled_transactions.len() + short_ids.len();
if prefilled_transactions.is_empty() {
return StatusCode::CompactBlockHasNotPrefilledCellbase.into();
} else {
let index: usize = prefilled_transactions.get(0).unwrap().index().unpack();
if index != 0 {
return StatusCode::CompactBlockHasNotPrefilledCellbase.into();
}
let index: usize = prefilled_transactions
.get(prefilled_transactions.len() - 1)
.unwrap()
.index()
.unpack();
if index >= txs_len {
return StatusCode::CompactBlockHasOutOfIndexPrefilledTransactions.into();
}
}
for i in 0..(prefilled_transactions.len() - 1) {
let idx0: usize = prefilled_transactions.get(i).unwrap().index().unpack();
let idx1: usize = prefilled_transactions.get(i + 1).unwrap().index().unpack();
if idx0 >= idx1 {
return StatusCode::CompactBlockHasOutOfOrderPrefilledTransactions.into();
}
}
Status::ok()
}
}
pub struct ShortIdsVerifier {}
impl ShortIdsVerifier {
pub(crate) fn verify(block: &packed::CompactBlock) -> Status {
let prefilled_transactions = block.prefilled_transactions();
let short_ids = &block.short_ids();
let short_ids_set: HashSet<packed::ProposalShortId> =
short_ids.clone().into_iter().collect();
if short_ids.len() != short_ids_set.len() {
return StatusCode::CompactBlockHasDuplicatedShortIds.into();
}
let is_intersect = prefilled_transactions
.into_iter()
.skip(1)
.any(|pt| short_ids_set.contains(&pt.transaction().proposal_short_id()));
if is_intersect {
return StatusCode::CompactBlockHasDuplicatedPrefilledTransactions.into();
}
Status::ok()
}
}