1use crate::ckb_constants::*;
2use crate::error::SysError;
3use crate::syscalls;
4use alloc::{ffi::CString, string::String, vec, vec::Vec};
5use ckb_types::{core::ScriptHashType, packed::*, prelude::*};
6use core::convert::Infallible;
7use core::ffi::CStr;
8use core::fmt::Write;
9
10pub const BUF_SIZE: usize = 256;
15
16pub fn load_tx_hash() -> Result<[u8; 32], SysError> {
26 let mut hash = [0u8; 32];
27 let len = syscalls::load_tx_hash(&mut hash, 0)?;
28 debug_assert_eq!(hash.len(), len);
29 Ok(hash)
30}
31
32pub fn load_script_hash() -> Result<[u8; 32], SysError> {
42 let mut hash = [0u8; 32];
43 let len = syscalls::load_script_hash(&mut hash, 0)?;
44 debug_assert_eq!(hash.len(), len);
45 Ok(hash)
46}
47
48fn load_data<F: Fn(&mut [u8], usize) -> Result<usize, SysError>>(
50 syscall: F,
51) -> Result<Vec<u8>, SysError> {
52 let mut buf = [0u8; BUF_SIZE];
53 match syscall(&mut buf, 0) {
54 Ok(len) => Ok(buf[..len].to_vec()),
55 Err(SysError::LengthNotEnough(actual_size)) => {
56 let mut data = vec![0; actual_size];
57 let loaded_len = buf.len();
58 data[..loaded_len].copy_from_slice(&buf);
59 let len = syscall(&mut data[loaded_len..], loaded_len)?;
60 debug_assert_eq!(len + loaded_len, actual_size);
61 Ok(data)
62 }
63 Err(err) => Err(err),
64 }
65}
66
67pub fn load_cell(index: usize, source: Source) -> Result<CellOutput, SysError> {
85 let data = load_data(|buf, offset| syscalls::load_cell(buf, offset, index, source))?;
86
87 match CellOutputReader::verify(&data, false) {
88 Ok(()) => Ok(CellOutput::new_unchecked(data.into())),
89 Err(_err) => Err(SysError::Encoding),
90 }
91}
92
93pub fn load_input(index: usize, source: Source) -> Result<CellInput, SysError> {
108 let mut data = [0u8; CellInput::TOTAL_SIZE];
109 syscalls::load_input(&mut data, 0, index, source)?;
110
111 match CellInputReader::verify(&data, false) {
112 Ok(()) => Ok(CellInput::new_unchecked(data.to_vec().into())),
113 Err(_err) => Err(SysError::Encoding),
114 }
115}
116
117pub fn load_header(index: usize, source: Source) -> Result<Header, SysError> {
132 let mut data = [0u8; Header::TOTAL_SIZE];
133 syscalls::load_header(&mut data, 0, index, source)?;
134
135 match HeaderReader::verify(&data, false) {
136 Ok(()) => Ok(Header::new_unchecked(data.to_vec().into())),
137 Err(_err) => Err(SysError::Encoding),
138 }
139}
140
141pub fn load_witness(index: usize, source: Source) -> Result<Vec<u8>, SysError> {
159 load_data(|buf, offset| syscalls::load_witness(buf, offset, index, source))
160}
161
162pub fn load_witness_args(index: usize, source: Source) -> Result<WitnessArgs, SysError> {
180 let data = load_data(|buf, offset| syscalls::load_witness(buf, offset, index, source))?;
181
182 match WitnessArgsReader::verify(&data, false) {
183 Ok(()) => Ok(WitnessArgs::new_unchecked(data.into())),
184 Err(_err) => Err(SysError::Encoding),
185 }
186}
187
188pub fn load_transaction() -> Result<Transaction, SysError> {
201 let data = load_data(|buf, offset| syscalls::load_transaction(buf, offset))?;
202
203 match TransactionReader::verify(&data, false) {
204 Ok(()) => Ok(Transaction::new_unchecked(data.into())),
205 Err(_err) => Err(SysError::Encoding),
206 }
207}
208
209pub fn load_cell_capacity(index: usize, source: Source) -> Result<u64, SysError> {
224 let mut buf = [0u8; 8];
225 let len = syscalls::load_cell_by_field(&mut buf, 0, index, source, CellField::Capacity)?;
226 debug_assert_eq!(len, buf.len());
227 Ok(u64::from_le_bytes(buf))
228}
229
230pub fn load_cell_occupied_capacity(index: usize, source: Source) -> Result<u64, SysError> {
243 let mut buf = [0u8; 8];
244 let len =
245 syscalls::load_cell_by_field(&mut buf, 0, index, source, CellField::OccupiedCapacity)?;
246 debug_assert_eq!(len, buf.len());
247 Ok(u64::from_le_bytes(buf))
248}
249
250pub fn load_cell_data_hash(index: usize, source: Source) -> Result<[u8; 32], SysError> {
263 let mut buf = [0u8; 32];
264 let len = syscalls::load_cell_by_field(&mut buf, 0, index, source, CellField::DataHash)?;
265 debug_assert_eq!(len, buf.len());
266 Ok(buf)
267}
268
269pub fn load_cell_lock_hash(index: usize, source: Source) -> Result<[u8; 32], SysError> {
282 let mut buf = [0u8; 32];
283 let len = syscalls::load_cell_by_field(&mut buf, 0, index, source, CellField::LockHash)?;
284 debug_assert_eq!(len, buf.len());
285 Ok(buf)
286}
287
288pub fn load_cell_type_hash(index: usize, source: Source) -> Result<Option<[u8; 32]>, SysError> {
303 let mut buf = [0u8; 32];
304 match syscalls::load_cell_by_field(&mut buf, 0, index, source, CellField::TypeHash) {
305 Ok(len) => {
306 debug_assert_eq!(len, buf.len());
307 Ok(Some(buf))
308 }
309 Err(SysError::ItemMissing) => Ok(None),
310 Err(err) => Err(err),
311 }
312}
313
314pub fn load_cell_lock(index: usize, source: Source) -> Result<Script, SysError> {
329 let data = load_data(|buf, offset| {
330 syscalls::load_cell_by_field(buf, offset, index, source, CellField::Lock)
331 })?;
332
333 match ScriptReader::verify(&data, false) {
334 Ok(()) => Ok(Script::new_unchecked(data.into())),
335 Err(_err) => Err(SysError::Encoding),
336 }
337}
338
339pub fn load_cell_type(index: usize, source: Source) -> Result<Option<Script>, SysError> {
354 let data = match load_data(|buf, offset| {
355 syscalls::load_cell_by_field(buf, offset, index, source, CellField::Type)
356 }) {
357 Ok(data) => data,
358 Err(SysError::ItemMissing) => return Ok(None),
359 Err(err) => return Err(err),
360 };
361
362 match ScriptReader::verify(&data, false) {
363 Ok(()) => Ok(Some(Script::new_unchecked(data.into()))),
364 Err(_err) => Err(SysError::Encoding),
365 }
366}
367
368pub fn load_header_epoch_number(index: usize, source: Source) -> Result<u64, SysError> {
381 let mut buf = [0u8; 8];
382 let len = syscalls::load_header_by_field(&mut buf, 0, index, source, HeaderField::EpochNumber)?;
383 debug_assert_eq!(len, buf.len());
384 Ok(u64::from_le_bytes(buf))
385}
386
387pub fn load_header_epoch_start_block_number(index: usize, source: Source) -> Result<u64, SysError> {
400 let mut buf = [0u8; 8];
401 let len = syscalls::load_header_by_field(
402 &mut buf,
403 0,
404 index,
405 source,
406 HeaderField::EpochStartBlockNumber,
407 )?;
408 debug_assert_eq!(len, buf.len());
409 Ok(u64::from_le_bytes(buf))
410}
411
412pub fn load_header_epoch_length(index: usize, source: Source) -> Result<u64, SysError> {
425 let mut buf = [0u8; 8];
426 let len = syscalls::load_header_by_field(&mut buf, 0, index, source, HeaderField::EpochLength)?;
427 debug_assert_eq!(len, buf.len());
428 Ok(u64::from_le_bytes(buf))
429}
430
431pub fn load_input_since(index: usize, source: Source) -> Result<u64, SysError> {
444 let mut buf = [0u8; 8];
445 let len = syscalls::load_input_by_field(&mut buf, 0, index, source, InputField::Since)?;
446 debug_assert_eq!(len, buf.len());
447 Ok(u64::from_le_bytes(buf))
448}
449
450pub fn load_input_out_point(index: usize, source: Source) -> Result<OutPoint, SysError> {
463 let mut data = [0u8; OutPoint::TOTAL_SIZE];
464 syscalls::load_input_by_field(&mut data, 0, index, source, InputField::OutPoint)?;
465
466 match OutPointReader::verify(&data, false) {
467 Ok(()) => Ok(OutPoint::new_unchecked(data.to_vec().into())),
468 Err(_err) => Err(SysError::Encoding),
469 }
470}
471
472pub fn load_cell_data(index: usize, source: Source) -> Result<Vec<u8>, SysError> {
488 load_data(|buf, offset| syscalls::load_cell_data(buf, offset, index, source))
489}
490
491pub fn load_script() -> Result<Script, SysError> {
499 let data = load_data(|buf, offset| syscalls::load_script(buf, offset))?;
500
501 match ScriptReader::verify(&data, false) {
502 Ok(()) => Ok(Script::new_unchecked(data.into())),
503 Err(_err) => Err(SysError::Encoding),
504 }
505}
506
507pub struct QueryIter<F> {
528 query_fn: F,
529 index: usize,
530 source: Source,
531}
532
533impl<F> QueryIter<F> {
534 pub fn new(query_fn: F, source: Source) -> Self {
550 QueryIter {
551 query_fn,
552 index: 0,
553 source,
554 }
555 }
556}
557
558impl<T, F: Fn(usize, Source) -> Result<T, SysError>> Iterator for QueryIter<F> {
559 type Item = T;
560
561 fn next(&mut self) -> Option<Self::Item> {
562 match (self.query_fn)(self.index, self.source) {
563 Ok(item) => {
564 self.index += 1;
565 Some(item)
566 }
567 Err(SysError::IndexOutOfBound) => None,
568 Err(err) => {
569 panic!("QueryIter error {:?}", err);
570 }
571 }
572 }
573}
574
575pub fn find_cell_by_data_hash(data_hash: &[u8], source: Source) -> Result<Option<usize>, SysError> {
581 let mut buf = [0u8; 32];
582 for i in 0.. {
583 let len = match syscalls::load_cell_by_field(&mut buf, 0, i, source, CellField::DataHash) {
584 Ok(len) => len,
585 Err(SysError::IndexOutOfBound) => break,
586 Err(err) => return Err(err),
587 };
588 debug_assert_eq!(len, buf.len());
589 if data_hash == &buf[..] {
590 return Ok(Some(i));
591 }
592 }
593 Ok(None)
594}
595
596pub fn look_for_dep_with_hash2(
600 code_hash: &[u8],
601 hash_type: ScriptHashType,
602) -> Result<usize, SysError> {
603 let field = match hash_type {
604 ScriptHashType::Type => CellField::TypeHash,
605 _ => CellField::DataHash,
606 };
607 let mut current: usize = 0;
608 loop {
609 let mut buf = [0u8; 32];
610 match syscalls::load_cell_by_field(&mut buf, 0, current, Source::CellDep, field) {
611 Ok(len) => {
612 debug_assert_eq!(len, buf.len());
613 if buf == code_hash {
614 return Ok(current);
615 }
616 }
617 Err(SysError::ItemMissing) => {}
618 Err(SysError::IndexOutOfBound) => {
619 return Err(SysError::IndexOutOfBound);
620 }
621 Err(err) => {
622 return Err(err);
623 }
624 }
625 current += 1;
626 }
627}
628
629pub fn look_for_dep_with_data_hash(data_hash: &[u8]) -> Result<usize, SysError> {
630 look_for_dep_with_hash2(data_hash, ScriptHashType::Data)
631}
632
633pub fn encode_hex(data: &[u8]) -> CString {
634 let mut s = String::with_capacity(data.len() * 2);
635 for &b in data {
636 write!(&mut s, "{:02x}", b).unwrap();
637 }
638 CString::new(s).unwrap()
639}
640
641pub fn decode_hex(data: &CStr) -> Result<Vec<u8>, SysError> {
642 let data = data.to_str().unwrap();
643 if data.len() & 1 != 0 {
644 return Err(SysError::Encoding);
645 }
646 (0..data.len())
647 .step_by(2)
648 .map(|i| u8::from_str_radix(&data[i..i + 2], 16).map_err(|_| SysError::Encoding))
649 .collect()
650}
651
652pub fn exec_cell(
665 code_hash: &[u8],
666 hash_type: ScriptHashType,
667 argv: &[&CStr],
668) -> Result<Infallible, SysError> {
669 #[cfg(not(feature = "native-simulator"))]
670 {
671 let index = look_for_dep_with_hash2(code_hash, hash_type)?;
672 let ret = syscalls::exec(index, Source::CellDep, 0, 0, argv);
673 let err = match ret {
674 1 => SysError::IndexOutOfBound,
675 2 => SysError::ItemMissing,
676 r => SysError::Unknown(r),
677 };
678 Err(err)
679 }
680 #[cfg(feature = "native-simulator")]
681 syscalls::exec_cell(code_hash, hash_type, argv)
682}
683
684pub fn spawn_cell(
698 code_hash: &[u8],
699 hash_type: ScriptHashType,
700 argv: &[&CStr],
701 inherited_fds: &[u64],
702) -> Result<u64, SysError> {
703 let mut inherited_fds = Vec::from(inherited_fds);
704 inherited_fds.push(0);
705 #[cfg(not(feature = "native-simulator"))]
706 {
707 let index = look_for_dep_with_hash2(code_hash, hash_type)?;
708 let argc = argv.len();
709 let mut process_id: u64 = 0;
710 let argv_ptr: Vec<*const i8> = argv.iter().map(|e| e.as_ptr() as *const i8).collect();
711 let mut spgs = syscalls::SpawnArgs {
712 argc: argc as u64,
713 argv: argv_ptr.as_ptr(),
714 process_id: &mut process_id as *mut u64,
715 inherited_fds: inherited_fds.as_ptr(),
716 };
717 syscalls::spawn(index, Source::CellDep, 0, 0, &mut spgs)?;
718 Ok(process_id)
719 }
720 #[cfg(feature = "native-simulator")]
721 syscalls::spawn_cell(code_hash, hash_type, argv, &inherited_fds)
722}
723
724pub fn inherited_fds() -> Vec<u64> {
732 let mut fds = [0u64; 64];
733 let l = syscalls::inherited_fds(&mut fds);
734 fds[..l as usize].to_vec()
735}