Skip to content

Commit

Permalink
Add exec v2
Browse files Browse the repository at this point in the history
  • Loading branch information
mohanson committed Jan 17, 2025
1 parent a7306cd commit 8e0553f
Show file tree
Hide file tree
Showing 9 changed files with 218 additions and 46 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion script/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ 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 = { path = "/home/ubuntu/src/ckb-vm", default-features = false }
ckb-vm = { git = "https://github.com/libraries/ckb-vm", branch="args_reader", 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"] }
Expand Down
76 changes: 54 additions & 22 deletions script/src/scheduler.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
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;
Expand Down Expand Up @@ -339,6 +339,29 @@ where
let messages: Vec<Message> = self.message_box.lock().expect("lock").drain(..).collect();
for message in messages {
match message {
Message::ExecV2(vm_id, args) => {
let (_, 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(EXEC_LOAD_ELF_V2_CYCLES_BASE)?;
let old_cycles = old_machine.machine.cycles();
let max_cycles = old_machine.machine.max_cycles();
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.data_piece_id,
args.offset,
args.length,
Some((vm_id, args.argc, args.argv)),
)?;
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)) {
Expand Down Expand Up @@ -760,26 +783,7 @@ where
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::<u64>(&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())?
}
};
sc.mark_program(&mut machine.machine, &metadata, data_piece_id, offset)?;
machine
.machine
.add_cycles_no_checking(transferred_byte_cycles(bytes))?;
}
self.load_vm_program(&context, &mut machine, data_piece_id, offset, length, 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
Expand All @@ -796,6 +800,34 @@ where
Ok(id)
}

// Load the program into an empty vm.
fn load_vm_program(
&mut self,
context: &MachineContext<DL>,
machine: &mut Machine,
data_piece_id: &DataPieceId,
offset: u64,
length: u64,
args: Option<(u64, u64, u64)>,
) -> Result<u64, Error> {
let mut sc = context.snapshot2_context().lock().expect("lock");
let (program, _) = sc.load_data(data_piece_id, offset, length)?;
let metadata = parse_elf::<u64>(&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())?,
};
sc.mark_program(&mut machine.machine, &metadata, data_piece_id, 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<DL>, Machine), Error> {
// The code here looks slightly weird, since I don't want to copy over all syscall
Expand Down
4 changes: 0 additions & 4 deletions script/src/syscalls/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ pub struct Exec<DL> {
outputs: Arc<Vec<CellMeta>>,
group_inputs: Indices,
group_outputs: Indices,
load_elf_base_fee: u64,
}

impl<DL: CellDataProvider> Exec<DL> {
Expand All @@ -36,15 +35,13 @@ impl<DL: CellDataProvider> Exec<DL> {
outputs: Arc<Vec<CellMeta>>,
group_inputs: Indices,
group_outputs: Indices,
load_elf_base_fee: u64,
) -> Exec<DL> {
Exec {
data_loader,
rtx,
outputs,
group_inputs,
group_outputs,
load_elf_base_fee,
}
}

Expand Down Expand Up @@ -192,7 +189,6 @@ impl<Mac: SupportMachine, DL: CellDataProvider + Send + Sync> Syscalls<Mac> 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))?;
Expand Down
124 changes: 124 additions & 0 deletions script/src/syscalls/exec_v2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
use crate::syscalls::{
Place, Source, EXEC, INDEX_OUT_OF_BOUND, SLICE_OUT_OF_BOUND, SOURCE_ENTRY_MASK,
SOURCE_GROUP_FLAG,
};
use crate::types::{DataPieceId, ExecV2Args, Message, TxData, VmId};
use ckb_traits::{CellDataProvider, ExtensionProvider, HeaderProvider};
use ckb_vm::{
registers::{A0, A1, A2, A3, A4, A5, A7},
snapshot2::Snapshot2Context,
Error as VMError, Register, SupportMachine, Syscalls,
};
use std::sync::{Arc, Mutex};

pub struct ExecV2<DL>
where
DL: CellDataProvider + HeaderProvider + ExtensionProvider + Send + Sync + Clone + 'static,
{
id: VmId,
message_box: Arc<Mutex<Vec<Message>>>,
snapshot2_context: Arc<Mutex<Snapshot2Context<DataPieceId, TxData<DL>>>>,
}

impl<DL> ExecV2<DL>
where
DL: CellDataProvider + HeaderProvider + ExtensionProvider + Send + Sync + Clone + 'static,
{
pub fn new(
id: VmId,
message_box: Arc<Mutex<Vec<Message>>>,
snapshot2_context: Arc<Mutex<Snapshot2Context<DataPieceId, TxData<DL>>>>,
) -> ExecV2<DL> {
ExecV2 {
id,
message_box,
snapshot2_context,
}
}
}

impl<Mac, DL> Syscalls<Mac> for ExecV2<DL>
where
Mac: SupportMachine,
DL: CellDataProvider + HeaderProvider + ExtensionProvider + Send + Sync + Clone + 'static,
{
fn initialize(&mut self, _machine: &mut Mac) -> Result<(), VMError> {
Ok(())
}

fn ecall(&mut self, machine: &mut Mac) -> Result<bool, VMError> {
if machine.registers()[A7].to_u64() != EXEC {
return Ok(false);
}
let index = machine.registers()[A0].to_u64();
let mut source = machine.registers()[A1].to_u64();
let place = machine.registers()[A2].to_u64();
// To keep compatible with the old behavior. When Source is wrong, a
// Vm internal error should be returned.
if let Source::Group(_) = Source::parse_from_u64(source)? {
source = source & SOURCE_ENTRY_MASK | SOURCE_GROUP_FLAG;
} else {
source &= SOURCE_ENTRY_MASK;
}
// To keep compatible with the old behavior.
Place::parse_from_u64(place)?;

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;

// We are fetching the actual cell here for some in-place validation
let mut sc = self
.snapshot2_context
.lock()
.map_err(|e| VMError::Unexpected(e.to_string()))?;
let (_, full_length) = match sc.load_data(&data_piece_id, 0, 0) {
Ok(val) => val,
Err(VMError::SnapshotDataLoadError) => {
// 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(true);
}
Err(e) => return Err(e),
};
if offset >= full_length {
machine.set_register(A0, Mac::REG::from_u8(SLICE_OUT_OF_BOUND));
return Ok(true);
}
if length > 0 {
let end = offset.checked_add(length).ok_or(VMError::MemOutOfBound(
offset,
ckb_vm::error::OutOfBoundKind::Memory,
))?;
if end > full_length {
machine.set_register(A0, Mac::REG::from_u8(SLICE_OUT_OF_BOUND));
return Ok(true);
}
}

let argc = machine.registers()[A4].clone();
let argv = machine.registers()[A5].clone();
self.message_box
.lock()
.map_err(|e| VMError::Unexpected(e.to_string()))?
.push(Message::ExecV2(
self.id,
ExecV2Args {
data_piece_id,
offset,
length,
argc: argc.to_u64(),
argv: argv.to_u64(),
},
));
Err(VMError::Yield)
}
}
2 changes: 2 additions & 0 deletions script/src/syscalls/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
10 changes: 10 additions & 0 deletions script/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,15 @@ pub enum VmState {
WaitForRead(ReadState),
}

#[derive(Clone, Debug)]
pub struct ExecV2Args {
pub data_piece_id: DataPieceId,
pub offset: u64,
pub length: u64,
pub argc: u64,
pub argv: u64,
}

#[derive(Clone, Debug)]
pub struct SpawnArgs {
pub data_piece_id: DataPieceId,
Expand Down Expand Up @@ -383,6 +392,7 @@ pub struct FdArgs {

#[derive(Clone, Debug)]
pub enum Message {
ExecV2(VmId, ExecV2Args),
Spawn(VmId, SpawnArgs),
Wait(VmId, WaitArgs),
Pipe(VmId, PipeArgs),
Expand Down
36 changes: 18 additions & 18 deletions script/src/verify.rs
Original file line number Diff line number Diff line change
@@ -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,
},
Expand Down Expand Up @@ -172,22 +172,23 @@ where
}

/// Build syscall: exec
pub fn build_exec(
&self,
group_inputs: Indices,
group_outputs: Indices,
load_elf_base_fee: u64,
) -> Exec<DL> {
pub fn build_exec(&self, group_inputs: Indices, group_outputs: Indices) -> Exec<DL> {
Exec::new(
self.data_loader.clone(),
Arc::clone(&self.rtx),
Arc::clone(&self.outputs),
group_inputs,
group_outputs,
load_elf_base_fee,
)
}

pub fn build_exec_v2(
&self,
snapshot2_context: Arc<Mutex<Snapshot2Context<DataPieceId, TxData<DL>>>>,
) -> ExecV2<DL> {
ExecV2::new(self.vm_id, Arc::clone(&self.message_box), snapshot2_context)
}

/// Build syscall: load_tx
pub fn build_load_tx(&self) -> LoadTx {
LoadTx::new(Arc::clone(&self.rtx))
Expand Down Expand Up @@ -326,15 +327,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(Arc::clone(&snapshot2_context)))
} else {
Box::new(self.build_exec(
Arc::clone(&script_group_input_indices),
Arc::clone(&script_group_output_indices),
))
},
Box::new(self.build_current_cycles()),
]);
}
Expand Down
Loading

0 comments on commit 8e0553f

Please sign in to comment.