diff --git a/Cargo.lock b/Cargo.lock index 8f98a9ae83..0971bece60 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1865,9 +1865,9 @@ dependencies = [ [[package]] name = "ckb-vm" -version = "0.24.12" +version = "0.24.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddff96029d3298cb630e95f29d4b9a93384e938a0b75758684aa8794b53bdd1a" +checksum = "49dc9651f4fe97dc45fcbc9d5b35f1e2d66accbab6d78f847d3000336aec4dbf" dependencies = [ "byteorder", "bytes", @@ -1883,9 +1883,9 @@ dependencies = [ [[package]] name = "ckb-vm-definitions" -version = "0.24.12" +version = "0.24.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c280bf1d589d23ab0358f58601c2187fc6be86a131644583ef72ea96a0a13ddd" +checksum = "95db407ba457416941e70dbaa28fb546d94a4f55be623316d24fb750320b1f45" dependencies = [ "paste", ] @@ -4267,9 +4267,9 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "openssl" -version = "0.10.68" +version = "0.10.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" +checksum = "61cfb4e166a8bb8c9b55c500bc2308550148ece889be90f609377e58140f42c6" dependencies = [ "bitflags 2.6.0", "cfg-if", @@ -4308,9 +4308,9 @@ dependencies = [ [[package]] name = "openssl-sys" -version = "0.9.104" +version = "0.9.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" +checksum = "8b22d5b84be05a8d6947c7cb71f7c849aa0f112acd4bf51c2a7c1c988ac0a9dc" dependencies = [ "cc", "libc", diff --git a/script/Cargo.toml b/script/Cargo.toml index f21bb770f7..acfbeb33e2 100644 --- a/script/Cargo.toml +++ b/script/Cargo.toml @@ -22,7 +22,7 @@ ckb-traits = { path = "../traits", version = "= 0.121.0-pre" } byteorder = "1.3.1" ckb-types = { path = "../util/types", version = "= 0.121.0-pre" } ckb-hash = { path = "../util/hash", version = "= 0.121.0-pre" } -ckb-vm = { version = "= 0.24.12", default-features = false } +ckb-vm = { version = "= 0.24.13", default-features = false } faster-hex = "0.6" ckb-logger = { path = "../util/logger", version = "= 0.121.0-pre", optional = true } serde = { version = "1.0", features = ["derive"] } diff --git a/script/src/scheduler.rs b/script/src/scheduler.rs index aee25168a8..b83b1b5b9d 100644 --- a/script/src/scheduler.rs +++ b/script/src/scheduler.rs @@ -1,15 +1,15 @@ use crate::cost_model::transferred_byte_cycles; use crate::syscalls::{ - INVALID_FD, MAX_FDS_CREATED, MAX_VMS_SPAWNED, OTHER_END_CLOSED, SPAWN_EXTRA_CYCLES_BASE, - SUCCESS, WAIT_FAILURE, + EXEC_LOAD_ELF_V2_CYCLES_BASE, INVALID_FD, MAX_FDS_CREATED, MAX_VMS_SPAWNED, OTHER_END_CLOSED, + SPAWN_EXTRA_CYCLES_BASE, SUCCESS, WAIT_FAILURE, }; use crate::types::MachineContext; use crate::verify::TransactionScriptsSyscallsGenerator; use crate::ScriptVersion; use crate::types::{ - CoreMachineType, DataPieceId, Fd, FdArgs, FullSuspendedState, Machine, Message, ReadState, - RunMode, TxData, VmId, VmState, WriteState, FIRST_FD_SLOT, FIRST_VM_ID, + CoreMachineType, DataLocation, DataPieceId, Fd, FdArgs, FullSuspendedState, Machine, Message, + ReadState, RunMode, TxData, VmId, VmState, WriteState, FIRST_FD_SLOT, FIRST_VM_ID, }; use ckb_traits::{CellDataProvider, ExtensionProvider, HeaderProvider}; use ckb_types::core::Cycle; @@ -22,7 +22,7 @@ use ckb_vm::{ memory::Memory, registers::A0, snapshot2::Snapshot2, - Error, Register, + Error, FlattenedArgsReader, Register, }; use std::collections::{BTreeMap, HashMap}; use std::sync::{Arc, Mutex}; @@ -208,7 +208,14 @@ where if self.states.is_empty() { // Booting phase, we will need to initialize the first VM. assert_eq!( - self.boot_vm(&DataPieceId::Program, 0, u64::MAX, &[])?, + self.boot_vm( + &DataLocation { + data_piece_id: DataPieceId::Program, + offset: 0, + length: u64::MAX, + }, + None + )?, ROOT_VM_ID ); } @@ -340,6 +347,39 @@ where let messages: Vec = self.message_box.lock().expect("lock").drain(..).collect(); for message in messages { match message { + Message::ExecV2(vm_id, args) => { + let (old_context, old_machine) = self + .instantiated + .get_mut(&vm_id) + .ok_or_else(|| Error::Unexpected("Unable to find VM Id".to_string()))?; + old_machine + .machine + .add_cycles_no_checking(EXEC_LOAD_ELF_V2_CYCLES_BASE)?; + let old_cycles = old_machine.machine.cycles(); + let max_cycles = old_machine.machine.max_cycles(); + let program = { + let mut sc = old_context.snapshot2_context().lock().expect("lock"); + sc.load_data( + &args.location.data_piece_id, + args.location.offset, + args.location.length, + )? + .0 + }; + let (context, mut new_machine) = self.create_dummy_vm(&vm_id)?; + new_machine.set_max_cycles(max_cycles); + new_machine.machine.add_cycles_no_checking(old_cycles)?; + self.load_vm_program( + &context, + &mut new_machine, + &args.location, + program, + Some((vm_id, args.argc, args.argv)), + )?; + // The insert operation removes the old vm instance and adds the new vm instance. + debug_assert!(self.instantiated.contains_key(&vm_id)); + self.instantiated.insert(vm_id, (context, new_machine)); + } Message::Spawn(vm_id, args) => { // All fds must belong to the correct owner if args.fds.iter().any(|fd| self.fds.get(fd) != Some(&vm_id)) { @@ -353,7 +393,7 @@ where continue; } let spawned_vm_id = - self.boot_vm(&args.data_piece_id, args.offset, args.length, &args.argv)?; + self.boot_vm(&args.location, Some((vm_id, args.argc, args.argv)))?; // Move passed fds from spawner to spawnee for fd in &args.fds { self.fds.insert(*fd, spawned_vm_id); @@ -746,11 +786,17 @@ where /// Boot a vm by given program and args. pub fn boot_vm( &mut self, - data_piece_id: &DataPieceId, - offset: u64, - length: u64, - args: &[Bytes], + location: &DataLocation, + args: Option<(u64, u64, u64)>, ) -> Result { + let id = self.next_vm_id; + self.next_vm_id += 1; + let (context, mut machine) = self.create_dummy_vm(&id)?; + let (program, _) = { + let mut sc = context.snapshot2_context().lock().expect("lock"); + sc.load_data(&location.data_piece_id, location.offset, location.length)? + }; + self.load_vm_program(&context, &mut machine, location, program, args)?; // Newly booted VM will be instantiated by default while self.instantiated.len() >= MAX_INSTANTIATED_VMS { // Instantiated is a BTreeMap, first_entry will maintain key order @@ -761,26 +807,43 @@ where .key(); self.suspend_vm(&id)?; } - - let id = self.next_vm_id; - self.next_vm_id += 1; - let (context, mut machine) = self.create_dummy_vm(&id)?; - { - let mut sc = context.snapshot2_context().lock().expect("lock"); - let (program, _) = sc.load_data(data_piece_id, offset, length)?; - let metadata = parse_elf::(&program, machine.machine.version())?; - let bytes = machine.load_program_with_metadata(&program, &metadata, args)?; - sc.mark_program(&mut machine.machine, &metadata, data_piece_id, offset)?; - machine - .machine - .add_cycles_no_checking(transferred_byte_cycles(bytes))?; - } self.instantiated.insert(id, (context, machine)); self.states.insert(id, VmState::Runnable); Ok(id) } + // Load the program into an empty vm. + fn load_vm_program( + &mut self, + context: &MachineContext
, + machine: &mut Machine, + location: &DataLocation, + program: Bytes, + args: Option<(u64, u64, u64)>, + ) -> Result { + let metadata = parse_elf::(&program, machine.machine.version())?; + let bytes = match args { + Some((vm_id, argc, argv)) => { + let (_, machine_from) = self.ensure_get_instantiated(&vm_id)?; + let argv = FlattenedArgsReader::new(machine_from.machine.memory_mut(), argc, argv); + machine.load_program_with_metadata(&program, &metadata, argv)? + } + None => machine.load_program_with_metadata(&program, &metadata, vec![].into_iter())?, + }; + let mut sc = context.snapshot2_context().lock().expect("lock"); + sc.mark_program( + &mut machine.machine, + &metadata, + &location.data_piece_id, + location.offset, + )?; + machine + .machine + .add_cycles_no_checking(transferred_byte_cycles(bytes))?; + Ok(bytes) + } + // Create a new VM instance with syscalls attached fn create_dummy_vm(&self, id: &VmId) -> Result<(MachineContext
, Machine), Error> { // The code here looks slightly weird, since I don't want to copy over all syscall diff --git a/script/src/syscalls/exec.rs b/script/src/syscalls/exec.rs index 9d42c8b8e4..1e934fddf8 100644 --- a/script/src/syscalls/exec.rs +++ b/script/src/syscalls/exec.rs @@ -1,5 +1,4 @@ use crate::cost_model::transferred_byte_cycles; -use crate::syscalls::utils::load_c_string; use crate::syscalls::{ Place, Source, SourceEntry, EXEC, INDEX_OUT_OF_BOUND, MAX_ARGV_LENGTH, SLICE_OUT_OF_BOUND, WRONG_FORMAT, @@ -9,6 +8,7 @@ use ckb_traits::CellDataProvider; use ckb_types::core::cell::{CellMeta, ResolvedTransaction}; use ckb_types::core::error::ARGV_TOO_LONG_TEXT; use ckb_types::packed::{Bytes as PackedBytes, BytesVec}; +use ckb_vm::memory::load_c_string_byte_by_byte; use ckb_vm::Memory; use ckb_vm::{ registers::{A0, A1, A2, A3, A4, A5, A7}, @@ -24,7 +24,6 @@ pub struct Exec
{ outputs: Arc>, group_inputs: Indices, group_outputs: Indices, - load_elf_base_fee: u64, } impl Exec
{ @@ -34,7 +33,6 @@ impl Exec
{ outputs: Arc>, group_inputs: Indices, group_outputs: Indices, - load_elf_base_fee: u64, ) -> Exec
{ Exec { data_loader, @@ -42,7 +40,6 @@ impl Exec
{ outputs, group_inputs, group_outputs, - load_elf_base_fee, } } @@ -154,6 +151,7 @@ impl Syscalls for let data = if length == 0 { data.slice(offset..data_size) } else { + // Both offset and length are <= u32::MAX, so offset.checked_add(length) will be always a Some. let end = offset.checked_add(length).ok_or(VMError::MemOutOfBound)?; if end > data_size { machine.set_register(A0, Mac::REG::from_u8(SLICE_OUT_OF_BOUND)); @@ -166,12 +164,8 @@ impl Syscalls for let mut argv = Vec::new(); let mut argv_length: u64 = 0; for _ in 0..argc { - let target_addr = machine - .memory_mut() - .load64(&Mac::REG::from_u64(addr))? - .to_u64(); - - let cstr = load_c_string(machine, target_addr)?; + let target_addr = machine.memory_mut().load64(&Mac::REG::from_u64(addr))?; + let cstr = load_c_string_byte_by_byte(machine.memory_mut(), &target_addr)?; let cstr_len = cstr.len(); argv.push(cstr); @@ -191,7 +185,6 @@ impl Syscalls for machine.reset(max_cycles); machine.set_cycles(cycles); - machine.add_cycles_no_checking(self.load_elf_base_fee)?; match machine.load_elf(&data, true) { Ok(size) => { machine.add_cycles_no_checking(transferred_byte_cycles(size))?; @@ -203,7 +196,7 @@ impl Syscalls for } match machine.initialize_stack( - &argv, + argv.into_iter().map(Ok), (RISCV_MAX_MEMORY - DEFAULT_STACK_SIZE) as u64, DEFAULT_STACK_SIZE as u64, ) { diff --git a/script/src/syscalls/exec_v2.rs b/script/src/syscalls/exec_v2.rs new file mode 100644 index 0000000000..ab5b2facce --- /dev/null +++ b/script/src/syscalls/exec_v2.rs @@ -0,0 +1,65 @@ +use crate::syscalls::{EXEC, INDEX_OUT_OF_BOUND}; +use crate::types::{DataLocation, DataPieceId, ExecV2Args, Message, VmId}; +use ckb_vm::{ + registers::{A0, A1, A2, A3, A4, A5, A7}, + Error as VMError, Register, SupportMachine, Syscalls, +}; +use std::sync::{Arc, Mutex}; + +pub struct ExecV2 { + id: VmId, + message_box: Arc>>, +} + +impl ExecV2 { + pub fn new(id: VmId, message_box: Arc>>) -> ExecV2 { + ExecV2 { id, message_box } + } +} + +impl Syscalls for ExecV2 +where + Mac: SupportMachine, +{ + fn initialize(&mut self, _machine: &mut Mac) -> Result<(), VMError> { + Ok(()) + } + + fn ecall(&mut self, machine: &mut Mac) -> Result { + if machine.registers()[A7].to_u64() != EXEC { + return Ok(false); + } + let index = machine.registers()[A0].to_u64(); + let source = machine.registers()[A1].to_u64(); + let place = machine.registers()[A2].to_u64(); + let data_piece_id = match DataPieceId::try_from((source, index, place)) { + Ok(id) => id, + Err(_) => { + machine.set_register(A0, Mac::REG::from_u8(INDEX_OUT_OF_BOUND)); + return Ok(true); + } + }; + let bounds = machine.registers()[A3].to_u64(); + let offset = bounds >> 32; + let length = bounds as u32 as u64; + + let argc = machine.registers()[A4].to_u64(); + let argv = machine.registers()[A5].to_u64(); + self.message_box + .lock() + .map_err(|e| VMError::Unexpected(e.to_string()))? + .push(Message::ExecV2( + self.id, + ExecV2Args { + location: DataLocation { + data_piece_id, + offset, + length, + }, + argc, + argv, + }, + )); + Err(VMError::Yield) + } +} diff --git a/script/src/syscalls/mod.rs b/script/src/syscalls/mod.rs index a7a3fd0459..24a4ddcef3 100644 --- a/script/src/syscalls/mod.rs +++ b/script/src/syscalls/mod.rs @@ -2,6 +2,7 @@ mod close; mod current_cycles; mod debugger; mod exec; +mod exec_v2; mod inherited_fd; mod load_block_extension; mod load_cell; @@ -31,6 +32,7 @@ pub use self::close::Close; pub use self::current_cycles::CurrentCycles; pub use self::debugger::Debugger; pub use self::exec::Exec; +pub use self::exec_v2::ExecV2; pub use self::inherited_fd::InheritedFd; pub use self::load_block_extension::LoadBlockExtension; pub use self::load_cell::LoadCell; diff --git a/script/src/syscalls/spawn.rs b/script/src/syscalls/spawn.rs index 838fc1de74..f4c7e82b87 100644 --- a/script/src/syscalls/spawn.rs +++ b/script/src/syscalls/spawn.rs @@ -1,11 +1,9 @@ -use crate::syscalls::utils::load_c_string; use crate::syscalls::{ - Source, INDEX_OUT_OF_BOUND, MAX_ARGV_LENGTH, SLICE_OUT_OF_BOUND, SOURCE_ENTRY_MASK, - SOURCE_GROUP_FLAG, SPAWN, SPAWN_EXTRA_CYCLES_BASE, SPAWN_YIELD_CYCLES_BASE, + Source, INDEX_OUT_OF_BOUND, SLICE_OUT_OF_BOUND, SOURCE_ENTRY_MASK, SOURCE_GROUP_FLAG, SPAWN, + SPAWN_EXTRA_CYCLES_BASE, SPAWN_YIELD_CYCLES_BASE, }; -use crate::types::{DataPieceId, Fd, Message, SpawnArgs, TxData, VmId}; +use crate::types::{DataLocation, DataPieceId, Fd, Message, SpawnArgs, TxData, VmId}; use ckb_traits::{CellDataProvider, ExtensionProvider, HeaderProvider}; -use ckb_types::core::error::ARGV_TOO_LONG_TEXT; use ckb_vm::{ machine::SupportMachine, memory::Memory, @@ -79,36 +77,11 @@ where let argc_addr = spgs_addr; let argc = machine .memory_mut() - .load64(&Mac::REG::from_u64(argc_addr))? - .to_u64(); - let argv_addr_addr = spgs_addr.wrapping_add(8); - let argv_addr = machine + .load64(&Mac::REG::from_u64(argc_addr))?; + let argv_addr = spgs_addr.wrapping_add(8); + let argv = machine .memory_mut() - .load64(&Mac::REG::from_u64(argv_addr_addr))? - .to_u64(); - let mut addr = argv_addr; - let mut argv = Vec::new(); - let mut argv_length: u64 = 0; - for _ in 0..argc { - let target_addr = machine - .memory_mut() - .load64(&Mac::REG::from_u64(addr))? - .to_u64(); - let cstr = load_c_string(machine, target_addr)?; - let cstr_len = cstr.len(); - argv.push(cstr); - - // Number of argv entries should also be considered - argv_length = argv_length - .saturating_add(8) - .saturating_add(cstr_len as u64); - if argv_length > MAX_ARGV_LENGTH { - return Err(VMError::Unexpected(ARGV_TOO_LONG_TEXT.to_string())); - } - - addr = addr.wrapping_add(8); - } - + .load64(&Mac::REG::from_u64(argv_addr))?; let process_id_addr_addr = spgs_addr.wrapping_add(16); let process_id_addr = machine .memory_mut() @@ -169,10 +142,13 @@ where .push(Message::Spawn( self.id, SpawnArgs { - data_piece_id, - offset, - length, - argv, + location: DataLocation { + data_piece_id, + offset, + length, + }, + argc: argc.to_u64(), + argv: argv.to_u64(), fds, process_id_addr, }, diff --git a/script/src/syscalls/utils.rs b/script/src/syscalls/utils.rs index a62d0900b3..8729e82759 100644 --- a/script/src/syscalls/utils.rs +++ b/script/src/syscalls/utils.rs @@ -1,7 +1,7 @@ use byteorder::{ByteOrder, LittleEndian}; use ckb_vm::{ registers::{A0, A1, A2}, - Bytes, Error as VMError, Memory, Register, SupportMachine, + Error as VMError, Memory, Register, SupportMachine, }; use std::cmp; @@ -28,22 +28,3 @@ pub fn store_u64(machine: &mut Mac, v: u64) -> Result(machine: &mut Mac, addr: u64) -> Result { - let mut buffer = Vec::new(); - let mut addr = addr; - - loop { - let byte = machine - .memory_mut() - .load8(&Mac::REG::from_u64(addr))? - .to_u8(); - if byte == 0 { - break; - } - buffer.push(byte); - addr += 1; - } - - Ok(Bytes::from(buffer)) -} diff --git a/script/src/types.rs b/script/src/types.rs index f2c28b1491..8f25a98799 100644 --- a/script/src/types.rs +++ b/script/src/types.rs @@ -351,11 +351,24 @@ pub enum VmState { } #[derive(Clone, Debug)] -pub struct SpawnArgs { +pub struct DataLocation { pub data_piece_id: DataPieceId, pub offset: u64, pub length: u64, - pub argv: Vec, +} + +#[derive(Clone, Debug)] +pub struct ExecV2Args { + pub location: DataLocation, + pub argc: u64, + pub argv: u64, +} + +#[derive(Clone, Debug)] +pub struct SpawnArgs { + pub location: DataLocation, + pub argc: u64, + pub argv: u64, pub fds: Vec, pub process_id_addr: u64, } @@ -382,6 +395,7 @@ pub struct FdArgs { #[derive(Clone, Debug)] pub enum Message { + ExecV2(VmId, ExecV2Args), Spawn(VmId, SpawnArgs), Wait(VmId, WaitArgs), Pipe(VmId, PipeArgs), diff --git a/script/src/verify.rs b/script/src/verify.rs index 6eac6981d6..a9315e3a79 100644 --- a/script/src/verify.rs +++ b/script/src/verify.rs @@ -1,14 +1,14 @@ use crate::scheduler::Scheduler; #[cfg(test)] use crate::syscalls::Pause; -use crate::syscalls::{InheritedFd, ProcessID, EXEC_LOAD_ELF_V2_CYCLES_BASE}; +use crate::syscalls::{InheritedFd, ProcessID}; use crate::types::{DataPieceId, FullSuspendedState, Message, RunMode, TxData, VmId, FIRST_VM_ID}; #[cfg(not(target_family = "wasm"))] use crate::ChunkCommand; use crate::{ error::{ScriptError, TransactionScriptError}, syscalls::{ - Close, CurrentCycles, Debugger, Exec, LoadBlockExtension, LoadCell, LoadCellData, + Close, CurrentCycles, Debugger, Exec, ExecV2, LoadBlockExtension, LoadCell, LoadCellData, LoadHeader, LoadInput, LoadScript, LoadScriptHash, LoadTx, LoadWitness, Pipe, Read, Spawn, VMVersion, Wait, Write, }, @@ -172,22 +172,21 @@ where } /// Build syscall: exec - pub fn build_exec( - &self, - group_inputs: Indices, - group_outputs: Indices, - load_elf_base_fee: u64, - ) -> Exec
{ + pub fn build_exec(&self, group_inputs: Indices, group_outputs: Indices) -> Exec
{ Exec::new( self.data_loader.clone(), Arc::clone(&self.rtx), Arc::clone(&self.outputs), group_inputs, group_outputs, - load_elf_base_fee, ) } + /// Build syscall: exec. When script version >= V2, this exec implementation is used. + pub fn build_exec_v2(&self) -> ExecV2 { + ExecV2::new(self.vm_id, Arc::clone(&self.message_box)) + } + /// Build syscall: load_tx pub fn build_load_tx(&self) -> LoadTx { LoadTx::new(Arc::clone(&self.rtx)) @@ -326,15 +325,14 @@ where if script_version >= ScriptVersion::V1 { syscalls.append(&mut vec![ Box::new(self.build_vm_version()), - Box::new(self.build_exec( - Arc::clone(&script_group_input_indices), - Arc::clone(&script_group_output_indices), - if script_version >= ScriptVersion::V2 { - EXEC_LOAD_ELF_V2_CYCLES_BASE - } else { - 0 - }, - )), + if script_version >= ScriptVersion::V2 { + Box::new(self.build_exec_v2()) + } else { + Box::new(self.build_exec( + Arc::clone(&script_group_input_indices), + Arc::clone(&script_group_output_indices), + )) + }, Box::new(self.build_current_cycles()), ]); } diff --git a/script/src/verify/tests/ckb_latest/features_since_v2021.rs b/script/src/verify/tests/ckb_latest/features_since_v2021.rs index f18494a601..4d274616fe 100644 --- a/script/src/verify/tests/ckb_latest/features_since_v2021.rs +++ b/script/src/verify/tests/ckb_latest/features_since_v2021.rs @@ -490,8 +490,17 @@ fn check_exec_big_offset_length() { let verifier = TransactionScriptsVerifierWithEnv::new(); let result = verifier.verify_without_limit(script_version, &rtx); - if script_version >= ScriptVersion::V1 { - assert!(result.unwrap_err().to_string().contains("error code 3")); + match script_version { + ScriptVersion::V0 => {} + ScriptVersion::V1 => { + assert!(result.unwrap_err().to_string().contains("error code 3")); + } + _ => { + assert!(result + .unwrap_err() + .to_string() + .contains("VM Internal Error: ElfParseError")); + } } } @@ -818,12 +827,17 @@ fn _check_typical_secp256k1_blake160_2_in_2_out_tx_with_chunk(step_cycles: Cycle #[test] fn check_typical_secp256k1_blake160_2_in_2_out_tx_with_chunk() { + let cycle_bound = if SCRIPT_VERSION >= ScriptVersion::V2 { + V2_CYCLE_BOUND + } else { + CYCLE_BOUND + }; if SCRIPT_VERSION >= ScriptVersion::V1 { let mut rng = thread_rng(); let step_cycles1 = rng.sample(Uniform::from(1..100u64)); _check_typical_secp256k1_blake160_2_in_2_out_tx_with_chunk(step_cycles1); - let step_cycles2 = rng.sample(Uniform::from(100u64..TWO_IN_TWO_OUT_CYCLES - CYCLE_BOUND)); + let step_cycles2 = rng.sample(Uniform::from(100u64..TWO_IN_TWO_OUT_CYCLES - cycle_bound)); _check_typical_secp256k1_blake160_2_in_2_out_tx_with_chunk(step_cycles2); } } @@ -876,12 +890,17 @@ fn _check_typical_secp256k1_blake160_2_in_2_out_tx_with_state(step_cycles: Cycle #[test] fn check_typical_secp256k1_blake160_2_in_2_out_tx_with_state() { + let cycle_bound = if SCRIPT_VERSION >= ScriptVersion::V2 { + V2_CYCLE_BOUND + } else { + CYCLE_BOUND + }; if SCRIPT_VERSION >= ScriptVersion::V1 { let mut rng = thread_rng(); let step_cycles1 = rng.sample(Uniform::from(1..100u64)); _check_typical_secp256k1_blake160_2_in_2_out_tx_with_state(step_cycles1); - let step_cycles2 = rng.sample(Uniform::from(100u64..TWO_IN_TWO_OUT_CYCLES - CYCLE_BOUND)); + let step_cycles2 = rng.sample(Uniform::from(100u64..TWO_IN_TWO_OUT_CYCLES - cycle_bound)); _check_typical_secp256k1_blake160_2_in_2_out_tx_with_state(step_cycles2); } } @@ -963,13 +982,18 @@ fn _check_typical_secp256k1_blake160_2_in_2_out_tx_with_snap(step_cycles: Cycle) #[test] fn check_typical_secp256k1_blake160_2_in_2_out_tx_with_snap() { + let cycle_bound = if SCRIPT_VERSION >= ScriptVersion::V2 { + V2_CYCLE_BOUND + } else { + CYCLE_BOUND + }; if SCRIPT_VERSION >= ScriptVersion::V1 { let mut rng = thread_rng(); let step_cycles1 = rng.sample(Uniform::from(1..100u64)); _check_typical_secp256k1_blake160_2_in_2_out_tx_with_snap(step_cycles1); let step_cycles2 = rng.sample(Uniform::from( - TWO_IN_TWO_OUT_CYCLES / 10..TWO_IN_TWO_OUT_CYCLES - CYCLE_BOUND, + TWO_IN_TWO_OUT_CYCLES / 10..TWO_IN_TWO_OUT_CYCLES - cycle_bound, )); _check_typical_secp256k1_blake160_2_in_2_out_tx_with_snap(step_cycles2); } @@ -1744,13 +1768,21 @@ fn exec_from_cell_data_source_out_bound() { #[test] fn exec_from_witness_place_error() { + let script_version = SCRIPT_VERSION; + let from = ExecFrom::OutOfBound(0, 1, 3, 0); - let res = Err("Place parse_from_u64".to_string()); + let res = if script_version <= ScriptVersion::V1 { + Err("Place parse_from_u64".to_string()) + } else { + Err("error code 1".to_string()) + }; test_exec(0b0000, 1, 2, 1, from, res); } #[test] fn exec_slice() { + let script_version = SCRIPT_VERSION; + let (exec_callee_cell, _exec_callee_data_hash) = load_cell_from_path("testdata/exec_configurable_callee"); let exec_callee_cell_data = exec_callee_cell.mem_cell_data.as_ref().unwrap(); @@ -1761,11 +1793,19 @@ fn exec_slice() { test_exec(0b0000, 1, 2, 1, from, res); let from = ExecFrom::OutOfSlice(length + 1); - let res = Err("error code 3".to_string()); + let res = if script_version >= ScriptVersion::V2 { + Ok(2) + } else { + Err("error code 3".to_string()) + }; test_exec(0b0000, 1, 2, 1, from, res); let from = ExecFrom::OutOfSlice(((length - 1) << 32) | 1); - let res = Err("MemWriteOnExecutablePage".to_string()); + let res = if script_version >= ScriptVersion::V2 { + Err("Malformed entity: Too small".to_string()) + } else { + Err("MemWriteOnExecutablePage".to_string()) + }; test_exec(0b0000, 1, 2, 1, from, res); let from = ExecFrom::Slice((10 << 32) | length);