From 1399a3e61dc220cb3a5aa55761c8484360c6d60c Mon Sep 17 00:00:00 2001 From: mohanson Date: Wed, 6 Mar 2024 16:41:07 +0800 Subject: [PATCH 1/7] Rewrite current_cycles --- script/src/syscalls/current_cycles.rs | 7 ++-- script/src/syscalls/spawn.rs | 5 ++- .../syscalls/tests/vm_latest/syscalls_2.rs | 2 +- script/src/v2_scheduler.rs | 3 +- script/src/v2_syscalls.rs | 32 +++-------------- script/src/verify.rs | 34 +++++++++---------- 6 files changed, 32 insertions(+), 51 deletions(-) diff --git a/script/src/syscalls/current_cycles.rs b/script/src/syscalls/current_cycles.rs index dc87cd281c..a791cef7a4 100644 --- a/script/src/syscalls/current_cycles.rs +++ b/script/src/syscalls/current_cycles.rs @@ -3,14 +3,15 @@ use ckb_vm::{ registers::{A0, A7}, Error as VMError, Register, SupportMachine, Syscalls, }; +use std::sync::{Arc, Mutex}; #[derive(Debug, Default)] pub struct CurrentCycles { - base: u64, + base: Arc>, } impl CurrentCycles { - pub fn new(base: u64) -> Self { + pub fn new(base: Arc>) -> Self { Self { base } } } @@ -26,6 +27,8 @@ impl Syscalls for CurrentCycles { } let cycles = self .base + .lock() + .map_err(|e| VMError::Unexpected(e.to_string()))? .checked_add(machine.cycles()) .ok_or(VMError::CyclesOverflow)?; machine.set_register(A0, Mac::REG::from_u64(cycles)); diff --git a/script/src/syscalls/spawn.rs b/script/src/syscalls/spawn.rs index 9b7fee0298..ad903e81b8 100644 --- a/script/src/syscalls/spawn.rs +++ b/script/src/syscalls/spawn.rs @@ -291,9 +291,8 @@ pub fn build_child_machine< let machine_builder = machine_syscalls .into_iter() .fold(machine_builder, |builder, syscall| builder.syscall(syscall)); - let machine_builder = machine_builder.syscall(Box::new( - syscalls_generator.build_current_cycles(*cycles_base), - )); + let machine_builder = + machine_builder.syscall(Box::new(syscalls_generator.build_current_cycles())); let machine_builder = machine_builder.syscall(Box::new( syscalls_generator.build_get_memory_limit(*callee_memory_limit), )); diff --git a/script/src/syscalls/tests/vm_latest/syscalls_2.rs b/script/src/syscalls/tests/vm_latest/syscalls_2.rs index 372b0377d3..bcc7ed5704 100644 --- a/script/src/syscalls/tests/vm_latest/syscalls_2.rs +++ b/script/src/syscalls/tests/vm_latest/syscalls_2.rs @@ -53,7 +53,7 @@ fn test_current_cycles() { machine.set_cycles(cycles); - let result = CurrentCycles::new(0).ecall(&mut machine); + let result = CurrentCycles::new(Arc::new(Mutex::new(0))).ecall(&mut machine); assert!(result.unwrap()); assert_eq!(machine.registers()[A0], cycles); diff --git a/script/src/v2_scheduler.rs b/script/src/v2_scheduler.rs index afc9865076..0f627ba102 100644 --- a/script/src/v2_scheduler.rs +++ b/script/src/v2_scheduler.rs @@ -767,8 +767,9 @@ impl { - id: VmId, - base_cycles: Arc>, - message_box: Arc>>, - snapshot2_context: Arc>>>, - script_version: ScriptVersion, + pub(crate) id: VmId, + pub(crate) base_cycles: Arc>, + pub(crate) message_box: Arc>>, + pub(crate) snapshot2_context: Arc>>>, + pub(crate) script_version: ScriptVersion, } impl @@ -49,25 +49,10 @@ impl u64 { - *self.base_cycles.lock().expect("lock") - } - pub fn set_base_cycles(&mut self, base_cycles: u64) { *self.base_cycles.lock().expect("lock") = base_cycles; } - // The different architecture here requires a re-implementation on current - // cycles syscall. - fn current_cycles(&mut self, machine: &mut Mac) -> Result<(), Error> { - let cycles = self - .base_cycles() - .checked_add(machine.cycles()) - .ok_or(Error::CyclesOverflow)?; - machine.set_register(A0, Mac::REG::from_u64(cycles)); - Ok(()) - } - // Reimplementation of load_cell_data but keep tracks of pages that are copied from // surrounding transaction data. Those pages do not need to be added to snapshots. fn load_cell_data(&mut self, machine: &mut Mac) -> Result<(), Error> { @@ -492,13 +477,6 @@ impl< fn ecall(&mut self, machine: &mut Mac) -> Result { let code = machine.registers()[A7].to_u64(); match code { - 2042 => { - if self.script_version >= ScriptVersion::V1 { - self.current_cycles(machine) - } else { - return Ok(false); - } - } 2091 => self.load_cell_data_as_code(machine), 2092 => self.load_cell_data(machine), 2177 => self.debug(machine), diff --git a/script/src/verify.rs b/script/src/verify.rs index 8f6f0e5cbe..1bb9e0ca09 100644 --- a/script/src/verify.rs +++ b/script/src/verify.rs @@ -144,20 +144,21 @@ impl Binaries { /// TransactionScriptsSyscallsGenerator can be cloned. #[derive(Clone)] pub struct TransactionScriptsSyscallsGenerator
{ + pub(crate) base_cycles: Arc>, pub(crate) data_loader: DL, - debug_printer: DebugPrinter, + pub(crate) debug_printer: DebugPrinter, pub(crate) outputs: Arc>, pub(crate) rtx: Arc, #[cfg(test)] - skip_pause: Arc, + pub(crate) skip_pause: Arc, } impl TransactionScriptsSyscallsGenerator
{ /// Build syscall: current_cycles - pub fn build_current_cycles(&self, base: u64) -> CurrentCycles { - CurrentCycles::new(base) + pub fn build_current_cycles(&self) -> CurrentCycles { + CurrentCycles::new(Arc::clone(&self.base_cycles)) } /// Build syscall: vm_version @@ -315,8 +316,6 @@ impl= ScriptVersion::V1 { syscalls.append(&mut vec![ Box::new(self.build_vm_version()), @@ -324,14 +323,16 @@ impl= ScriptVersion::V2 { syscalls.push(Box::new( self.build_load_block_extension(Arc::clone(&script_group_input_indices)), )); } + #[cfg(test)] + syscalls.push(Box::new(Pause::new(Arc::clone(&self.skip_pause)))); syscalls } @@ -343,9 +344,6 @@ impl>, ) -> Vec)>> { let mut syscalls = self.generate_same_syscalls(script_version, script_group); - if script_version >= ScriptVersion::V1 { - syscalls.push(Box::new(self.build_current_cycles(0))); - } if script_version >= ScriptVersion::V2 { syscalls.append(&mut vec![ Box::new(self.build_get_memory_limit(8)), @@ -385,7 +383,7 @@ pub struct TransactionScriptsVerifier
{ consensus: Arc, tx_env: Arc, - generator: TransactionScriptsSyscallsGenerator
, + syscalls_generator: TransactionScriptsSyscallsGenerator
, } impl @@ -481,7 +479,8 @@ impl(&mut self, func: F) { - self.generator.debug_printer = Arc::new(func); + self.syscalls_generator.debug_printer = Arc::new(func); } #[cfg(test)] @@ -1065,7 +1064,7 @@ impl>, ) -> Vec)>> { - self.generator + self.syscalls_generator .generate_root_syscalls(script_version, script_group, context) } @@ -1104,7 +1103,8 @@ impl ScriptError::ExceededMaximumCycles(max_cycles), @@ -1248,7 +1248,7 @@ impl Date: Wed, 6 Mar 2024 20:30:49 +0800 Subject: [PATCH 2/7] Rewrite process_id --- script/src/syscalls/mod.rs | 3 +++ script/src/syscalls/process_id.rs | 30 ++++++++++++++++++++++++++++++ script/src/v2_scheduler.rs | 19 +++++++++++-------- script/src/v2_syscalls.rs | 14 -------------- script/src/verify.rs | 16 +++++++++++++--- 5 files changed, 57 insertions(+), 25 deletions(-) create mode 100644 script/src/syscalls/process_id.rs diff --git a/script/src/syscalls/mod.rs b/script/src/syscalls/mod.rs index ed0f5fc839..1e3935006b 100644 --- a/script/src/syscalls/mod.rs +++ b/script/src/syscalls/mod.rs @@ -12,6 +12,7 @@ mod load_script; mod load_script_hash; mod load_tx; mod load_witness; +mod process_id; mod set_content; pub(crate) mod spawn; mod utils; @@ -37,6 +38,7 @@ pub use self::load_script::LoadScript; pub use self::load_script_hash::LoadScriptHash; pub use self::load_tx::LoadTx; pub use self::load_witness::LoadWitness; +pub use self::process_id::ProcessID; pub use self::set_content::SetContent; pub use self::spawn::Spawn; pub use self::vm_version::VMVersion; @@ -81,6 +83,7 @@ pub const SET_CONTENT: u64 = 2103; pub const LOAD_BLOCK_EXTENSION: u64 = 2104; pub const CURRENT_MEMORY: u64 = 2105; pub const DEBUG_PRINT_SYSCALL_NUMBER: u64 = 2177; +pub const PROCESS_ID: u64 = 2603; #[cfg(test)] pub const DEBUG_PAUSE: u64 = 2178; diff --git a/script/src/syscalls/process_id.rs b/script/src/syscalls/process_id.rs new file mode 100644 index 0000000000..55114ae18a --- /dev/null +++ b/script/src/syscalls/process_id.rs @@ -0,0 +1,30 @@ +use crate::syscalls::PROCESS_ID; +use ckb_vm::{ + registers::{A0, A7}, + Error as VMError, Register, SupportMachine, Syscalls, +}; + +#[derive(Debug, Default)] +pub struct ProcessID { + id: u64, +} + +impl ProcessID { + pub fn new(id: u64) -> Self { + Self { id } + } +} + +impl Syscalls for ProcessID { + fn initialize(&mut self, _machine: &mut Mac) -> Result<(), VMError> { + Ok(()) + } + + fn ecall(&mut self, machine: &mut Mac) -> Result { + if machine.registers()[A7].to_u64() != PROCESS_ID { + return Ok(false); + } + machine.set_register(A0, Mac::REG::from_u64(self.id)); + Ok(true) + } +} diff --git a/script/src/v2_scheduler.rs b/script/src/v2_scheduler.rs index 0f627ba102..8648506442 100644 --- a/script/src/v2_scheduler.rs +++ b/script/src/v2_scheduler.rs @@ -52,7 +52,7 @@ pub struct Scheduler< // implementation is strictly tied to TransactionScriptsVerifier, we // are using it here to save some extra code. script_version: ScriptVersion, - syscalls: TransactionScriptsSyscallsGenerator
, + syscalls_generator: TransactionScriptsSyscallsGenerator
, total_cycles: Cycle, next_vm_id: VmId, @@ -76,12 +76,12 @@ impl, script_version: ScriptVersion, - syscalls: TransactionScriptsSyscallsGenerator
, + syscalls_generator: TransactionScriptsSyscallsGenerator
, ) -> Self { Self { tx_data, script_version, - syscalls, + syscalls_generator, total_cycles: 0, next_vm_id: FIRST_VM_ID, next_pipe_slot: FIRST_PIPE_SLOT, @@ -103,13 +103,13 @@ impl, script_version: ScriptVersion, - syscalls: TransactionScriptsSyscallsGenerator
, + syscalls_generator: TransactionScriptsSyscallsGenerator
, full: FullSuspendedState, ) -> Self { Self { tx_data, script_version, - syscalls, + syscalls_generator, total_cycles: full.total_cycles, next_vm_id: full.next_vm_id, next_pipe_slot: full.next_pipe_slot, @@ -767,9 +767,13 @@ impl(&mut self, machine: &mut Mac) -> Result<(), Error> { - // TODO: charge cycles - machine.set_register(A0, Mac::REG::from_u64(self.id)); - Ok(()) - } - // Create a pair of pipes fn pipe(&mut self, machine: &mut Mac) -> Result<(), Error> { let pipe1_addr = machine.registers()[A0].to_u64(); @@ -496,13 +489,6 @@ impl< return Ok(false); } } - 2603 => { - if self.script_version >= ScriptVersion::V2 { - self.process_id(machine) - } else { - return Ok(false); - } - } 2604 => { if self.script_version >= ScriptVersion::V2 { self.pipe(machine) diff --git a/script/src/verify.rs b/script/src/verify.rs index 1bb9e0ca09..2a450a86ab 100644 --- a/script/src/verify.rs +++ b/script/src/verify.rs @@ -1,7 +1,9 @@ #[cfg(test)] use crate::syscalls::Pause; +use crate::syscalls::ProcessID; use crate::v2_scheduler::Scheduler; use crate::v2_types::{RunMode, TxData}; +use crate::v2_types::{VmId, FIRST_VM_ID}; use crate::{ cost_model::transferred_byte_cycles, error::{ScriptError, TransactionScriptError}, @@ -151,6 +153,7 @@ pub struct TransactionScriptsSyscallsGenerator
{ pub(crate) rtx: Arc, #[cfg(test)] pub(crate) skip_pause: Arc, + pub(crate) vm_id: VmId, } impl @@ -279,6 +282,11 @@ impl ProcessID { + ProcessID::new(id) + } + /// Build syscall: current_memory pub fn build_current_memory(&self, current_memory: u64) -> CurrentMemory { CurrentMemory::new(current_memory) @@ -327,9 +335,10 @@ impl= ScriptVersion::V2 { - syscalls.push(Box::new( - self.build_load_block_extension(Arc::clone(&script_group_input_indices)), - )); + syscalls.append(&mut vec![ + Box::new(self.build_load_block_extension(Arc::clone(&script_group_input_indices))), + Box::new(self.build_process_id(self.vm_id)), + ]); } #[cfg(test)] syscalls.push(Box::new(Pause::new(Arc::clone(&self.skip_pause)))); @@ -487,6 +496,7 @@ impl Date: Wed, 6 Mar 2024 21:17:32 +0800 Subject: [PATCH 3/7] Rewrite pipe --- script/src/syscalls/mod.rs | 3 +++ script/src/syscalls/pipe.rs | 44 +++++++++++++++++++++++++++++++++++++ script/src/v2_scheduler.rs | 3 ++- script/src/v2_syscalls.rs | 23 ------------------- script/src/verify.rs | 19 +++++++++++----- 5 files changed, 62 insertions(+), 30 deletions(-) create mode 100644 script/src/syscalls/pipe.rs diff --git a/script/src/syscalls/mod.rs b/script/src/syscalls/mod.rs index 1e3935006b..cfecfd51dc 100644 --- a/script/src/syscalls/mod.rs +++ b/script/src/syscalls/mod.rs @@ -12,6 +12,7 @@ mod load_script; mod load_script_hash; mod load_tx; mod load_witness; +mod pipe; mod process_id; mod set_content; pub(crate) mod spawn; @@ -38,6 +39,7 @@ pub use self::load_script::LoadScript; pub use self::load_script_hash::LoadScriptHash; pub use self::load_tx::LoadTx; pub use self::load_witness::LoadWitness; +pub use self::pipe::Pipe; pub use self::process_id::ProcessID; pub use self::set_content::SetContent; pub use self::spawn::Spawn; @@ -84,6 +86,7 @@ pub const LOAD_BLOCK_EXTENSION: u64 = 2104; pub const CURRENT_MEMORY: u64 = 2105; pub const DEBUG_PRINT_SYSCALL_NUMBER: u64 = 2177; pub const PROCESS_ID: u64 = 2603; +pub const PIPE: u64 = 2604; #[cfg(test)] pub const DEBUG_PAUSE: u64 = 2178; diff --git a/script/src/syscalls/pipe.rs b/script/src/syscalls/pipe.rs new file mode 100644 index 0000000000..07c508b0b4 --- /dev/null +++ b/script/src/syscalls/pipe.rs @@ -0,0 +1,44 @@ +use crate::syscalls::PIPE; +use crate::v2_types::{Message, PipeArgs, VmId}; +use ckb_vm::{ + registers::{A0, A7}, + Error as VMError, Register, SupportMachine, Syscalls, +}; +use std::sync::{Arc, Mutex}; + +#[derive(Debug)] +pub struct Pipe { + id: VmId, + message_box: Arc>>, +} + +impl Pipe { + pub fn new(id: VmId, message_box: Arc>>) -> Self { + Self { id, message_box } + } +} + +impl Syscalls for Pipe { + fn initialize(&mut self, _machine: &mut Mac) -> Result<(), VMError> { + Ok(()) + } + + fn ecall(&mut self, machine: &mut Mac) -> Result { + if machine.registers()[A7].to_u64() != PIPE { + return Ok(false); + } + let pipe1_addr = machine.registers()[A0].to_u64(); + let pipe2_addr = pipe1_addr.wrapping_add(8); + self.message_box + .lock() + .map_err(|e| VMError::Unexpected(e.to_string()))? + .push(Message::Pipe( + self.id, + PipeArgs { + pipe1_addr, + pipe2_addr, + }, + )); + Err(VMError::External("YIELD".to_string())) + } +} diff --git a/script/src/v2_scheduler.rs b/script/src/v2_scheduler.rs index 8648506442..3e3745f69f 100644 --- a/script/src/v2_scheduler.rs +++ b/script/src/v2_scheduler.rs @@ -78,6 +78,7 @@ impl, ) -> Self { + let message_box = syscalls_generator.message_box.clone(); Self { tx_data, script_version, @@ -90,7 +91,7 @@ impl(&mut self, machine: &mut Mac) -> Result<(), Error> { - let pipe1_addr = machine.registers()[A0].to_u64(); - let pipe2_addr = pipe1_addr.wrapping_add(8); - // TODO: charge cycles - self.message_box.lock().expect("lock").push(Message::Pipe( - self.id, - PipeArgs { - pipe1_addr, - pipe2_addr, - }, - )); - - Err(Error::External("YIELD".to_string())) - } - // Write to pipe fn pipe_write(&mut self, machine: &mut Mac) -> Result<(), Error> { let pipe = PipeId(machine.registers()[A0].to_u64()); @@ -489,13 +473,6 @@ impl< return Ok(false); } } - 2604 => { - if self.script_version >= ScriptVersion::V2 { - self.pipe(machine) - } else { - return Ok(false); - } - } 2605 => { if self.script_version >= ScriptVersion::V2 { self.pipe_write(machine) diff --git a/script/src/verify.rs b/script/src/verify.rs index 2a450a86ab..303639b0ed 100644 --- a/script/src/verify.rs +++ b/script/src/verify.rs @@ -2,15 +2,14 @@ use crate::syscalls::Pause; use crate::syscalls::ProcessID; use crate::v2_scheduler::Scheduler; -use crate::v2_types::{RunMode, TxData}; -use crate::v2_types::{VmId, FIRST_VM_ID}; +use crate::v2_types::{Message, RunMode, TxData, VmId, FIRST_VM_ID}; use crate::{ cost_model::transferred_byte_cycles, error::{ScriptError, TransactionScriptError}, syscalls::{ spawn::{build_child_machine, update_caller_machine}, CurrentCycles, CurrentMemory, Debugger, Exec, GetMemoryLimit, LoadBlockExtension, LoadCell, - LoadCellData, LoadHeader, LoadInput, LoadScript, LoadScriptHash, LoadTx, LoadWitness, + LoadCellData, LoadHeader, LoadInput, LoadScript, LoadScriptHash, LoadTx, LoadWitness, Pipe, SetContent, Spawn, VMVersion, }, type_id::TypeIdSystemScript, @@ -149,6 +148,7 @@ pub struct TransactionScriptsSyscallsGenerator
{ pub(crate) base_cycles: Arc>, pub(crate) data_loader: DL, pub(crate) debug_printer: DebugPrinter, + pub(crate) message_box: Arc>>, pub(crate) outputs: Arc>, pub(crate) rtx: Arc, #[cfg(test)] @@ -283,8 +283,13 @@ impl ProcessID { - ProcessID::new(id) + pub fn build_process_id(&self) -> ProcessID { + ProcessID::new(self.vm_id) + } + + /// Build syscall: pipe + pub fn build_pipe(&self) -> Pipe { + Pipe::new(self.vm_id, self.message_box.clone()) } /// Build syscall: current_memory @@ -337,7 +342,8 @@ impl= ScriptVersion::V2 { syscalls.append(&mut vec![ Box::new(self.build_load_block_extension(Arc::clone(&script_group_input_indices))), - Box::new(self.build_process_id(self.vm_id)), + Box::new(self.build_process_id()), + Box::new(self.build_pipe()), ]); } #[cfg(test)] @@ -492,6 +498,7 @@ impl Date: Thu, 7 Mar 2024 09:12:29 +0800 Subject: [PATCH 4/7] Rewrite wait --- script/src/syscalls/mod.rs | 11 ++++++---- script/src/syscalls/wait.rs | 44 +++++++++++++++++++++++++++++++++++++ script/src/v2_syscalls.rs | 26 ---------------------- script/src/verify.rs | 8 ++++++- 4 files changed, 58 insertions(+), 31 deletions(-) create mode 100644 script/src/syscalls/wait.rs diff --git a/script/src/syscalls/mod.rs b/script/src/syscalls/mod.rs index cfecfd51dc..0493001704 100644 --- a/script/src/syscalls/mod.rs +++ b/script/src/syscalls/mod.rs @@ -18,6 +18,7 @@ mod set_content; pub(crate) mod spawn; mod utils; mod vm_version; +mod wait; #[cfg(test)] mod pause; @@ -44,6 +45,7 @@ pub use self::process_id::ProcessID; pub use self::set_content::SetContent; pub use self::spawn::Spawn; pub use self::vm_version::VMVersion; +pub use self::wait::Wait; #[cfg(test)] pub use self::pause::Pause; @@ -79,14 +81,15 @@ pub const LOAD_HEADER_BY_FIELD_SYSCALL_NUMBER: u64 = 2082; pub const LOAD_INPUT_BY_FIELD_SYSCALL_NUMBER: u64 = 2083; pub const LOAD_CELL_DATA_AS_CODE_SYSCALL_NUMBER: u64 = 2091; pub const LOAD_CELL_DATA_SYSCALL_NUMBER: u64 = 2092; -pub const SPAWN: u64 = 2101; +pub const LOAD_BLOCK_EXTENSION: u64 = 2104; +pub const SPAWN: u64 = 2601; +pub const WAIT: u64 = 2602; +pub const PROCESS_ID: u64 = 2603; +pub const PIPE: u64 = 2604; pub const GET_MEMORY_LIMIT: u64 = 2102; pub const SET_CONTENT: u64 = 2103; -pub const LOAD_BLOCK_EXTENSION: u64 = 2104; pub const CURRENT_MEMORY: u64 = 2105; pub const DEBUG_PRINT_SYSCALL_NUMBER: u64 = 2177; -pub const PROCESS_ID: u64 = 2603; -pub const PIPE: u64 = 2604; #[cfg(test)] pub const DEBUG_PAUSE: u64 = 2178; diff --git a/script/src/syscalls/wait.rs b/script/src/syscalls/wait.rs new file mode 100644 index 0000000000..f2b4dc74b6 --- /dev/null +++ b/script/src/syscalls/wait.rs @@ -0,0 +1,44 @@ +use crate::syscalls::WAIT; +use crate::v2_types::{Message, VmId, WaitArgs}; +use ckb_vm::{ + registers::{A0, A1, A7}, + Error as VMError, Register, SupportMachine, Syscalls, +}; +use std::sync::{Arc, Mutex}; + +#[derive(Debug)] +pub struct Wait { + id: VmId, + message_box: Arc>>, +} + +impl Wait { + pub fn new(id: VmId, message_box: Arc>>) -> Self { + Self { id, message_box } + } +} + +impl Syscalls for Wait { + fn initialize(&mut self, _machine: &mut Mac) -> Result<(), VMError> { + Ok(()) + } + + fn ecall(&mut self, machine: &mut Mac) -> Result { + if machine.registers()[A7].to_u64() != WAIT { + return Ok(false); + } + let target_id = machine.registers()[A0].to_u64(); + let exit_code_addr = machine.registers()[A1].to_u64(); + self.message_box + .lock() + .map_err(|e| VMError::Unexpected(e.to_string()))? + .push(Message::Wait( + self.id, + WaitArgs { + target_id, + exit_code_addr, + }, + )); + Err(VMError::External("YIELD".to_string())) + } +} diff --git a/script/src/v2_syscalls.rs b/script/src/v2_syscalls.rs index db92ccd68b..0d82d5f7b7 100644 --- a/script/src/v2_syscalls.rs +++ b/script/src/v2_syscalls.rs @@ -320,25 +320,6 @@ impl(&mut self, machine: &mut Mac) -> Result<(), Error> { - let target_id = machine.registers()[A0].to_u64(); - let exit_code_addr = machine.registers()[A1].to_u64(); - - // TODO: charge cycles - self.message_box.lock().expect("lock").push(Message::Wait( - self.id, - WaitArgs { - target_id, - exit_code_addr, - }, - )); - - // Like spawn, join yields control upon success - Err(Error::External("YIELD".to_string())) - } - // Write to pipe fn pipe_write(&mut self, machine: &mut Mac) -> Result<(), Error> { let pipe = PipeId(machine.registers()[A0].to_u64()); @@ -466,13 +447,6 @@ impl< return Ok(false); } } - 2602 => { - if self.script_version >= ScriptVersion::V2 { - self.wait(machine) - } else { - return Ok(false); - } - } 2605 => { if self.script_version >= ScriptVersion::V2 { self.pipe_write(machine) diff --git a/script/src/verify.rs b/script/src/verify.rs index 303639b0ed..5137e54219 100644 --- a/script/src/verify.rs +++ b/script/src/verify.rs @@ -10,7 +10,7 @@ use crate::{ spawn::{build_child_machine, update_caller_machine}, CurrentCycles, CurrentMemory, Debugger, Exec, GetMemoryLimit, LoadBlockExtension, LoadCell, LoadCellData, LoadHeader, LoadInput, LoadScript, LoadScriptHash, LoadTx, LoadWitness, Pipe, - SetContent, Spawn, VMVersion, + SetContent, Spawn, VMVersion, Wait, }, type_id::TypeIdSystemScript, types::{ @@ -282,6 +282,11 @@ impl Wait { + Wait::new(self.vm_id, self.message_box.clone()) + } + /// Build syscall: process_id pub fn build_process_id(&self) -> ProcessID { ProcessID::new(self.vm_id) @@ -344,6 +349,7 @@ impl Date: Thu, 7 Mar 2024 09:52:12 +0800 Subject: [PATCH 5/7] Rewrite read/write --- script/src/syscalls/mod.rs | 6 +++ script/src/syscalls/read.rs | 62 +++++++++++++++++++++++++ script/src/syscalls/write.rs | 62 +++++++++++++++++++++++++ script/src/v2_syscalls.rs | 90 +----------------------------------- script/src/verify.rs | 14 +++++- 5 files changed, 144 insertions(+), 90 deletions(-) create mode 100644 script/src/syscalls/read.rs create mode 100644 script/src/syscalls/write.rs diff --git a/script/src/syscalls/mod.rs b/script/src/syscalls/mod.rs index 0493001704..eb548e9d5d 100644 --- a/script/src/syscalls/mod.rs +++ b/script/src/syscalls/mod.rs @@ -14,11 +14,13 @@ mod load_tx; mod load_witness; mod pipe; mod process_id; +mod read; mod set_content; pub(crate) mod spawn; mod utils; mod vm_version; mod wait; +mod write; #[cfg(test)] mod pause; @@ -42,10 +44,12 @@ pub use self::load_tx::LoadTx; pub use self::load_witness::LoadWitness; pub use self::pipe::Pipe; pub use self::process_id::ProcessID; +pub use self::read::Read; pub use self::set_content::SetContent; pub use self::spawn::Spawn; pub use self::vm_version::VMVersion; pub use self::wait::Wait; +pub use self::write::Write; #[cfg(test)] pub use self::pause::Pause; @@ -86,6 +90,8 @@ pub const SPAWN: u64 = 2601; pub const WAIT: u64 = 2602; pub const PROCESS_ID: u64 = 2603; pub const PIPE: u64 = 2604; +pub const WRITE: u64 = 2605; +pub const READ: u64 = 2606; pub const GET_MEMORY_LIMIT: u64 = 2102; pub const SET_CONTENT: u64 = 2103; pub const CURRENT_MEMORY: u64 = 2105; diff --git a/script/src/syscalls/read.rs b/script/src/syscalls/read.rs new file mode 100644 index 0000000000..90ce16e793 --- /dev/null +++ b/script/src/syscalls/read.rs @@ -0,0 +1,62 @@ +use crate::cost_model::transferred_byte_cycles; +use crate::syscalls::READ; +use crate::v2_syscalls::INVALID_PIPE; +use crate::v2_types::{Message, PipeId, PipeIoArgs, VmId}; +use ckb_vm::{ + registers::{A0, A1, A2, A7}, + Error as VMError, Memory, Register, SupportMachine, Syscalls, +}; +use std::sync::{Arc, Mutex}; + +#[derive(Debug)] +pub struct Read { + id: VmId, + message_box: Arc>>, +} + +impl Read { + pub fn new(id: VmId, message_box: Arc>>) -> Self { + Self { id, message_box } + } +} + +impl Syscalls for Read { + fn initialize(&mut self, _machine: &mut Mac) -> Result<(), VMError> { + Ok(()) + } + + fn ecall(&mut self, machine: &mut Mac) -> Result { + if machine.registers()[A7].to_u64() != READ { + return Ok(false); + } + let pipe = PipeId(machine.registers()[A0].to_u64()); + let buffer_addr = machine.registers()[A1].to_u64(); + let length_addr = machine.registers()[A2].to_u64(); + let length = machine + .memory_mut() + .load64(&Mac::REG::from_u64(length_addr))? + .to_u64(); + + // We can only do basic checks here, when the message is actually processed, + // more complete checks will be performed. + // We will also leave to the actual write operation to test memory permissions. + if !pipe.is_read() { + machine.set_register(A0, Mac::REG::from_u8(INVALID_PIPE)); + return Ok(true); + } + machine.add_cycles_no_checking(transferred_byte_cycles(length))?; + self.message_box + .lock() + .map_err(|e| VMError::Unexpected(e.to_string()))? + .push(Message::PipeRead( + self.id, + PipeIoArgs { + pipe, + length, + buffer_addr, + length_addr, + }, + )); + Err(VMError::External("YIELD".to_string())) + } +} diff --git a/script/src/syscalls/write.rs b/script/src/syscalls/write.rs new file mode 100644 index 0000000000..19ec918469 --- /dev/null +++ b/script/src/syscalls/write.rs @@ -0,0 +1,62 @@ +use crate::cost_model::transferred_byte_cycles; +use crate::syscalls::WRITE; +use crate::v2_syscalls::INVALID_PIPE; +use crate::v2_types::{Message, PipeId, PipeIoArgs, VmId}; +use ckb_vm::{ + registers::{A0, A1, A2, A7}, + Error as VMError, Memory, Register, SupportMachine, Syscalls, +}; +use std::sync::{Arc, Mutex}; + +#[derive(Debug)] +pub struct Write { + id: VmId, + message_box: Arc>>, +} + +impl Write { + pub fn new(id: VmId, message_box: Arc>>) -> Self { + Self { id, message_box } + } +} + +impl Syscalls for Write { + fn initialize(&mut self, _machine: &mut Mac) -> Result<(), VMError> { + Ok(()) + } + + fn ecall(&mut self, machine: &mut Mac) -> Result { + if machine.registers()[A7].to_u64() != WRITE { + return Ok(false); + } + let pipe = PipeId(machine.registers()[A0].to_u64()); + let buffer_addr = machine.registers()[A1].to_u64(); + let length_addr = machine.registers()[A2].to_u64(); + let length = machine + .memory_mut() + .load64(&Mac::REG::from_u64(length_addr))? + .to_u64(); + + // We can only do basic checks here, when the message is actually processed, + // more complete checks will be performed. + // We will also leave to the actual write operation to test memory permissions. + if !pipe.is_write() { + machine.set_register(A0, Mac::REG::from_u8(INVALID_PIPE)); + return Ok(true); + } + machine.add_cycles_no_checking(transferred_byte_cycles(length))?; + self.message_box + .lock() + .map_err(|e| VMError::Unexpected(e.to_string()))? + .push(Message::PipeWrite( + self.id, + PipeIoArgs { + pipe, + length, + buffer_addr, + length_addr, + }, + )); + Err(VMError::External("YIELD".to_string())) + } +} diff --git a/script/src/v2_syscalls.rs b/script/src/v2_syscalls.rs index 0d82d5f7b7..cd4e2fa090 100644 --- a/script/src/v2_syscalls.rs +++ b/script/src/v2_syscalls.rs @@ -1,7 +1,5 @@ use crate::{ - v2_types::{ - DataPieceId, Message, PipeArgs, PipeId, PipeIoArgs, SpawnArgs, TxData, VmId, WaitArgs, - }, + v2_types::{DataPieceId, Message, PipeId, PipeIoArgs, SpawnArgs, TxData, VmId}, ScriptVersion, }; use ckb_traits::{CellDataProvider, ExtensionProvider, HeaderProvider}; @@ -320,78 +318,6 @@ impl(&mut self, machine: &mut Mac) -> Result<(), Error> { - let pipe = PipeId(machine.registers()[A0].to_u64()); - let buffer_addr = machine.registers()[A1].to_u64(); - let length_addr = machine.registers()[A2].to_u64(); - let length = machine - .memory_mut() - .load64(&Mac::REG::from_u64(length_addr))? - .to_u64(); - - // We can only do basic checks here, when the message is actually processed, - // more complete checks will be performed. - // We will also leave to the actual write operation to test memory permissions. - if !pipe.is_write() { - machine.set_register(A0, Mac::REG::from_u8(INVALID_PIPE)); - return Ok(()); - } - - // TODO: charge cycles - self.message_box - .lock() - .expect("lock") - .push(Message::PipeWrite( - self.id, - PipeIoArgs { - pipe, - length, - buffer_addr, - length_addr, - }, - )); - - // A0 will be updated once the write operation is fulfilled - Err(Error::External("YIELD".to_string())) - } - - // Read from pipe - fn pipe_read(&mut self, machine: &mut Mac) -> Result<(), Error> { - let pipe = PipeId(machine.registers()[A0].to_u64()); - let buffer_addr = machine.registers()[A1].to_u64(); - let length_addr = machine.registers()[A2].to_u64(); - let length = machine - .memory_mut() - .load64(&Mac::REG::from_u64(length_addr))? - .to_u64(); - - // We can only do basic checks here, when the message is actually processed, - // more complete checks will be performed. - // We will also leave to the actual write operation to test memory permissions. - if !pipe.is_read() { - machine.set_register(A0, Mac::REG::from_u8(INVALID_PIPE)); - return Ok(()); - } - - // TODO: charge cycles - self.message_box - .lock() - .expect("lock") - .push(Message::PipeRead( - self.id, - PipeIoArgs { - pipe, - length, - buffer_addr, - length_addr, - }, - )); - - // A0 will be updated once the read operation is fulfilled - Err(Error::External("YIELD".to_string())) - } - fn inherited_file_descriptors( &mut self, machine: &mut Mac, @@ -447,20 +373,6 @@ impl< return Ok(false); } } - 2605 => { - if self.script_version >= ScriptVersion::V2 { - self.pipe_write(machine) - } else { - return Ok(false); - } - } - 2606 => { - if self.script_version >= ScriptVersion::V2 { - self.pipe_read(machine) - } else { - return Ok(false); - } - } 2607 => { if self.script_version >= ScriptVersion::V2 { self.inherited_file_descriptors(machine) diff --git a/script/src/verify.rs b/script/src/verify.rs index 5137e54219..83d15a4202 100644 --- a/script/src/verify.rs +++ b/script/src/verify.rs @@ -10,7 +10,7 @@ use crate::{ spawn::{build_child_machine, update_caller_machine}, CurrentCycles, CurrentMemory, Debugger, Exec, GetMemoryLimit, LoadBlockExtension, LoadCell, LoadCellData, LoadHeader, LoadInput, LoadScript, LoadScriptHash, LoadTx, LoadWitness, Pipe, - SetContent, Spawn, VMVersion, Wait, + Read, SetContent, Spawn, VMVersion, Wait, Write, }, type_id::TypeIdSystemScript, types::{ @@ -297,6 +297,16 @@ impl Write { + Write::new(self.vm_id, self.message_box.clone()) + } + + /// Build syscall: read + pub fn build_read(&self) -> Read { + Read::new(self.vm_id, self.message_box.clone()) + } + /// Build syscall: current_memory pub fn build_current_memory(&self, current_memory: u64) -> CurrentMemory { CurrentMemory::new(current_memory) @@ -350,6 +360,8 @@ impl Date: Thu, 7 Mar 2024 10:18:59 +0800 Subject: [PATCH 6/7] Rewrite inherited_fd --- script/src/syscalls/inherited_fd.rs | 46 +++++++++++++++++++++++++++++ script/src/syscalls/mod.rs | 3 ++ script/src/v2_syscalls.rs | 30 +------------------ script/src/verify.rs | 8 ++++- 4 files changed, 57 insertions(+), 30 deletions(-) create mode 100644 script/src/syscalls/inherited_fd.rs diff --git a/script/src/syscalls/inherited_fd.rs b/script/src/syscalls/inherited_fd.rs new file mode 100644 index 0000000000..b9c79ca15d --- /dev/null +++ b/script/src/syscalls/inherited_fd.rs @@ -0,0 +1,46 @@ +use crate::syscalls::INHERITED_FD; +use crate::v2_types::{Message, PipeId, PipeIoArgs, VmId}; +use ckb_vm::{ + registers::{A0, A1, A7}, + Error as VMError, Register, SupportMachine, Syscalls, +}; +use std::sync::{Arc, Mutex}; + +#[derive(Debug)] +pub struct InheritedFd { + id: VmId, + message_box: Arc>>, +} + +impl InheritedFd { + pub fn new(id: VmId, message_box: Arc>>) -> Self { + Self { id, message_box } + } +} + +impl Syscalls for InheritedFd { + fn initialize(&mut self, _machine: &mut Mac) -> Result<(), VMError> { + Ok(()) + } + + fn ecall(&mut self, machine: &mut Mac) -> Result { + if machine.registers()[A7].to_u64() != INHERITED_FD { + return Ok(false); + } + let buffer_addr = machine.registers()[A0].to_u64(); + let length_addr = machine.registers()[A1].to_u64(); + self.message_box + .lock() + .map_err(|e| VMError::Unexpected(e.to_string()))? + .push(Message::InheritedFileDescriptor( + self.id, + PipeIoArgs { + pipe: PipeId(0), + length: 0, + buffer_addr, + length_addr, + }, + )); + Err(VMError::External("YIELD".to_string())) + } +} diff --git a/script/src/syscalls/mod.rs b/script/src/syscalls/mod.rs index eb548e9d5d..7e03010188 100644 --- a/script/src/syscalls/mod.rs +++ b/script/src/syscalls/mod.rs @@ -3,6 +3,7 @@ mod current_memory; mod debugger; mod exec; mod get_memory_limit; +mod inherited_fd; mod load_block_extension; mod load_cell; mod load_cell_data; @@ -33,6 +34,7 @@ pub use self::current_memory::CurrentMemory; pub use self::debugger::Debugger; pub use self::exec::Exec; pub use self::get_memory_limit::GetMemoryLimit; +pub use self::inherited_fd::InheritedFd; pub use self::load_block_extension::LoadBlockExtension; pub use self::load_cell::LoadCell; pub use self::load_cell_data::LoadCellData; @@ -92,6 +94,7 @@ pub const PROCESS_ID: u64 = 2603; pub const PIPE: u64 = 2604; pub const WRITE: u64 = 2605; pub const READ: u64 = 2606; +pub const INHERITED_FD: u64 = 2607; pub const GET_MEMORY_LIMIT: u64 = 2102; pub const SET_CONTENT: u64 = 2103; pub const CURRENT_MEMORY: u64 = 2105; diff --git a/script/src/v2_syscalls.rs b/script/src/v2_syscalls.rs index cd4e2fa090..e65a356fe4 100644 --- a/script/src/v2_syscalls.rs +++ b/script/src/v2_syscalls.rs @@ -1,5 +1,5 @@ use crate::{ - v2_types::{DataPieceId, Message, PipeId, PipeIoArgs, SpawnArgs, TxData, VmId}, + v2_types::{DataPieceId, Message, PipeId, SpawnArgs, TxData, VmId}, ScriptVersion, }; use ckb_traits::{CellDataProvider, ExtensionProvider, HeaderProvider}; @@ -318,27 +318,6 @@ impl( - &mut self, - machine: &mut Mac, - ) -> Result<(), Error> { - let buffer_addr = machine.registers()[A0].to_u64(); - let length_addr = machine.registers()[A1].to_u64(); - self.message_box - .lock() - .expect("lock") - .push(Message::InheritedFileDescriptor( - self.id, - PipeIoArgs { - pipe: PipeId(0), - length: 0, - buffer_addr, - length_addr, - }, - )); - Err(Error::External("YIELD".to_string())) - } - fn close(&mut self, machine: &mut Mac) -> Result<(), Error> { let pipe = PipeId(machine.registers()[A0].to_u64()); self.message_box @@ -373,13 +352,6 @@ impl< return Ok(false); } } - 2607 => { - if self.script_version >= ScriptVersion::V2 { - self.inherited_file_descriptors(machine) - } else { - return Ok(false); - } - } 2608 => { if self.script_version >= ScriptVersion::V2 { self.close(machine) diff --git a/script/src/verify.rs b/script/src/verify.rs index 83d15a4202..780386f00b 100644 --- a/script/src/verify.rs +++ b/script/src/verify.rs @@ -1,6 +1,6 @@ #[cfg(test)] use crate::syscalls::Pause; -use crate::syscalls::ProcessID; +use crate::syscalls::{InheritedFd, ProcessID}; use crate::v2_scheduler::Scheduler; use crate::v2_types::{Message, RunMode, TxData, VmId, FIRST_VM_ID}; use crate::{ @@ -307,6 +307,11 @@ impl InheritedFd { + InheritedFd::new(self.vm_id, self.message_box.clone()) + } + /// Build syscall: current_memory pub fn build_current_memory(&self, current_memory: u64) -> CurrentMemory { CurrentMemory::new(current_memory) @@ -362,6 +367,7 @@ impl Date: Thu, 7 Mar 2024 10:38:32 +0800 Subject: [PATCH 7/7] Rewrite close --- script/src/syscalls/close.rs | 37 ++++++++++++++++++++++++++++++++++++ script/src/syscalls/mod.rs | 3 +++ script/src/v2_syscalls.rs | 16 ---------------- script/src/verify.rs | 12 +++++++++--- 4 files changed, 49 insertions(+), 19 deletions(-) create mode 100644 script/src/syscalls/close.rs diff --git a/script/src/syscalls/close.rs b/script/src/syscalls/close.rs new file mode 100644 index 0000000000..b797736202 --- /dev/null +++ b/script/src/syscalls/close.rs @@ -0,0 +1,37 @@ +use crate::syscalls::CLOSE; +use crate::v2_types::{Message, PipeId, VmId}; +use ckb_vm::{ + registers::{A0, A7}, + Error as VMError, Register, SupportMachine, Syscalls, +}; +use std::sync::{Arc, Mutex}; + +#[derive(Debug)] +pub struct Close { + id: VmId, + message_box: Arc>>, +} + +impl Close { + pub fn new(id: VmId, message_box: Arc>>) -> Self { + Self { id, message_box } + } +} + +impl Syscalls for Close { + fn initialize(&mut self, _machine: &mut Mac) -> Result<(), VMError> { + Ok(()) + } + + fn ecall(&mut self, machine: &mut Mac) -> Result { + if machine.registers()[A7].to_u64() != CLOSE { + return Ok(false); + } + let pipe = PipeId(machine.registers()[A0].to_u64()); + self.message_box + .lock() + .map_err(|e| VMError::Unexpected(e.to_string()))? + .push(Message::Close(self.id, pipe)); + Err(VMError::External("YIELD".to_string())) + } +} diff --git a/script/src/syscalls/mod.rs b/script/src/syscalls/mod.rs index 7e03010188..0bdfdbf4be 100644 --- a/script/src/syscalls/mod.rs +++ b/script/src/syscalls/mod.rs @@ -1,3 +1,4 @@ +mod close; mod current_cycles; mod current_memory; mod debugger; @@ -29,6 +30,7 @@ mod pause; #[cfg(test)] mod tests; +pub use self::close::Close; pub use self::current_cycles::CurrentCycles; pub use self::current_memory::CurrentMemory; pub use self::debugger::Debugger; @@ -95,6 +97,7 @@ pub const PIPE: u64 = 2604; pub const WRITE: u64 = 2605; pub const READ: u64 = 2606; pub const INHERITED_FD: u64 = 2607; +pub const CLOSE: u64 = 2608; pub const GET_MEMORY_LIMIT: u64 = 2102; pub const SET_CONTENT: u64 = 2103; pub const CURRENT_MEMORY: u64 = 2105; diff --git a/script/src/v2_syscalls.rs b/script/src/v2_syscalls.rs index e65a356fe4..39973f5afe 100644 --- a/script/src/v2_syscalls.rs +++ b/script/src/v2_syscalls.rs @@ -317,15 +317,6 @@ impl(&mut self, machine: &mut Mac) -> Result<(), Error> { - let pipe = PipeId(machine.registers()[A0].to_u64()); - self.message_box - .lock() - .expect("lock") - .push(Message::Close(self.id, pipe)); - Err(Error::External("YIELD".to_string())) - } } impl< @@ -352,13 +343,6 @@ impl< return Ok(false); } } - 2608 => { - if self.script_version >= ScriptVersion::V2 { - self.close(machine) - } else { - return Ok(false); - } - } _ => return Ok(false), }?; Ok(true) diff --git a/script/src/verify.rs b/script/src/verify.rs index 780386f00b..fa61136bba 100644 --- a/script/src/verify.rs +++ b/script/src/verify.rs @@ -8,9 +8,9 @@ use crate::{ error::{ScriptError, TransactionScriptError}, syscalls::{ spawn::{build_child_machine, update_caller_machine}, - CurrentCycles, CurrentMemory, Debugger, Exec, GetMemoryLimit, LoadBlockExtension, LoadCell, - LoadCellData, LoadHeader, LoadInput, LoadScript, LoadScriptHash, LoadTx, LoadWitness, Pipe, - Read, SetContent, Spawn, VMVersion, Wait, Write, + Close, CurrentCycles, CurrentMemory, Debugger, Exec, GetMemoryLimit, LoadBlockExtension, + LoadCell, LoadCellData, LoadHeader, LoadInput, LoadScript, LoadScriptHash, LoadTx, + LoadWitness, Pipe, Read, SetContent, Spawn, VMVersion, Wait, Write, }, type_id::TypeIdSystemScript, types::{ @@ -312,6 +312,11 @@ impl Close { + Close::new(self.vm_id, self.message_box.clone()) + } + /// Build syscall: current_memory pub fn build_current_memory(&self, current_memory: u64) -> CurrentMemory { CurrentMemory::new(current_memory) @@ -368,6 +373,7 @@ impl