Skip to content

Commit

Permalink
Merge pull request #3908 from mohanson/script_version_2
Browse files Browse the repository at this point in the history
script: Add script version 2
  • Loading branch information
zhangsoledad authored Mar 29, 2023
2 parents f56e66c + 0a4ee69 commit 898b4e5
Show file tree
Hide file tree
Showing 74 changed files with 1,743 additions and 219 deletions.
8 changes: 4 additions & 4 deletions Cargo.lock

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

3 changes: 2 additions & 1 deletion rpc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6581,11 +6581,12 @@ Allowed kinds: “data”, “type” and “data1”.

Refer to the section [Code Locating](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0022-transaction-structure/0022-transaction-structure.md#code-locating) and [Upgradable Script](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0022-transaction-structure/0022-transaction-structure.md#upgradable-script) in the RFC *CKB Transaction Structure*.

`ScriptHashType` is equivalent to `"data" | "type" | "data1"`.
`ScriptHashType` is equivalent to `"data" | "type" | "data1" | "data2"`.

* Type “data” matches script code via cell data hash, and run the script code in v0 CKB VM.
* Type “type” matches script code via cell type script hash.
* Type “data1” matches script code via cell data hash, and run the script code in v1 CKB VM.
* Type “data2” matches script code via cell data hash, and run the script code in v2 CKB VM.


### Type `SerializedBlock`
Expand Down
2 changes: 1 addition & 1 deletion script/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ ckb-traits = { path = "../traits", version = "= 0.109.0-pre" }
byteorder = "1.3.1"
ckb-types = { path = "../util/types", version = "= 0.109.0-pre" }
ckb-hash = { path = "../util/hash", version = "= 0.109.0-pre" }
ckb-vm = { version = "=0.23.2", default-features = false }
ckb-vm = { version = "=0.24.0-beta", default-features = false }
faster-hex = "0.6"
ckb-logger = { path = "../util/logger", version = "= 0.109.0-pre", optional = true }
serde = { version = "1.0", features = ["derive"] }
Expand Down
54 changes: 0 additions & 54 deletions script/src/cost_model.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
//! CKB VM cost model.
//!
//! The cost model assign cycles to instructions.
use ckb_vm::{
instructions::{extract_opcode, insts},
Instruction,
};

/// How many bytes can transfer when VM costs one cycle.
// 0.25 cycles per byte
Expand All @@ -15,53 +11,3 @@ pub fn transferred_byte_cycles(bytes: u64) -> u64 {
// Compiler will optimize the divisin here to shifts.
(bytes + BYTES_PER_CYCLE - 1) / BYTES_PER_CYCLE
}

/// Returns the spent cycles to execute the secific instruction.
pub fn instruction_cycles(i: Instruction) -> u64 {
match extract_opcode(i) {
// IMC
insts::OP_JALR => 3,
insts::OP_LD => 2,
insts::OP_LW => 3,
insts::OP_LH => 3,
insts::OP_LB => 3,
insts::OP_LWU => 3,
insts::OP_LHU => 3,
insts::OP_LBU => 3,
insts::OP_SB => 3,
insts::OP_SH => 3,
insts::OP_SW => 3,
insts::OP_SD => 2,
insts::OP_BEQ => 3,
insts::OP_BGE => 3,
insts::OP_BGEU => 3,
insts::OP_BLT => 3,
insts::OP_BLTU => 3,
insts::OP_BNE => 3,
insts::OP_EBREAK => 500,
insts::OP_ECALL => 500,
insts::OP_JAL => 3,
insts::OP_MUL => 5,
insts::OP_MULW => 5,
insts::OP_MULH => 5,
insts::OP_MULHU => 5,
insts::OP_MULHSU => 5,
insts::OP_DIV => 32,
insts::OP_DIVW => 32,
insts::OP_DIVU => 32,
insts::OP_DIVUW => 32,
insts::OP_REM => 32,
insts::OP_REMW => 32,
insts::OP_REMU => 32,
insts::OP_REMUW => 32,
// MOP
insts::OP_WIDE_MUL => 5,
insts::OP_WIDE_MULU => 5,
insts::OP_WIDE_MULSU => 5,
insts::OP_WIDE_DIV => 32,
insts::OP_WIDE_DIVU => 32,
insts::OP_FAR_JUMP_REL => 3,
insts::OP_FAR_JUMP_ABS => 3,
_ => 1,
}
}
2 changes: 1 addition & 1 deletion script/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ impl ScriptError {
/// Creates a script error originated the script and its exit code.
pub fn validation_failure(script: &Script, exit_code: i8) -> ScriptError {
let url_path = match ScriptHashType::try_from(script.hash_type()).expect("checked data") {
ScriptHashType::Data | ScriptHashType::Data1 => {
ScriptHashType::Data | ScriptHashType::Data1 | ScriptHashType::Data2 => {
format!("by-data-hash/{:x}", script.code_hash())
}
ScriptHashType::Type => {
Expand Down
2 changes: 1 addition & 1 deletion script/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ pub use crate::types::{
CoreMachine, ScriptGroup, ScriptGroupType, ScriptVersion, TransactionSnapshot,
TransactionState, VerifyResult, VmIsa, VmVersion,
};
pub use crate::verify::TransactionScriptsVerifier;
pub use crate::verify::{TransactionScriptsSyscallsGenerator, TransactionScriptsVerifier};
pub use crate::verify_env::TxVerifyEnv;
2 changes: 1 addition & 1 deletion script/src/syscalls/current_cycles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use ckb_vm::{
Error as VMError, Register, SupportMachine, Syscalls,
};

#[derive(Debug)]
#[derive(Debug, Default)]
pub struct CurrentCycles {}

impl CurrentCycles {
Expand Down
22 changes: 2 additions & 20 deletions script/src/syscalls/exec.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
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, SLICE_OUT_OF_BOUND, WRONG_FORMAT,
};
Expand All @@ -9,7 +10,7 @@ use ckb_types::packed::{Bytes as PackedBytes, BytesVec};
use ckb_vm::Memory;
use ckb_vm::{
registers::{A0, A1, A2, A3, A4, A5, A7},
Bytes, Error as VMError, Register, SupportMachine, Syscalls,
Error as VMError, Register, SupportMachine, Syscalls,
};
use ckb_vm::{DEFAULT_STACK_SIZE, RISCV_MAX_MEMORY};
use std::sync::Arc;
Expand Down Expand Up @@ -99,25 +100,6 @@ impl<DL: CellDataProvider> Exec<DL> {
}
}

fn load_c_string<Mac: SupportMachine>(machine: &mut Mac, addr: u64) -> Result<Bytes, VMError> {
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))
}

impl<Mac: SupportMachine, DL: CellDataProvider + Send + Sync> Syscalls<Mac> for Exec<DL> {
fn initialize(&mut self, _machine: &mut Mac) -> Result<(), VMError> {
Ok(())
Expand Down
30 changes: 30 additions & 0 deletions script/src/syscalls/get_memory_limit.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use crate::syscalls::GET_MEMORY_LIMIT;
use ckb_vm::{
registers::{A0, A7},
Error as VMError, Register, SupportMachine, Syscalls,
};

#[derive(Debug)]
pub struct GetMemoryLimit {
memory_limit: u64,
}

impl GetMemoryLimit {
pub fn new(memory_limit: u64) -> Self {
Self { memory_limit }
}
}

impl<Mac: SupportMachine> Syscalls<Mac> for GetMemoryLimit {
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() != GET_MEMORY_LIMIT {
return Ok(false);
}
machine.set_register(A0, Mac::REG::from_u64(self.memory_limit));
Ok(true)
}
}
17 changes: 17 additions & 0 deletions script/src/syscalls/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
mod current_cycles;
mod debugger;
mod exec;
mod get_memory_limit;
mod load_cell;
mod load_cell_data;
mod load_header;
Expand All @@ -9,6 +10,8 @@ mod load_script;
mod load_script_hash;
mod load_tx;
mod load_witness;
mod set_content;
mod spawn;
mod utils;
mod vm_version;

Expand All @@ -21,6 +24,7 @@ mod tests;
pub use self::current_cycles::CurrentCycles;
pub use self::debugger::Debugger;
pub use self::exec::Exec;
pub use self::get_memory_limit::GetMemoryLimit;
pub use self::load_cell::LoadCell;
pub use self::load_cell_data::LoadCellData;
pub use self::load_header::LoadHeader;
Expand All @@ -29,6 +33,8 @@ pub use self::load_script::LoadScript;
pub use self::load_script_hash::LoadScriptHash;
pub use self::load_tx::LoadTx;
pub use self::load_witness::LoadWitness;
pub use self::set_content::SetContent;
pub use self::spawn::Spawn;
pub use self::vm_version::VMVersion;

#[cfg(test)]
Expand All @@ -45,6 +51,9 @@ pub const INDEX_OUT_OF_BOUND: u8 = 1;
pub const ITEM_MISSING: u8 = 2;
pub const SLICE_OUT_OF_BOUND: u8 = 3;
pub const WRONG_FORMAT: u8 = 4;
pub const SPAWN_EXCEEDED_MAX_CONTENT_LENGTH: u8 = 5;
pub const SPAWN_WRONG_MEMORY_LIMIT: u8 = 6;
pub const SPAWN_EXCEEDED_MAX_PEAK_MEMORY: u8 = 7;

pub const VM_VERSION: u64 = 2041;
pub const CURRENT_CYCLES: u64 = 2042;
Expand All @@ -62,10 +71,18 @@ pub const LOAD_HEADER_BY_FIELD_SYSCALL_NUMBER: u64 = 2082;
pub const LOAD_INPUT_BY_FIELD_SYSCALL_NUMBER: u64 = 2083;
pub const LOAD_CELL_DATA_AS_CODE_SYSCALL_NUMBER: u64 = 2091;
pub const LOAD_CELL_DATA_SYSCALL_NUMBER: u64 = 2092;
pub const SPAWN: u64 = 2101;
pub const GET_MEMORY_LIMIT: u64 = 2102;
pub const SET_CONTENT: u64 = 2103;
pub const DEBUG_PRINT_SYSCALL_NUMBER: u64 = 2177;
#[cfg(test)]
pub const DEBUG_PAUSE: u64 = 2178;

pub const SPAWN_MAX_MEMORY: u64 = 8;
pub const SPAWN_MAX_PEAK_MEMORY: u64 = 64; // 64 * 0.5M = 32M
pub const SPAWN_MEMORY_PAGE_SIZE: u64 = 512 * 1024; // 0.5M
pub const SPAWN_MAX_CONTENT_LENGTH: u64 = 256 * 1024; // 256K

#[derive(Debug, PartialEq, Clone, Copy, Eq)]
enum CellField {
Capacity = 0,
Expand Down
51 changes: 51 additions & 0 deletions script/src/syscalls/set_content.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
use crate::cost_model::transferred_byte_cycles;
use crate::syscalls::utils::load_bytes;
use crate::syscalls::SET_CONTENT;
use ckb_vm::{
registers::{A0, A1, A7},
Error as VMError, Memory, Register, SupportMachine, Syscalls,
};
use std::sync::{Arc, Mutex};

#[derive(Debug)]
pub struct SetContent {
content: Arc<Mutex<Vec<u8>>>,
content_size: u64,
}

impl SetContent {
pub fn new(content: Arc<Mutex<Vec<u8>>>, content_size: u64) -> Self {
Self {
content,
content_size,
}
}
}

impl<Mac: SupportMachine> Syscalls<Mac> for SetContent {
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() != SET_CONTENT {
return Ok(false);
}
let content_addr = machine.registers()[A0].to_u64();
let request_size_addr = machine.registers()[A1].to_u64();
let request_size = machine
.memory_mut()
.load64(&Mac::REG::from_u64(request_size_addr))?;
let size = std::cmp::min(self.content_size, request_size.to_u64());
self.content.lock().unwrap().resize(size as usize, 0);
let content = load_bytes(machine, content_addr, size)?;
self.content.lock().unwrap().copy_from_slice(&content);
machine.memory_mut().store64(
&Mac::REG::from_u64(request_size_addr),
&Mac::REG::from_u64(size),
)?;
machine.add_cycles_no_checking(transferred_byte_cycles(size))?;
machine.set_register(A0, Mac::REG::from_u64(0));
Ok(true)
}
}
Loading

0 comments on commit 898b4e5

Please sign in to comment.