ckb_script/syscalls/
spawn.rs1use crate::syscalls::{
2 INDEX_OUT_OF_BOUND, SLICE_OUT_OF_BOUND, SOURCE_ENTRY_MASK, SOURCE_GROUP_FLAG, SPAWN,
3 SPAWN_EXTRA_CYCLES_BASE, SPAWN_YIELD_CYCLES_BASE, Source,
4};
5use crate::types::{DataLocation, DataPieceId, Fd, Message, SgData, SpawnArgs, VmContext, VmId};
6use ckb_traits::{CellDataProvider, ExtensionProvider, HeaderProvider};
7use ckb_vm::{
8 Error as VMError, Register,
9 machine::SupportMachine,
10 memory::Memory,
11 registers::{A0, A1, A2, A3, A4, A7},
12 snapshot2::Snapshot2Context,
13 syscalls::Syscalls,
14};
15use std::sync::{Arc, Mutex};
16
17pub struct Spawn<DL>
18where
19 DL: CellDataProvider + HeaderProvider + ExtensionProvider + Send + Sync + Clone + 'static,
20{
21 id: VmId,
22 message_box: Arc<Mutex<Vec<Message>>>,
23 snapshot2_context: Arc<Mutex<Snapshot2Context<DataPieceId, SgData<DL>>>>,
24}
25
26impl<DL> Spawn<DL>
27where
28 DL: CellDataProvider + HeaderProvider + ExtensionProvider + Send + Sync + Clone + 'static,
29{
30 pub fn new(vm_id: &VmId, vm_context: &VmContext<DL>) -> Self {
31 Self {
32 id: *vm_id,
33 message_box: Arc::clone(&vm_context.message_box),
34 snapshot2_context: Arc::clone(&vm_context.snapshot2_context),
35 }
36 }
37}
38
39impl<Mac, DL> Syscalls<Mac> for Spawn<DL>
40where
41 Mac: SupportMachine,
42 DL: CellDataProvider + HeaderProvider + ExtensionProvider + Send + Sync + Clone + 'static,
43{
44 fn initialize(&mut self, _machine: &mut Mac) -> Result<(), VMError> {
45 Ok(())
46 }
47
48 fn ecall(&mut self, machine: &mut Mac) -> Result<bool, VMError> {
49 if machine.registers()[A7].to_u64() != SPAWN {
50 return Ok(false);
51 }
52 let index = machine.registers()[A0].to_u64();
53 let mut source = machine.registers()[A1].to_u64();
54 let place = machine.registers()[A2].to_u64();
55 if let Source::Group(_) = Source::parse_from_u64(source)? {
58 source = source & SOURCE_ENTRY_MASK | SOURCE_GROUP_FLAG;
59 } else {
60 source &= SOURCE_ENTRY_MASK;
61 }
62 let data_piece_id = match DataPieceId::try_from((source, index, place)) {
63 Ok(id) => id,
64 Err(_) => {
65 machine.set_register(A0, Mac::REG::from_u8(INDEX_OUT_OF_BOUND));
66 return Ok(true);
67 }
68 };
69 let bounds = machine.registers()[A3].to_u64();
70 let offset = bounds >> 32;
71 let length = bounds as u32 as u64;
72 let spgs_addr = machine.registers()[A4].to_u64();
73 let argc_addr = spgs_addr;
74 let argc = machine
75 .memory_mut()
76 .load64(&Mac::REG::from_u64(argc_addr))?;
77 let argv_addr = spgs_addr.wrapping_add(8);
78 let argv = machine
79 .memory_mut()
80 .load64(&Mac::REG::from_u64(argv_addr))?;
81 let process_id_addr_addr = spgs_addr.wrapping_add(16);
82 let process_id_addr = machine
83 .memory_mut()
84 .load64(&Mac::REG::from_u64(process_id_addr_addr))?
85 .to_u64();
86 let fds_addr_addr = spgs_addr.wrapping_add(24);
87 let mut fds_addr = machine
88 .memory_mut()
89 .load64(&Mac::REG::from_u64(fds_addr_addr))?
90 .to_u64();
91
92 let mut fds = vec![];
93 if fds_addr != 0 {
94 loop {
95 let fd = machine
96 .memory_mut()
97 .load64(&Mac::REG::from_u64(fds_addr))?
98 .to_u64();
99 if fd == 0 {
100 break;
101 }
102 fds.push(Fd(fd));
103 fds_addr += 8;
104 }
105 }
106
107 let sc = self
109 .snapshot2_context
110 .lock()
111 .map_err(|e| VMError::Unexpected(e.to_string()))?;
112 let (_, full_length) = match sc.load_data(&data_piece_id, 0, 0) {
113 Ok(val) => val,
114 Err(VMError::SnapshotDataLoadError) => {
115 machine.set_register(A0, Mac::REG::from_u8(INDEX_OUT_OF_BOUND));
118 return Ok(true);
119 }
120 Err(e) => return Err(e),
121 };
122 if offset >= full_length {
123 machine.set_register(A0, Mac::REG::from_u8(SLICE_OUT_OF_BOUND));
124 return Ok(true);
125 }
126 if length > 0 {
127 let end = offset.checked_add(length).ok_or(VMError::MemOutOfBound)?;
128 if end > full_length {
129 machine.set_register(A0, Mac::REG::from_u8(SLICE_OUT_OF_BOUND));
130 return Ok(true);
131 }
132 }
133 machine.add_cycles_no_checking(SPAWN_EXTRA_CYCLES_BASE)?;
134 machine.add_cycles_no_checking(SPAWN_YIELD_CYCLES_BASE)?;
135 self.message_box
136 .lock()
137 .map_err(|e| VMError::Unexpected(e.to_string()))?
138 .push(Message::Spawn(
139 self.id,
140 SpawnArgs {
141 location: DataLocation {
142 data_piece_id,
143 offset,
144 length,
145 },
146 argc: argc.to_u64(),
147 argv: argv.to_u64(),
148 fds,
149 process_id_addr,
150 },
151 ));
152 Err(VMError::Yield)
153 }
154}