diff --git a/script/src/v2_scheduler.rs b/script/src/v2_scheduler.rs index 8efc260547a..3d66a9ee6c3 100644 --- a/script/src/v2_scheduler.rs +++ b/script/src/v2_scheduler.rs @@ -33,6 +33,7 @@ use std::{ }; const ROOT_VM_ID: VmId = FIRST_VM_ID; +const MAX_VMS_COUNT: u64 = 16; const MAX_INSTANTIATED_VMS: usize = 4; /// A single Scheduler instance is used to verify a single script @@ -53,6 +54,7 @@ where script_version: ScriptVersion, syscalls_generator: TransactionScriptsSyscallsGenerator
, + max_vms_count: u64, total_cycles: Cycle, next_vm_id: VmId, next_pipe_slot: u64, @@ -83,6 +85,7 @@ where tx_data, script_version, syscalls_generator, + max_vms_count: MAX_VMS_COUNT, total_cycles: 0, next_vm_id: FIRST_VM_ID, next_pipe_slot: FIRST_PIPE_SLOT, @@ -112,6 +115,7 @@ where tx_data, script_version, syscalls_generator, + max_vms_count: full.max_vms_count, total_cycles: full.total_cycles, next_vm_id: full.next_vm_id, next_pipe_slot: full.next_pipe_slot, @@ -135,6 +139,7 @@ where /// Suspend current scheduler into a serializable full state pub fn suspend(mut self) -> Result { + assert!(self.message_box.lock().expect("lock").is_empty()); let mut vms = Vec::with_capacity(self.states.len()); let instantiated_ids: Vec<_> = self.instantiated.keys().cloned().collect(); for id in instantiated_ids { @@ -145,6 +150,7 @@ where vms.push((id, state, snapshot)); } Ok(FullSuspendedState { + max_vms_count: self.max_vms_count, total_cycles: self.total_cycles, next_vm_id: self.next_vm_id, next_pipe_slot: self.next_pipe_slot, @@ -313,7 +319,13 @@ where if !pipes_valid { continue; } - // TODO: spawn limits + if self.suspended.len() + self.instantiated.len() > self.max_vms_count as usize + { + self.ensure_vms_instantiated(&[vm_id])?; + let (_, machine) = self.instantiated.get_mut(&vm_id).unwrap(); + machine.machine.set_register(A0, MAX_VMS_SPAWNED as u64); + continue; + } let spawned_vm_id = self.boot_vm(&args.data_piece_id, args.offset, args.length, &args.argv)?; // Move passed pipes from spawner to spawnee diff --git a/script/src/v2_syscalls.rs b/script/src/v2_syscalls.rs index 5e17bd9c544..868de598689 100644 --- a/script/src/v2_syscalls.rs +++ b/script/src/v2_syscalls.rs @@ -43,4 +43,4 @@ where pub fn set_base_cycles(&mut self, base_cycles: u64) { *self.base_cycles.lock().expect("lock") = base_cycles; } -} +} \ No newline at end of file diff --git a/script/src/v2_types.rs b/script/src/v2_types.rs index 599dbe6abb1..42e5eb6a192 100644 --- a/script/src/v2_types.rs +++ b/script/src/v2_types.rs @@ -141,6 +141,7 @@ impl TryFrom<(u64, u64, u64)> for DataPieceId { /// fully recover the running environment with the full transaction environment. #[derive(Clone, Debug)] pub struct FullSuspendedState { + pub max_vms_count: u64, pub total_cycles: Cycle, pub next_vm_id: VmId, pub next_pipe_slot: u64, diff --git a/script/src/verify/tests/ckb_latest/features_since_v2023.rs b/script/src/verify/tests/ckb_latest/features_since_v2023.rs index 73c4f263a89..77df460c086 100644 --- a/script/src/verify/tests/ckb_latest/features_since_v2023.rs +++ b/script/src/verify/tests/ckb_latest/features_since_v2023.rs @@ -95,6 +95,12 @@ fn check_spawn_read_then_close() { assert_eq!(result.is_ok(), SCRIPT_VERSION == ScriptVersion::V2); } +#[test] +fn check_spawn_max_vms_count() { + let result = simple_spawn_test("testdata/spawn_cases", &[10]); + assert_eq!(result.is_ok(), SCRIPT_VERSION == ScriptVersion::V2); +} + #[test] fn check_vm_version() { let script_version = SCRIPT_VERSION; @@ -348,7 +354,7 @@ fn check_spawn_recursive() { let result = verifier.verify(script_version, &rtx, 70_000_000); if script_version >= ScriptVersion::V2 { let msg = result.unwrap_err().to_string(); - assert!(msg.contains("ExceededMaximumCycles")) + assert!(msg.contains("error code 8")) } else { assert!(result.is_err()) } diff --git a/script/testdata/spawn_cases b/script/testdata/spawn_cases index 06ee2e2349c..b80d3cd078d 100755 Binary files a/script/testdata/spawn_cases and b/script/testdata/spawn_cases differ diff --git a/script/testdata/spawn_cases.c b/script/testdata/spawn_cases.c index 712cace0d0c..f43a4505b27 100644 --- a/script/testdata/spawn_cases.c +++ b/script/testdata/spawn_cases.c @@ -320,6 +320,20 @@ int child_read_then_close() { return err; } +int parent_max_vms_count() { + const char* argv[2] = {"", 0}; + return simple_spawn_args(0, 1, argv); +} + +int child_max_vms_count() { + const char* argv[2] = {"", 0}; + int err = simple_spawn_args(0, 1, argv); + CHECK2(err == 0 || err == CKB_MAX_VMS_SPAWNED, -2); + err = 0; +exit: + return err; +} + int parent_entry(int case_id) { int err = 0; uint64_t pid = 0; @@ -341,6 +355,9 @@ int parent_entry(int case_id) { err = parent_inherited_fds_without_owner(&pid); } else if (case_id == 9) { err = parent_read_then_close(&pid); + } else if (case_id == 10) { + err = parent_max_vms_count(&pid); + return err; } else { CHECK2(false, -2); } @@ -373,6 +390,8 @@ int child_entry(int case_id) { return 0; } else if (case_id == 9) { return child_read_then_close(); + } else if (case_id == 10) { + return child_max_vms_count(); } else { return -1; }