Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

script: Add script version 2 #3908

Merged
merged 6 commits into from
Mar 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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