Skip to content

Commit

Permalink
feat: Add syscall for loading embeds
Browse files Browse the repository at this point in the history
  • Loading branch information
xxuejie committed Mar 27, 2019
1 parent 6c91283 commit 6fe7668
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 2 deletions.
42 changes: 42 additions & 0 deletions script/src/syscalls/load_embed.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use crate::syscalls::{utils::store_data, ITEM_MISSING, LOAD_EMBED_SYSCALL_NUMBER, SUCCESS};
use ckb_vm::{CoreMachine, Error as VMError, Memory, Register, Syscalls, A0, A3, A7};

#[derive(Debug)]
pub struct LoadEmbed<'a> {
embeds: &'a [&'a Vec<u8>],
}

impl<'a> LoadEmbed<'a> {
pub fn new(embeds: &'a [&'a Vec<u8>]) -> Self {
LoadEmbed { embeds }
}
}

impl<'a, R: Register, M: Memory> Syscalls<R, M> for LoadEmbed<'a> {
fn initialize(&mut self, _machine: &mut CoreMachine<R, M>) -> Result<(), VMError> {
Ok(())
}

fn ecall(&mut self, machine: &mut CoreMachine<R, M>) -> Result<bool, VMError> {
if machine.registers()[A7].to_u64() != LOAD_EMBED_SYSCALL_NUMBER {
return Ok(false);
}
machine.add_cycles(100);

let index = machine.registers()[A3].to_usize();
let length = match self.embeds.get(index) {
Some(data) => {
store_data(machine, &data)?;
machine.registers_mut()[A0] = R::from_u8(SUCCESS);
data.len()
}
None => {
machine.registers_mut()[A0] = R::from_u8(ITEM_MISSING);
0
}
};

machine.add_cycles(length as u64 * 10);
Ok(true)
}
}
44 changes: 44 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 builder;
mod debugger;
mod load_cell;
mod load_cell_by_field;
mod load_embed;
mod load_input_by_field;
mod load_tx;
mod utils;
Expand All @@ -10,6 +11,7 @@ pub use self::builder::build_tx;
pub use self::debugger::Debugger;
pub use self::load_cell::LoadCell;
pub use self::load_cell_by_field::LoadCellByField;
pub use self::load_embed::LoadEmbed;
pub use self::load_input_by_field::LoadInputByField;
pub use self::load_tx::LoadTx;

Expand All @@ -22,6 +24,7 @@ pub const LOAD_TX_SYSCALL_NUMBER: u64 = 2049;
pub const LOAD_CELL_SYSCALL_NUMBER: u64 = 2053;
pub const LOAD_CELL_BY_FIELD_SYSCALL_NUMBER: u64 = 2054;
pub const LOAD_INPUT_BY_FIELD_SYSCALL_NUMBER: u64 = 2055;
pub const LOAD_EMBED_SYSCALL_NUMBER: u64 = 2056;
pub const DEBUG_PRINT_SYSCALL_NUMBER: u64 = 2177;

#[derive(Debug, PartialEq, Clone, Copy, Eq)]
Expand Down Expand Up @@ -919,4 +922,45 @@ mod tests {
_test_load_dep_cell_data_hash(data)?;
}
}

fn _test_load_embed(data: Vec<u8>) -> Result<(), TestCaseError> {
let mut machine = DefaultCoreMachine::<u64, SparseMemory>::default();
let size_addr = 0;
let addr = 100;

machine.registers_mut()[A0] = addr; // addr
machine.registers_mut()[A1] = size_addr; // size_addr
machine.registers_mut()[A2] = 0; // offset
machine.registers_mut()[A3] = 1; //index
machine.registers_mut()[A7] = LOAD_EMBED_SYSCALL_NUMBER; // syscall number

let empty_embed = vec![];
let embeds = vec![&empty_embed, &data];
let mut load_embed = LoadEmbed::new(&embeds);

prop_assert!(machine
.memory_mut()
.store64(size_addr as usize, data.len() as u64 + 20)
.is_ok());

prop_assert!(load_embed.ecall(&mut machine).is_ok());
prop_assert_eq!(machine.registers()[A0], u64::from(SUCCESS));

prop_assert_eq!(
machine.memory_mut().load64(size_addr as usize),
Ok(data.len() as u64)
);

for (i, addr) in (addr as usize..addr as usize + data.len() as usize).enumerate() {
prop_assert_eq!(machine.memory_mut().load8(addr), Ok(data[i]));
}
Ok(())
}

proptest! {
#[test]
fn test_load_embed(data in any_with::<Vec<u8>>(size_range(1000).lift())) {
_test_load_embed(data)?;
}
}
}
14 changes: 12 additions & 2 deletions script/src/verify.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use crate::{
cost_model::instruction_cycles,
syscalls::{build_tx, Debugger, LoadCell, LoadCellByField, LoadInputByField, LoadTx},
syscalls::{
build_tx, Debugger, LoadCell, LoadCellByField, LoadEmbed, LoadInputByField, LoadTx,
},
ScriptError,
};
use ckb_core::cell::ResolvedTransaction;
Expand All @@ -24,6 +26,7 @@ pub struct TransactionScriptsVerifier<'a> {
tx_builder: FlatBufferBuilder<'a>,
input_cells: Vec<&'a CellOutput>,
dep_cells: Vec<&'a CellOutput>,
embeds: Vec<&'a Vec<u8>>,
hash: H256,
}

Expand All @@ -47,12 +50,13 @@ impl<'a> TransactionScriptsVerifier<'a> {
.collect();
let inputs = rtx.transaction.inputs().iter().collect();
let outputs = rtx.transaction.outputs().iter().collect();
let embeds: Vec<&'a Vec<u8>> = rtx.transaction.embeds().iter().collect();

let mut binary_index: FnvHashMap<H256, &'a [u8]> = FnvHashMap::default();
for dep_cell in &dep_cells {
binary_index.insert(dep_cell.data_hash(), &dep_cell.data);
}
for embed in rtx.transaction.embeds() {
for embed in &embeds {
binary_index.insert(blake2b_256(&embed).into(), &embed);
}

Expand All @@ -67,6 +71,7 @@ impl<'a> TransactionScriptsVerifier<'a> {
outputs,
input_cells,
dep_cells,
embeds,
hash: rtx.transaction.hash().clone(),
}
}
Expand All @@ -75,6 +80,10 @@ impl<'a> TransactionScriptsVerifier<'a> {
LoadTx::new(self.tx_builder.finished_data())
}

fn build_load_embeds(&self) -> LoadEmbed {
LoadEmbed::new(&self.embeds)
}

fn build_load_cell(&self, current_cell: &'a CellOutput) -> LoadCell {
LoadCell::new(
&self.outputs,
Expand Down Expand Up @@ -128,6 +137,7 @@ impl<'a> TransactionScriptsVerifier<'a> {
machine.add_syscall_module(Box::new(self.build_load_cell(current_cell)));
machine.add_syscall_module(Box::new(self.build_load_cell_by_field(current_cell)));
machine.add_syscall_module(Box::new(self.build_load_input_by_field(current_input)));
machine.add_syscall_module(Box::new(self.build_load_embeds()));
machine.add_syscall_module(Box::new(Debugger::new(prefix)));
machine
.run(script_binary, &args)
Expand Down

0 comments on commit 6fe7668

Please sign in to comment.