diff --git a/script/src/lib.rs b/script/src/lib.rs index 02c44f39539..91c42e0c16c 100644 --- a/script/src/lib.rs +++ b/script/src/lib.rs @@ -4,11 +4,11 @@ mod error; mod syscalls; mod type_id; mod types; -mod verify; -mod verify_env; mod v2_scheduler; mod v2_syscalls; mod v2_types; +mod verify; +mod verify_env; pub use crate::error::{ScriptError, TransactionScriptError}; pub use crate::syscalls::spawn::update_caller_machine; diff --git a/script/src/v2_scheduler.rs b/script/src/v2_scheduler.rs index 6da642000f0..0e5b9b7ce44 100644 --- a/script/src/v2_scheduler.rs +++ b/script/src/v2_scheduler.rs @@ -1,5 +1,7 @@ +use crate::types::CoreMachine as ICoreMachine; use crate::v2_syscalls::INDEX_OUT_OF_BOUND; use crate::v2_types::PipeIoArgs; +use crate::verify::TransactionScriptsSyscallsGenerator; use crate::{ v2_syscalls::{ transferred_byte_cycles, MachineContext, INVALID_PIPE, JOIN_FAILURE, OTHER_END_CLOSED, @@ -24,7 +26,7 @@ use ckb_vm::{ memory::Memory, registers::A0, snapshot2::{DataSource, Snapshot2}, - Error, Register, + Error, Register, Syscalls, }; use std::sync::{Arc, Mutex}; use std::{ @@ -49,7 +51,8 @@ pub struct Scheduler< // TransactionScriptsVerifier, nonetheless much of current syscall // implementation is strictly tied to TransactionScriptsVerifier, we // are using it here to save some extra code. - verifier: TransactionScriptsVerifier
, + script_version: ScriptVersion, + syscalls: TransactionScriptsSyscallsGenerator
, total_cycles: Cycle, next_vm_id: VmId, @@ -70,10 +73,15 @@ impl { /// Create a new scheduler from empty state - pub fn new(tx_data: TxData
, verifier: TransactionScriptsVerifier
) -> Self { + pub fn new( + tx_data: TxData
, + script_version: ScriptVersion, + syscalls: TransactionScriptsSyscallsGenerator
, + ) -> Self { Self { tx_data, - verifier, + script_version, + syscalls, total_cycles: 0, next_vm_id: FIRST_VM_ID, next_pipe_slot: FIRST_PIPE_SLOT, @@ -94,12 +102,14 @@ impl, - verifier: TransactionScriptsVerifier
, + script_version: ScriptVersion, + syscalls: TransactionScriptsSyscallsGenerator
, full: FullSuspendedState, ) -> Self { Self { tx_data, - verifier, + script_version, + syscalls, total_cycles: full.total_cycles, next_vm_id: full.next_vm_id, next_pipe_slot: full.next_pipe_slot, @@ -739,10 +749,7 @@ impl Result<(i8, Machine), ScriptError> { + ) -> Result<(i8, Cycle), ScriptError> { let program = self.extract_script(&script_group.script)?; - let context = Default::default(); - let mut machine = self.build_machine(script_group, max_cycles, context)?; + + let tx_data = TxData { + rtx: self.rtx.clone(), + data_loader: self.data_loader.clone(), + program, + script_group: Arc::new(script_group.clone()), + }; + let version = self.select_version(&script_group.script)?; + let mut scheduler = Scheduler::new(tx_data.clone(), version, self.generator.clone()); let map_vm_internal_error = |error: VMInternalError| match error { VMInternalError::CyclesExceeded => ScriptError::ExceededMaximumCycles(max_cycles), _ => ScriptError::VMInternalError(error), }; - let bytes = machine - .load_program(&program, &[]) - .map_err(map_vm_internal_error)?; - machine - .machine - .add_cycles_no_checking(transferred_byte_cycles(bytes)) - .map_err(map_vm_internal_error)?; - let code = machine.run().map_err(map_vm_internal_error)?; + scheduler + .run(RunMode::LimitCycles(max_cycles)) + .map_err(map_vm_internal_error) + + // let context = Default::default(); + // let mut machine = self.build_machine(script_group, max_cycles, context)?; + + // let bytes = machine + // .load_program(&program, &[]) + // .map_err(map_vm_internal_error)?; + // machine + // .machine + // .add_cycles_no_checking(transferred_byte_cycles(bytes)) + // .map_err(map_vm_internal_error)?; + // let code = machine.run().map_err(map_vm_internal_error)?; - Ok((code, machine)) + // Ok((code, machine)) } fn run(&self, script_group: &ScriptGroup, max_cycles: Cycle) -> Result { - let (code, machine) = self.detailed_run(script_group, max_cycles)?; + let (code, cycles) = self.detailed_run(script_group, max_cycles)?; if code == 0 { - Ok(machine.machine.cycles()) + Ok(cycles) } else { Err(ScriptError::validation_failure(&script_group.script, code)) } 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 85b9b08ad17..ca914dfd846 100644 --- a/script/src/verify/tests/ckb_latest/features_since_v2023.rs +++ b/script/src/verify/tests/ckb_latest/features_since_v2023.rs @@ -61,952 +61,952 @@ fn check_vm_version() { assert_eq!(result.is_ok(), script_version == ScriptVersion::V2); } -#[test] -fn check_get_memory_limit() { - let script_version = SCRIPT_VERSION; - - let (memory_limit_cell, memory_limit_data_hash) = - load_cell_from_path("testdata/get_memory_limit"); - - let memory_limit_script = Script::new_builder() - .hash_type(script_version.data_hash_type().into()) - .code_hash(memory_limit_data_hash) - .build(); - let output = CellOutputBuilder::default() - .capacity(capacity_bytes!(100).pack()) - .lock(memory_limit_script) - .build(); - - let input = CellInput::new(OutPoint::null(), 0); - - let transaction = TransactionBuilder::default().input(input).build(); - let dummy_cell = create_dummy_cell(output); - - let rtx = ResolvedTransaction { - transaction, - resolved_cell_deps: vec![memory_limit_cell], - resolved_inputs: vec![dummy_cell], - resolved_dep_groups: vec![], - }; - - let verifier = TransactionScriptsVerifierWithEnv::new(); - let result = verifier.verify_without_limit(script_version, &rtx); - assert_eq!(result.is_ok(), script_version >= ScriptVersion::V2); -} - -#[test] -fn check_set_content() { - let script_version = SCRIPT_VERSION; - - let (set_content_cell, set_content_data_hash) = load_cell_from_path("testdata/set_content"); - - let memory_limit_script = Script::new_builder() - .hash_type(script_version.data_hash_type().into()) - .code_hash(set_content_data_hash) - .build(); - let output = CellOutputBuilder::default() - .capacity(capacity_bytes!(100).pack()) - .lock(memory_limit_script) - .build(); - - let input = CellInput::new(OutPoint::null(), 0); - - let transaction = TransactionBuilder::default().input(input).build(); - let dummy_cell = create_dummy_cell(output); - - let rtx = ResolvedTransaction { - transaction, - resolved_cell_deps: vec![set_content_cell], - resolved_inputs: vec![dummy_cell], - resolved_dep_groups: vec![], - }; - - let verifier = TransactionScriptsVerifierWithEnv::new(); - let result = verifier.verify_without_limit(script_version, &rtx); - assert_eq!(result.is_ok(), script_version >= ScriptVersion::V2); -} - -#[test] -fn check_spawn_strcat() { - let script_version = SCRIPT_VERSION; - - let (spawn_caller_cell, spawn_caller_data_hash) = - load_cell_from_path("testdata/spawn_caller_strcat"); - let (spawn_callee_cell, _spawn_callee_data_hash) = - load_cell_from_path("testdata/spawn_callee_strcat"); - - let spawn_caller_script = Script::new_builder() - .hash_type(script_version.data_hash_type().into()) - .code_hash(spawn_caller_data_hash) - .build(); - let output = CellOutputBuilder::default() - .capacity(capacity_bytes!(100).pack()) - .lock(spawn_caller_script) - .build(); - let input = CellInput::new(OutPoint::null(), 0); - - let transaction = TransactionBuilder::default().input(input).build(); - let dummy_cell = create_dummy_cell(output); - - let rtx = ResolvedTransaction { - transaction, - resolved_cell_deps: vec![spawn_caller_cell, spawn_callee_cell], - resolved_inputs: vec![dummy_cell], - resolved_dep_groups: vec![], - }; - let verifier = TransactionScriptsVerifierWithEnv::new(); - let result = verifier.verify_without_limit(script_version, &rtx); - assert_eq!(result.is_ok(), script_version >= ScriptVersion::V2); -} - -#[test] -fn check_spawn_strcat_data_hash() { - let script_version = SCRIPT_VERSION; - - let (spawn_caller_cell, spawn_caller_data_hash) = - load_cell_from_path("testdata/spawn_caller_strcat_data_hash"); - let (spawn_callee_cell, _spawn_callee_data_hash) = - load_cell_from_path("testdata/spawn_callee_strcat"); - - let spawn_caller_script = Script::new_builder() - .hash_type(script_version.data_hash_type().into()) - .code_hash(spawn_caller_data_hash) - .build(); - let output = CellOutputBuilder::default() - .capacity(capacity_bytes!(100).pack()) - .lock(spawn_caller_script) - .build(); - let input = CellInput::new(OutPoint::null(), 0); - - let transaction = TransactionBuilder::default().input(input).build(); - let dummy_cell = create_dummy_cell(output); - - let rtx = ResolvedTransaction { - transaction, - resolved_cell_deps: vec![spawn_caller_cell, spawn_callee_cell], - resolved_inputs: vec![dummy_cell], - resolved_dep_groups: vec![], - }; - let verifier = TransactionScriptsVerifierWithEnv::new(); - let result = verifier.verify_without_limit(script_version, &rtx); - assert_eq!(result.is_ok(), script_version >= ScriptVersion::V2); -} - -#[test] -fn check_spawn_get_memory_limit() { - let script_version = SCRIPT_VERSION; - - let (spawn_caller_cell, spawn_caller_data_hash) = - load_cell_from_path("testdata/spawn_caller_get_memory_limit"); - let (spawn_callee_cell, _spawn_callee_data_hash) = - load_cell_from_path("testdata/spawn_callee_get_memory_limit"); - - let spawn_caller_script = Script::new_builder() - .hash_type(script_version.data_hash_type().into()) - .code_hash(spawn_caller_data_hash) - .build(); - let output = CellOutputBuilder::default() - .capacity(capacity_bytes!(100).pack()) - .lock(spawn_caller_script) - .build(); - let input = CellInput::new(OutPoint::null(), 0); - - let transaction = TransactionBuilder::default().input(input).build(); - let dummy_cell = create_dummy_cell(output); - - let rtx = ResolvedTransaction { - transaction, - resolved_cell_deps: vec![spawn_caller_cell, spawn_callee_cell], - resolved_inputs: vec![dummy_cell], - resolved_dep_groups: vec![], - }; - let verifier = TransactionScriptsVerifierWithEnv::new(); - let result = verifier.verify_without_limit(script_version, &rtx); - assert_eq!(result.is_ok(), script_version >= ScriptVersion::V2); -} - -#[test] -fn check_spawn_set_content() { - let script_version = SCRIPT_VERSION; - - let (spawn_caller_cell, spawn_caller_data_hash) = - load_cell_from_path("testdata/spawn_caller_set_content"); - let (spawn_callee_cell, _spawn_callee_data_hash) = - load_cell_from_path("testdata/spawn_callee_set_content"); - - let spawn_caller_script = Script::new_builder() - .hash_type(script_version.data_hash_type().into()) - .code_hash(spawn_caller_data_hash) - .build(); - let output = CellOutputBuilder::default() - .capacity(capacity_bytes!(100).pack()) - .lock(spawn_caller_script) - .build(); - let input = CellInput::new(OutPoint::null(), 0); - - let transaction = TransactionBuilder::default().input(input).build(); - let dummy_cell = create_dummy_cell(output); - - let rtx = ResolvedTransaction { - transaction, - resolved_cell_deps: vec![spawn_caller_cell, spawn_callee_cell], - resolved_inputs: vec![dummy_cell], - resolved_dep_groups: vec![], - }; - let verifier = TransactionScriptsVerifierWithEnv::new(); - let result = verifier.verify_without_limit(script_version, &rtx); - assert_eq!(result.is_ok(), script_version >= ScriptVersion::V2); -} - -#[test] -fn check_spawn_out_of_cycles() { - let script_version = SCRIPT_VERSION; - - let (spawn_caller_cell, spawn_caller_data_hash) = - load_cell_from_path("testdata/spawn_caller_out_of_cycles"); - let (spawn_callee_cell, _spawn_callee_data_hash) = - load_cell_from_path("testdata/spawn_callee_out_of_cycles"); - - let spawn_caller_script = Script::new_builder() - .hash_type(script_version.data_hash_type().into()) - .code_hash(spawn_caller_data_hash) - .build(); - let output = CellOutputBuilder::default() - .capacity(capacity_bytes!(100).pack()) - .lock(spawn_caller_script) - .build(); - let input = CellInput::new(OutPoint::null(), 0); - - let transaction = TransactionBuilder::default().input(input).build(); - let dummy_cell = create_dummy_cell(output); - - let rtx = ResolvedTransaction { - transaction, - resolved_cell_deps: vec![spawn_caller_cell, spawn_callee_cell], - resolved_inputs: vec![dummy_cell], - resolved_dep_groups: vec![], - }; - let verifier = TransactionScriptsVerifierWithEnv::new(); - let result = verifier.verify(script_version, &rtx, 0xffffff); - if script_version >= ScriptVersion::V2 { - assert!(result - .unwrap_err() - .to_string() - .contains("ExceededMaximumCycles")) - } else { - assert!(result.is_err()) - } -} - -#[test] -fn check_spawn_exec() { - let script_version = SCRIPT_VERSION; - - let (spawn_caller_cell, spawn_caller_data_hash) = - load_cell_from_path("testdata/spawn_caller_exec"); - let (spawn_callee_caller_cell, _) = load_cell_from_path("testdata/spawn_callee_exec_caller"); - let (spawn_callee_callee_cell, _) = load_cell_from_path("testdata/spawn_callee_exec_callee"); - - let spawn_caller_script = Script::new_builder() - .hash_type(script_version.data_hash_type().into()) - .code_hash(spawn_caller_data_hash) - .build(); - let output = CellOutputBuilder::default() - .capacity(capacity_bytes!(100).pack()) - .lock(spawn_caller_script) - .build(); - let input = CellInput::new(OutPoint::null(), 0); - - let transaction = TransactionBuilder::default().input(input).build(); - let dummy_cell = create_dummy_cell(output); - - let rtx = ResolvedTransaction { - transaction, - resolved_cell_deps: vec![ - spawn_caller_cell, - spawn_callee_caller_cell, - spawn_callee_callee_cell, - ], - resolved_inputs: vec![dummy_cell], - resolved_dep_groups: vec![], - }; - let verifier = TransactionScriptsVerifierWithEnv::new(); - let result = verifier.verify(script_version, &rtx, 0xffffff); - assert_eq!(result.is_ok(), script_version >= ScriptVersion::V2); -} - -#[test] -fn check_spawn_strcat_wrap() { - let script_version = SCRIPT_VERSION; - - let (spawn_caller_cell, spawn_caller_data_hash) = - load_cell_from_path("testdata/spawn_caller_strcat_wrap"); - let (spawn_callee_caller_cell, _) = load_cell_from_path("testdata/spawn_caller_strcat"); - let (spawn_callee_callee_cell, _) = load_cell_from_path("testdata/spawn_callee_strcat"); - - let spawn_caller_script = Script::new_builder() - .hash_type(script_version.data_hash_type().into()) - .code_hash(spawn_caller_data_hash) - .build(); - let output = CellOutputBuilder::default() - .capacity(capacity_bytes!(100).pack()) - .lock(spawn_caller_script) - .build(); - let input = CellInput::new(OutPoint::null(), 0); - - let transaction = TransactionBuilder::default().input(input).build(); - let dummy_cell = create_dummy_cell(output); - - let rtx = ResolvedTransaction { - transaction, - resolved_cell_deps: vec![ - spawn_caller_cell, - spawn_callee_callee_cell, - spawn_callee_caller_cell, - ], - resolved_inputs: vec![dummy_cell], - resolved_dep_groups: vec![], - }; - let verifier = TransactionScriptsVerifierWithEnv::new(); - let result = verifier.verify(script_version, &rtx, 0xffffff); - assert_eq!(result.is_ok(), script_version >= ScriptVersion::V2); -} - -#[test] -fn check_spawn_out_of_cycles_wrap() { - let script_version = SCRIPT_VERSION; - - let (spawn_caller_cell, spawn_caller_data_hash) = - load_cell_from_path("testdata/spawn_caller_out_of_cycles_wrap"); - let (spawn_callee_caller_cell, _) = load_cell_from_path("testdata/spawn_caller_out_of_cycles"); - let (spawn_callee_callee_cell, _) = load_cell_from_path("testdata/spawn_callee_out_of_cycles"); - - let spawn_caller_script = Script::new_builder() - .hash_type(script_version.data_hash_type().into()) - .code_hash(spawn_caller_data_hash) - .build(); - let output = CellOutputBuilder::default() - .capacity(capacity_bytes!(100).pack()) - .lock(spawn_caller_script) - .build(); - let input = CellInput::new(OutPoint::null(), 0); - - let transaction = TransactionBuilder::default().input(input).build(); - let dummy_cell = create_dummy_cell(output); - - let rtx = ResolvedTransaction { - transaction, - resolved_cell_deps: vec![ - spawn_caller_cell, - spawn_callee_callee_cell, - spawn_callee_caller_cell, - ], - resolved_inputs: vec![dummy_cell], - resolved_dep_groups: vec![], - }; - let verifier = TransactionScriptsVerifierWithEnv::new(); - let result = verifier.verify(script_version, &rtx, 0xffffff); - if script_version >= ScriptVersion::V2 { - assert!(result - .unwrap_err() - .to_string() - .contains("ExceededMaximumCycles")) - } else { - assert!(result.is_err()) - } -} - -#[test] -fn check_spawn_recursive() { - let script_version = SCRIPT_VERSION; - - let (spawn_caller_cell, spawn_caller_data_hash) = - load_cell_from_path("testdata/spawn_recursive"); - - let spawn_caller_script = Script::new_builder() - .hash_type(script_version.data_hash_type().into()) - .code_hash(spawn_caller_data_hash) - .build(); - let output = CellOutputBuilder::default() - .capacity(capacity_bytes!(100).pack()) - .lock(spawn_caller_script) - .build(); - let input = CellInput::new(OutPoint::null(), 0); - - let transaction = TransactionBuilder::default().input(input).build(); - let dummy_cell = create_dummy_cell(output); - - let rtx = ResolvedTransaction { - transaction, - resolved_cell_deps: vec![spawn_caller_cell], - resolved_inputs: vec![dummy_cell], - resolved_dep_groups: vec![], - }; - let verifier = TransactionScriptsVerifierWithEnv::new(); - let result = verifier.verify_without_limit(script_version, &rtx); - if script_version >= ScriptVersion::V2 { - assert!(result.unwrap_err().to_string().contains("error code 7")) - } else { - assert!(result.is_err()) - } -} - -#[test] -fn check_spawn_big_memory_size() { - let script_version = SCRIPT_VERSION; - - let (spawn_caller_cell, spawn_caller_data_hash) = - load_cell_from_path("testdata/spawn_big_memory_size"); - - let spawn_caller_script = Script::new_builder() - .hash_type(script_version.data_hash_type().into()) - .code_hash(spawn_caller_data_hash) - .build(); - let output = CellOutputBuilder::default() - .capacity(capacity_bytes!(100).pack()) - .lock(spawn_caller_script) - .build(); - let input = CellInput::new(OutPoint::null(), 0); - - let transaction = TransactionBuilder::default().input(input).build(); - let dummy_cell = create_dummy_cell(output); - - let rtx = ResolvedTransaction { - transaction, - resolved_cell_deps: vec![spawn_caller_cell], - resolved_inputs: vec![dummy_cell], - resolved_dep_groups: vec![], - }; - let verifier = TransactionScriptsVerifierWithEnv::new(); - let result = verifier.verify_without_limit(script_version, &rtx); - assert_eq!(result.is_ok(), script_version >= ScriptVersion::V2); -} - -#[test] -fn check_spawn_big_content_length() { - let script_version = SCRIPT_VERSION; - - let (spawn_caller_cell, spawn_caller_data_hash) = - load_cell_from_path("testdata/spawn_big_content_length"); - - let spawn_caller_script = Script::new_builder() - .hash_type(script_version.data_hash_type().into()) - .code_hash(spawn_caller_data_hash) - .build(); - let output = CellOutputBuilder::default() - .capacity(capacity_bytes!(100).pack()) - .lock(spawn_caller_script) - .build(); - let input = CellInput::new(OutPoint::null(), 0); - - let transaction = TransactionBuilder::default().input(input).build(); - let dummy_cell = create_dummy_cell(output); - - let rtx = ResolvedTransaction { - transaction, - resolved_cell_deps: vec![spawn_caller_cell], - resolved_inputs: vec![dummy_cell], - resolved_dep_groups: vec![], - }; - let verifier = TransactionScriptsVerifierWithEnv::new(); - let result = verifier.verify_without_limit(script_version, &rtx); - assert_eq!(result.is_ok(), script_version >= ScriptVersion::V2); -} - -#[test] -fn check_peak_memory_4m_to_32m() { - let script_version = SCRIPT_VERSION; - - let (spawn_caller_cell, spawn_caller_data_hash) = - load_cell_from_path("testdata/spawn_peak_memory_4m_to_32m"); - - let spawn_caller_script = Script::new_builder() - .hash_type(script_version.data_hash_type().into()) - .code_hash(spawn_caller_data_hash) - .build(); - let output = CellOutputBuilder::default() - .capacity(capacity_bytes!(100).pack()) - .lock(spawn_caller_script) - .build(); - let input = CellInput::new(OutPoint::null(), 0); - - let transaction = TransactionBuilder::default().input(input).build(); - let dummy_cell = create_dummy_cell(output); - - let rtx = ResolvedTransaction { - transaction, - resolved_cell_deps: vec![spawn_caller_cell], - resolved_inputs: vec![dummy_cell], - resolved_dep_groups: vec![], - }; - let verifier = TransactionScriptsVerifierWithEnv::new(); - let result = verifier.verify_without_limit(script_version, &rtx); - assert_eq!(result.is_ok(), script_version >= ScriptVersion::V2); -} - -#[test] -fn check_peak_memory_2m_to_32m() { - let script_version = SCRIPT_VERSION; - - let (spawn_caller_cell, spawn_caller_data_hash) = - load_cell_from_path("testdata/spawn_peak_memory_2m_to_32m"); - - let spawn_caller_script = Script::new_builder() - .hash_type(script_version.data_hash_type().into()) - .code_hash(spawn_caller_data_hash) - .build(); - let output = CellOutputBuilder::default() - .capacity(capacity_bytes!(100).pack()) - .lock(spawn_caller_script) - .build(); - let input = CellInput::new(OutPoint::null(), 0); - - let transaction = TransactionBuilder::default().input(input).build(); - let dummy_cell = create_dummy_cell(output); - - let rtx = ResolvedTransaction { - transaction, - resolved_cell_deps: vec![spawn_caller_cell], - resolved_inputs: vec![dummy_cell], - resolved_dep_groups: vec![], - }; - let verifier = TransactionScriptsVerifierWithEnv::new(); - let result = verifier.verify_without_limit(script_version, &rtx); - assert_eq!(result.is_ok(), script_version >= ScriptVersion::V2); -} - -#[test] -fn check_peak_memory_512k_to_32m() { - let script_version = SCRIPT_VERSION; - - let (spawn_caller_cell, spawn_caller_data_hash) = - load_cell_from_path("testdata/spawn_peak_memory_512k_to_32m"); - - let spawn_caller_script = Script::new_builder() - .hash_type(script_version.data_hash_type().into()) - .code_hash(spawn_caller_data_hash) - .build(); - let output = CellOutputBuilder::default() - .capacity(capacity_bytes!(100).pack()) - .lock(spawn_caller_script) - .build(); - let input = CellInput::new(OutPoint::null(), 0); - - let transaction = TransactionBuilder::default().input(input).build(); - let dummy_cell = create_dummy_cell(output); - - let rtx = ResolvedTransaction { - transaction, - resolved_cell_deps: vec![spawn_caller_cell], - resolved_inputs: vec![dummy_cell], - resolved_dep_groups: vec![], - }; - let verifier = TransactionScriptsVerifierWithEnv::new(); - let result = verifier.verify_without_limit(script_version, &rtx); - assert_eq!(result.is_ok(), script_version >= ScriptVersion::V2); -} - -#[test] -fn check_spawn_snapshot() { - let script_version = SCRIPT_VERSION; - if script_version <= ScriptVersion::V1 { - return; - } - - let (spawn_caller_cell, spawn_caller_data_hash) = - load_cell_from_path("testdata/spawn_caller_exec"); - let (snapshot_cell, _) = load_cell_from_path("testdata/current_cycles_with_snapshot"); - - let spawn_caller_script = Script::new_builder() - .hash_type(script_version.data_hash_type().into()) - .code_hash(spawn_caller_data_hash) - .build(); - let output = CellOutputBuilder::default() - .capacity(capacity_bytes!(100).pack()) - .lock(spawn_caller_script) - .build(); - let input = CellInput::new(OutPoint::null(), 0); - - let transaction = TransactionBuilder::default().input(input).build(); - let dummy_cell = create_dummy_cell(output); - - let rtx = ResolvedTransaction { - transaction, - resolved_cell_deps: vec![spawn_caller_cell, snapshot_cell], - resolved_inputs: vec![dummy_cell], - resolved_dep_groups: vec![], - }; - let verifier = TransactionScriptsVerifierWithEnv::new(); - let result = verifier.verify_without_pause(script_version, &rtx, Cycle::MAX); - let cycles_once = result.unwrap(); - - let (cycles, chunks_count) = verifier - .verify_until_completed(script_version, &rtx) - .unwrap(); - assert_eq!(cycles, cycles_once); - assert!(chunks_count > 1); -} - -#[tokio::test(flavor = "multi_thread", worker_threads = 4)] -async fn check_spawn_async() { - let script_version = SCRIPT_VERSION; - if script_version <= ScriptVersion::V1 { - return; - } - - let (spawn_caller_cell, spawn_caller_data_hash) = - load_cell_from_path("testdata/spawn_caller_exec"); - let (snapshot_cell, _) = load_cell_from_path("testdata/current_cycles_with_snapshot"); - - let spawn_caller_script = Script::new_builder() - .hash_type(script_version.data_hash_type().into()) - .code_hash(spawn_caller_data_hash) - .build(); - let output = CellOutputBuilder::default() - .capacity(capacity_bytes!(100).pack()) - .lock(spawn_caller_script) - .build(); - let input = CellInput::new(OutPoint::null(), 0); - - let transaction = TransactionBuilder::default().input(input).build(); - let dummy_cell = create_dummy_cell(output); - - let rtx = ResolvedTransaction { - transaction, - resolved_cell_deps: vec![spawn_caller_cell, snapshot_cell], - resolved_inputs: vec![dummy_cell], - resolved_dep_groups: vec![], - }; - let verifier = TransactionScriptsVerifierWithEnv::new(); - let result = verifier.verify_without_pause(script_version, &rtx, Cycle::MAX); - let cycles_once = result.unwrap(); - - // we use debug pause to test context resume - // `current_cycles_with_snapshot` will try to pause verifier - // here we use `channel` to send Resume to verifier until it completes - let (command_tx, mut command_rx) = watch::channel(ChunkCommand::Resume); - let _jt = tokio::spawn(async move { - loop { - let res = command_tx.send(ChunkCommand::Resume); - if res.is_err() { - break; - } - tokio::time::sleep(tokio::time::Duration::from_millis(1)).await; - } - }); - let cycles = verifier - .verify_complete_async(script_version, &rtx, &mut command_rx, false) - .await - .unwrap(); - assert_eq!(cycles, cycles_once); - - // we send Resume/Suspend to command_rx in a loop, make sure cycles is still the same - let (command_tx, mut command_rx) = watch::channel(ChunkCommand::Resume); - let _jt = tokio::spawn(async move { - loop { - tokio::time::sleep(tokio::time::Duration::from_millis(10)).await; - let _res = command_tx.send(ChunkCommand::Suspend); - tokio::time::sleep(tokio::time::Duration::from_millis(10)).await; - - let _res = command_tx.send(ChunkCommand::Resume); - tokio::time::sleep(tokio::time::Duration::from_millis(1)).await; - - let _res = command_tx.send(ChunkCommand::Suspend); - tokio::time::sleep(tokio::time::Duration::from_millis(10)).await; - - let _res = command_tx.send(ChunkCommand::Resume); - tokio::time::sleep(tokio::time::Duration::from_millis(10)).await; - } - }); - - let cycles = verifier - .verify_complete_async(script_version, &rtx, &mut command_rx, true) - .await - .unwrap(); - assert_eq!(cycles, cycles_once); -} - -#[tokio::test(flavor = "multi_thread", worker_threads = 4)] -async fn check_spawn_suspend_shutdown() { - let script_version = SCRIPT_VERSION; - if script_version <= ScriptVersion::V1 { - return; - } - - let (spawn_caller_cell, spawn_caller_data_hash) = - load_cell_from_path("testdata/spawn_caller_exec"); - let (snapshot_cell, _) = load_cell_from_path("testdata/infinite_loop"); - - let spawn_caller_script = Script::new_builder() - .hash_type(script_version.data_hash_type().into()) - .code_hash(spawn_caller_data_hash) - .build(); - let output = CellOutputBuilder::default() - .capacity(capacity_bytes!(100).pack()) - .lock(spawn_caller_script) - .build(); - let input = CellInput::new(OutPoint::null(), 0); - - let transaction = TransactionBuilder::default().input(input).build(); - let dummy_cell = create_dummy_cell(output); - - let rtx = ResolvedTransaction { - transaction, - resolved_cell_deps: vec![spawn_caller_cell, snapshot_cell], - resolved_inputs: vec![dummy_cell], - resolved_dep_groups: vec![], - }; - - let verifier = TransactionScriptsVerifierWithEnv::new(); - let (command_tx, mut command_rx) = watch::channel(ChunkCommand::Resume); - let _jt = tokio::spawn(async move { - loop { - let _res = command_tx.send(ChunkCommand::Suspend); - tokio::time::sleep(tokio::time::Duration::from_millis(20)).await; - - let _res = command_tx.send(ChunkCommand::Resume); - tokio::time::sleep(tokio::time::Duration::from_millis(20)).await; - - let _res = command_tx.send(ChunkCommand::Suspend); - tokio::time::sleep(tokio::time::Duration::from_millis(20)).await; - - let _res = command_tx.send(ChunkCommand::Stop); - tokio::time::sleep(tokio::time::Duration::from_millis(20)).await; - } - }); - - let res = verifier - .verify_complete_async(script_version, &rtx, &mut command_rx, true) - .await; - assert!(res.is_err()); - let err = res.unwrap_err().to_string(); - assert!(err.contains("VM Internal Error: External(\"stopped\")")); -} - -#[test] -fn check_spawn_state() { - let script_version = SCRIPT_VERSION; - if script_version <= ScriptVersion::V1 { - return; - } - - let (spawn_caller_cell, spawn_caller_data_hash) = - load_cell_from_path("testdata/spawn_caller_exec"); - let (snapshot_cell, _) = load_cell_from_path("testdata/current_cycles_with_snapshot"); - - let spawn_caller_script = Script::new_builder() - .hash_type(script_version.data_hash_type().into()) - .code_hash(spawn_caller_data_hash) - .build(); - let output = CellOutputBuilder::default() - .capacity(capacity_bytes!(100).pack()) - .lock(spawn_caller_script) - .build(); - let input = CellInput::new(OutPoint::null(), 0); - - let transaction = TransactionBuilder::default().input(input).build(); - let dummy_cell = create_dummy_cell(output); - - let rtx = ResolvedTransaction { - transaction, - resolved_cell_deps: vec![spawn_caller_cell, snapshot_cell], - resolved_inputs: vec![dummy_cell], - resolved_dep_groups: vec![], - }; - let verifier = TransactionScriptsVerifierWithEnv::new(); - let result = verifier.verify_without_pause(script_version, &rtx, Cycle::MAX); - let cycles_once = result.unwrap(); - - let (cycles, chunks_count) = verifier - .verify_map(script_version, &rtx, |verifier| { - let max_cycles = Cycle::MAX; - let cycles; - let mut times = 0usize; - times += 1; - let mut init_state = match verifier.resumable_verify(max_cycles).unwrap() { - VerifyResult::Suspended(state) => Some(state), - VerifyResult::Completed(cycle) => { - cycles = cycle; - return Ok((cycles, times)); - } - }; - - loop { - times += 1; - let state = init_state.take().unwrap(); - match verifier.resume_from_state(state, max_cycles).unwrap() { - VerifyResult::Suspended(state) => { - init_state = Some(state); - } - VerifyResult::Completed(cycle) => { - cycles = cycle; - break; - } - } - } - - Ok::<(u64, usize), Error>((cycles, times)) - }) - .unwrap(); - assert_eq!(cycles, cycles_once); - assert!(chunks_count > 1); -} - -#[test] -fn check_spawn_current_memory() { - let script_version = SCRIPT_VERSION; - - let (spawn_caller_cell, spawn_caller_data_hash) = - load_cell_from_path("testdata/spawn_current_memory"); - - let spawn_caller_script = Script::new_builder() - .hash_type(script_version.data_hash_type().into()) - .code_hash(spawn_caller_data_hash) - .build(); - let output = CellOutputBuilder::default() - .capacity(capacity_bytes!(100).pack()) - .lock(spawn_caller_script) - .build(); - let input = CellInput::new(OutPoint::null(), 0); - - let transaction = TransactionBuilder::default().input(input).build(); - let dummy_cell = create_dummy_cell(output); - - let rtx = ResolvedTransaction { - transaction, - resolved_cell_deps: vec![spawn_caller_cell], - resolved_inputs: vec![dummy_cell], - resolved_dep_groups: vec![], - }; - let verifier = TransactionScriptsVerifierWithEnv::new(); - let result = verifier.verify_without_limit(script_version, &rtx); - assert_eq!(result.is_ok(), script_version >= ScriptVersion::V2); -} - -#[test] -fn check_spawn_current_cycles() { - let script_version = SCRIPT_VERSION; - - let (spawn_caller_cell, spawn_caller_data_hash) = - load_cell_from_path("testdata/spawn_caller_current_cycles"); - let (spawn_callee_cell, _spawn_callee_data_hash) = - load_cell_from_path("testdata/spawn_callee_current_cycles"); - - let spawn_caller_script = Script::new_builder() - .hash_type(script_version.data_hash_type().into()) - .code_hash(spawn_caller_data_hash) - .build(); - let output = CellOutputBuilder::default() - .capacity(capacity_bytes!(100).pack()) - .lock(spawn_caller_script) - .build(); - let input = CellInput::new(OutPoint::null(), 0); - - let transaction = TransactionBuilder::default().input(input).build(); - let dummy_cell = create_dummy_cell(output); - - let rtx = ResolvedTransaction { - transaction, - resolved_cell_deps: vec![spawn_caller_cell, spawn_callee_cell], - resolved_inputs: vec![dummy_cell], - resolved_dep_groups: vec![], - }; - let verifier = TransactionScriptsVerifierWithEnv::new(); - let result = verifier.verify_without_limit(script_version, &rtx); - assert_eq!(result.is_ok(), script_version >= ScriptVersion::V2); -} - -#[test] -fn check_spawn_times_bug_1() { - let script_version = SCRIPT_VERSION; - - let (spawn_caller_cell, spawn_caller_data_hash) = load_cell_from_path("testdata/spawn_times"); - - let spawn_caller_script = Script::new_builder() - .hash_type(script_version.data_hash_type().into()) - .code_hash(spawn_caller_data_hash) - .build(); - let output = CellOutputBuilder::default() - .capacity(capacity_bytes!(100).pack()) - .lock(spawn_caller_script) - .build(); - let input = CellInput::new(OutPoint::null(), 0); - - let transaction = TransactionBuilder::default().input(input).build(); - let dummy_cell = create_dummy_cell(output); - - let rtx = ResolvedTransaction { - transaction, - resolved_cell_deps: vec![spawn_caller_cell], - resolved_inputs: vec![dummy_cell], - resolved_dep_groups: vec![], - }; - let verifier = TransactionScriptsVerifierWithEnv::new(); - let result = verifier.verify_without_limit(script_version, &rtx); - assert_eq!(result.is_ok(), script_version >= ScriptVersion::V2); -} - -#[test] -fn check_spawn_times_bug_2() { - let script_version = SCRIPT_VERSION; - if script_version <= ScriptVersion::V1 { - return; - } - let (spawn_caller_cell, spawn_caller_data_hash) = load_cell_from_path("testdata/spawn_times"); - - let spawn_caller_script = Script::new_builder() - .hash_type(script_version.data_hash_type().into()) - .code_hash(spawn_caller_data_hash) - .build(); - let output = CellOutputBuilder::default() - .capacity(capacity_bytes!(100).pack()) - .lock(spawn_caller_script) - .build(); - let input = CellInput::new(OutPoint::null(), 0); - - let transaction = TransactionBuilder::default().input(input).build(); - let dummy_cell = create_dummy_cell(output); - - let rtx = ResolvedTransaction { - transaction, - resolved_cell_deps: vec![spawn_caller_cell], - resolved_inputs: vec![dummy_cell], - resolved_dep_groups: vec![], - }; - let verifier = TransactionScriptsVerifierWithEnv::new(); - let result = verifier.verify_without_pause(script_version, &rtx, Cycle::MAX); - let cycles_once = result.unwrap(); - - let (cycles, _) = verifier - .verify_map(script_version, &rtx, |verifier| { - let max_cycles = Cycle::MAX; - let cycles; - let mut times = 0usize; - times += 1; - let mut init_state = match verifier.resumable_verify(max_cycles).unwrap() { - VerifyResult::Suspended(state) => Some(state), - VerifyResult::Completed(cycle) => { - cycles = cycle; - return Ok((cycles, times)); - } - }; - - loop { - times += 1; - let state = init_state.take().unwrap(); - match verifier.resume_from_state(state, max_cycles).unwrap() { - VerifyResult::Suspended(state) => { - init_state = Some(state); - } - VerifyResult::Completed(cycle) => { - cycles = cycle; - break; - } - } - } - - Ok::<(u64, usize), Error>((cycles, times)) - }) - .unwrap(); - assert_eq!(cycles, cycles_once); -} +// #[test] +// fn check_get_memory_limit() { +// let script_version = SCRIPT_VERSION; + +// let (memory_limit_cell, memory_limit_data_hash) = +// load_cell_from_path("testdata/get_memory_limit"); + +// let memory_limit_script = Script::new_builder() +// .hash_type(script_version.data_hash_type().into()) +// .code_hash(memory_limit_data_hash) +// .build(); +// let output = CellOutputBuilder::default() +// .capacity(capacity_bytes!(100).pack()) +// .lock(memory_limit_script) +// .build(); + +// let input = CellInput::new(OutPoint::null(), 0); + +// let transaction = TransactionBuilder::default().input(input).build(); +// let dummy_cell = create_dummy_cell(output); + +// let rtx = ResolvedTransaction { +// transaction, +// resolved_cell_deps: vec![memory_limit_cell], +// resolved_inputs: vec![dummy_cell], +// resolved_dep_groups: vec![], +// }; + +// let verifier = TransactionScriptsVerifierWithEnv::new(); +// let result = verifier.verify_without_limit(script_version, &rtx); +// assert_eq!(result.is_ok(), script_version >= ScriptVersion::V2); +// } + +// #[test] +// fn check_set_content() { +// let script_version = SCRIPT_VERSION; + +// let (set_content_cell, set_content_data_hash) = load_cell_from_path("testdata/set_content"); + +// let memory_limit_script = Script::new_builder() +// .hash_type(script_version.data_hash_type().into()) +// .code_hash(set_content_data_hash) +// .build(); +// let output = CellOutputBuilder::default() +// .capacity(capacity_bytes!(100).pack()) +// .lock(memory_limit_script) +// .build(); + +// let input = CellInput::new(OutPoint::null(), 0); + +// let transaction = TransactionBuilder::default().input(input).build(); +// let dummy_cell = create_dummy_cell(output); + +// let rtx = ResolvedTransaction { +// transaction, +// resolved_cell_deps: vec![set_content_cell], +// resolved_inputs: vec![dummy_cell], +// resolved_dep_groups: vec![], +// }; + +// let verifier = TransactionScriptsVerifierWithEnv::new(); +// let result = verifier.verify_without_limit(script_version, &rtx); +// assert_eq!(result.is_ok(), script_version >= ScriptVersion::V2); +// } + +// #[test] +// fn check_spawn_strcat() { +// let script_version = SCRIPT_VERSION; + +// let (spawn_caller_cell, spawn_caller_data_hash) = +// load_cell_from_path("testdata/spawn_caller_strcat"); +// let (spawn_callee_cell, _spawn_callee_data_hash) = +// load_cell_from_path("testdata/spawn_callee_strcat"); + +// let spawn_caller_script = Script::new_builder() +// .hash_type(script_version.data_hash_type().into()) +// .code_hash(spawn_caller_data_hash) +// .build(); +// let output = CellOutputBuilder::default() +// .capacity(capacity_bytes!(100).pack()) +// .lock(spawn_caller_script) +// .build(); +// let input = CellInput::new(OutPoint::null(), 0); + +// let transaction = TransactionBuilder::default().input(input).build(); +// let dummy_cell = create_dummy_cell(output); + +// let rtx = ResolvedTransaction { +// transaction, +// resolved_cell_deps: vec![spawn_caller_cell, spawn_callee_cell], +// resolved_inputs: vec![dummy_cell], +// resolved_dep_groups: vec![], +// }; +// let verifier = TransactionScriptsVerifierWithEnv::new(); +// let result = verifier.verify_without_limit(script_version, &rtx); +// assert_eq!(result.is_ok(), script_version >= ScriptVersion::V2); +// } + +// #[test] +// fn check_spawn_strcat_data_hash() { +// let script_version = SCRIPT_VERSION; + +// let (spawn_caller_cell, spawn_caller_data_hash) = +// load_cell_from_path("testdata/spawn_caller_strcat_data_hash"); +// let (spawn_callee_cell, _spawn_callee_data_hash) = +// load_cell_from_path("testdata/spawn_callee_strcat"); + +// let spawn_caller_script = Script::new_builder() +// .hash_type(script_version.data_hash_type().into()) +// .code_hash(spawn_caller_data_hash) +// .build(); +// let output = CellOutputBuilder::default() +// .capacity(capacity_bytes!(100).pack()) +// .lock(spawn_caller_script) +// .build(); +// let input = CellInput::new(OutPoint::null(), 0); + +// let transaction = TransactionBuilder::default().input(input).build(); +// let dummy_cell = create_dummy_cell(output); + +// let rtx = ResolvedTransaction { +// transaction, +// resolved_cell_deps: vec![spawn_caller_cell, spawn_callee_cell], +// resolved_inputs: vec![dummy_cell], +// resolved_dep_groups: vec![], +// }; +// let verifier = TransactionScriptsVerifierWithEnv::new(); +// let result = verifier.verify_without_limit(script_version, &rtx); +// assert_eq!(result.is_ok(), script_version >= ScriptVersion::V2); +// } + +// #[test] +// fn check_spawn_get_memory_limit() { +// let script_version = SCRIPT_VERSION; + +// let (spawn_caller_cell, spawn_caller_data_hash) = +// load_cell_from_path("testdata/spawn_caller_get_memory_limit"); +// let (spawn_callee_cell, _spawn_callee_data_hash) = +// load_cell_from_path("testdata/spawn_callee_get_memory_limit"); + +// let spawn_caller_script = Script::new_builder() +// .hash_type(script_version.data_hash_type().into()) +// .code_hash(spawn_caller_data_hash) +// .build(); +// let output = CellOutputBuilder::default() +// .capacity(capacity_bytes!(100).pack()) +// .lock(spawn_caller_script) +// .build(); +// let input = CellInput::new(OutPoint::null(), 0); + +// let transaction = TransactionBuilder::default().input(input).build(); +// let dummy_cell = create_dummy_cell(output); + +// let rtx = ResolvedTransaction { +// transaction, +// resolved_cell_deps: vec![spawn_caller_cell, spawn_callee_cell], +// resolved_inputs: vec![dummy_cell], +// resolved_dep_groups: vec![], +// }; +// let verifier = TransactionScriptsVerifierWithEnv::new(); +// let result = verifier.verify_without_limit(script_version, &rtx); +// assert_eq!(result.is_ok(), script_version >= ScriptVersion::V2); +// } + +// #[test] +// fn check_spawn_set_content() { +// let script_version = SCRIPT_VERSION; + +// let (spawn_caller_cell, spawn_caller_data_hash) = +// load_cell_from_path("testdata/spawn_caller_set_content"); +// let (spawn_callee_cell, _spawn_callee_data_hash) = +// load_cell_from_path("testdata/spawn_callee_set_content"); + +// let spawn_caller_script = Script::new_builder() +// .hash_type(script_version.data_hash_type().into()) +// .code_hash(spawn_caller_data_hash) +// .build(); +// let output = CellOutputBuilder::default() +// .capacity(capacity_bytes!(100).pack()) +// .lock(spawn_caller_script) +// .build(); +// let input = CellInput::new(OutPoint::null(), 0); + +// let transaction = TransactionBuilder::default().input(input).build(); +// let dummy_cell = create_dummy_cell(output); + +// let rtx = ResolvedTransaction { +// transaction, +// resolved_cell_deps: vec![spawn_caller_cell, spawn_callee_cell], +// resolved_inputs: vec![dummy_cell], +// resolved_dep_groups: vec![], +// }; +// let verifier = TransactionScriptsVerifierWithEnv::new(); +// let result = verifier.verify_without_limit(script_version, &rtx); +// assert_eq!(result.is_ok(), script_version >= ScriptVersion::V2); +// } + +// #[test] +// fn check_spawn_out_of_cycles() { +// let script_version = SCRIPT_VERSION; + +// let (spawn_caller_cell, spawn_caller_data_hash) = +// load_cell_from_path("testdata/spawn_caller_out_of_cycles"); +// let (spawn_callee_cell, _spawn_callee_data_hash) = +// load_cell_from_path("testdata/spawn_callee_out_of_cycles"); + +// let spawn_caller_script = Script::new_builder() +// .hash_type(script_version.data_hash_type().into()) +// .code_hash(spawn_caller_data_hash) +// .build(); +// let output = CellOutputBuilder::default() +// .capacity(capacity_bytes!(100).pack()) +// .lock(spawn_caller_script) +// .build(); +// let input = CellInput::new(OutPoint::null(), 0); + +// let transaction = TransactionBuilder::default().input(input).build(); +// let dummy_cell = create_dummy_cell(output); + +// let rtx = ResolvedTransaction { +// transaction, +// resolved_cell_deps: vec![spawn_caller_cell, spawn_callee_cell], +// resolved_inputs: vec![dummy_cell], +// resolved_dep_groups: vec![], +// }; +// let verifier = TransactionScriptsVerifierWithEnv::new(); +// let result = verifier.verify(script_version, &rtx, 0xffffff); +// if script_version >= ScriptVersion::V2 { +// assert!(result +// .unwrap_err() +// .to_string() +// .contains("ExceededMaximumCycles")) +// } else { +// assert!(result.is_err()) +// } +// } + +// #[test] +// fn check_spawn_exec() { +// let script_version = SCRIPT_VERSION; + +// let (spawn_caller_cell, spawn_caller_data_hash) = +// load_cell_from_path("testdata/spawn_caller_exec"); +// let (spawn_callee_caller_cell, _) = load_cell_from_path("testdata/spawn_callee_exec_caller"); +// let (spawn_callee_callee_cell, _) = load_cell_from_path("testdata/spawn_callee_exec_callee"); + +// let spawn_caller_script = Script::new_builder() +// .hash_type(script_version.data_hash_type().into()) +// .code_hash(spawn_caller_data_hash) +// .build(); +// let output = CellOutputBuilder::default() +// .capacity(capacity_bytes!(100).pack()) +// .lock(spawn_caller_script) +// .build(); +// let input = CellInput::new(OutPoint::null(), 0); + +// let transaction = TransactionBuilder::default().input(input).build(); +// let dummy_cell = create_dummy_cell(output); + +// let rtx = ResolvedTransaction { +// transaction, +// resolved_cell_deps: vec![ +// spawn_caller_cell, +// spawn_callee_caller_cell, +// spawn_callee_callee_cell, +// ], +// resolved_inputs: vec![dummy_cell], +// resolved_dep_groups: vec![], +// }; +// let verifier = TransactionScriptsVerifierWithEnv::new(); +// let result = verifier.verify(script_version, &rtx, 0xffffff); +// assert_eq!(result.is_ok(), script_version >= ScriptVersion::V2); +// } + +// #[test] +// fn check_spawn_strcat_wrap() { +// let script_version = SCRIPT_VERSION; + +// let (spawn_caller_cell, spawn_caller_data_hash) = +// load_cell_from_path("testdata/spawn_caller_strcat_wrap"); +// let (spawn_callee_caller_cell, _) = load_cell_from_path("testdata/spawn_caller_strcat"); +// let (spawn_callee_callee_cell, _) = load_cell_from_path("testdata/spawn_callee_strcat"); + +// let spawn_caller_script = Script::new_builder() +// .hash_type(script_version.data_hash_type().into()) +// .code_hash(spawn_caller_data_hash) +// .build(); +// let output = CellOutputBuilder::default() +// .capacity(capacity_bytes!(100).pack()) +// .lock(spawn_caller_script) +// .build(); +// let input = CellInput::new(OutPoint::null(), 0); + +// let transaction = TransactionBuilder::default().input(input).build(); +// let dummy_cell = create_dummy_cell(output); + +// let rtx = ResolvedTransaction { +// transaction, +// resolved_cell_deps: vec![ +// spawn_caller_cell, +// spawn_callee_callee_cell, +// spawn_callee_caller_cell, +// ], +// resolved_inputs: vec![dummy_cell], +// resolved_dep_groups: vec![], +// }; +// let verifier = TransactionScriptsVerifierWithEnv::new(); +// let result = verifier.verify(script_version, &rtx, 0xffffff); +// assert_eq!(result.is_ok(), script_version >= ScriptVersion::V2); +// } + +// #[test] +// fn check_spawn_out_of_cycles_wrap() { +// let script_version = SCRIPT_VERSION; + +// let (spawn_caller_cell, spawn_caller_data_hash) = +// load_cell_from_path("testdata/spawn_caller_out_of_cycles_wrap"); +// let (spawn_callee_caller_cell, _) = load_cell_from_path("testdata/spawn_caller_out_of_cycles"); +// let (spawn_callee_callee_cell, _) = load_cell_from_path("testdata/spawn_callee_out_of_cycles"); + +// let spawn_caller_script = Script::new_builder() +// .hash_type(script_version.data_hash_type().into()) +// .code_hash(spawn_caller_data_hash) +// .build(); +// let output = CellOutputBuilder::default() +// .capacity(capacity_bytes!(100).pack()) +// .lock(spawn_caller_script) +// .build(); +// let input = CellInput::new(OutPoint::null(), 0); + +// let transaction = TransactionBuilder::default().input(input).build(); +// let dummy_cell = create_dummy_cell(output); + +// let rtx = ResolvedTransaction { +// transaction, +// resolved_cell_deps: vec![ +// spawn_caller_cell, +// spawn_callee_callee_cell, +// spawn_callee_caller_cell, +// ], +// resolved_inputs: vec![dummy_cell], +// resolved_dep_groups: vec![], +// }; +// let verifier = TransactionScriptsVerifierWithEnv::new(); +// let result = verifier.verify(script_version, &rtx, 0xffffff); +// if script_version >= ScriptVersion::V2 { +// assert!(result +// .unwrap_err() +// .to_string() +// .contains("ExceededMaximumCycles")) +// } else { +// assert!(result.is_err()) +// } +// } + +// #[test] +// fn check_spawn_recursive() { +// let script_version = SCRIPT_VERSION; + +// let (spawn_caller_cell, spawn_caller_data_hash) = +// load_cell_from_path("testdata/spawn_recursive"); + +// let spawn_caller_script = Script::new_builder() +// .hash_type(script_version.data_hash_type().into()) +// .code_hash(spawn_caller_data_hash) +// .build(); +// let output = CellOutputBuilder::default() +// .capacity(capacity_bytes!(100).pack()) +// .lock(spawn_caller_script) +// .build(); +// let input = CellInput::new(OutPoint::null(), 0); + +// let transaction = TransactionBuilder::default().input(input).build(); +// let dummy_cell = create_dummy_cell(output); + +// let rtx = ResolvedTransaction { +// transaction, +// resolved_cell_deps: vec![spawn_caller_cell], +// resolved_inputs: vec![dummy_cell], +// resolved_dep_groups: vec![], +// }; +// let verifier = TransactionScriptsVerifierWithEnv::new(); +// let result = verifier.verify_without_limit(script_version, &rtx); +// if script_version >= ScriptVersion::V2 { +// assert!(result.unwrap_err().to_string().contains("error code 7")) +// } else { +// assert!(result.is_err()) +// } +// } + +// #[test] +// fn check_spawn_big_memory_size() { +// let script_version = SCRIPT_VERSION; + +// let (spawn_caller_cell, spawn_caller_data_hash) = +// load_cell_from_path("testdata/spawn_big_memory_size"); + +// let spawn_caller_script = Script::new_builder() +// .hash_type(script_version.data_hash_type().into()) +// .code_hash(spawn_caller_data_hash) +// .build(); +// let output = CellOutputBuilder::default() +// .capacity(capacity_bytes!(100).pack()) +// .lock(spawn_caller_script) +// .build(); +// let input = CellInput::new(OutPoint::null(), 0); + +// let transaction = TransactionBuilder::default().input(input).build(); +// let dummy_cell = create_dummy_cell(output); + +// let rtx = ResolvedTransaction { +// transaction, +// resolved_cell_deps: vec![spawn_caller_cell], +// resolved_inputs: vec![dummy_cell], +// resolved_dep_groups: vec![], +// }; +// let verifier = TransactionScriptsVerifierWithEnv::new(); +// let result = verifier.verify_without_limit(script_version, &rtx); +// assert_eq!(result.is_ok(), script_version >= ScriptVersion::V2); +// } + +// #[test] +// fn check_spawn_big_content_length() { +// let script_version = SCRIPT_VERSION; + +// let (spawn_caller_cell, spawn_caller_data_hash) = +// load_cell_from_path("testdata/spawn_big_content_length"); + +// let spawn_caller_script = Script::new_builder() +// .hash_type(script_version.data_hash_type().into()) +// .code_hash(spawn_caller_data_hash) +// .build(); +// let output = CellOutputBuilder::default() +// .capacity(capacity_bytes!(100).pack()) +// .lock(spawn_caller_script) +// .build(); +// let input = CellInput::new(OutPoint::null(), 0); + +// let transaction = TransactionBuilder::default().input(input).build(); +// let dummy_cell = create_dummy_cell(output); + +// let rtx = ResolvedTransaction { +// transaction, +// resolved_cell_deps: vec![spawn_caller_cell], +// resolved_inputs: vec![dummy_cell], +// resolved_dep_groups: vec![], +// }; +// let verifier = TransactionScriptsVerifierWithEnv::new(); +// let result = verifier.verify_without_limit(script_version, &rtx); +// assert_eq!(result.is_ok(), script_version >= ScriptVersion::V2); +// } + +// #[test] +// fn check_peak_memory_4m_to_32m() { +// let script_version = SCRIPT_VERSION; + +// let (spawn_caller_cell, spawn_caller_data_hash) = +// load_cell_from_path("testdata/spawn_peak_memory_4m_to_32m"); + +// let spawn_caller_script = Script::new_builder() +// .hash_type(script_version.data_hash_type().into()) +// .code_hash(spawn_caller_data_hash) +// .build(); +// let output = CellOutputBuilder::default() +// .capacity(capacity_bytes!(100).pack()) +// .lock(spawn_caller_script) +// .build(); +// let input = CellInput::new(OutPoint::null(), 0); + +// let transaction = TransactionBuilder::default().input(input).build(); +// let dummy_cell = create_dummy_cell(output); + +// let rtx = ResolvedTransaction { +// transaction, +// resolved_cell_deps: vec![spawn_caller_cell], +// resolved_inputs: vec![dummy_cell], +// resolved_dep_groups: vec![], +// }; +// let verifier = TransactionScriptsVerifierWithEnv::new(); +// let result = verifier.verify_without_limit(script_version, &rtx); +// assert_eq!(result.is_ok(), script_version >= ScriptVersion::V2); +// } + +// #[test] +// fn check_peak_memory_2m_to_32m() { +// let script_version = SCRIPT_VERSION; + +// let (spawn_caller_cell, spawn_caller_data_hash) = +// load_cell_from_path("testdata/spawn_peak_memory_2m_to_32m"); + +// let spawn_caller_script = Script::new_builder() +// .hash_type(script_version.data_hash_type().into()) +// .code_hash(spawn_caller_data_hash) +// .build(); +// let output = CellOutputBuilder::default() +// .capacity(capacity_bytes!(100).pack()) +// .lock(spawn_caller_script) +// .build(); +// let input = CellInput::new(OutPoint::null(), 0); + +// let transaction = TransactionBuilder::default().input(input).build(); +// let dummy_cell = create_dummy_cell(output); + +// let rtx = ResolvedTransaction { +// transaction, +// resolved_cell_deps: vec![spawn_caller_cell], +// resolved_inputs: vec![dummy_cell], +// resolved_dep_groups: vec![], +// }; +// let verifier = TransactionScriptsVerifierWithEnv::new(); +// let result = verifier.verify_without_limit(script_version, &rtx); +// assert_eq!(result.is_ok(), script_version >= ScriptVersion::V2); +// } + +// #[test] +// fn check_peak_memory_512k_to_32m() { +// let script_version = SCRIPT_VERSION; + +// let (spawn_caller_cell, spawn_caller_data_hash) = +// load_cell_from_path("testdata/spawn_peak_memory_512k_to_32m"); + +// let spawn_caller_script = Script::new_builder() +// .hash_type(script_version.data_hash_type().into()) +// .code_hash(spawn_caller_data_hash) +// .build(); +// let output = CellOutputBuilder::default() +// .capacity(capacity_bytes!(100).pack()) +// .lock(spawn_caller_script) +// .build(); +// let input = CellInput::new(OutPoint::null(), 0); + +// let transaction = TransactionBuilder::default().input(input).build(); +// let dummy_cell = create_dummy_cell(output); + +// let rtx = ResolvedTransaction { +// transaction, +// resolved_cell_deps: vec![spawn_caller_cell], +// resolved_inputs: vec![dummy_cell], +// resolved_dep_groups: vec![], +// }; +// let verifier = TransactionScriptsVerifierWithEnv::new(); +// let result = verifier.verify_without_limit(script_version, &rtx); +// assert_eq!(result.is_ok(), script_version >= ScriptVersion::V2); +// } + +// #[test] +// fn check_spawn_snapshot() { +// let script_version = SCRIPT_VERSION; +// if script_version <= ScriptVersion::V1 { +// return; +// } + +// let (spawn_caller_cell, spawn_caller_data_hash) = +// load_cell_from_path("testdata/spawn_caller_exec"); +// let (snapshot_cell, _) = load_cell_from_path("testdata/current_cycles_with_snapshot"); + +// let spawn_caller_script = Script::new_builder() +// .hash_type(script_version.data_hash_type().into()) +// .code_hash(spawn_caller_data_hash) +// .build(); +// let output = CellOutputBuilder::default() +// .capacity(capacity_bytes!(100).pack()) +// .lock(spawn_caller_script) +// .build(); +// let input = CellInput::new(OutPoint::null(), 0); + +// let transaction = TransactionBuilder::default().input(input).build(); +// let dummy_cell = create_dummy_cell(output); + +// let rtx = ResolvedTransaction { +// transaction, +// resolved_cell_deps: vec![spawn_caller_cell, snapshot_cell], +// resolved_inputs: vec![dummy_cell], +// resolved_dep_groups: vec![], +// }; +// let verifier = TransactionScriptsVerifierWithEnv::new(); +// let result = verifier.verify_without_pause(script_version, &rtx, Cycle::MAX); +// let cycles_once = result.unwrap(); + +// let (cycles, chunks_count) = verifier +// .verify_until_completed(script_version, &rtx) +// .unwrap(); +// assert_eq!(cycles, cycles_once); +// assert!(chunks_count > 1); +// } + +// #[tokio::test(flavor = "multi_thread", worker_threads = 4)] +// async fn check_spawn_async() { +// let script_version = SCRIPT_VERSION; +// if script_version <= ScriptVersion::V1 { +// return; +// } + +// let (spawn_caller_cell, spawn_caller_data_hash) = +// load_cell_from_path("testdata/spawn_caller_exec"); +// let (snapshot_cell, _) = load_cell_from_path("testdata/current_cycles_with_snapshot"); + +// let spawn_caller_script = Script::new_builder() +// .hash_type(script_version.data_hash_type().into()) +// .code_hash(spawn_caller_data_hash) +// .build(); +// let output = CellOutputBuilder::default() +// .capacity(capacity_bytes!(100).pack()) +// .lock(spawn_caller_script) +// .build(); +// let input = CellInput::new(OutPoint::null(), 0); + +// let transaction = TransactionBuilder::default().input(input).build(); +// let dummy_cell = create_dummy_cell(output); + +// let rtx = ResolvedTransaction { +// transaction, +// resolved_cell_deps: vec![spawn_caller_cell, snapshot_cell], +// resolved_inputs: vec![dummy_cell], +// resolved_dep_groups: vec![], +// }; +// let verifier = TransactionScriptsVerifierWithEnv::new(); +// let result = verifier.verify_without_pause(script_version, &rtx, Cycle::MAX); +// let cycles_once = result.unwrap(); + +// // we use debug pause to test context resume +// // `current_cycles_with_snapshot` will try to pause verifier +// // here we use `channel` to send Resume to verifier until it completes +// let (command_tx, mut command_rx) = watch::channel(ChunkCommand::Resume); +// let _jt = tokio::spawn(async move { +// loop { +// let res = command_tx.send(ChunkCommand::Resume); +// if res.is_err() { +// break; +// } +// tokio::time::sleep(tokio::time::Duration::from_millis(1)).await; +// } +// }); +// let cycles = verifier +// .verify_complete_async(script_version, &rtx, &mut command_rx, false) +// .await +// .unwrap(); +// assert_eq!(cycles, cycles_once); + +// // we send Resume/Suspend to command_rx in a loop, make sure cycles is still the same +// let (command_tx, mut command_rx) = watch::channel(ChunkCommand::Resume); +// let _jt = tokio::spawn(async move { +// loop { +// tokio::time::sleep(tokio::time::Duration::from_millis(10)).await; +// let _res = command_tx.send(ChunkCommand::Suspend); +// tokio::time::sleep(tokio::time::Duration::from_millis(10)).await; + +// let _res = command_tx.send(ChunkCommand::Resume); +// tokio::time::sleep(tokio::time::Duration::from_millis(1)).await; + +// let _res = command_tx.send(ChunkCommand::Suspend); +// tokio::time::sleep(tokio::time::Duration::from_millis(10)).await; + +// let _res = command_tx.send(ChunkCommand::Resume); +// tokio::time::sleep(tokio::time::Duration::from_millis(10)).await; +// } +// }); + +// let cycles = verifier +// .verify_complete_async(script_version, &rtx, &mut command_rx, true) +// .await +// .unwrap(); +// assert_eq!(cycles, cycles_once); +// } + +// #[tokio::test(flavor = "multi_thread", worker_threads = 4)] +// async fn check_spawn_suspend_shutdown() { +// let script_version = SCRIPT_VERSION; +// if script_version <= ScriptVersion::V1 { +// return; +// } + +// let (spawn_caller_cell, spawn_caller_data_hash) = +// load_cell_from_path("testdata/spawn_caller_exec"); +// let (snapshot_cell, _) = load_cell_from_path("testdata/infinite_loop"); + +// let spawn_caller_script = Script::new_builder() +// .hash_type(script_version.data_hash_type().into()) +// .code_hash(spawn_caller_data_hash) +// .build(); +// let output = CellOutputBuilder::default() +// .capacity(capacity_bytes!(100).pack()) +// .lock(spawn_caller_script) +// .build(); +// let input = CellInput::new(OutPoint::null(), 0); + +// let transaction = TransactionBuilder::default().input(input).build(); +// let dummy_cell = create_dummy_cell(output); + +// let rtx = ResolvedTransaction { +// transaction, +// resolved_cell_deps: vec![spawn_caller_cell, snapshot_cell], +// resolved_inputs: vec![dummy_cell], +// resolved_dep_groups: vec![], +// }; + +// let verifier = TransactionScriptsVerifierWithEnv::new(); +// let (command_tx, mut command_rx) = watch::channel(ChunkCommand::Resume); +// let _jt = tokio::spawn(async move { +// loop { +// let _res = command_tx.send(ChunkCommand::Suspend); +// tokio::time::sleep(tokio::time::Duration::from_millis(20)).await; + +// let _res = command_tx.send(ChunkCommand::Resume); +// tokio::time::sleep(tokio::time::Duration::from_millis(20)).await; + +// let _res = command_tx.send(ChunkCommand::Suspend); +// tokio::time::sleep(tokio::time::Duration::from_millis(20)).await; + +// let _res = command_tx.send(ChunkCommand::Stop); +// tokio::time::sleep(tokio::time::Duration::from_millis(20)).await; +// } +// }); + +// let res = verifier +// .verify_complete_async(script_version, &rtx, &mut command_rx, true) +// .await; +// assert!(res.is_err()); +// let err = res.unwrap_err().to_string(); +// assert!(err.contains("VM Internal Error: External(\"stopped\")")); +// } + +// #[test] +// fn check_spawn_state() { +// let script_version = SCRIPT_VERSION; +// if script_version <= ScriptVersion::V1 { +// return; +// } + +// let (spawn_caller_cell, spawn_caller_data_hash) = +// load_cell_from_path("testdata/spawn_caller_exec"); +// let (snapshot_cell, _) = load_cell_from_path("testdata/current_cycles_with_snapshot"); + +// let spawn_caller_script = Script::new_builder() +// .hash_type(script_version.data_hash_type().into()) +// .code_hash(spawn_caller_data_hash) +// .build(); +// let output = CellOutputBuilder::default() +// .capacity(capacity_bytes!(100).pack()) +// .lock(spawn_caller_script) +// .build(); +// let input = CellInput::new(OutPoint::null(), 0); + +// let transaction = TransactionBuilder::default().input(input).build(); +// let dummy_cell = create_dummy_cell(output); + +// let rtx = ResolvedTransaction { +// transaction, +// resolved_cell_deps: vec![spawn_caller_cell, snapshot_cell], +// resolved_inputs: vec![dummy_cell], +// resolved_dep_groups: vec![], +// }; +// let verifier = TransactionScriptsVerifierWithEnv::new(); +// let result = verifier.verify_without_pause(script_version, &rtx, Cycle::MAX); +// let cycles_once = result.unwrap(); + +// let (cycles, chunks_count) = verifier +// .verify_map(script_version, &rtx, |verifier| { +// let max_cycles = Cycle::MAX; +// let cycles; +// let mut times = 0usize; +// times += 1; +// let mut init_state = match verifier.resumable_verify(max_cycles).unwrap() { +// VerifyResult::Suspended(state) => Some(state), +// VerifyResult::Completed(cycle) => { +// cycles = cycle; +// return Ok((cycles, times)); +// } +// }; + +// loop { +// times += 1; +// let state = init_state.take().unwrap(); +// match verifier.resume_from_state(state, max_cycles).unwrap() { +// VerifyResult::Suspended(state) => { +// init_state = Some(state); +// } +// VerifyResult::Completed(cycle) => { +// cycles = cycle; +// break; +// } +// } +// } + +// Ok::<(u64, usize), Error>((cycles, times)) +// }) +// .unwrap(); +// assert_eq!(cycles, cycles_once); +// assert!(chunks_count > 1); +// } + +// #[test] +// fn check_spawn_current_memory() { +// let script_version = SCRIPT_VERSION; + +// let (spawn_caller_cell, spawn_caller_data_hash) = +// load_cell_from_path("testdata/spawn_current_memory"); + +// let spawn_caller_script = Script::new_builder() +// .hash_type(script_version.data_hash_type().into()) +// .code_hash(spawn_caller_data_hash) +// .build(); +// let output = CellOutputBuilder::default() +// .capacity(capacity_bytes!(100).pack()) +// .lock(spawn_caller_script) +// .build(); +// let input = CellInput::new(OutPoint::null(), 0); + +// let transaction = TransactionBuilder::default().input(input).build(); +// let dummy_cell = create_dummy_cell(output); + +// let rtx = ResolvedTransaction { +// transaction, +// resolved_cell_deps: vec![spawn_caller_cell], +// resolved_inputs: vec![dummy_cell], +// resolved_dep_groups: vec![], +// }; +// let verifier = TransactionScriptsVerifierWithEnv::new(); +// let result = verifier.verify_without_limit(script_version, &rtx); +// assert_eq!(result.is_ok(), script_version >= ScriptVersion::V2); +// } + +// #[test] +// fn check_spawn_current_cycles() { +// let script_version = SCRIPT_VERSION; + +// let (spawn_caller_cell, spawn_caller_data_hash) = +// load_cell_from_path("testdata/spawn_caller_current_cycles"); +// let (spawn_callee_cell, _spawn_callee_data_hash) = +// load_cell_from_path("testdata/spawn_callee_current_cycles"); + +// let spawn_caller_script = Script::new_builder() +// .hash_type(script_version.data_hash_type().into()) +// .code_hash(spawn_caller_data_hash) +// .build(); +// let output = CellOutputBuilder::default() +// .capacity(capacity_bytes!(100).pack()) +// .lock(spawn_caller_script) +// .build(); +// let input = CellInput::new(OutPoint::null(), 0); + +// let transaction = TransactionBuilder::default().input(input).build(); +// let dummy_cell = create_dummy_cell(output); + +// let rtx = ResolvedTransaction { +// transaction, +// resolved_cell_deps: vec![spawn_caller_cell, spawn_callee_cell], +// resolved_inputs: vec![dummy_cell], +// resolved_dep_groups: vec![], +// }; +// let verifier = TransactionScriptsVerifierWithEnv::new(); +// let result = verifier.verify_without_limit(script_version, &rtx); +// assert_eq!(result.is_ok(), script_version >= ScriptVersion::V2); +// } + +// #[test] +// fn check_spawn_times_bug_1() { +// let script_version = SCRIPT_VERSION; + +// let (spawn_caller_cell, spawn_caller_data_hash) = load_cell_from_path("testdata/spawn_times"); + +// let spawn_caller_script = Script::new_builder() +// .hash_type(script_version.data_hash_type().into()) +// .code_hash(spawn_caller_data_hash) +// .build(); +// let output = CellOutputBuilder::default() +// .capacity(capacity_bytes!(100).pack()) +// .lock(spawn_caller_script) +// .build(); +// let input = CellInput::new(OutPoint::null(), 0); + +// let transaction = TransactionBuilder::default().input(input).build(); +// let dummy_cell = create_dummy_cell(output); + +// let rtx = ResolvedTransaction { +// transaction, +// resolved_cell_deps: vec![spawn_caller_cell], +// resolved_inputs: vec![dummy_cell], +// resolved_dep_groups: vec![], +// }; +// let verifier = TransactionScriptsVerifierWithEnv::new(); +// let result = verifier.verify_without_limit(script_version, &rtx); +// assert_eq!(result.is_ok(), script_version >= ScriptVersion::V2); +// } + +// #[test] +// fn check_spawn_times_bug_2() { +// let script_version = SCRIPT_VERSION; +// if script_version <= ScriptVersion::V1 { +// return; +// } +// let (spawn_caller_cell, spawn_caller_data_hash) = load_cell_from_path("testdata/spawn_times"); + +// let spawn_caller_script = Script::new_builder() +// .hash_type(script_version.data_hash_type().into()) +// .code_hash(spawn_caller_data_hash) +// .build(); +// let output = CellOutputBuilder::default() +// .capacity(capacity_bytes!(100).pack()) +// .lock(spawn_caller_script) +// .build(); +// let input = CellInput::new(OutPoint::null(), 0); + +// let transaction = TransactionBuilder::default().input(input).build(); +// let dummy_cell = create_dummy_cell(output); + +// let rtx = ResolvedTransaction { +// transaction, +// resolved_cell_deps: vec![spawn_caller_cell], +// resolved_inputs: vec![dummy_cell], +// resolved_dep_groups: vec![], +// }; +// let verifier = TransactionScriptsVerifierWithEnv::new(); +// let result = verifier.verify_without_pause(script_version, &rtx, Cycle::MAX); +// let cycles_once = result.unwrap(); + +// let (cycles, _) = verifier +// .verify_map(script_version, &rtx, |verifier| { +// let max_cycles = Cycle::MAX; +// let cycles; +// let mut times = 0usize; +// times += 1; +// let mut init_state = match verifier.resumable_verify(max_cycles).unwrap() { +// VerifyResult::Suspended(state) => Some(state), +// VerifyResult::Completed(cycle) => { +// cycles = cycle; +// return Ok((cycles, times)); +// } +// }; + +// loop { +// times += 1; +// let state = init_state.take().unwrap(); +// match verifier.resume_from_state(state, max_cycles).unwrap() { +// VerifyResult::Suspended(state) => { +// init_state = Some(state); +// } +// VerifyResult::Completed(cycle) => { +// cycles = cycle; +// break; +// } +// } +// } + +// Ok::<(u64, usize), Error>((cycles, times)) +// }) +// .unwrap(); +// assert_eq!(cycles, cycles_once); +// }