diff --git a/script/src/syscalls/load_cell_data.rs b/script/src/syscalls/load_cell_data.rs index 11adfadca7..5147e44f8d 100644 --- a/script/src/syscalls/load_cell_data.rs +++ b/script/src/syscalls/load_cell_data.rs @@ -1,86 +1,73 @@ -use crate::types::Indices; +use crate::v2_types::{DataPieceId, TxData}; use crate::{ cost_model::transferred_byte_cycles, syscalls::{ - utils::store_data, Source, SourceEntry, INDEX_OUT_OF_BOUND, - LOAD_CELL_DATA_AS_CODE_SYSCALL_NUMBER, LOAD_CELL_DATA_SYSCALL_NUMBER, SLICE_OUT_OF_BOUND, - SUCCESS, + INDEX_OUT_OF_BOUND, LOAD_CELL_DATA_AS_CODE_SYSCALL_NUMBER, LOAD_CELL_DATA_SYSCALL_NUMBER, + SLICE_OUT_OF_BOUND, SUCCESS, }, }; -use ckb_traits::CellDataProvider; -use ckb_types::core::cell::{CellMeta, ResolvedTransaction}; +use ckb_traits::{CellDataProvider, ExtensionProvider, HeaderProvider}; use ckb_vm::{ memory::{Memory, FLAG_EXECUTABLE, FLAG_FREEZED}, registers::{A0, A1, A2, A3, A4, A5, A7}, + snapshot2::{DataSource, Snapshot2Context}, Error as VMError, Register, SupportMachine, Syscalls, }; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; -pub struct LoadCellData
{ - data_loader: DL, - rtx: Arc, - outputs: Arc>, - group_inputs: Indices, - group_outputs: Indices, +pub struct LoadCellData
+where + DL: CellDataProvider + HeaderProvider + ExtensionProvider + Send + Sync + Clone + 'static, +{ + snapshot2_context: Arc>>>, } -impl LoadCellData
{ +impl
LoadCellData
+where + DL: CellDataProvider + HeaderProvider + ExtensionProvider + Send + Sync + Clone + 'static, +{ pub fn new( - data_loader: DL, - rtx: Arc, - outputs: Arc>, - group_inputs: Indices, - group_outputs: Indices, + snapshot2_context: Arc>>>, ) -> LoadCellData
{ - LoadCellData { - data_loader, - rtx, - outputs, - group_inputs, - group_outputs, - } - } - - #[inline] - fn resolved_inputs(&self) -> &Vec { - &self.rtx.resolved_inputs - } - - #[inline] - fn resolved_cell_deps(&self) -> &Vec { - &self.rtx.resolved_cell_deps + LoadCellData { snapshot2_context } } - fn fetch_cell(&self, source: Source, index: usize) -> Result<&CellMeta, u8> { - match source { - Source::Transaction(SourceEntry::Input) => { - self.resolved_inputs().get(index).ok_or(INDEX_OUT_OF_BOUND) - } - Source::Transaction(SourceEntry::Output) => { - self.outputs.get(index).ok_or(INDEX_OUT_OF_BOUND) + fn load_data(&self, machine: &mut Mac) -> Result<(), VMError> { + let index = machine.registers()[A3].to_u64(); + let source = machine.registers()[A4].to_u64(); + let data_piece_id = match DataPieceId::try_from((source, index, 0)) { + Ok(id) => id, + Err(_) => { + machine.set_register(A0, Mac::REG::from_u8(INDEX_OUT_OF_BOUND)); + return Ok(()); } - Source::Transaction(SourceEntry::CellDep) => self - .resolved_cell_deps() - .get(index) - .ok_or(INDEX_OUT_OF_BOUND), - Source::Transaction(SourceEntry::HeaderDep) => Err(INDEX_OUT_OF_BOUND), - Source::Group(SourceEntry::Input) => self - .group_inputs - .get(index) - .ok_or(INDEX_OUT_OF_BOUND) - .and_then(|actual_index| { - self.resolved_inputs() - .get(*actual_index) - .ok_or(INDEX_OUT_OF_BOUND) - }), - Source::Group(SourceEntry::Output) => self - .group_outputs - .get(index) - .ok_or(INDEX_OUT_OF_BOUND) - .and_then(|actual_index| self.outputs.get(*actual_index).ok_or(INDEX_OUT_OF_BOUND)), - Source::Group(SourceEntry::CellDep) => Err(INDEX_OUT_OF_BOUND), - Source::Group(SourceEntry::HeaderDep) => Err(INDEX_OUT_OF_BOUND), - } + }; + let addr = machine.registers()[A0].to_u64(); + let size_addr = machine.registers()[A1].clone(); + let size = machine.memory_mut().load64(&size_addr)?.to_u64(); + let offset = machine.registers()[A2].to_u64(); + let mut sc = self + .snapshot2_context + .lock() + .map_err(|e| VMError::Unexpected(e.to_string()))?; + + let (wrote_size, full_size) = + match sc.store_bytes(machine, addr, &data_piece_id, offset, size) { + Ok(val) => val, + Err(VMError::External(m)) if m == "INDEX_OUT_OF_BOUND" => { + // This comes from TxData results in an out of bound error, to + // mimic current behavior, we would return INDEX_OUT_OF_BOUND error. + machine.set_register(A0, Mac::REG::from_u8(INDEX_OUT_OF_BOUND)); + return Ok(()); + } + Err(e) => return Err(e), + }; + machine + .memory_mut() + .store64(&size_addr, &Mac::REG::from_u64(full_size))?; + machine.add_cycles_no_checking(transferred_byte_cycles(wrote_size))?; + machine.set_register(A0, Mac::REG::from_u8(SUCCESS)); + Ok(()) } fn load_data_as_code(&self, machine: &mut Mac) -> Result<(), VMError> { @@ -88,75 +75,63 @@ impl LoadCellData
{ let memory_size = machine.registers()[A1].to_u64(); let content_offset = machine.registers()[A2].to_u64(); let content_size = machine.registers()[A3].to_u64(); - let index = machine.registers()[A4].to_u64(); - let source = Source::parse_from_u64(machine.registers()[A5].to_u64())?; - - let cell = self.fetch_cell(source, index as usize); - if let Err(err) = cell { - machine.set_register(A0, Mac::REG::from_u8(err)); - return Ok(()); - } - let cell = cell.unwrap(); - + let source = machine.registers()[A5].to_u64(); + let data_piece_id = match DataPieceId::try_from((source, index, 0)) { + Ok(id) => id, + Err(_) => { + machine.set_register(A0, Mac::REG::from_u8(INDEX_OUT_OF_BOUND)); + return Ok(()); + } + }; + let mut sc = self + .snapshot2_context + .lock() + .map_err(|e| VMError::Unexpected(e.to_string()))?; + // We are using 0..u64::max_value() to fetch full cell, there is + // also no need to keep the full length value. Since cell's length + // is already full length. + let (cell, _) = match sc + .data_source() + .load_data(&data_piece_id, 0, u64::max_value()) + { + Ok(val) => val, + Err(VMError::External(m)) if m == "INDEX_OUT_OF_BOUND" => { + // This comes from TxData results in an out of bound error, to + // mimic current behavior, we would return INDEX_OUT_OF_BOUND error. + machine.set_register(A0, Mac::REG::from_u8(INDEX_OUT_OF_BOUND)); + return Ok(()); + } + Err(e) => return Err(e), + }; let content_end = content_offset .checked_add(content_size) .ok_or(VMError::MemOutOfBound)?; - if content_offset >= cell.data_bytes - || content_end > cell.data_bytes + if content_offset >= cell.len() as u64 + || content_end > cell.len() as u64 || content_size > memory_size { machine.set_register(A0, Mac::REG::from_u8(SLICE_OUT_OF_BOUND)); return Ok(()); } - let data = self - .data_loader - .load_cell_data(cell) - .ok_or_else(|| { - VMError::Unexpected(format!( - "Unexpected load_cell_data failed {}", - cell.out_point, - )) - })? - .slice((content_offset as usize)..(content_end as usize)); machine.memory_mut().init_pages( addr, memory_size, FLAG_EXECUTABLE | FLAG_FREEZED, - Some(data), + Some(cell.slice((content_offset as usize)..(content_end as usize))), 0, )?; - + sc.track_pages(machine, addr, memory_size, &data_piece_id, content_offset)?; machine.add_cycles_no_checking(transferred_byte_cycles(memory_size))?; machine.set_register(A0, Mac::REG::from_u8(SUCCESS)); Ok(()) } - - fn load_data(&self, machine: &mut Mac) -> Result<(), VMError> { - let index = machine.registers()[A3].to_u64(); - let source = Source::parse_from_u64(machine.registers()[A4].to_u64())?; - - let cell = self.fetch_cell(source, index as usize); - if let Err(err) = cell { - machine.set_register(A0, Mac::REG::from_u8(err)); - return Ok(()); - } - let cell = cell.unwrap(); - let data = self.data_loader.load_cell_data(cell).ok_or_else(|| { - VMError::Unexpected(format!( - "Unexpected load_cell_data failed {}", - cell.out_point, - )) - })?; - - let wrote_size = store_data(machine, &data)?; - machine.add_cycles_no_checking(transferred_byte_cycles(wrote_size))?; - machine.set_register(A0, Mac::REG::from_u8(SUCCESS)); - Ok(()) - } } -impl Syscalls for LoadCellData
{ +impl Syscalls for LoadCellData
+where + DL: CellDataProvider + HeaderProvider + ExtensionProvider + Send + Sync + Clone + 'static, +{ fn initialize(&mut self, _machine: &mut Mac) -> Result<(), VMError> { Ok(()) } diff --git a/script/src/syscalls/tests/vm_latest/syscalls_1.rs b/script/src/syscalls/tests/vm_latest/syscalls_1.rs index 391320a556..5e67fd5346 100644 --- a/script/src/syscalls/tests/vm_latest/syscalls_1.rs +++ b/script/src/syscalls/tests/vm_latest/syscalls_1.rs @@ -14,14 +14,17 @@ use ckb_types::{ use ckb_vm::{ memory::{FLAG_DIRTY, FLAG_EXECUTABLE, FLAG_FREEZED, FLAG_WRITABLE}, registers::{A0, A1, A2, A3, A4, A5, A7}, + snapshot2::{DataSource, Snapshot2, Snapshot2Context}, CoreMachine, Error as VMError, Memory, Syscalls, RISCV_PAGESIZE, }; use proptest::{collection::size_range, prelude::*}; use std::collections::HashMap; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; use super::SCRIPT_VERSION; use crate::syscalls::{tests::utils::*, *}; +use crate::types::{ScriptGroup, ScriptGroupType}; +use crate::v2_types::TxData; fn _test_load_cell_not_exist(data: &[u8]) -> Result<(), TestCaseError> { let mut machine = SCRIPT_VERSION.init_core_machine_without_limit(); @@ -1453,17 +1456,26 @@ fn _test_load_cell_data_as_code( let output = build_cell_meta(100, data.clone()); let input_cell = build_cell_meta(100, data.clone()); - let outputs = Arc::new(vec![output]); - let group_inputs = Arc::new(vec![0]); - let group_outputs = Arc::new(vec![0]); let data_loader = new_mock_data_loader(); let rtx = Arc::new(ResolvedTransaction { - transaction: TransactionBuilder::default().build(), + transaction: TransactionBuilder::default() + .output_data(data.pack()) + .build(), resolved_cell_deps: vec![dep_cell], resolved_inputs: vec![input_cell], resolved_dep_groups: vec![], }); - let mut load_code = LoadCellData::new(data_loader, rtx, outputs, group_inputs, group_outputs); + let mut load_code = LoadCellData::new(Arc::new(Mutex::new(Snapshot2Context::new(TxData { + rtx: rtx, + data_loader: data_loader, + program: Bytes::new(), + script_group: Arc::new(ScriptGroup { + script: Default::default(), + group_type: ScriptGroupType::Lock, + input_indices: vec![0], + output_indices: vec![0], + }), + })))); prop_assert!(machine.memory_mut().store_byte(addr, addr_size, 1).is_ok()); @@ -1474,7 +1486,7 @@ fn _test_load_cell_data_as_code( } else { prop_assert_eq!(machine.registers()[A0], u64::from(SUCCESS)); - let flags = FLAG_EXECUTABLE | FLAG_FREEZED | FLAG_DIRTY; + let flags = FLAG_EXECUTABLE | FLAG_FREEZED; prop_assert_eq!( machine .memory_mut() @@ -1517,19 +1529,27 @@ fn _test_load_cell_data( let dep_cell = build_cell_meta(10000, data.clone()); let output = build_cell_meta(100, data.clone()); let input_cell = build_cell_meta(100, data.clone()); - - let outputs = Arc::new(vec![output]); - let group_inputs = Arc::new(vec![0]); - let group_outputs = Arc::new(vec![0]); let data_loader = new_mock_data_loader(); let rtx = Arc::new(ResolvedTransaction { - transaction: TransactionBuilder::default().build(), + transaction: TransactionBuilder::default() + .output_data(data.pack()) + .build(), resolved_cell_deps: vec![dep_cell], resolved_inputs: vec![input_cell], resolved_dep_groups: vec![], }); - let mut load_code = LoadCellData::new(data_loader, rtx, outputs, group_inputs, group_outputs); + let mut load_code = LoadCellData::new(Arc::new(Mutex::new(Snapshot2Context::new(TxData { + rtx: rtx, + data_loader: data_loader, + program: Bytes::new(), + script_group: Arc::new(ScriptGroup { + script: Default::default(), + group_type: ScriptGroupType::Lock, + input_indices: vec![0], + output_indices: vec![0], + }), + })))); prop_assert!(load_code.ecall(&mut machine).is_ok()); @@ -1537,8 +1557,11 @@ fn _test_load_cell_data( prop_assert_eq!(machine.registers()[A0], u64::from(code)); } else { prop_assert_eq!(machine.registers()[A0], u64::from(SUCCESS)); - - let flags = FLAG_WRITABLE | FLAG_DIRTY; + let flags = if data.len() < RISCV_PAGESIZE { + FLAG_WRITABLE | FLAG_DIRTY + } else { + FLAG_WRITABLE + }; prop_assert_eq!( machine .memory_mut() @@ -1618,9 +1641,6 @@ fn test_load_overflowed_cell_data_as_code() { let dep_cell = build_cell_meta(10000, dep_cell_data); let data_loader = new_mock_data_loader(); - let outputs = Arc::new(vec![]); - let group_inputs = Arc::new(vec![]); - let group_outputs = Arc::new(vec![]); let rtx = Arc::new(ResolvedTransaction { transaction: TransactionBuilder::default().build(), @@ -1629,7 +1649,17 @@ fn test_load_overflowed_cell_data_as_code() { resolved_dep_groups: vec![], }); - let mut load_code = LoadCellData::new(data_loader, rtx, outputs, group_inputs, group_outputs); + let mut load_code = LoadCellData::new(Arc::new(Mutex::new(Snapshot2Context::new(TxData { + rtx: rtx, + data_loader: data_loader, + program: Bytes::new(), + script_group: Arc::new(ScriptGroup { + script: Default::default(), + group_type: ScriptGroupType::Lock, + input_indices: Default::default(), + output_indices: Default::default(), + }), + })))); assert!(machine.memory_mut().store_byte(addr, addr_size, 1).is_ok()); @@ -1637,7 +1667,61 @@ fn test_load_overflowed_cell_data_as_code() { assert_eq!(result.unwrap_err(), VMError::MemOutOfBound); } -fn _test_load_cell_data_on_freezed_memory(as_code: bool, data: &[u8]) -> Result<(), TestCaseError> { +fn _test_load_cell_data_on_freezed_memory(data: &[u8]) -> Result<(), TestCaseError> { + let mut machine = SCRIPT_VERSION.init_core_machine_without_limit(); + let addr = 8192; + let addr_size = 4096; + let size_addr = 100; + + prop_assert!(machine + .memory_mut() + .store64(&size_addr, &(data.len() as u64)) + .is_ok()); + prop_assert!(machine + .memory_mut() + .init_pages(addr, addr_size, FLAG_EXECUTABLE | FLAG_FREEZED, None, 0) + .is_ok()); + + machine.set_register(A0, addr); // addr + machine.set_register(A1, size_addr); // size + machine.set_register(A2, 0); // content offset + machine.set_register(A3, 0); //index + machine.set_register(A4, u64::from(Source::Transaction(SourceEntry::CellDep))); //source + machine.set_register(A7, LOAD_CELL_DATA_SYSCALL_NUMBER); // syscall number + + let dep_cell_data = Bytes::from(data.to_owned()); + let dep_cell = build_cell_meta(10000, dep_cell_data); + + let data_loader = new_mock_data_loader(); + + let rtx = Arc::new(ResolvedTransaction { + transaction: TransactionBuilder::default().build(), + resolved_cell_deps: vec![dep_cell], + resolved_inputs: vec![], + resolved_dep_groups: vec![], + }); + + let mut load_code = LoadCellData::new(Arc::new(Mutex::new(Snapshot2Context::new(TxData { + rtx: rtx, + data_loader: data_loader, + program: Bytes::new(), + script_group: Arc::new(ScriptGroup { + script: Default::default(), + group_type: ScriptGroupType::Lock, + input_indices: Default::default(), + output_indices: Default::default(), + }), + })))); + + prop_assert!(load_code.ecall(&mut machine).is_err()); + + for i in addr..addr + addr_size { + assert_eq!(machine.memory_mut().load8(&i), Ok(0)); + } + Ok(()) +} + +fn _test_load_cell_data_as_code_on_freezed_memory(data: &[u8]) -> Result<(), TestCaseError> { let mut machine = SCRIPT_VERSION.init_core_machine_without_limit(); let addr = 8192; let addr_size = 4096; @@ -1653,20 +1737,12 @@ fn _test_load_cell_data_on_freezed_memory(as_code: bool, data: &[u8]) -> Result< machine.set_register(A3, data.len() as u64); // content size machine.set_register(A4, 0); //index machine.set_register(A5, u64::from(Source::Transaction(SourceEntry::CellDep))); //source - let syscall = if as_code { - LOAD_CELL_DATA_AS_CODE_SYSCALL_NUMBER - } else { - LOAD_CELL_DATA_SYSCALL_NUMBER - }; - machine.set_register(A7, syscall); // syscall number + machine.set_register(A7, LOAD_CELL_DATA_AS_CODE_SYSCALL_NUMBER); // syscall number let dep_cell_data = Bytes::from(data.to_owned()); let dep_cell = build_cell_meta(10000, dep_cell_data); let data_loader = new_mock_data_loader(); - let outputs = Arc::new(vec![]); - let group_inputs = Arc::new(vec![]); - let group_outputs = Arc::new(vec![]); let rtx = Arc::new(ResolvedTransaction { transaction: TransactionBuilder::default().build(), @@ -1675,7 +1751,17 @@ fn _test_load_cell_data_on_freezed_memory(as_code: bool, data: &[u8]) -> Result< resolved_dep_groups: vec![], }); - let mut load_code = LoadCellData::new(data_loader, rtx, outputs, group_inputs, group_outputs); + let mut load_code = LoadCellData::new(Arc::new(Mutex::new(Snapshot2Context::new(TxData { + rtx: rtx, + data_loader: data_loader, + program: Bytes::new(), + script_group: Arc::new(ScriptGroup { + script: Default::default(), + group_type: ScriptGroupType::Lock, + input_indices: Default::default(), + output_indices: Default::default(), + }), + })))); prop_assert!(load_code.ecall(&mut machine).is_err()); @@ -1691,12 +1777,12 @@ proptest! { })] #[test] fn test_load_code_on_freezed_memory(ref data in any_with::>(size_range(4096).lift())) { - _test_load_cell_data_on_freezed_memory(true, data)?; + _test_load_cell_data_as_code_on_freezed_memory(data)?; } #[test] fn test_load_data_on_freezed_memory(ref data in any_with::>(size_range(4096).lift())) { - _test_load_cell_data_on_freezed_memory(false, data)?; + _test_load_cell_data_on_freezed_memory(data)?; } } @@ -1718,9 +1804,6 @@ fn test_load_code_unaligned_error() { let dep_cell = build_cell_meta(10000, dep_cell_data); let data_loader = new_mock_data_loader(); - let outputs = Arc::new(vec![]); - let group_inputs = Arc::new(vec![]); - let group_outputs = Arc::new(vec![]); let rtx = Arc::new(ResolvedTransaction { transaction: TransactionBuilder::default().build(), @@ -1729,7 +1812,17 @@ fn test_load_code_unaligned_error() { resolved_dep_groups: vec![], }); - let mut load_code = LoadCellData::new(data_loader, rtx, outputs, group_inputs, group_outputs); + let mut load_code = LoadCellData::new(Arc::new(Mutex::new(Snapshot2Context::new(TxData { + rtx: rtx, + data_loader: data_loader, + program: Bytes::new(), + script_group: Arc::new(ScriptGroup { + script: Default::default(), + group_type: ScriptGroupType::Lock, + input_indices: Default::default(), + output_indices: Default::default(), + }), + })))); assert!(machine.memory_mut().store_byte(addr, addr_size, 1).is_ok()); @@ -1759,9 +1852,6 @@ fn test_load_code_slice_out_of_bound_error() { let dep_cell = build_cell_meta(10000, dep_cell_data); let data_loader = new_mock_data_loader(); - let outputs = Arc::new(vec![]); - let group_inputs = Arc::new(vec![]); - let group_outputs = Arc::new(vec![]); let rtx = Arc::new(ResolvedTransaction { transaction: TransactionBuilder::default().build(), @@ -1770,7 +1860,17 @@ fn test_load_code_slice_out_of_bound_error() { resolved_dep_groups: vec![], }); - let mut load_code = LoadCellData::new(data_loader, rtx, outputs, group_inputs, group_outputs); + let mut load_code = LoadCellData::new(Arc::new(Mutex::new(Snapshot2Context::new(TxData { + rtx: rtx, + data_loader: data_loader, + program: Bytes::new(), + script_group: Arc::new(ScriptGroup { + script: Default::default(), + group_type: ScriptGroupType::Lock, + input_indices: Default::default(), + output_indices: Default::default(), + }), + })))); assert!(machine.memory_mut().store_byte(addr, addr_size, 1).is_ok()); @@ -1803,9 +1903,6 @@ fn test_load_code_not_enough_space_error() { let dep_cell = build_cell_meta(10000, dep_cell_data); let data_loader = new_mock_data_loader(); - let outputs = Arc::new(vec![]); - let group_inputs = Arc::new(vec![]); - let group_outputs = Arc::new(vec![]); let rtx = Arc::new(ResolvedTransaction { transaction: TransactionBuilder::default().build(), @@ -1814,7 +1911,17 @@ fn test_load_code_not_enough_space_error() { resolved_dep_groups: vec![], }); - let mut load_code = LoadCellData::new(data_loader, rtx, outputs, group_inputs, group_outputs); + let mut load_code = LoadCellData::new(Arc::new(Mutex::new(Snapshot2Context::new(TxData { + rtx: rtx, + data_loader: data_loader, + program: Bytes::new(), + script_group: Arc::new(ScriptGroup { + script: Default::default(), + group_type: ScriptGroupType::Lock, + input_indices: Default::default(), + output_indices: Default::default(), + }), + })))); assert!(machine.memory_mut().store_byte(addr, addr_size, 1).is_ok()); diff --git a/script/src/v2_syscalls.rs b/script/src/v2_syscalls.rs index 087ac72e50..7ca9a0425c 100644 --- a/script/src/v2_syscalls.rs +++ b/script/src/v2_syscalls.rs @@ -53,127 +53,6 @@ where *self.base_cycles.lock().expect("lock") = base_cycles; } - // Reimplementation of load_cell_data but keep tracks of pages that are copied from - // surrounding transaction data. Those pages do not need to be added to snapshots. - fn load_cell_data(&mut self, machine: &mut Mac) -> Result<(), Error> { - let index = machine.registers()[A3].to_u64(); - let source = machine.registers()[A4].to_u64(); - - let data_piece_id = match DataPieceId::try_from((source, index, 0)) { - Ok(id) => id, - Err(e) => { - // Current implementation would throw an error immediately - // for some source values, but return INDEX_OUT_OF_BOUND error - // for other values. Here for simplicity, we would return - // INDEX_OUT_OF_BOUND error in all cases. But the code might - // differ to mimic current on-chain behavior - println!("DataPieceId parsing error: {:?}", e); - machine.set_register(A0, Mac::REG::from_u8(INDEX_OUT_OF_BOUND)); - return Ok(()); - } - }; - - let addr = machine.registers()[A0].to_u64(); - let size_addr = machine.registers()[A1].clone(); - let size = machine.memory_mut().load64(&size_addr)?.to_u64(); - let offset = machine.registers()[A2].to_u64(); - - let mut sc = self.snapshot2_context().lock().expect("lock"); - let (wrote_size, full_size) = - match sc.store_bytes(machine, addr, &data_piece_id, offset, size) { - Ok(val) => val, - Err(Error::External(m)) if m == "INDEX_OUT_OF_BOUND" => { - // This comes from TxData results in an out of bound error, to - // mimic current behavior, we would return INDEX_OUT_OF_BOUND error. - machine.set_register(A0, Mac::REG::from_u8(INDEX_OUT_OF_BOUND)); - return Ok(()); - } - Err(e) => return Err(e), - }; - - machine - .memory_mut() - .store64(&size_addr, &Mac::REG::from_u64(full_size))?; - machine.add_cycles_no_checking(transferred_byte_cycles(wrote_size))?; - machine.set_register(A0, Mac::REG::from_u8(SUCCESS)); - Ok(()) - } - - // Reimplementation of load_cell_data_as_code but keep tracks of pages that are copied from - // surrounding transaction data. Those pages do not need to be added to snapshots. - // - // Different from load_cell_data, this method showcases advanced usage of Snapshot2, where - // one manually does the actual memory copying, then calls track_pages method to setup metadata - // used by Snapshot2. It does not rely on higher level methods provided by Snapshot2. - fn load_cell_data_as_code( - &mut self, - machine: &mut Mac, - ) -> Result<(), Error> { - let addr = machine.registers()[A0].to_u64(); - let memory_size = machine.registers()[A1].to_u64(); - let content_offset = machine.registers()[A2].to_u64(); - let content_size = machine.registers()[A3].to_u64(); - - let index = machine.registers()[A4].to_u64(); - let source = machine.registers()[A5].to_u64(); - - let data_piece_id = match DataPieceId::try_from((source, index, 0)) { - Ok(id) => id, - Err(e) => { - // Current implementation would throw an error immediately - // for some source values, but return INDEX_OUT_OF_BOUND error - // for other values. Here for simplicity, we would return - // INDEX_OUT_OF_BOUND error in all cases. But the code might - // differ to mimic current on-chain behavior - println!("DataPieceId parsing error: {:?}", e); - machine.set_register(A0, Mac::REG::from_u8(INDEX_OUT_OF_BOUND)); - return Ok(()); - } - }; - - let mut sc = self.snapshot2_context().lock().expect("lock"); - // We are using 0..u64::max_value() to fetch full cell, there is - // also no need to keep the full length value. Since cell's length - // is already full length. - let (cell, _) = match sc - .data_source() - .load_data(&data_piece_id, 0, u64::max_value()) - { - Ok(val) => val, - Err(Error::External(m)) if m == "INDEX_OUT_OF_BOUND" => { - // This comes from TxData results in an out of bound error, to - // mimic current behavior, we would return INDEX_OUT_OF_BOUND error. - machine.set_register(A0, Mac::REG::from_u8(INDEX_OUT_OF_BOUND)); - return Ok(()); - } - Err(e) => return Err(e), - }; - - let content_end = content_offset - .checked_add(content_size) - .ok_or(Error::MemOutOfBound)?; - if content_offset >= cell.len() as u64 - || content_end > cell.len() as u64 - || content_size > memory_size - { - machine.set_register(A0, Mac::REG::from_u8(SLICE_OUT_OF_BOUND)); - return Ok(()); - } - - machine.memory_mut().init_pages( - addr, - memory_size, - FLAG_EXECUTABLE | FLAG_FREEZED, - Some(cell.slice((content_offset as usize)..(content_end as usize))), - 0, - )?; - sc.track_pages(machine, addr, memory_size, &data_piece_id, content_offset)?; - - machine.add_cycles_no_checking(transferred_byte_cycles(memory_size))?; - machine.set_register(A0, Mac::REG::from_u8(SUCCESS)); - Ok(()) - } - // Reimplementing debug syscall for printing debug messages fn debug(&mut self, machine: &mut Mac) -> Result<(), Error> { let mut addr = machine.registers()[A0].to_u64(); @@ -211,8 +90,6 @@ where fn ecall(&mut self, machine: &mut Mac) -> Result { let code = machine.registers()[A7].to_u64(); match code { - 2091 => self.load_cell_data_as_code(machine), - 2092 => self.load_cell_data(machine), 2177 => self.debug(machine), _ => return Ok(false), }?; diff --git a/script/src/verify.rs b/script/src/verify.rs index 5f014cd617..7341316fa5 100644 --- a/script/src/verify.rs +++ b/script/src/verify.rs @@ -202,18 +202,8 @@ where } /// Build syscall: load_cell_data - pub fn build_load_cell_data( - &self, - group_inputs: Indices, - group_outputs: Indices, - ) -> LoadCellData
{ - LoadCellData::new( - self.data_loader.clone(), - Arc::clone(&self.rtx), - Arc::clone(&self.outputs), - group_inputs, - group_outputs, - ) + pub fn build_load_cell_data(&self) -> LoadCellData
{ + LoadCellData::new(self.snapshot2_context.clone()) } ///Build syscall: load_input @@ -321,10 +311,7 @@ where Arc::clone(&script_group_output_indices), )), Box::new(self.build_load_script(script_group.script.clone())), - Box::new(self.build_load_cell_data( - Arc::clone(&script_group_input_indices), - Arc::clone(&script_group_output_indices), - )), + Box::new(self.build_load_cell_data()), Box::new(Debugger::new( current_script_hash, Arc::clone(&self.debug_printer),