use crate::{
ckb_constants::Source,
error::SysError,
high_level::{QueryIter, load_cell_type_hash, load_input, load_script, load_script_hash},
syscalls::load_cell,
};
use alloc::vec::Vec;
use ckb_hash::new_blake2b;
use ckb_types::prelude::Entity;
fn is_cell_present(index: usize, source: Source) -> bool {
let buf = &mut [];
matches!(
load_cell(buf, 0, index, source),
Ok(_) | Err(SysError::LengthNotEnough(_))
)
}
fn locate_index() -> Result<usize, SysError> {
let hash = load_script_hash()?;
let index = QueryIter::new(load_cell_type_hash, Source::Output)
.position(|type_hash| type_hash == Some(hash))
.ok_or(SysError::TypeIDError)?;
Ok(index)
}
pub fn validate_type_id(type_id: &[u8]) -> Result<(), SysError> {
if is_cell_present(1, Source::GroupInput) || is_cell_present(1, Source::GroupOutput) {
return Err(SysError::TypeIDError);
}
if !is_cell_present(0, Source::GroupInput) {
let index = locate_index()? as u64;
let input = load_input(0, Source::Input)?;
let mut blake2b = new_blake2b();
blake2b.update(input.as_slice());
blake2b.update(&index.to_le_bytes());
let mut ret = [0; 32];
blake2b.finalize(&mut ret);
if type_id.len() > ret.len() {
return Err(SysError::TypeIDError);
}
if &ret[..type_id.len()] != type_id {
return Err(SysError::TypeIDError);
}
}
Ok(())
}
fn load_id_from_args(offset: usize, length: usize) -> Result<Vec<u8>, SysError> {
let script = load_script()?;
let args = script.as_reader().args();
let args_data = args.raw_data();
Ok(args_data
.get(offset..offset + length)
.ok_or(SysError::TypeIDError)?
.to_vec())
}
pub fn check_type_id(offset: usize, length: usize) -> Result<(), SysError> {
let type_id = load_id_from_args(offset, length)?;
validate_type_id(&type_id)?;
Ok(())
}