ckb_std/
high_level.rs

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
10/// Default buffer size, it is used to load data from syscall.
11/// The default value is set to 256, which will be enough for most cases:
12/// * load a `Script`, the typical size is 73 ~ 86
13/// * load a `CellOutput`, the typical size is 97 ~ 195
14pub const BUF_SIZE: usize = 256;
15
16/// Load tx hash
17///
18/// Return the tx hash or a syscall error
19///
20/// # Example
21///
22/// ```
23/// let tx_hash = load_tx_hash().unwrap();
24/// ```
25pub 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
32/// Load script hash
33///
34/// Return the script hash or a syscall error
35///
36/// # Example
37///
38/// ```
39/// let script_hash = load_script_hash().unwrap();
40/// ```
41pub 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
48/// Common method to fully load data from syscall
49fn 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
67/// Load cell
68///
69/// Return the cell or a syscall error
70///
71/// # Arguments
72///
73/// * `index` - index
74/// * `source` - source
75///
76/// # Example
77///
78/// ```
79/// let cell_output = load_cell(0, Source::Input).unwrap();
80/// ```
81///
82/// **Note:** This function can panic if the underlying data is too large,
83/// potentially causing an out-of-memory error.
84pub 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
93/// Load input
94///
95/// Return the input or a syscall error
96///
97/// # Arguments
98///
99/// * `index` - index
100/// * `source` - source
101///
102/// # Example
103///
104/// ```
105/// let input = load_input(0, Source::Input).unwrap();
106/// ```
107pub 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
117/// Load header
118///
119/// Return the header or a syscall error
120///
121/// # Arguments
122///
123/// * `index` - index
124/// * `source` - source
125///
126/// # Example
127///
128/// ```
129/// let header = load_header(0, Source::HeaderDep).unwrap();
130/// ```
131pub 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
141/// Load witness
142///
143/// Return the witness or a syscall error
144///
145/// # Arguments
146///
147/// * `index` - index
148/// * `source` - source
149///
150/// # Example
151///
152/// ```
153/// let witness = load_witness(0, Source::Input).unwrap();
154/// ```
155///
156/// **Note:** This function can panic if the underlying data is too large,
157/// potentially causing an out-of-memory error.
158pub 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
162/// Load witness args
163///
164/// Return the witness args or a syscall error
165///
166/// # Arguments
167///
168/// * `index` - index
169/// * `source` - source
170///
171/// # Example
172///
173/// ```
174/// let witness_args = load_witness_args(0, Source::Input).unwrap();
175/// ```
176///
177/// **Note:** This function can panic if the underlying data is too large,
178/// potentially causing an out-of-memory error.
179pub 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
188/// Load transaction
189///
190/// Return the transaction or a syscall error
191///
192/// # Example
193///
194/// ```
195/// let tx = load_transaction().unwrap();
196/// ```
197///
198/// **Note:** This function can panic if the underlying data is too large,
199/// potentially causing an out-of-memory error.
200pub 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
209/// Load cell capacity
210///
211/// Return the loaded data length or a syscall error
212///
213/// # Arguments
214///
215/// * `index` - index
216/// * `source` - source
217///
218/// # Example
219///
220/// ```
221/// let capacity = syscalls::load_cell_capacity(index, source).unwrap();
222/// ```
223pub 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
230/// Load cell occupied capacity
231///
232/// # Arguments
233///
234/// * `index` - index
235/// * `source` - source
236///
237/// # Example
238///
239/// ```
240/// let occupied_capacity = load_cell_occupied_capacity(index, source).unwrap();
241/// ```
242pub 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
250/// Load cell data hash
251///
252/// # Arguments
253///
254/// * `index` - index
255/// * `source` - source
256///
257/// # Example
258///
259/// ```
260/// let data_hash = load_cell_data_hash(index, source).unwrap();
261/// ```
262pub 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
269/// Load cell lock hash
270///
271/// # Arguments
272///
273/// * `index` - index
274/// * `source` - source
275///
276/// # Example
277///
278/// ```
279/// let lock_hash = load_cell_lock_hash(index, source).unwrap();
280/// ```
281pub 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
288/// Load cell type hash
289///
290/// return None if the cell has no type
291///
292/// # Arguments
293///
294/// * `index` - index
295/// * `source` - source
296///
297/// # Example
298///
299/// ```
300/// let type_hash = load_cell_type_hash(index, source).unwrap().unwrap();
301/// ```
302pub 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
314/// Load cell lock
315///
316/// Return the lock script or a syscall error
317///
318/// # Arguments
319///
320/// * `index` - index
321/// * `source` - source
322///
323/// # Example
324///
325/// ```
326/// let lock = load_cell_lock(index, source).unwrap();
327/// ```
328pub 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
339/// Load cell type
340///
341/// Return the type script or a syscall error, return None if the cell has no type
342///
343/// # Arguments
344///
345/// * `index` - index
346/// * `source` - source
347///
348/// # Example
349///
350/// ```
351/// let type_script = load_cell_type(index, source).unwrap().unwrap();
352/// ```
353pub 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
368// Load header epoch number
369///
370/// # Arguments
371///
372/// * `index` - index
373/// * `source` - source
374///
375/// # Example
376///
377/// ```
378/// let epoch_number = load_header_epoch_number(index, source).unwrap();
379/// ```
380pub 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
387/// Load header epoch start block number
388///
389/// # Arguments
390///
391/// * `index` - index
392/// * `source` - source
393///
394/// # Example
395///
396/// ```
397/// let epoch_start_block_number = load_header_epoch_start_block_number(index, source).unwrap();
398/// ```
399pub 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
412/// Load header epoch length
413///
414/// # Arguments
415///
416/// * `index` - index
417/// * `source` - source
418///
419/// # Example
420///
421/// ```
422/// let epoch_length = load_header_epoch_length(index, source).unwrap();
423/// ```
424pub 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
431/// Load input since
432///
433/// # Arguments
434///
435/// * `index` - index
436/// * `source` - source
437///
438/// # Example
439///
440/// ```
441/// let since = load_input_since(index, source).unwrap();
442/// ```
443pub 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
450/// Load input out point
451///
452/// # Arguments
453///
454/// * `index` - index
455/// * `source` - source
456///
457/// # Example
458///
459/// ```
460/// let out_point = load_input_out_point(index, source).unwrap();
461/// ```
462pub 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
472/// Load cell data
473///
474/// # Arguments
475///
476/// * `index` - index
477/// * `source` - source
478///
479/// # Example
480///
481/// ```
482/// let data = load_cell_data(index, source).unwrap();
483/// ```
484///
485/// **Note:** This function can panic if the underlying data is too large,
486/// potentially causing an out-of-memory error.
487pub 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
491/// Load script
492///
493/// # Example
494///
495/// ```
496/// let script = load_script().unwrap();
497/// ```
498pub 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
507/// QueryIter
508///
509/// A advanced iterator to manipulate cells/inputs/headers/witnesses
510///
511/// # Example
512///
513/// ```
514/// use high_level::load_cell_capacity;
515/// // calculate all inputs capacity
516/// let inputs_capacity = QueryIter::new(load_cell_capacity, Source::Input)
517/// .map(|capacity| capacity.unwrap_or(0))
518/// .sum::<u64>();
519///
520/// // calculate all outputs capacity
521/// let outputs_capacity = QueryIter::new(load_cell_capacity, Source::Output)
522/// .map(|capacity| capacity.unwrap_or(0))
523/// .sum::<u64>();
524///
525/// assert_eq!(inputs_capacity, outputs_capacity);
526/// ```
527pub struct QueryIter<F> {
528    query_fn: F,
529    index: usize,
530    source: Source,
531}
532
533impl<F> QueryIter<F> {
534    /// new
535    ///
536    /// # Arguments
537    ///
538    /// * `query_fn` - A high level query function, which accept `(index, source)` as args and
539    /// returns Result<T, SysError>. Examples: `load_cell`, `load_cell_data`,`load_witness_args`, `load_input`, `load_header`, ...
540    /// * `source` - source
541    ///
542    /// # Example
543    ///
544    /// ```
545    /// use high_level::load_cell;
546    /// // iterate all inputs cells
547    /// let iter = QueryIter::new(load_cell, Source::Input)
548    /// ```
549    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
575/// Find cell by data_hash
576///
577/// Iterate and find the cell which data hash equals `data_hash`,
578/// return the index of the first cell we found, otherwise return None.
579///
580pub 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
596/// Look for a dep cell with specific code hash, code_hash should be a buffer
597/// with 32 bytes.
598///
599pub 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
652/// Exec a cell in cell dep.
653///
654/// # Arguments
655///
656/// * `code_hash` - the code hash to search cell in cell deps.
657/// * `hash_type` - the hash type to search cell in cell deps.
658/// * `argv` - subprocess arguments. In most cases two types of parameters can be accepted:
659///            - if the parameter you want to pass can be represented by a string:
660///              - CStr::from_bytes_with_nul(b"arg0\0").unwrap();
661///              - CString::new("arg0").unwrap().as_c_str();
662///            - if you want to pass a piece of bytes data, you may encode it to hexadecimal string or other format:
663///              - high_level::encode_hex(&vec![0xff, 0xfe, 0xfd]);
664pub 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
684/// Spawn a cell in cell dep.
685///
686/// # Arguments
687///
688/// * `code_hash` - the code hash to search cell in cell deps.
689/// * `hash_type` - the hash type to search cell in cell deps.
690/// * `argv` - subprocess arguments. In most cases two types of parameters can be accepted:
691///            - if the parameter you want to pass can be represented by a string:
692///              - CStr::from_bytes_with_nul(b"arg0\0").unwrap();
693///              - CString::new("arg0").unwrap().as_c_str();
694///            - if you want to pass a piece of bytes data, you may encode it to hexadecimal string or other format:
695///              - high_level::encode_hex(&vec![0xff, 0xfe, 0xfd]);
696/// * `inherited_fds` - the fd list to be passed to the child process.
697pub 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
724/// Get inherited file descriptors.
725///
726/// # Example
727///
728/// ```
729/// let fds = inherited_fds();
730/// ```
731pub 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}