diff --git a/examples/ckb-js-script/README.md b/examples/ckb-js-script/README.md index 42fb7d2d5..dc8027e01 100644 --- a/examples/ckb-js-script/README.md +++ b/examples/ckb-js-script/README.md @@ -12,8 +12,8 @@ In this project, we show different ways to integrate CKB-js-vm into your smart c called spawn, where you can call CKB-js-vm from your script use `ckb_spawn` systcall and one is to use Script structure to load and execute your JavaScript script in a live cell. -There is also a full tutorial covering all the details for yout to run JavaScript smart contracts -on CKB in the official docs webesite: [docs.nervos.org](https://docs.nervos.org). +There is also a full tutorial covering all the details for you to run JavaScript smart contracts +on CKB in the official docs website: [docs.nervos.org](https://docs.nervos.org). *This project was bootstrapped with [ckb-script-templates].* diff --git a/examples/ckb-js-script/contracts/run-js/Cargo.toml b/examples/ckb-js-script/contracts/run-js/Cargo.toml deleted file mode 100644 index 9042f0939..000000000 --- a/examples/ckb-js-script/contracts/run-js/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "run-js" -version = "0.1.0" -edition = "2021" - -[dependencies] -ckb-std = {version = "0.15.1", features = ["ckb2023"]} - -[build-dependencies] -ckb-gen-types = "0.114.0" diff --git a/examples/ckb-js-script/contracts/run-js/src/main.rs b/examples/ckb-js-script/contracts/run-js/src/main.rs deleted file mode 100644 index 4ad8a3fc2..000000000 --- a/examples/ckb-js-script/contracts/run-js/src/main.rs +++ /dev/null @@ -1,44 +0,0 @@ -#![no_std] -#![cfg_attr(not(test), no_main)] - -#[cfg(test)] -extern crate alloc; - -#[cfg(not(test))] -use ckb_std::default_alloc; -use ckb_std::syscalls; -#[cfg(not(test))] -ckb_std::entry!(program_entry); -#[cfg(not(test))] -default_alloc!(); - -pub fn program_entry() -> i8 { - ckb_std::debug!("This is a sample run js code contract!"); - - let mut spgs_exit_code: i8 = -1; - - let mut spgs_content = [0u8; 80]; - let mut spgs_content_length: u64 = 80; - let spgs = syscalls::SpawnArgs { - memory_limit: 8, - exit_code: &mut spgs_exit_code as *mut i8, - content: &mut spgs_content as *mut u8, - content_length: &mut spgs_content_length as *mut u64, - }; - - // we supposed the first cell in cellDeps is the ckb-js-vm cell - // we then call ckb-js-vm script using spawn syscall to execute the js code in the script args - let result = - ckb_std::syscalls::spawn(0, ckb_std::ckb_constants::Source::CellDep, 0, &[], &spgs); - ckb_std::debug!("spawn result: {:?}", result); - - if result != 0 { - return 1; - } - - if spgs_exit_code != 0 { - return 1; - } - - 0 -} diff --git a/examples/ckb-js-script/deps/README.md b/examples/ckb-js-script/deps/README.md index fdde6e71d..de72fcd6e 100644 --- a/examples/ckb-js-script/deps/README.md +++ b/examples/ckb-js-script/deps/README.md @@ -1 +1,7 @@ -ckb-js-vm is a binary built for javascript engine on CKB-VM, you can rebuild it from https://github.com/nervosnetwork/ckb-js-vm +# ckb-js-vm + +`ckb-js-vm` is a binary built for javascript engine on CKB-VM, you can rebuild it from https://github.com/nervosnetwork/ckb-js-vm + +This binary is locked with the commit hash [c158de314783151b6fb023420dd5d5bff2bc2772](https://github.com/nervosnetwork/ckb-js-vm/commit/c158de314783151b6fb023420dd5d5bff2bc2772) + +`compile.awk` is copied from https://github.com/nervosnetwork/ckb-js-vm/blob/c158de314783151b6fb023420dd5d5bff2bc2772/tools/compile.awk and used to compile js source code into binary for CKB-VM. diff --git a/examples/ckb-js-script/deps/ckb-js-vm b/examples/ckb-js-script/deps/ckb-js-vm index 8e62cb3c9..bef946df9 100755 Binary files a/examples/ckb-js-script/deps/ckb-js-vm and b/examples/ckb-js-script/deps/ckb-js-vm differ diff --git a/examples/ckb-js-script/deps/compile.awk b/examples/ckb-js-script/deps/compile.awk new file mode 100644 index 000000000..bacc338c0 --- /dev/null +++ b/examples/ckb-js-script/deps/compile.awk @@ -0,0 +1,14 @@ +#!/usr/bin/awk -f + +{ + # Check if the line starts with "Script log: " + if ($0 ~ /^Script log: /) { + # Remove "Script log: " from the line + line_data = gensub(/^Script log: /, "", "g") + + # If the remaining line is not empty, print it + if (line_data != "") { + print line_data + } + } +} diff --git a/examples/ckb-js-script/js/build/sudt.bc b/examples/ckb-js-script/js/build/sudt.bc index 189bf111c..e69de29bb 100644 Binary files a/examples/ckb-js-script/js/build/sudt.bc and b/examples/ckb-js-script/js/build/sudt.bc differ diff --git a/examples/ckb-js-script/tests/Cargo.toml b/examples/ckb-js-script/tests/Cargo.toml deleted file mode 100644 index f0cf31333..000000000 --- a/examples/ckb-js-script/tests/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "tests" -version = "0.1.0" -edition = "2021" - -[dependencies] -ckb-testtool = "0.10.2" -serde_json = "1.0" -hex = { version = "0.4", default-features = false, features = ["alloc"]} diff --git a/examples/ckb-js-script/tests/src/tests.rs b/examples/ckb-js-script/tests/src/tests.rs deleted file mode 100644 index 91a4c887e..000000000 --- a/examples/ckb-js-script/tests/src/tests.rs +++ /dev/null @@ -1,303 +0,0 @@ -// Include our tests here -// See https://github.com/xxuejie/ckb-native-build-sample/blob/main/tests/src/tests.rs for examples - -use super::*; -use ckb_testtool::{ - builtin::ALWAYS_SUCCESS, - ckb_types::{bytes::Bytes, core::TransactionBuilder, packed::*, prelude::*}, - context::Context, -}; - -const MAX_CYCLES: u64 = 10_000_000; - -#[test] -fn hello_script() { - // deploy contract - let mut context = Context::default(); - let loader = Loader::default(); - let js_vm_bin = loader.load_binary("../../deps/ckb-js-vm"); - let js_vm_out_point = context.deploy_cell(js_vm_bin); - let js_vm_cell_dep = CellDep::new_builder() - .out_point(js_vm_out_point.clone()) - .build(); - - let js_script_bin = loader.load_binary("../../js/build/hello.bc"); - let js_script_out_point = context.deploy_cell(js_script_bin.clone()); - let js_script_cell_dep = CellDep::new_builder() - .out_point(js_script_out_point.clone()) - .build(); - - // prepare scripts - let always_success_out_point = context.deploy_cell(ALWAYS_SUCCESS.clone()); - let lock_script = context - .build_script(&always_success_out_point.clone(), Default::default()) - .expect("script"); - let lock_script_dep = CellDep::new_builder() - .out_point(always_success_out_point) - .build(); - - // prepare cell deps - let cell_deps: Vec = vec![lock_script_dep, js_vm_cell_dep, js_script_cell_dep]; - - // prepare cells - let input_out_point = context.create_cell( - CellOutput::new_builder() - .capacity(1000u64.pack()) - .lock(lock_script.clone()) - .build(), - Bytes::new(), - ); - let input = CellInput::new_builder() - .previous_output(input_out_point.clone()) - .build(); - - // args: - let mut type_script_args: [u8; 35] = [0u8; 35]; - let reserved = [0u8; 2]; - let (js_cell, _) = context.get_cell(&js_script_out_point.clone()).unwrap(); - let js_type_script = js_cell.type_().to_opt().unwrap(); - let code_hash = js_type_script.calc_script_hash(); - let hash_type = js_type_script.hash_type(); - type_script_args[..2].copy_from_slice(&reserved); - type_script_args[2..34].copy_from_slice(code_hash.as_slice()); - type_script_args[34..35].copy_from_slice(&hash_type.as_slice()); - - let type_script = context - .build_script(&js_vm_out_point, type_script_args.to_vec().into()) - .expect("script"); - - let outputs = vec![ - CellOutput::new_builder() - .capacity(500u64.pack()) - .lock(lock_script.clone()) - .type_(Some(type_script.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(500u64.pack()) - .lock(lock_script) - .build(), - ]; - - // prepare output cell data - let outputs_data = vec![Bytes::new(), Bytes::new()]; - - // build transaction - let tx = TransactionBuilder::default() - .cell_deps(cell_deps) - .input(input) - .outputs(outputs) - .outputs_data(outputs_data.pack()) - .build(); - - let tx = tx.as_advanced_builder().build(); - - // run - let cycles = context - .verify_tx(&tx, MAX_CYCLES) - .expect("pass verification"); - println!("consume cycles: {}", cycles); -} - -#[test] -fn fib_script() { - // deploy contract - let mut context = Context::default(); - let loader = Loader::default(); - let js_vm_bin = loader.load_binary("../../deps/ckb-js-vm"); - let js_vm_out_point = context.deploy_cell(js_vm_bin); - let js_vm_cell_dep = CellDep::new_builder() - .out_point(js_vm_out_point.clone()) - .build(); - - let js_script_bin = loader.load_binary("../../js/build/fib.bc"); - let js_script_out_point = context.deploy_cell(js_script_bin.clone()); - let js_script_cell_dep = CellDep::new_builder() - .out_point(js_script_out_point.clone()) - .build(); - - // prepare scripts - let always_success_out_point = context.deploy_cell(ALWAYS_SUCCESS.clone()); - let lock_script = context - .build_script(&always_success_out_point.clone(), Default::default()) - .expect("script"); - let lock_script_dep = CellDep::new_builder() - .out_point(always_success_out_point) - .build(); - - // prepare cell deps - let cell_deps: Vec = vec![lock_script_dep, js_vm_cell_dep, js_script_cell_dep]; - - // prepare cells - let input_out_point = context.create_cell( - CellOutput::new_builder() - .capacity(1000u64.pack()) - .lock(lock_script.clone()) - .build(), - Bytes::new(), - ); - let input = CellInput::new_builder() - .previous_output(input_out_point.clone()) - .build(); - - // args: - let mut type_script_args: [u8; 35] = [0u8; 35]; - let reserved = [0u8; 2]; - let (js_cell, _) = context.get_cell(&js_script_out_point.clone()).unwrap(); - let js_type_script = js_cell.type_().to_opt().unwrap(); - let code_hash = js_type_script.calc_script_hash(); - let hash_type = js_type_script.hash_type(); - type_script_args[..2].copy_from_slice(&reserved); - type_script_args[2..34].copy_from_slice(code_hash.as_slice()); - type_script_args[34..35].copy_from_slice(&hash_type.as_slice()); - - let type_script = context - .build_script(&js_vm_out_point, type_script_args.to_vec().into()) - .expect("script"); - - let outputs = vec![ - CellOutput::new_builder() - .capacity(500u64.pack()) - .lock(lock_script.clone()) - .type_(Some(type_script.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(500u64.pack()) - .lock(lock_script) - .build(), - ]; - - // prepare output cell data - let outputs_data = vec![Bytes::new(), Bytes::new()]; - - // build transaction - let tx = TransactionBuilder::default() - .cell_deps(cell_deps) - .input(input) - .outputs(outputs) - .outputs_data(outputs_data.pack()) - .build(); - - let tx = tx.as_advanced_builder().build(); - - // run - let cycles = context - .verify_tx(&tx, MAX_CYCLES) - .expect("pass verification"); - println!("consume cycles: {}", cycles); -} - -#[test] -fn sudt_script() { - // deploy contract - let mut context = Context::default(); - let loader = Loader::default(); - let js_vm_bin = loader.load_binary("../../deps/ckb-js-vm"); - let js_vm_out_point = context.deploy_cell(js_vm_bin); - let js_vm_cell_dep = CellDep::new_builder() - .out_point(js_vm_out_point.clone()) - .build(); - - let run_js_bin = loader.load_binary("run-js"); - let run_js_out_point = context.deploy_cell(run_js_bin); - let run_js_cell_dep = CellDep::new_builder() - .out_point(run_js_out_point.clone()) - .build(); - - let js_script_bin = loader.load_binary("../../js/build/sudt.bc"); - let js_script_out_point = context.deploy_cell(js_script_bin.clone()); - let js_script_cell_dep = CellDep::new_builder() - .out_point(js_script_out_point.clone()) - .build(); - - // prepare scripts - let always_success_out_point = context.deploy_cell(ALWAYS_SUCCESS.clone()); - let lock_script = context - .build_script(&always_success_out_point.clone(), Default::default()) - .expect("script"); - let lock_script_dep = CellDep::new_builder() - .out_point(always_success_out_point) - .build(); - - // prepare cell deps - let cell_deps: Vec = vec![ - js_vm_cell_dep, - run_js_cell_dep, - lock_script_dep, - js_script_cell_dep, - ]; - - // prepare cells - let input_out_point = context.create_cell( - CellOutput::new_builder() - .capacity(1000u64.pack()) - .lock(lock_script.clone()) - .build(), - Bytes::new(), - ); - let input = CellInput::new_builder() - .previous_output(input_out_point.clone()) - .build(); - - // args: - let mut type_script_args: [u8; 67] = [0u8; 67]; - let reserved = [0u8; 2]; - let (js_cell, _) = context.get_cell(&js_script_out_point.clone()).unwrap(); - let js_type_script = js_cell.type_().to_opt().unwrap(); - let code_hash = js_type_script.calc_script_hash(); - let hash_type = js_type_script.hash_type(); - let owner_lock_script_hash = lock_script.clone().calc_script_hash(); - - type_script_args[..2].copy_from_slice(&reserved); - type_script_args[2..34].copy_from_slice(code_hash.as_slice()); - type_script_args[34..35].copy_from_slice(&hash_type.as_slice()); - type_script_args[35..].copy_from_slice(owner_lock_script_hash.as_slice()); - - let type_script = context - .build_script(&run_js_out_point, type_script_args.to_vec().into()) - .expect("script"); - - let outputs = vec![ - CellOutput::new_builder() - .capacity(500u64.pack()) - .lock(lock_script.clone()) - .type_(Some(type_script.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(500u64.pack()) - .lock(lock_script) - .build(), - ]; - - // prepare output cell data - let sudt_amount: u128 = 10; // issue 10 tokens - let outputs_data = vec![ - Bytes::from(sudt_amount.to_le_bytes().to_vec()), - Bytes::new(), - ]; - - // build transaction - let tx = TransactionBuilder::default() - .cell_deps(cell_deps) - .input(input) - .outputs(outputs) - .outputs_data(outputs_data.pack()) - .build(); - - let tx = tx.as_advanced_builder().build(); - - // run - let cycles = context - .verify_tx(&tx, MAX_CYCLES) - .expect("pass verification"); - println!("consume cycles: {}", cycles); -} - -fn _assert_script_error(err: Error, err_code: i8) { - let error_string = err.to_string(); - assert!( - error_string.contains(format!("error code {} ", err_code).as_str()), - "error_string: {}, expected_error_code: {}", - error_string, - err_code - ); -} diff --git a/examples/create-dob/offckb/system-scripts.json b/examples/create-dob/offckb/system-scripts.json index 1c3b2e0c5..c2ac800dc 100644 --- a/examples/create-dob/offckb/system-scripts.json +++ b/examples/create-dob/offckb/system-scripts.json @@ -110,6 +110,15 @@ }, "depType": "code" } + }, + { + "cellDep": { + "outPoint": { + "txHash": "0x75be96e1871693f030db27ddae47890a28ab180e88e36ebb3575d9f1377d3da7", + "index": 0 + }, + "depType": "depGroup" + } } ] } @@ -287,7 +296,6 @@ }, "secp256k1_blake160_multisig_all": { "name": "secp256k1_blake160_multisig_all", - "file": "Bundled(specs/cells/secp256k1_blake160_multisig_all)", "script": { "codeHash": "0x5c5069eb0857efc65e1bca0c07df34c31663b3622fd3876c876320fc9634e2a8", "hashType": "type", @@ -335,6 +343,11 @@ "index": 0 }, "depType": "code" + }, + "type": { + "codeHash": "0x00000000000000000000000000000000000000000000000000545950455f4944", + "hashType": "type", + "args": "0x44ec8b96663e06cc94c8c468a4d46d7d9af69eaf418f6390c9f11bb763dda0ae" } } ] @@ -346,6 +359,15 @@ "codeHash": "0xf329effd1c475a2978453c8600e1eaf0bc2087ee093c3ee64cc96ec6847752cb", "hashType": "type", "cellDeps": [ + { + "cellDep": { + "outPoint": { + "txHash": "0xf8de3bb47d055cdf460d93a2a6e1b05f7432f9777c8c474abf4eec1d4aee5d37", + "index": 0 + }, + "depType": "depGroup" + } + }, { "cellDep": { "outPoint": { @@ -353,6 +375,11 @@ "index": 0 }, "depType": "code" + }, + "type": { + "codeHash": "0x00000000000000000000000000000000000000000000000000545950455f4944", + "hashType": "type", + "args": "0x761f51fc9cd6a504c32c6ae64b3746594d1af27629b427c5ccf6c9a725a89144" } } ] @@ -564,6 +591,15 @@ "codeHash": "0x9b819793a64463aed77c615d6cb226eea5487ccfc0783043a587254cda2b6f26", "hashType": "type", "cellDeps": [ + { + "cellDep": { + "outPoint": { + "txHash": "0x71a7ba8fc96349fea0ed3a5c47992e3b4084b031a42264a018e0072e8172e46c", + "index": 0 + }, + "depType": "depGroup" + } + }, { "cellDep": { "outPoint": { @@ -571,6 +607,11 @@ "index": 0 }, "depType": "code" + }, + "type": { + "codeHash": "0x00000000000000000000000000000000000000000000000000545950455f4944", + "hashType": "type", + "args": "0x855508fe0f0ca25b935b070452ecaee48f6c9f1d66cd15f046616b99e948236a" } } ] diff --git a/examples/simple-lock/frontend/offckb.config.ts b/examples/simple-lock/frontend/offckb.config.ts index 57644176a..a0de72941 100644 --- a/examples/simple-lock/frontend/offckb.config.ts +++ b/examples/simple-lock/frontend/offckb.config.ts @@ -92,7 +92,7 @@ export function readEnvNetwork(): Network { const offCKBConfig: OffCKBConfig = { version: '0.3.0-rc2', - contractBinFolder: '../build/release', + contractBinFolder: '../../build/release', // this folder record the script deployment information // If you change this folder, you need to update the following get systemScripts and get myScripts method contractInfoFolder: './offckb', diff --git a/examples/simple-lock/frontend/offckb/my-scripts.json b/examples/simple-lock/frontend/offckb/my-scripts.json index b241b5144..840d3050b 100644 --- a/examples/simple-lock/frontend/offckb/my-scripts.json +++ b/examples/simple-lock/frontend/offckb/my-scripts.json @@ -1,5 +1,126 @@ { - "devnet": {}, + "devnet": { + "ckb-js-vm": { + "codeHash": "0x0f5af28d9b049d341397991fd53d6e1bf4d9819dddc6a93fd0e13328dde9d573", + "hashType": "data1", + "cellDeps": [ + { + "cellDep": { + "outPoint": { + "txHash": "0x01a0b6c271bd9fca29d6312037c31343707c69e0f39a5bf95ed75db38d9c5c54", + "index": 0 + }, + "depType": "code" + } + } + ] + }, + "fib.bc": { + "codeHash": "0x3ec9f6344eedbfaabeabb7c7d4c9ca6f30a8bbc1a97b7dfe2bdd761a01199ec4", + "hashType": "type", + "cellDeps": [ + { + "cellDep": { + "outPoint": { + "txHash": "0xcc8d2cd2cb51c0f89d91280f0dcc009e5fb30814192852c37200282c021e6cea", + "index": 0 + }, + "depType": "code" + } + } + ] + }, + "hash-lock": { + "codeHash": "0xe72cbf476f4301fc4c7b79a5072069a2ba4d826755318288025cb1cf8fa19db9", + "hashType": "data1", + "cellDeps": [ + { + "cellDep": { + "outPoint": { + "txHash": "0x53b920085b0727fb0524903b91cec924d11b43c862838559ee2b98fdd534ed27", + "index": 0 + }, + "depType": "code" + } + } + ] + }, + "hello.bc": { + "codeHash": "0xee651f5f8a34182329fb84edb5ba1b4f9216e306bd6505d674e31b6bc90fdbc6", + "hashType": "type", + "cellDeps": [ + { + "cellDep": { + "outPoint": { + "txHash": "0xcc7a322a520a27a150f97bc570c09e8dba7082f957215e026517500df80bb370", + "index": 0 + }, + "depType": "code" + } + } + ] + }, + "nostr-binding": { + "codeHash": "0x2e393f3d1ea99d5dbc339fcf09118cab747adb81c41c7d4a49938b3633a4b623", + "hashType": "type", + "cellDeps": [ + { + "cellDep": { + "outPoint": { + "txHash": "0x54cba84233f57aa841386997dc8c67987d80736b2506b2cac7c89b876ccb1788", + "index": 0 + }, + "depType": "code" + } + } + ] + }, + "nostr-lock": { + "codeHash": "0x35880e57ca540cf954489e997efe50311ec16d65cae74316292459a5a0f2110c", + "hashType": "type", + "cellDeps": [ + { + "cellDep": { + "outPoint": { + "txHash": "0xdda674cebb6cdaae8a9fcba7beb534f7beae5ece6c906a92a7379b3670e9acbe", + "index": 0 + }, + "depType": "code" + } + } + ] + }, + "run-js": { + "codeHash": "0x1da2844ec7aaf9cf093b8057abd9365620418ef657702619ecbad94de8561d91", + "hashType": "data1", + "cellDeps": [ + { + "cellDep": { + "outPoint": { + "txHash": "0x77597fdf0087e09cf20227e21869a79eda582493476732016b41d2f0af7d84be", + "index": 0 + }, + "depType": "code" + } + } + ] + }, + "sudt.bc": { + "codeHash": "0x8ce2540966078e998bde2ea96bad036346a996b3dbae92f4b519a57e938663e4", + "hashType": "type", + "cellDeps": [ + { + "cellDep": { + "outPoint": { + "txHash": "0xc75788a5e0570fe5f4d839a0728eb2e031d75aab73dd7f325268520f4f8c40fa", + "index": 0 + }, + "depType": "code" + } + } + ] + } + }, "testnet": {}, "mainnet": {} -} +} \ No newline at end of file diff --git a/examples/simple-lock/frontend/offckb/system-scripts.json b/examples/simple-lock/frontend/offckb/system-scripts.json index 1c3b2e0c5..c2ac800dc 100644 --- a/examples/simple-lock/frontend/offckb/system-scripts.json +++ b/examples/simple-lock/frontend/offckb/system-scripts.json @@ -110,6 +110,15 @@ }, "depType": "code" } + }, + { + "cellDep": { + "outPoint": { + "txHash": "0x75be96e1871693f030db27ddae47890a28ab180e88e36ebb3575d9f1377d3da7", + "index": 0 + }, + "depType": "depGroup" + } } ] } @@ -287,7 +296,6 @@ }, "secp256k1_blake160_multisig_all": { "name": "secp256k1_blake160_multisig_all", - "file": "Bundled(specs/cells/secp256k1_blake160_multisig_all)", "script": { "codeHash": "0x5c5069eb0857efc65e1bca0c07df34c31663b3622fd3876c876320fc9634e2a8", "hashType": "type", @@ -335,6 +343,11 @@ "index": 0 }, "depType": "code" + }, + "type": { + "codeHash": "0x00000000000000000000000000000000000000000000000000545950455f4944", + "hashType": "type", + "args": "0x44ec8b96663e06cc94c8c468a4d46d7d9af69eaf418f6390c9f11bb763dda0ae" } } ] @@ -346,6 +359,15 @@ "codeHash": "0xf329effd1c475a2978453c8600e1eaf0bc2087ee093c3ee64cc96ec6847752cb", "hashType": "type", "cellDeps": [ + { + "cellDep": { + "outPoint": { + "txHash": "0xf8de3bb47d055cdf460d93a2a6e1b05f7432f9777c8c474abf4eec1d4aee5d37", + "index": 0 + }, + "depType": "depGroup" + } + }, { "cellDep": { "outPoint": { @@ -353,6 +375,11 @@ "index": 0 }, "depType": "code" + }, + "type": { + "codeHash": "0x00000000000000000000000000000000000000000000000000545950455f4944", + "hashType": "type", + "args": "0x761f51fc9cd6a504c32c6ae64b3746594d1af27629b427c5ccf6c9a725a89144" } } ] @@ -564,6 +591,15 @@ "codeHash": "0x9b819793a64463aed77c615d6cb226eea5487ccfc0783043a587254cda2b6f26", "hashType": "type", "cellDeps": [ + { + "cellDep": { + "outPoint": { + "txHash": "0x71a7ba8fc96349fea0ed3a5c47992e3b4084b031a42264a018e0072e8172e46c", + "index": 0 + }, + "depType": "depGroup" + } + }, { "cellDep": { "outPoint": { @@ -571,6 +607,11 @@ "index": 0 }, "depType": "code" + }, + "type": { + "codeHash": "0x00000000000000000000000000000000000000000000000000545950455f4944", + "hashType": "type", + "args": "0x855508fe0f0ca25b935b070452ecaee48f6c9f1d66cd15f046616b99e948236a" } } ] diff --git a/examples/simple-transfer/offckb/system-scripts.json b/examples/simple-transfer/offckb/system-scripts.json index 1c3b2e0c5..c2ac800dc 100644 --- a/examples/simple-transfer/offckb/system-scripts.json +++ b/examples/simple-transfer/offckb/system-scripts.json @@ -110,6 +110,15 @@ }, "depType": "code" } + }, + { + "cellDep": { + "outPoint": { + "txHash": "0x75be96e1871693f030db27ddae47890a28ab180e88e36ebb3575d9f1377d3da7", + "index": 0 + }, + "depType": "depGroup" + } } ] } @@ -287,7 +296,6 @@ }, "secp256k1_blake160_multisig_all": { "name": "secp256k1_blake160_multisig_all", - "file": "Bundled(specs/cells/secp256k1_blake160_multisig_all)", "script": { "codeHash": "0x5c5069eb0857efc65e1bca0c07df34c31663b3622fd3876c876320fc9634e2a8", "hashType": "type", @@ -335,6 +343,11 @@ "index": 0 }, "depType": "code" + }, + "type": { + "codeHash": "0x00000000000000000000000000000000000000000000000000545950455f4944", + "hashType": "type", + "args": "0x44ec8b96663e06cc94c8c468a4d46d7d9af69eaf418f6390c9f11bb763dda0ae" } } ] @@ -346,6 +359,15 @@ "codeHash": "0xf329effd1c475a2978453c8600e1eaf0bc2087ee093c3ee64cc96ec6847752cb", "hashType": "type", "cellDeps": [ + { + "cellDep": { + "outPoint": { + "txHash": "0xf8de3bb47d055cdf460d93a2a6e1b05f7432f9777c8c474abf4eec1d4aee5d37", + "index": 0 + }, + "depType": "depGroup" + } + }, { "cellDep": { "outPoint": { @@ -353,6 +375,11 @@ "index": 0 }, "depType": "code" + }, + "type": { + "codeHash": "0x00000000000000000000000000000000000000000000000000545950455f4944", + "hashType": "type", + "args": "0x761f51fc9cd6a504c32c6ae64b3746594d1af27629b427c5ccf6c9a725a89144" } } ] @@ -564,6 +591,15 @@ "codeHash": "0x9b819793a64463aed77c615d6cb226eea5487ccfc0783043a587254cda2b6f26", "hashType": "type", "cellDeps": [ + { + "cellDep": { + "outPoint": { + "txHash": "0x71a7ba8fc96349fea0ed3a5c47992e3b4084b031a42264a018e0072e8172e46c", + "index": 0 + }, + "depType": "depGroup" + } + }, { "cellDep": { "outPoint": { @@ -571,6 +607,11 @@ "index": 0 }, "depType": "code" + }, + "type": { + "codeHash": "0x00000000000000000000000000000000000000000000000000545950455f4944", + "hashType": "type", + "args": "0x855508fe0f0ca25b935b070452ecaee48f6c9f1d66cd15f046616b99e948236a" } } ] diff --git a/examples/spawn-script/.gitignore b/examples/spawn-script/.gitignore new file mode 100644 index 000000000..0ff4f2fa8 --- /dev/null +++ b/examples/spawn-script/.gitignore @@ -0,0 +1,3 @@ +/build +/target +/tests/failed_txs diff --git a/examples/ckb-js-script/Cargo.lock b/examples/spawn-script/Cargo.lock similarity index 56% rename from examples/ckb-js-script/Cargo.lock rename to examples/spawn-script/Cargo.lock index e5bbd7e82..ecf309781 100644 --- a/examples/ckb-js-script/Cargo.lock +++ b/examples/spawn-script/Cargo.lock @@ -2,6 +2,15 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +dependencies = [ + "gimli", +] + [[package]] name = "adler" version = "1.0.2" @@ -14,31 +23,43 @@ version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ - "getrandom 0.2.14", + "getrandom 0.2.15", "once_cell", "version_check", ] [[package]] -name = "aho-corasick" -version = "1.1.3" +name = "anyhow" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] -name = "anyhow" -version = "1.0.82" +name = "autocfg" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] -name = "autocfg" -version = "1.2.0" +name = "backtrace" +version = "0.3.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "bit-vec" @@ -52,6 +73,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + [[package]] name = "blake2b-ref" version = "0.3.1" @@ -68,11 +95,20 @@ dependencies = [ "cty", ] +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + [[package]] name = "buddy-alloc" -version = "0.5.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f0d2da64a6a895d5a7e0724882825d50f83c13396b1b9f1878e19a024bab395" +checksum = "ee741d62dcaf41ca303576ef890989ccb01d5dd77f8ce1a6d6c7846ab5d09efb" [[package]] name = "byteorder" @@ -89,11 +125,52 @@ dependencies = [ "serde", ] +[[package]] +name = "cacache" +version = "12.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "142316461ed3a3dfcba10417317472da5bfd0461e4d276bf7c07b330766d9490" +dependencies = [ + "digest", + "either", + "futures", + "hex", + "libc", + "memmap2", + "miette", + "reflink-copy", + "serde", + "serde_derive", + "serde_json", + "sha1", + "sha2", + "ssri", + "tempfile", + "thiserror", + "tokio", + "tokio-stream", + "walkdir", +] + +[[package]] +name = "callee" +version = "0.1.0" +dependencies = [ + "ckb-std", +] + +[[package]] +name = "caller" +version = "0.1.0" +dependencies = [ + "ckb-std", +] + [[package]] name = "cc" -version = "1.0.95" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d32a725bc159af97c3e629873bb9f88fb8cf8a4867175f76dc987815ea07c83b" +checksum = "907d8581360765417f8f2e0e7d602733bbed60156b4465b7617243689ef9b83d" [[package]] name = "cfg-if" @@ -109,60 +186,61 @@ checksum = "8b3b72a38c9920a29990df12002c4d069a147c8782f0c211f8a01b2df8f42bfd" [[package]] name = "ckb-chain-spec" -version = "0.112.1" +version = "0.119.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa9b89cadf419c220fa8e1c655af73540bbc010e8c0e177127644848a25830c2" +checksum = "084b4b3c2d0d5ca51e47812130615535cad47772005af3535f3d4e6a63e947ae" dependencies = [ + "cacache", "ckb-constant", "ckb-crypto", "ckb-dao-utils", - "ckb-error 0.112.1", - "ckb-hash 0.112.1", + "ckb-error", + "ckb-hash", "ckb-jsonrpc-types", + "ckb-logger", "ckb-pow", "ckb-rational", "ckb-resource", "ckb-traits", "ckb-types", - "ckb-util", "serde", "toml", ] [[package]] name = "ckb-channel" -version = "0.112.1" +version = "0.119.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82c904fe3e29474e4d09e8e2775a472456242f8faf18edeeb8c71502710daa38" +checksum = "2c4c7f5530737f8a02329075581b29ab7003a72d6ee747d1b2ea9d2239faea7a" dependencies = [ "crossbeam-channel", ] [[package]] name = "ckb-constant" -version = "0.112.1" +version = "0.119.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7d562e7156216f00c5bf55c8f4c86bc25f9ec0603fcfa6df9b66747462a031a" +checksum = "7e1424bf7490c14cdbd13697629ece8c1ba0ed02ff1c8a5b14a8713431ec6ff8" [[package]] name = "ckb-crypto" -version = "0.112.1" +version = "0.119.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abac585cec6f1562e374d66b369c55a52357b33a632d30d2e45cbc455183b22d" +checksum = "ee335e672a67e4d951a65d5a3b03072f038dc1487e559133953912bcbe41d4d9" dependencies = [ - "ckb-fixed-hash 0.112.1", + "ckb-fixed-hash", "faster-hex", "lazy_static", - "rand 0.7.3", + "rand 0.8.5", "secp256k1", "thiserror", ] [[package]] name = "ckb-dao" -version = "0.112.1" +version = "0.119.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c6b5b85ebe6e02bebcc1f1a4db28f1594e1a9e43e8922c05175459f798e844" +checksum = "956a82fae564f5d207118f8a152f7c8daf1db4119ac4d3a18dfe5695bcd9b0e4" dependencies = [ "byteorder", "ckb-chain-spec", @@ -173,76 +251,44 @@ dependencies = [ [[package]] name = "ckb-dao-utils" -version = "0.112.1" +version = "0.119.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff55485163b842c94061b755c9e6230d1a4bb092b6bc81d8387358911c750e70" +checksum = "766da195cb9a17f5a625de6924058ef1f12241317835cc83a09368018074366a" dependencies = [ "byteorder", - "ckb-error 0.112.1", + "ckb-error", "ckb-types", ] [[package]] name = "ckb-error" -version = "0.112.1" +version = "0.119.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8418901ea0d15a8e26255bec0b71be5c59056858f51968894796f77f7eefa3e" +checksum = "109adb3c26e697861e3f57c1ca8cf2f2a399c46e64c97be2b05f751535ac1b75" dependencies = [ "anyhow", - "ckb-occupied-capacity 0.112.1", - "derive_more", - "thiserror", -] - -[[package]] -name = "ckb-error" -version = "0.114.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6d7bc8a43e036195079e3b6a144547970b6c6e1a5591ecbeea7a5478bfebcfa" -dependencies = [ - "anyhow", - "ckb-occupied-capacity 0.114.0", + "ckb-occupied-capacity", "derive_more", "thiserror", ] [[package]] name = "ckb-fixed-hash" -version = "0.112.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1254aafda84e9abc85301e9e4c5b920c00a9bff0d42248fccf921b340ec5f13e" -dependencies = [ - "ckb-fixed-hash-core 0.112.1", - "ckb-fixed-hash-macros 0.112.1", -] - -[[package]] -name = "ckb-fixed-hash" -version = "0.114.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ab27de1271bc1064ed242d08fca2d79ca64e3f99b2680b145ac63ba069dc907" -dependencies = [ - "ckb-fixed-hash-core 0.114.0", - "ckb-fixed-hash-macros 0.114.0", -] - -[[package]] -name = "ckb-fixed-hash-core" -version = "0.112.1" +version = "0.119.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ffc2850ac8b5643c65913185020de747b290b447d1ee1fd59a2cfdf1a7ceb4f" +checksum = "71ea8f4896f945ecdb473cc8b747a47a9f282393a37a681bcbe0cdde94894bfc" dependencies = [ - "faster-hex", - "serde", - "thiserror", + "ckb-fixed-hash-core", + "ckb-fixed-hash-macros", ] [[package]] name = "ckb-fixed-hash-core" -version = "0.114.0" +version = "0.119.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64b63d1bc55ac6e578cdc9ad861f427e46b225a4a48bf5d0a55f6fa4a127a822" +checksum = "e1c265cd6b0ec00b8dc671b9344906a2428f9b756e4e789660c71f535252fe2d" dependencies = [ + "ckb_schemars", "faster-hex", "serde", "thiserror", @@ -250,23 +296,11 @@ dependencies = [ [[package]] name = "ckb-fixed-hash-macros" -version = "0.112.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baa5a19a7d18caa5a3a65e66506e28943e95696e286df44457a77692319de429" -dependencies = [ - "ckb-fixed-hash-core 0.112.1", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "ckb-fixed-hash-macros" -version = "0.114.0" +version = "0.119.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "008f7221e3d20c4de5c7e23910d343d4938002fa9eb509e3e6fa5898dc4ecba9" +checksum = "976b10df5474be0ff33b22a84b44875e065679fc41155350c11e420124910ca1" dependencies = [ - "ckb-fixed-hash-core 0.114.0", + "ckb-fixed-hash-core", "proc-macro2", "quote", "syn 1.0.109", @@ -274,49 +308,24 @@ dependencies = [ [[package]] name = "ckb-gen-types" -version = "0.112.1" +version = "0.119.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a12020d50dd3757cde0fdc88d3837b7a2ab503fe38bd11be86ddace11318c77" +checksum = "1bc221d4b9d6d39215b1d62be855861b8b0c8d668ca29874903b0bf5d0b4d9fa" dependencies = [ "cfg-if", - "ckb-error 0.112.1", - "ckb-fixed-hash 0.112.1", - "ckb-hash 0.112.1", - "ckb-occupied-capacity 0.112.1", + "ckb-error", + "ckb-fixed-hash", + "ckb-hash", + "ckb-occupied-capacity", "molecule", "numext-fixed-uint", ] -[[package]] -name = "ckb-gen-types" -version = "0.114.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e565b056266184d99aab11115245531127e4a8d13b7700c4839b469763a3c54" -dependencies = [ - "cfg-if", - "ckb-error 0.114.0", - "ckb-fixed-hash 0.114.0", - "ckb-hash 0.114.0", - "ckb-occupied-capacity 0.114.0", - "molecule", - "numext-fixed-uint", -] - -[[package]] -name = "ckb-hash" -version = "0.112.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25af660fc8746f7c756444e6aa47ede9a874206563b6a1ce1b230a5b86519392" -dependencies = [ - "blake2b-ref", - "blake2b-rs", -] - [[package]] name = "ckb-hash" -version = "0.114.0" +version = "0.119.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99970478850566472a03e5cc4d57e388bb7a8255771f4308b42036f0d8a623d8" +checksum = "99ba7c72f86f239b3e0154f51d6cd5d0d83bbaa8775fdc7b6bcac459ae24b6fd" dependencies = [ "blake2b-ref", "blake2b-rs", @@ -324,11 +333,12 @@ dependencies = [ [[package]] name = "ckb-jsonrpc-types" -version = "0.112.1" +version = "0.119.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06798b5bacd7fd4125a34f1c9ebf45be59d50aff0ada003bb8b1c6634a447c73" +checksum = "3983584cc6e269125c3bf502fa6d84a4f6e47d5b4c1e3a4070db86382ed4ba15" dependencies = [ "ckb-types", + "ckb_schemars", "faster-hex", "serde", "serde_json", @@ -336,9 +346,9 @@ dependencies = [ [[package]] name = "ckb-logger" -version = "0.112.1" +version = "0.119.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8d8de618d1dbc59ba9e6338a55d17f370f89aa009064dcbdd7eb0c8e8782fe" +checksum = "b19523bb7b582ccd98615a48c687e41ce1511e72d903520ea36100ef5c5ba9a3" dependencies = [ "log", ] @@ -354,9 +364,9 @@ dependencies = [ [[package]] name = "ckb-mock-tx-types" -version = "0.112.1" +version = "0.119.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accabfa378c927109844630e4c90e0d7e7e6d6a9174c232f194f490b09e4b757" +checksum = "3bce36d06097bca7df141a89ba970566bbf4075945c6dd95a0771e8830c2c1a8" dependencies = [ "ckb-jsonrpc-types", "ckb-traits", @@ -366,72 +376,42 @@ dependencies = [ [[package]] name = "ckb-occupied-capacity" -version = "0.112.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be7132362f12a0495b3b24218afb4e774f9dc0d9254173d2444ec4ac1447461e" -dependencies = [ - "ckb-occupied-capacity-core 0.112.1", - "ckb-occupied-capacity-macros 0.112.1", -] - -[[package]] -name = "ckb-occupied-capacity" -version = "0.114.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca8adc8c7723b98636ae3aeb7d14417c68edcc61cf2913414e42eca1eb2b4f7b" -dependencies = [ - "ckb-occupied-capacity-core 0.114.0", - "ckb-occupied-capacity-macros 0.114.0", -] - -[[package]] -name = "ckb-occupied-capacity-core" -version = "0.112.1" +version = "0.119.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4ebe8725d6ee4feb9d376e9a600b2c78cc1dbde5aa754c9a47de871ab917635" +checksum = "a6b706bce252b627543ce3bac5240f4d2f1e5d73daca9e451c88db44c2ea94bb" dependencies = [ - "serde", + "ckb-occupied-capacity-core", + "ckb-occupied-capacity-macros", ] [[package]] name = "ckb-occupied-capacity-core" -version = "0.114.0" +version = "0.119.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1589ebe2d556a85b70d02f8dd0d022b990de1420a5de66c356eb3ea8a5526b6c" +checksum = "510608e5c7c2f3bf025c6ae80ed7782a1cd12897e15dc930167c8dbd3165ece6" dependencies = [ "serde", ] [[package]] name = "ckb-occupied-capacity-macros" -version = "0.112.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201a21d35a377b76440ce12ca62b39e548d019a6330fbdcb40ac0f73fe976cb3" -dependencies = [ - "ckb-occupied-capacity-core 0.112.1", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "ckb-occupied-capacity-macros" -version = "0.114.0" +version = "0.119.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb9842edc4f65f556e57176ecce956ed32fcddcd272118a3a688116d2aba8c80" +checksum = "b79a3fd71708b5068fb377497d6be6dbca53725f1a13d174335105c4bd39ffd5" dependencies = [ - "ckb-occupied-capacity-core 0.114.0", + "ckb-occupied-capacity-core", "quote", "syn 1.0.109", ] [[package]] name = "ckb-pow" -version = "0.112.1" +version = "0.119.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5895b4799fbb7e537ef0a778493b8f8678284c2bb20b476edce3f3375d1c4aa1" +checksum = "40266a0bbf46eb4d92fc7137c93b22b8518d7a5a8991d6b52931b1fc43cb9863" dependencies = [ "byteorder", - "ckb-hash 0.112.1", + "ckb-hash", "ckb-types", "eaglesong", "log", @@ -440,9 +420,9 @@ dependencies = [ [[package]] name = "ckb-rational" -version = "0.112.1" +version = "0.119.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5134dae6f59b1c10457d2a5def081865407e756dd42dd4c7aaf5d6c6bc92b6d1" +checksum = "91835c60dba878e54da2dfcfad62369638b88f910d9e8c7eb31f9c357a331ff7" dependencies = [ "numext-fixed-uint", "serde", @@ -450,9 +430,9 @@ dependencies = [ [[package]] name = "ckb-resource" -version = "0.112.1" +version = "0.119.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3c79b7c1586ca652d150b2cfdc5ec8594055659f04e30f832178a14313cfff4" +checksum = "9ec19c5f0d6e96a0347492acdf992f6db7838f70b1c3ae4d32e9d3558f0557f0" dependencies = [ "ckb-system-scripts", "ckb-types", @@ -465,31 +445,33 @@ dependencies = [ [[package]] name = "ckb-script" -version = "0.112.1" +version = "0.119.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "058cb8c72a706bfc95c9b90f7c0256abbc4f44e9c5cabcbf7d1d882df977e82b" +checksum = "3c247ea3580c240a7eb82516258c8523c7c22219b6681016be83284ebb15cd22" dependencies = [ "byteorder", "ckb-chain-spec", - "ckb-error 0.112.1", - "ckb-hash 0.112.1", + "ckb-error", + "ckb-hash", "ckb-logger", "ckb-traits", "ckb-types", "ckb-vm", "faster-hex", "serde", + "tokio", ] [[package]] name = "ckb-std" -version = "0.15.3" +version = "0.16.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9357d9464ed36a8e542a7d588e894aff25ccb0cdd66221ac94e76bc69ca3ad55" +checksum = "4a673595baadfa1712ff03a36e1519f28015cf9944282410863d5e256336f5b9" dependencies = [ "buddy-alloc", "cc", - "ckb-gen-types 0.112.1", + "ckb-gen-types", + "ckb-x64-simulator", "gcd", ] @@ -508,21 +490,21 @@ dependencies = [ [[package]] name = "ckb-systemtime" -version = "0.112.1" +version = "0.119.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace369d09f2a4d5d0e0b97359cf34e3282a5a90171f685e8bbab1aa21e80cd54" +checksum = "c0acbeae9e64b10d26ea477dc982caf643d4143f086cb5cf69f2d0f94e4fa2e4" [[package]] name = "ckb-testtool" -version = "0.10.2" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed25ee2af0e899736bb95e4fd1dd4c89f03dd8ae0061ae708b83e405d394431" +checksum = "f04def89b489205dfcf3cb03468f427e23990987fcdd5aa274515a775846c8c5" dependencies = [ "ckb-always-success-script", "ckb-chain-spec", "ckb-crypto", - "ckb-error 0.112.1", - "ckb-hash 0.112.1", + "ckb-error", + "ckb-hash", "ckb-jsonrpc-types", "ckb-mock-tx-types", "ckb-resource", @@ -530,35 +512,38 @@ dependencies = [ "ckb-traits", "ckb-types", "ckb-verification", + "faster-hex", "lazy_static", + "libloading", "rand 0.8.5", + "serde_json", ] [[package]] name = "ckb-traits" -version = "0.112.1" +version = "0.119.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3396b8f328bc76bdfd9bc14ddd984a07d08120cd4e661ba1dc23fecb3a7607a3" +checksum = "ab91cb32bd5655b5b4c6574d6f07dd919d93759dc9e07f9ee6a2a9823848c4dc" dependencies = [ "ckb-types", ] [[package]] name = "ckb-types" -version = "0.112.1" +version = "0.119.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2df7c7410664bc917f1b663c574ec7c0e25711fe4f63eb0043c47c197afb0875" +checksum = "f02dc76ea18e9838ec996c0f1f8a822d65176d2c9f052b3855c1d0a2d0a4d885" dependencies = [ "bit-vec", "bytes", "ckb-channel", "ckb-constant", - "ckb-error 0.112.1", - "ckb-fixed-hash 0.112.1", - "ckb-gen-types 0.112.1", - "ckb-hash 0.112.1", + "ckb-error", + "ckb-fixed-hash", + "ckb-gen-types", + "ckb-hash", "ckb-merkle-mountain-range", - "ckb-occupied-capacity 0.112.1", + "ckb-occupied-capacity", "ckb-rational", "derive_more", "golomb-coded-set", @@ -569,28 +554,16 @@ dependencies = [ "paste", ] -[[package]] -name = "ckb-util" -version = "0.112.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e6326a9adcfe1f4afa14f1a0da267e5718873e28cc271a5e03fc57ff02ce233" -dependencies = [ - "linked-hash-map", - "once_cell", - "parking_lot", - "regex", -] - [[package]] name = "ckb-verification" -version = "0.112.1" +version = "0.119.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56d157e70aea7d47af07b96415c952a7d97810572c659f8da2e9ecb6f98a1c7c" +checksum = "b45211151ba0f3d949739f7e4b0bb3368064f6388022c977c2fb316373ccf5f3" dependencies = [ "ckb-chain-spec", "ckb-dao", "ckb-dao-utils", - "ckb-error 0.112.1", + "ckb-error", "ckb-pow", "ckb-script", "ckb-systemtime", @@ -599,23 +572,24 @@ dependencies = [ "ckb-verification-traits", "derive_more", "lru", + "tokio", ] [[package]] name = "ckb-verification-traits" -version = "0.112.1" +version = "0.119.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d43456c274b362c89a18388a95418f18adfebb3ab25950a09e267f00284e66fd" +checksum = "468d29a43ebacfdecb5cd5a7b9f90a9dc6fb610380a4251208e567fdcce88c0d" dependencies = [ - "bitflags", - "ckb-error 0.112.1", + "bitflags 1.3.2", + "ckb-error", ] [[package]] name = "ckb-vm" -version = "0.24.6" +version = "0.24.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc004a826b9bc9319ffae0b8415690e1b5f1482266d55fbd43843aa40ddcd63" +checksum = "ddff96029d3298cb630e95f29d4b9a93384e938a0b75758684aa8794b53bdd1a" dependencies = [ "byteorder", "bytes", @@ -631,42 +605,103 @@ dependencies = [ [[package]] name = "ckb-vm-definitions" -version = "0.24.6" +version = "0.24.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4ced3ff9d79b53d93c106720f6c1f855694290e33581850e05c859500eee83f" +checksum = "c280bf1d589d23ab0358f58601c2187fc6be86a131644583ef72ea96a0a13ddd" dependencies = [ "paste", ] +[[package]] +name = "ckb-x64-simulator" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd4734273cff42f99205f5d3b6d6673786339443ca169ed5ff85bfc69730d910" +dependencies = [ + "cc", + "ckb-mock-tx-types", + "ckb-types", + "faster-hex", + "lazy_static", + "libc", + "libloading", + "serde", + "serde_derive", + "serde_json", +] + +[[package]] +name = "ckb_schemars" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f21f99fca82a4eb8708e406e99246987b087ecc1e1babeece1a0b1d5238b1750" +dependencies = [ + "ckb_schemars_derive", + "dyn-clone", + "serde", + "serde_json", +] + +[[package]] +name = "ckb_schemars_derive" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c813b4fadbdd9f33b1cf02a1ddfa9537d955c8d2fbe150d1fc1684dbf78e73" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 1.0.109", +] + [[package]] name = "convert_case" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" +[[package]] +name = "cpufeatures" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" +dependencies = [ + "libc", +] + [[package]] name = "crc32fast" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ "cfg-if", ] [[package]] name = "crossbeam-channel" -version = "0.5.12" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" +checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] [[package]] name = "cty" @@ -676,45 +711,182 @@ checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" [[package]] name = "derive_more" -version = "0.99.17" +version = "0.99.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" dependencies = [ "convert_case", "proc-macro2", "quote", "rustc_version", - "syn 1.0.109", + "syn 2.0.70", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", ] +[[package]] +name = "dyn-clone" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" + [[package]] name = "eaglesong" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d978bd5d343e8ab9b5c0fc8d93ff9c602fdc96616ffff9c05ac7a155419b824" +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "faster-hex" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51e2ce894d53b295cf97b05685aa077950ff3e8541af83217fc720a6437169f8" +[[package]] +name = "fastrand" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" + [[package]] name = "flate2" -version = "1.0.28" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" dependencies = [ "crc32fast", "miniz_oxide", ] +[[package]] +name = "futures" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.70", +] + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + [[package]] name = "gcd" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a" +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "getrandom" version = "0.1.16" @@ -728,15 +900,21 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", "wasi 0.11.0+wasi-snapshot-preview1", ] +[[package]] +name = "gimli" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" + [[package]] name = "goblin" version = "0.2.3" @@ -786,6 +964,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + [[package]] name = "hex" version = "0.4.3" @@ -821,40 +1005,37 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.153" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] -name = "linked-hash-map" -version = "0.5.6" +name = "libloading" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" +checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ - "serde", + "cfg-if", + "windows-targets", ] [[package]] -name = "lock_api" -version = "0.4.11" +name = "linux-raw-sys" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" -dependencies = [ - "autocfg", - "scopeguard", -] +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "log" -version = "0.4.21" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "lru" @@ -867,9 +1048,18 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.2" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "memmap2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" +dependencies = [ + "libc", +] [[package]] name = "merkle-cbt" @@ -880,20 +1070,55 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "miette" +version = "5.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59bb584eaeeab6bd0226ccf3509a69d7936d148cf3d036ad350abe35e8c6856e" +dependencies = [ + "miette-derive", + "once_cell", + "thiserror", + "unicode-width", +] + +[[package]] +name = "miette-derive" +version = "5.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49e7bc1560b95a3c4a25d03de42fe76ca718ab92d1a22a55b9b4cf67b3ae635c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.70", +] + [[package]] name = "miniz_oxide" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" dependencies = [ "adler", ] +[[package]] +name = "mio" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +dependencies = [ + "hermit-abi", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.52.0", +] + [[package]] name = "molecule" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fd9767ab5e5f2ea40f71ff4c8bdb633c50509052e093c2fdd0e390a749dfa3" +checksum = "6efe1c7efcd0bdf4ca590e104bcb13087d9968956ae4ae98e92fb8c1da0f3730" dependencies = [ "bytes", "cfg-if", @@ -947,39 +1172,25 @@ dependencies = [ ] [[package]] -name = "once_cell" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "parking_lot" -version = "0.12.1" +name = "object" +version = "0.36.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" dependencies = [ - "lock_api", - "parking_lot_core", + "memchr", ] [[package]] -name = "parking_lot_core" -version = "0.9.9" +name = "once_cell" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets", -] +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "paste" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "phf" @@ -1019,6 +1230,18 @@ dependencies = [ "siphasher", ] +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + [[package]] name = "plain" version = "0.2.3" @@ -1033,9 +1256,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.81" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] @@ -1109,7 +1332,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.14", + "getrandom 0.2.15", ] [[package]] @@ -1131,65 +1354,49 @@ dependencies = [ ] [[package]] -name = "redox_syscall" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags", -] - -[[package]] -name = "regex" -version = "1.10.4" +name = "reflink-copy" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +checksum = "dc31414597d1cd7fdd2422798b7652a6329dda0fe0219e6335a13d5bcaa9aeb6" dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", + "cfg-if", + "rustix", + "windows", ] [[package]] -name = "regex-automata" -version = "0.4.6" +name = "rustc-demangle" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] -name = "regex-syntax" -version = "0.8.3" +name = "rustc_version" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" - -[[package]] -name = "run-js" -version = "0.1.0" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "ckb-gen-types 0.114.0", - "ckb-std", + "semver", ] [[package]] -name = "rustc_version" -version = "0.4.0" +name = "rustix" +version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ - "semver", + "bitflags 2.6.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", ] [[package]] name = "ryu" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "same-file" @@ -1200,12 +1407,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - [[package]] name = "scroll" version = "0.10.2" @@ -1228,59 +1429,112 @@ dependencies = [ [[package]] name = "secp256k1" -version = "0.24.3" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b1629c9c557ef9b293568b338dddfc8208c98a18c59d722a9d53f859d9c9b62" +checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113" dependencies = [ "secp256k1-sys", ] [[package]] name = "secp256k1-sys" -version = "0.6.1" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83080e2c2fc1006e625be82e5d1eb6a43b7fd9578b617fcc55814daf286bba4b" +checksum = "d4387882333d3aa8cb20530a17c69a3752e97837832f34f6dccc760e715001d9" dependencies = [ "cc", ] [[package]] name = "semver" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.198" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9846a40c979031340571da2545a4e5b7c4163bdae79b301d5f86d03979451fcc" +checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.198" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e88edab869b01783ba905e7d0153f9fc1a6505a96e4ad3018011eedb838566d9" +checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.70", +] + +[[package]] +name = "serde_derive_internals" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", ] [[package]] name = "serde_json" -version = "1.0.116" +version = "1.0.120" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813" +checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" dependencies = [ "itoa", "ryu", "serde", ] +[[package]] +name = "sha-1" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + [[package]] name = "siphasher" version = "0.3.11" @@ -1288,10 +1542,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" [[package]] -name = "smallvec" -version = "1.13.2" +name = "slab" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "ssri" +version = "9.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da7a2b3c2bc9693bcb40870c4e9b5bf0d79f9cb46273321bf855ec513e919082" +dependencies = [ + "base64", + "digest", + "hex", + "miette", + "serde", + "sha-1", + "sha2", + "thiserror", + "xxhash-rust", +] [[package]] name = "syn" @@ -1306,42 +1580,92 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.60" +version = "2.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" +checksum = "2f0209b68b3613b093e0ec905354eccaedcfe83b8cb37cbdeae64026c3064c16" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "tempfile" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" +dependencies = [ + "cfg-if", + "fastrand", + "once_cell", + "rustix", + "windows-sys 0.59.0", +] + [[package]] name = "tests" version = "0.1.0" dependencies = [ "ckb-testtool", - "hex", "serde_json", ] [[package]] name = "thiserror" -version = "1.0.58" +version = "1.0.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" +checksum = "f2675633b1499176c2dff06b0856a27976a8f9d436737b4cf4f312d4d91d8bbb" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.58" +version = "1.0.62" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d20468752b09f49e909e55a5d338caa8bedf615594e9d80bc4c565d30faf798c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.70", +] + +[[package]] +name = "tokio" +version = "1.39.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9babc99b9923bfa4804bd74722ff02c0381021eafa4db9949217e3be8e84fff5" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "pin-project-lite", + "signal-hook-registry", + "tokio-macros", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-macros" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.70", +] + +[[package]] +name = "tokio-stream" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", ] [[package]] @@ -1353,12 +1677,24 @@ dependencies = [ "serde", ] +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "unicode-width" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" + [[package]] name = "version_check" version = "0.9.4" @@ -1405,11 +1741,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" dependencies = [ - "winapi", + "windows-sys 0.52.0", ] [[package]] @@ -1418,15 +1754,98 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" +dependencies = [ + "windows-core", + "windows-targets", +] + +[[package]] +name = "windows-core" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-result", + "windows-strings", + "windows-targets", +] + +[[package]] +name = "windows-implement" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.70", +] + +[[package]] +name = "windows-interface" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.70", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + [[package]] name = "windows-targets" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", + "windows_i686_gnullvm", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", @@ -1435,42 +1854,54 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" -version = "0.48.5" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" -version = "0.48.5" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "xxhash-rust" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +checksum = "6a5cbf750400958819fb6178eaa83bee5cd9c29a26a40cc241df8c70fdd46984" diff --git a/examples/ckb-js-script/Cargo.toml b/examples/spawn-script/Cargo.toml similarity index 78% rename from examples/ckb-js-script/Cargo.toml rename to examples/spawn-script/Cargo.toml index f4055c7c5..e7f80e6a5 100644 --- a/examples/ckb-js-script/Cargo.toml +++ b/examples/spawn-script/Cargo.toml @@ -5,11 +5,13 @@ members = [ # Please don't remove the following line, we use it to automatically # detect insertion point for newly generated crates. # @@INSERTION_POINT@@ - "contracts/run-js", + "contracts/callee", + "contracts/caller", "tests", ] [profile.release] overflow-checks = true -strip = true +strip = false codegen-units = 1 +debug = true diff --git a/examples/ckb-js-script/Makefile b/examples/spawn-script/Makefile similarity index 71% rename from examples/ckb-js-script/Makefile rename to examples/spawn-script/Makefile index a8736f311..ebb24a667 100644 --- a/examples/ckb-js-script/Makefile +++ b/examples/spawn-script/Makefile @@ -6,14 +6,14 @@ TOP := $(cur_dir) # RUSTFLAGS that are likely to be tweaked by developers. For example, # while we enable debug logs by default here, some might want to strip them # for minimal code size / consumed cycles. -CUSTOM_RUSTFLAGS := --cfg debug_assertions +CUSTOM_RUSTFLAGS := -C debug-assertions # Additional cargo args to append here. For example, one can use # make test CARGO_ARGS="-- --nocapture" so as to inspect data emitted to # stdout in unit tests CARGO_ARGS := MODE := release # Tweak this to change the clang version to use for building C code. By default -# we use a bash script with some heuristics to find clang in current system. +# we use a bash script with somes heuristics to find clang in current system. CLANG := $(shell $(TOP)/scripts/find_clang) # When this is set, a single contract will be built instead of all contracts CONTRACT := @@ -23,6 +23,10 @@ CONTRACT := CLEAN_BUILD_DIR_FIRST := true BUILD_DIR := build/$(MODE) +ifeq (release,$(MODE)) + MODE_ARGS := --release +endif + # Pass setups to child make processes export CUSTOM_RUSTFLAGS export TOP @@ -44,9 +48,16 @@ build: for contract in $(wildcard contracts/*); do \ $(MAKE) -e -C $$contract build; \ done; \ + for crate in $(wildcard crates/*); do \ + cargo build -p $$(basename $$crate) $(MODE_ARGS) $(CARGO_ARGS); \ + done; \ + for sim in $(wildcard native-simulators/*); do \ + cargo build -p $$(basename $$sim) $(CARGO_ARGS); \ + done; \ else \ $(MAKE) -e -C contracts/$(CONTRACT) build; \ - fi + cargo build -p $(CONTRACT)-sim; \ + fi; # Run a single make task for a specific contract. For example: # @@ -60,11 +71,6 @@ run: test: cargo test $(CARGO_ARGS) -compile-js: - @read -p "Enter file name without .js: " js_file; \ - echo "compiling js/$$js_file.js"; \ - ckb-debugger --read-file "js/$$js_file.js" --bin deps/ckb-js-vm -- -c | awk '/Run result: 0/{{exit}} {{print}}' | xxd -r -p > js/build/$$js_file.bc - check: cargo check $(CARGO_ARGS) @@ -99,15 +105,31 @@ generate: cargo generate $(TEMPLATE_TYPE) $(TEMPLATE_REPO) $(TEMPLATE) \ --destination $(DESTINATION); \ GENERATED_DIR=$$(ls -dt $(DESTINATION)/* | head -n 1); \ + if [ -f "$$GENERATED_DIR/.cargo-generate/tests.rs" ]; then \ + cat $$GENERATED_DIR/.cargo-generate/tests.rs >> tests/src/tests.rs; \ + rm -rf $$GENERATED_DIR/.cargo-generate/; \ + fi; \ sed "s,@@INSERTION_POINT@@,@@INSERTION_POINT@@\n \"$$GENERATED_DIR\"\,," Cargo.toml > Cargo.toml.new; \ mv Cargo.toml.new Cargo.toml; \ else \ cargo generate $(TEMPLATE_TYPE) $(TEMPLATE_REPO) $(TEMPLATE) \ --destination $(DESTINATION) \ --name $(CRATE); \ + if [ -f "$(DESTINATION)/$(CRATE)/.cargo-generate/tests.rs" ]; then \ + cat $(DESTINATION)/$(CRATE)/.cargo-generate/tests.rs >> tests/src/tests.rs; \ + rm -rf $(DESTINATION)/$(CRATE)/.cargo-generate/; \ + fi; \ sed '/@@INSERTION_POINT@@/s/$$/\n "$(DESTINATION)\/$(CRATE)",/' Cargo.toml > Cargo.toml.new; \ mv Cargo.toml.new Cargo.toml; \ - fi + fi; + +generate-native-simulator: + @set -eu; \ + cargo generate $(TEMPLATE_TYPE) $(TEMPLATE_REPO) native-simulator \ + -n $(CRATE)-sim \ + --destination native-simulators; \ + sed '/@@INSERTION_POINT@@/s/$$/\n "native-simulators\/$(CRATE)-sim",/' Cargo.toml > Cargo.toml.new; \ + mv Cargo.toml.new Cargo.toml; prepare: rustup target add riscv64imac-unknown-none-elf @@ -115,6 +137,6 @@ prepare: # Generate checksum info for reproducible build CHECKSUM_FILE := build/checksums-$(MODE).txt checksum: build - sha256sum build/$(MODE)/* > $(CHECKSUM_FILE) + shasum -a 256 build/$(MODE)/* > $(CHECKSUM_FILE) -.PHONY: build test compile-js check clippy fmt cargo clean prepare checksum +.PHONY: build test check clippy fmt cargo clean prepare checksum diff --git a/examples/spawn-script/README.md b/examples/spawn-script/README.md new file mode 100644 index 000000000..5a2fceea1 --- /dev/null +++ b/examples/spawn-script/README.md @@ -0,0 +1,7 @@ +# spawn-script + +TODO: Write this readme + +*This project was bootstrapped with [ckb-script-templates].* + +[ckb-script-templates]: https://github.com/cryptape/ckb-script-templates diff --git a/examples/ckb-js-script/contracts/run-js/.gitignore b/examples/spawn-script/contracts/callee/.gitignore similarity index 100% rename from examples/ckb-js-script/contracts/run-js/.gitignore rename to examples/spawn-script/contracts/callee/.gitignore diff --git a/examples/spawn-script/contracts/callee/Cargo.toml b/examples/spawn-script/contracts/callee/Cargo.toml new file mode 100644 index 000000000..51f8fc8be --- /dev/null +++ b/examples/spawn-script/contracts/callee/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "callee" +version = "0.1.0" +edition = "2021" + +[dependencies] +ckb-std = "0.16.3" + +[features] +native-simulator = ["ckb-std/native-simulator"] diff --git a/examples/ckb-js-script/contracts/run-js/Makefile b/examples/spawn-script/contracts/callee/Makefile similarity index 81% rename from examples/ckb-js-script/contracts/run-js/Makefile rename to examples/spawn-script/contracts/callee/Makefile index 4b5b94e66..7e88d6e9f 100644 --- a/examples/ckb-js-script/contracts/run-js/Makefile +++ b/examples/spawn-script/contracts/callee/Makefile @@ -6,18 +6,20 @@ TOP := $(cur_dir) # RUSTFLAGS that are likely to be tweaked by developers. For example, # while we enable debug logs by default here, some might want to strip them # for minimal code size / consumed cycles. -CUSTOM_RUSTFLAGS := --cfg debug_assertions +CUSTOM_RUSTFLAGS := -C debug-assertions # RUSTFLAGS that are less likely to be tweaked by developers. Most likely # one would want to keep the default values here. -FULL_RUSTFLAGS := -C target-feature=+zba,+zbb,+zbc,+zbs $(CUSTOM_RUSTFLAGS) +FULL_RUSTFLAGS := -C target-feature=+zba,+zbb,+zbc,+zbs,-a $(CUSTOM_RUSTFLAGS) # Additional cargo args to append here. For example, one can use # make test CARGO_ARGS="-- --nocapture" so as to inspect data emitted to # stdout in unit tests CARGO_ARGS := MODE := release # Tweak this to change the clang version to use for building C code. By default -# we use a bash script with some heuristics to find clang in current system. +# we use a bash script with somes heuristics to find clang in current system. CLANG := $(shell $(TOP)/scripts/find_clang) +AR := $(subst clang,llvm-ar,$(CLANG)) +OBJCOPY := $(subst clang,llvm-objcopy,$(CLANG)) # When this is set to some value, the generated binaries will be copied over BUILD_DIR := # Generated binaries to copy. By convention, a Rust crate's directory name will @@ -33,13 +35,15 @@ endif default: build test build: - RUSTFLAGS="$(FULL_RUSTFLAGS)" TARGET_CC="$(CLANG)" \ + RUSTFLAGS="$(FULL_RUSTFLAGS)" TARGET_CC="$(CLANG)" TARGET_AR="$(AR)" \ cargo build --target=riscv64imac-unknown-none-elf $(MODE_ARGS) $(CARGO_ARGS) @set -eu; \ if [ "x$(BUILD_DIR)" != "x" ]; then \ for binary in $(BINARIES); do \ echo "Copying binary $$binary to build directory"; \ cp $(TOP)/target/riscv64imac-unknown-none-elf/$(MODE)/$$binary $(TOP)/$(BUILD_DIR); \ + cp $(TOP)/$(BUILD_DIR)/$$binary $(TOP)/$(BUILD_DIR)/$$binary.debug; \ + $(OBJCOPY) --strip-debug --strip-all $(TOP)/$(BUILD_DIR)/$$binary; \ done \ fi diff --git a/examples/ckb-js-script/contracts/run-js/README.md b/examples/spawn-script/contracts/callee/README.md similarity index 94% rename from examples/ckb-js-script/contracts/run-js/README.md rename to examples/spawn-script/contracts/callee/README.md index 82b7c21cf..7a6c9f217 100644 --- a/examples/ckb-js-script/contracts/run-js/README.md +++ b/examples/spawn-script/contracts/callee/README.md @@ -1,4 +1,4 @@ -# run-js +# callee TODO: Write this readme diff --git a/examples/spawn-script/contracts/callee/src/error.rs b/examples/spawn-script/contracts/callee/src/error.rs new file mode 100644 index 000000000..1a0a03500 --- /dev/null +++ b/examples/spawn-script/contracts/callee/src/error.rs @@ -0,0 +1,35 @@ +use ckb_std::error::SysError; + +#[cfg(test)] +extern crate alloc; + +#[repr(i8)] +pub enum Error { + IndexOutOfBound = 1, + ItemMissing, + LengthNotEnough, + Encoding, + WaitFailure, + InvalidFD, + OtherEndClose, + MaxVmSpawned, + MaxFdCreated, + // Add customized errors here... +} + +impl From for Error { + fn from(err: SysError) -> Self { + match err { + SysError::IndexOutOfBound => Self::IndexOutOfBound, + SysError::ItemMissing => Self::ItemMissing, + SysError::LengthNotEnough(_) => Self::LengthNotEnough, + SysError::Encoding => Self::Encoding, + SysError::WaitFailure => Self::WaitFailure, + SysError::InvalidFd => Self::InvalidFD, + SysError::OtherEndClosed => Self::OtherEndClose, + SysError::MaxVmsSpawned => Self::MaxVmSpawned, + SysError::MaxFdsCreated => Self::MaxFdCreated, + SysError::Unknown(err_code) => panic!("unexpected sys error {}", err_code), + } + } +} diff --git a/examples/spawn-script/contracts/callee/src/lib.rs b/examples/spawn-script/contracts/callee/src/lib.rs new file mode 100644 index 000000000..7b58725d6 --- /dev/null +++ b/examples/spawn-script/contracts/callee/src/lib.rs @@ -0,0 +1,7 @@ +#![cfg_attr(not(feature = "native-simulator"), no_std)] +#![allow(special_module_name)] +#![allow(unused_attributes)] +#[cfg(feature = "native-simulator")] +mod main; +#[cfg(feature = "native-simulator")] +pub use main::program_entry; diff --git a/examples/spawn-script/contracts/callee/src/main.rs b/examples/spawn-script/contracts/callee/src/main.rs new file mode 100644 index 000000000..11a8869e9 --- /dev/null +++ b/examples/spawn-script/contracts/callee/src/main.rs @@ -0,0 +1,35 @@ +#![cfg_attr(not(any(feature = "native-simulator", test)), no_std)] +#![cfg_attr(not(test), no_main)] + +#[cfg(any(feature = "native-simulator", test))] +extern crate alloc; + +#[cfg(not(any(feature = "native-simulator", test)))] +ckb_std::entry!(program_entry); +#[cfg(not(any(feature = "native-simulator", test)))] +ckb_std::default_alloc!(); + +mod error; +use alloc::vec; + +pub fn program_entry() -> i8 { + ckb_std::debug!("Enter callee contract!"); + + match callee() { + Ok(_) => 0, + Err(err) => err as i8, + } +} + +pub fn callee() -> Result<(), error::Error> { + let argv = ckb_std::env::argv(); + let mut to_parent_fds: [u64; 2] = [0; 2]; + ckb_std::syscalls::inherited_fds(&mut to_parent_fds); + let mut out = vec![]; + for arg in argv { + out.extend_from_slice(arg.to_bytes()); + } + let len = ckb_std::syscalls::write(to_parent_fds[1], &out)?; + assert_eq!(len, 10); + Ok(()) +} diff --git a/examples/spawn-script/contracts/caller/.gitignore b/examples/spawn-script/contracts/caller/.gitignore new file mode 100644 index 000000000..c3dca1b96 --- /dev/null +++ b/examples/spawn-script/contracts/caller/.gitignore @@ -0,0 +1,2 @@ +/build +/target diff --git a/examples/spawn-script/contracts/caller/Cargo.toml b/examples/spawn-script/contracts/caller/Cargo.toml new file mode 100644 index 000000000..6725ee6fc --- /dev/null +++ b/examples/spawn-script/contracts/caller/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "caller" +version = "0.1.0" +edition = "2021" + +[dependencies] +ckb-std = "0.16.3" + +[features] +native-simulator = ["ckb-std/native-simulator"] diff --git a/examples/spawn-script/contracts/caller/Makefile b/examples/spawn-script/contracts/caller/Makefile new file mode 100644 index 000000000..7e88d6e9f --- /dev/null +++ b/examples/spawn-script/contracts/caller/Makefile @@ -0,0 +1,80 @@ +# We cannot use $(shell pwd), which will return unix path format on Windows, +# making it hard to use. +cur_dir = $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) + +TOP := $(cur_dir) +# RUSTFLAGS that are likely to be tweaked by developers. For example, +# while we enable debug logs by default here, some might want to strip them +# for minimal code size / consumed cycles. +CUSTOM_RUSTFLAGS := -C debug-assertions +# RUSTFLAGS that are less likely to be tweaked by developers. Most likely +# one would want to keep the default values here. +FULL_RUSTFLAGS := -C target-feature=+zba,+zbb,+zbc,+zbs,-a $(CUSTOM_RUSTFLAGS) +# Additional cargo args to append here. For example, one can use +# make test CARGO_ARGS="-- --nocapture" so as to inspect data emitted to +# stdout in unit tests +CARGO_ARGS := +MODE := release +# Tweak this to change the clang version to use for building C code. By default +# we use a bash script with somes heuristics to find clang in current system. +CLANG := $(shell $(TOP)/scripts/find_clang) +AR := $(subst clang,llvm-ar,$(CLANG)) +OBJCOPY := $(subst clang,llvm-objcopy,$(CLANG)) +# When this is set to some value, the generated binaries will be copied over +BUILD_DIR := +# Generated binaries to copy. By convention, a Rust crate's directory name will +# likely match the crate name, which is also the name of the final binary. +# However if this is not the case, you can tweak this variable. As the name hints, +# more than one binary is supported here. +BINARIES := $(notdir $(shell pwd)) + +ifeq (release,$(MODE)) + MODE_ARGS := --release +endif + +default: build test + +build: + RUSTFLAGS="$(FULL_RUSTFLAGS)" TARGET_CC="$(CLANG)" TARGET_AR="$(AR)" \ + cargo build --target=riscv64imac-unknown-none-elf $(MODE_ARGS) $(CARGO_ARGS) + @set -eu; \ + if [ "x$(BUILD_DIR)" != "x" ]; then \ + for binary in $(BINARIES); do \ + echo "Copying binary $$binary to build directory"; \ + cp $(TOP)/target/riscv64imac-unknown-none-elf/$(MODE)/$$binary $(TOP)/$(BUILD_DIR); \ + cp $(TOP)/$(BUILD_DIR)/$$binary $(TOP)/$(BUILD_DIR)/$$binary.debug; \ + $(OBJCOPY) --strip-debug --strip-all $(TOP)/$(BUILD_DIR)/$$binary; \ + done \ + fi + +# test, check, clippy and fmt here are provided for completeness, +# there is nothing wrong invoking cargo directly instead of make. +test: + cargo test $(CARGO_ARGS) + +check: + cargo check $(CARGO_ARGS) + +clippy: + cargo clippy $(CARGO_ARGS) + +fmt: + cargo fmt $(CARGO_ARGS) + +# Arbitrary cargo command is supported here. For example: +# +# make cargo CARGO_CMD=expand CARGO_ARGS="--ugly" +# +# Invokes: +# cargo expand --ugly +CARGO_CMD := +cargo: + cargo $(CARGO_CMD) $(CARGO_ARGS) + +clean: + cargo clean + +prepare: + rustup target add riscv64imac-unknown-none-elf + +.PHONY: build test check clippy fmt cargo clean prepare diff --git a/examples/spawn-script/contracts/caller/README.md b/examples/spawn-script/contracts/caller/README.md new file mode 100644 index 000000000..59c5a74e7 --- /dev/null +++ b/examples/spawn-script/contracts/caller/README.md @@ -0,0 +1,7 @@ +# caller + +TODO: Write this readme + +*This contract was bootstrapped with [ckb-script-templates].* + +[ckb-script-templates]: https://github.com/cryptape/ckb-script-templates diff --git a/examples/spawn-script/contracts/caller/src/error.rs b/examples/spawn-script/contracts/caller/src/error.rs new file mode 100644 index 000000000..1a0a03500 --- /dev/null +++ b/examples/spawn-script/contracts/caller/src/error.rs @@ -0,0 +1,35 @@ +use ckb_std::error::SysError; + +#[cfg(test)] +extern crate alloc; + +#[repr(i8)] +pub enum Error { + IndexOutOfBound = 1, + ItemMissing, + LengthNotEnough, + Encoding, + WaitFailure, + InvalidFD, + OtherEndClose, + MaxVmSpawned, + MaxFdCreated, + // Add customized errors here... +} + +impl From for Error { + fn from(err: SysError) -> Self { + match err { + SysError::IndexOutOfBound => Self::IndexOutOfBound, + SysError::ItemMissing => Self::ItemMissing, + SysError::LengthNotEnough(_) => Self::LengthNotEnough, + SysError::Encoding => Self::Encoding, + SysError::WaitFailure => Self::WaitFailure, + SysError::InvalidFd => Self::InvalidFD, + SysError::OtherEndClosed => Self::OtherEndClose, + SysError::MaxVmsSpawned => Self::MaxVmSpawned, + SysError::MaxFdsCreated => Self::MaxFdCreated, + SysError::Unknown(err_code) => panic!("unexpected sys error {}", err_code), + } + } +} diff --git a/examples/spawn-script/contracts/caller/src/lib.rs b/examples/spawn-script/contracts/caller/src/lib.rs new file mode 100644 index 000000000..7b58725d6 --- /dev/null +++ b/examples/spawn-script/contracts/caller/src/lib.rs @@ -0,0 +1,7 @@ +#![cfg_attr(not(feature = "native-simulator"), no_std)] +#![allow(special_module_name)] +#![allow(unused_attributes)] +#[cfg(feature = "native-simulator")] +mod main; +#[cfg(feature = "native-simulator")] +pub use main::program_entry; diff --git a/examples/spawn-script/contracts/caller/src/main.rs b/examples/spawn-script/contracts/caller/src/main.rs new file mode 100644 index 000000000..66aa0c8dd --- /dev/null +++ b/examples/spawn-script/contracts/caller/src/main.rs @@ -0,0 +1,62 @@ +#![cfg_attr(not(any(feature = "native-simulator", test)), no_std)] +#![cfg_attr(not(test), no_main)] + +#[cfg(any(feature = "native-simulator", test))] +extern crate alloc; + +#[cfg(not(any(feature = "native-simulator", test)))] +ckb_std::entry!(program_entry); +#[cfg(not(any(feature = "native-simulator", test)))] +ckb_std::default_alloc!(); + +mod error; +use ckb_std::syscalls::SpawnArgs; +use core::ffi::CStr; + +pub fn program_entry() -> i8 { + ckb_std::debug!("Enter caller contract!"); + + match caller() { + Ok(_) => 0, + Err(err) => err as i8, + } +} + +fn caller() -> Result<(), error::Error> { + let (r1, w1) = ckb_std::syscalls::pipe()?; + let (r2, w2) = ckb_std::syscalls::pipe()?; + let to_parent_fds: [u64; 2] = [r1, w2]; + let to_child_fds: [u64; 3] = [r2, w1, 0]; // must ends with 0 + + let mut pid: u64 = 0; + let place = 0; // 0 means read from cell data + let bounds = 0; // 0 means read to end + let argc: u64 = 2; + let argv = [ + CStr::from_bytes_with_nul(b"hello\0").unwrap().as_ptr(), + CStr::from_bytes_with_nul(b"world\0").unwrap().as_ptr(), + ]; + let mut spgs: SpawnArgs = SpawnArgs { + argc, + argv: argv.as_ptr(), + process_id: &mut pid as *mut u64, + inherited_fds: to_child_fds.as_ptr(), + }; + ckb_std::syscalls::spawn( + 0, + ckb_std::ckb_constants::Source::CellDep, + place, + bounds, + &mut spgs, + )?; + + let mut buf = [0; 256]; + let len = ckb_std::syscalls::read(to_parent_fds[0], &mut buf)?; + assert_eq!(len, 10); + buf[len] = 0; + assert_eq!( + CStr::from_bytes_until_nul(&buf).unwrap().to_str().unwrap(), + "helloworld" + ); + Ok(()) +} diff --git a/examples/ckb-js-script/scripts/find_clang b/examples/spawn-script/scripts/find_clang similarity index 86% rename from examples/ckb-js-script/scripts/find_clang rename to examples/spawn-script/scripts/find_clang index 6994c9a49..f1ffeed4c 100755 --- a/examples/ckb-js-script/scripts/find_clang +++ b/examples/spawn-script/scripts/find_clang @@ -7,7 +7,7 @@ if [[ -n "${CLANG}" ]]; then exit 0 fi -CANDIDATES=("clang" "clang-16" "clang-17") +CANDIDATES=("clang" "clang-16" "clang-17" "clang-18") BREW_PREFIX=$(brew --prefix 2> /dev/null) if [[ -n "${BREW_PREFIX}" ]]; then @@ -15,6 +15,7 @@ if [[ -n "${BREW_PREFIX}" ]]; then "${BREW_PREFIX}/opt/llvm/bin/clang" "${BREW_PREFIX}/opt/llvm@16/bin/clang" "${BREW_PREFIX}/opt/llvm@17/bin/clang" + "${BREW_PREFIX}/opt/llvm@18/bin/clang" ) fi diff --git a/examples/spawn-script/scripts/reproducible_build_docker b/examples/spawn-script/scripts/reproducible_build_docker new file mode 100755 index 000000000..fdf35ad84 --- /dev/null +++ b/examples/spawn-script/scripts/reproducible_build_docker @@ -0,0 +1,66 @@ +#!/usr/bin/env bash +# +# An utility script helping with reproducible script builds via docker. +# Note that this utility serves only as one example, docker is not +# necessarily THE way to do reproducible build, nor is it the best way +# to do reproducible build. +set -ex + +DOCKER="${DOCKER:-docker}" +# docker pull docker.io/cryptape/llvm-n-rust:20240630 +DOCKER_IMAGE="${DOCKER_IMAGE:-docker.io/cryptape/llvm-n-rust@sha256:bafaf76d4f342a69b8691c08e77a330b7740631f3d1d9c9bee4ead521b29ee55}" +CHECKSUM_FILE_PATH="${CHECKSUM_FILE_PATH:-checksums.txt}" + +# We are parsing command line arguments based on tips from: +# https://stackoverflow.com/a/14203146 + +while [[ $# -gt 0 ]]; do + case $1 in + -p|--proxy) + PROXY="$2" + shift # past argument + shift # past value + ;; + -u|--update) + UPDATE="yes" + shift # past argument + ;; + --no-clean) + NOCLEAN="yes" + shift # past argument + ;; + -*|--*) + echo "Unknown option $1" + exit 1 + ;; + *) + echo "Unknown argument $1" + exit 1 + ;; + esac +done + +if [[ -n "${PROXY}" ]]; then + DOCKER_RUN_ARGS="-e ALL_PROXY=${PROXY} -e HTTPS_PROXY=${PROXY} -e HTTP_PROXY=${PROXY} ${DOCKER_RUN_ARGS}" +fi + +TASKS="" +if [[ "${NOCLEAN}" != "yes" ]]; then + TASKS+=" clean " +fi + +if [[ "${UPDATE}" = "yes" ]]; then + TASKS+=" checksum CHECKSUM_FILE=${CHECKSUM_FILE_PATH} " +else + TASKS+=" build " +fi + +$DOCKER run --rm $DOCKER_RUN_ARGS -v `pwd`:/code $DOCKER_IMAGE make $TASKS +# Reset file ownerships for all files docker might touch +$DOCKER run --rm $DOCKER_RUN_ARGS -e UID=`id -u` -e GID=`id -g` -v `pwd`:/code $DOCKER_IMAGE bash -c 'chown -R -f $UID:$GID checksums.txt build target' + +if [[ "${UPDATE}" = "yes" ]]; then + echo "${CHECKSUM_FILE_PATH} file is updated with latest binary hashes!" +else + shasum -a 256 -c ${CHECKSUM_FILE_PATH} +fi diff --git a/examples/spawn-script/tests/Cargo.toml b/examples/spawn-script/tests/Cargo.toml new file mode 100644 index 000000000..c749f2d5b --- /dev/null +++ b/examples/spawn-script/tests/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "tests" +version = "0.1.0" +edition = "2021" + +[features] +native-simulator = [ "ckb-testtool/native-simulator" ] + +[dependencies] +ckb-testtool = "0.14.0" +serde_json = "1.0" diff --git a/examples/ckb-js-script/tests/src/lib.rs b/examples/spawn-script/tests/src/lib.rs similarity index 100% rename from examples/ckb-js-script/tests/src/lib.rs rename to examples/spawn-script/tests/src/lib.rs diff --git a/examples/spawn-script/tests/src/tests.rs b/examples/spawn-script/tests/src/tests.rs new file mode 100644 index 000000000..0587bcaad --- /dev/null +++ b/examples/spawn-script/tests/src/tests.rs @@ -0,0 +1,75 @@ +use crate::Loader; +use ckb_testtool::ckb_types::{ + bytes::Bytes, + core::TransactionBuilder, + packed::*, + prelude::*, +}; +use ckb_testtool::context::Context; + +// Include your tests here +// See https://github.com/xxuejie/ckb-native-build-sample/blob/main/tests/src/tests.rs for more examples + +// generated unit test for contract caller +#[test] +fn test_spawn() { + // deploy contract + let mut context = Context::default(); + let caller_contract_bin: Bytes = Loader::default().load_binary("caller"); + let caller_out_point = context.deploy_cell(caller_contract_bin); + let callee_contract_bin: Bytes = Loader::default().load_binary("callee"); + let callee_out_point = context.deploy_cell(callee_contract_bin); + + // prepare scripts + let lock_script = context + .build_script(&caller_out_point, Bytes::from(vec![42])) + .expect("script"); + + // prepare cells + let input_out_point = context.create_cell( + CellOutput::new_builder() + .capacity(1000u64.pack()) + .lock(lock_script.clone()) + .build(), + Bytes::new(), + ); + let input = CellInput::new_builder() + .previous_output(input_out_point) + .build(); + let outputs = vec![ + CellOutput::new_builder() + .capacity(500u64.pack()) + .lock(lock_script.clone()) + .build(), + CellOutput::new_builder() + .capacity(500u64.pack()) + .lock(lock_script) + .build(), + ]; + + let outputs_data = vec![Bytes::new(); 2]; + + // prepare cell deps + let callee_dep = CellDep::new_builder() + .out_point(callee_out_point) + .build(); + let caller_dep = CellDep::new_builder() + .out_point(caller_out_point) + .build(); + let cell_deps: Vec = vec![callee_dep, caller_dep]; + + // build transaction + let tx = TransactionBuilder::default() + .input(input) + .outputs(outputs) + .outputs_data(outputs_data.pack()) + .cell_deps(cell_deps) + .build(); + let tx = context.complete_tx(tx); + + // run + let cycles = context + .verify_tx(&tx, 10_000_000) + .expect("pass verification"); + println!("consume cycles: {}", cycles); +} diff --git a/examples/store-data-on-cell/offckb/system-scripts.json b/examples/store-data-on-cell/offckb/system-scripts.json index 1c3b2e0c5..c2ac800dc 100644 --- a/examples/store-data-on-cell/offckb/system-scripts.json +++ b/examples/store-data-on-cell/offckb/system-scripts.json @@ -110,6 +110,15 @@ }, "depType": "code" } + }, + { + "cellDep": { + "outPoint": { + "txHash": "0x75be96e1871693f030db27ddae47890a28ab180e88e36ebb3575d9f1377d3da7", + "index": 0 + }, + "depType": "depGroup" + } } ] } @@ -287,7 +296,6 @@ }, "secp256k1_blake160_multisig_all": { "name": "secp256k1_blake160_multisig_all", - "file": "Bundled(specs/cells/secp256k1_blake160_multisig_all)", "script": { "codeHash": "0x5c5069eb0857efc65e1bca0c07df34c31663b3622fd3876c876320fc9634e2a8", "hashType": "type", @@ -335,6 +343,11 @@ "index": 0 }, "depType": "code" + }, + "type": { + "codeHash": "0x00000000000000000000000000000000000000000000000000545950455f4944", + "hashType": "type", + "args": "0x44ec8b96663e06cc94c8c468a4d46d7d9af69eaf418f6390c9f11bb763dda0ae" } } ] @@ -346,6 +359,15 @@ "codeHash": "0xf329effd1c475a2978453c8600e1eaf0bc2087ee093c3ee64cc96ec6847752cb", "hashType": "type", "cellDeps": [ + { + "cellDep": { + "outPoint": { + "txHash": "0xf8de3bb47d055cdf460d93a2a6e1b05f7432f9777c8c474abf4eec1d4aee5d37", + "index": 0 + }, + "depType": "depGroup" + } + }, { "cellDep": { "outPoint": { @@ -353,6 +375,11 @@ "index": 0 }, "depType": "code" + }, + "type": { + "codeHash": "0x00000000000000000000000000000000000000000000000000545950455f4944", + "hashType": "type", + "args": "0x761f51fc9cd6a504c32c6ae64b3746594d1af27629b427c5ccf6c9a725a89144" } } ] @@ -564,6 +591,15 @@ "codeHash": "0x9b819793a64463aed77c615d6cb226eea5487ccfc0783043a587254cda2b6f26", "hashType": "type", "cellDeps": [ + { + "cellDep": { + "outPoint": { + "txHash": "0x71a7ba8fc96349fea0ed3a5c47992e3b4084b031a42264a018e0072e8172e46c", + "index": 0 + }, + "depType": "depGroup" + } + }, { "cellDep": { "outPoint": { @@ -571,6 +607,11 @@ "index": 0 }, "depType": "code" + }, + "type": { + "codeHash": "0x00000000000000000000000000000000000000000000000000545950455f4944", + "hashType": "type", + "args": "0x855508fe0f0ca25b935b070452ecaee48f6c9f1d66cd15f046616b99e948236a" } } ] diff --git a/examples/xudt/offckb/system-scripts.json b/examples/xudt/offckb/system-scripts.json index 1c3b2e0c5..c2ac800dc 100644 --- a/examples/xudt/offckb/system-scripts.json +++ b/examples/xudt/offckb/system-scripts.json @@ -110,6 +110,15 @@ }, "depType": "code" } + }, + { + "cellDep": { + "outPoint": { + "txHash": "0x75be96e1871693f030db27ddae47890a28ab180e88e36ebb3575d9f1377d3da7", + "index": 0 + }, + "depType": "depGroup" + } } ] } @@ -287,7 +296,6 @@ }, "secp256k1_blake160_multisig_all": { "name": "secp256k1_blake160_multisig_all", - "file": "Bundled(specs/cells/secp256k1_blake160_multisig_all)", "script": { "codeHash": "0x5c5069eb0857efc65e1bca0c07df34c31663b3622fd3876c876320fc9634e2a8", "hashType": "type", @@ -335,6 +343,11 @@ "index": 0 }, "depType": "code" + }, + "type": { + "codeHash": "0x00000000000000000000000000000000000000000000000000545950455f4944", + "hashType": "type", + "args": "0x44ec8b96663e06cc94c8c468a4d46d7d9af69eaf418f6390c9f11bb763dda0ae" } } ] @@ -346,6 +359,15 @@ "codeHash": "0xf329effd1c475a2978453c8600e1eaf0bc2087ee093c3ee64cc96ec6847752cb", "hashType": "type", "cellDeps": [ + { + "cellDep": { + "outPoint": { + "txHash": "0xf8de3bb47d055cdf460d93a2a6e1b05f7432f9777c8c474abf4eec1d4aee5d37", + "index": 0 + }, + "depType": "depGroup" + } + }, { "cellDep": { "outPoint": { @@ -353,6 +375,11 @@ "index": 0 }, "depType": "code" + }, + "type": { + "codeHash": "0x00000000000000000000000000000000000000000000000000545950455f4944", + "hashType": "type", + "args": "0x761f51fc9cd6a504c32c6ae64b3746594d1af27629b427c5ccf6c9a725a89144" } } ] @@ -564,6 +591,15 @@ "codeHash": "0x9b819793a64463aed77c615d6cb226eea5487ccfc0783043a587254cda2b6f26", "hashType": "type", "cellDeps": [ + { + "cellDep": { + "outPoint": { + "txHash": "0x71a7ba8fc96349fea0ed3a5c47992e3b4084b031a42264a018e0072e8172e46c", + "index": 0 + }, + "depType": "depGroup" + } + }, { "cellDep": { "outPoint": { @@ -571,6 +607,11 @@ "index": 0 }, "depType": "code" + }, + "type": { + "codeHash": "0x00000000000000000000000000000000000000000000000000545950455f4944", + "hashType": "type", + "args": "0x855508fe0f0ca25b935b070452ecaee48f6c9f1d66cd15f046616b99e948236a" } } ] diff --git a/website/docs/dapp/TutorialOverview.tsx b/website/docs/dapp/TutorialOverview.tsx deleted file mode 100644 index f3cab499a..000000000 --- a/website/docs/dapp/TutorialOverview.tsx +++ /dev/null @@ -1,283 +0,0 @@ -import Link from "@docusaurus/Link"; -import { TutorialHeaderProps } from "@site/src/components/TutorialHeader"; - -const TRANSFEROVERVIEW: TutorialHeaderProps = { - time: "2 - 5 min", - topics: [ - { label: "Cell Model", link: "/docs/tech-explanation/cell-model" }, - { - label: "Transaction", - link: "/docs/tech-explanation/glossary#transaction", - }, - { label: "Witness", link: "/docs/tech-explanation/glossary#witness" }, - { - label: "Signature", - link: "/docs/tech-explanation/glossary#cryptographic-signature", - }, - ], - tools: [ -
An IDE/Editor that supports TypeScript
, -
- - Node.js - - {" and "} - - Yarn - {" "} - With{" "} - - CCC - {" "} - Javascript SDK -
, -
- CKB dev environment:{" "} - - OffCKB - - {", version >= "} - - v0.3.0-rc2 - -
, - ], -}; -const WRITEOVERVIEW: TutorialHeaderProps = { - time: "2 - 5 min", - topics: [ - { label: "Cell Model", link: "/docs/tech-explanation/cell-model" }, - { label: "Data", link: "/docs/tech-explanation/glossary#data" }, - { - label: "Transaction Hash", - link: "/docs/tech-explanation/glossary#transaction-hash", - }, - ], - tools: [ -
An IDE/Editor that supports TypeScript
, -
- - Node.js - - {" and "} - - Yarn - {" "} - With{" "} - - CCC - {" "} - Javascript SDK -
, -
- CKB dev environment:{" "} - - OffCKB - - {", version >= "} - - v0.3.0-rc2 - -
, - ], -}; -const TOKENOVERVIEW: TutorialHeaderProps = { - time: "5 - 10 min", - topics: [ - { label: "UDT", link: "/docs/tech-explanation/glossary#udt" }, - { - label: "Fungible Token", - link: "/docs/tech-explanation/glossary#fungible-token", - }, - { - label: "xUDT", - link: "https://github.com/XuJiandong/rfcs/blob/xudt/rfcs/0052-extensible-udt/0052-extensible-udt.md", - }, - ], - tools: [ -
An IDE/Editor that supports TypeScript
, -
- - Node.js - - {" and "} - - Yarn - {" "} - With{" "} - - CCC - {" "} - Javascript SDK -
, -
- CKB dev environment:{" "} - - OffCKB - - {", version >= "} - - v0.3.0-rc2 - -
, - ], -}; -const DOBOVERVIEW: TutorialHeaderProps = { - time: "5 - 10 min", - topics: [ - { - label: "DOB", - link: "/docs/tech-explanation/glossary#digital-object-dob", - }, - { - label: "NFT", - link: "/docs/tech-explanation/glossary#non-fungible-token", - }, - { label: "Spore Protocol", link: "https://spore.pro" }, - ], - tools: [ -
An IDE/Editor that supports TypeScript
, -
- - Node.js - - {" and "} - - Yarn - {" "} - With{" "} - - CCC - {" "} - Javascript SDK -
, -
- CKB dev environment:{" "} - - OffCKB - - {", version >= "} - - v0.3.0-rc2 - -
, - ], -}; - -const LOCKOVERVIEW: TutorialHeaderProps = { - time: "10 - 15 min", - topics: [ - { - label: "Full-Stack", - link: "/docs/getting-started/quick-start#dapp-project-structure", - }, - { - label: "Lock Script", - link: "/docs/tech-explanation/glossary#lock-script", - }, - { - label: "Witness", - link: "/docs/tech-explanation/glossary#witness", - }, - { - label: "Cryptographic hash function", - link: "https://en.wikipedia.org/wiki/Cryptographic_hash_function", - }, - ], - tools: [ -
An IDE/Editor that supports TypeScript
, -
- - Node.js - - {" and "} - - Yarn - {" "} - With{" "} - - CCC - {" "} - Javascript SDK -
, -
- CKB dev environment:{" "} - - OffCKB - - {", version >= "} - - v0.3.0-rc2 - -
, -
Script develop tools
, - ], -}; - -export { - TRANSFEROVERVIEW, - WRITEOVERVIEW, - TOKENOVERVIEW, - DOBOVERVIEW, - LOCKOVERVIEW, -}; diff --git a/website/docs/dapp/create-dob.mdx b/website/docs/dapp/create-dob.mdx index 6011521ef..6cabf57f6 100644 --- a/website/docs/dapp/create-dob.mdx +++ b/website/docs/dapp/create-dob.mdx @@ -7,21 +7,16 @@ import Tabs from "@theme/Tabs"; import TabItem from "@theme/TabItem"; import TutorialHeader from "@components/TutorialHeader"; import Tooltip from "@components/Tooltip"; -import { DOBOVERVIEW } from "./TutorialOverview.tsx"; import SetupProject from "./SetupProject.tsx"; import SwitchToTestnet from "./_SwitchToTestnet.mdx"; # Create a Digital Object Using Spore Protocol - + -## Spore Protocol on CKB +## Tutorial Overview -Spore is an on-chain digital object (DOB) protocol backed by CKB. An "on-chain" asset refers to a digital asset whose data is directly encoded onto the blockchain. A Spore Cell can hold any type of assets users want to store on-chain, the following data structure is used in the Spore Cell: +Spore is an on-chain digital object (DOB) protocol backed by CKB. An “on-chain” asset refers to a digital asset with its data directly encoded on the blockchain. A Spore Cell can hold any type of asset users want to store on-chain. The data structure for a Spore Cell is as follows: ```js data: @@ -37,9 +32,9 @@ lock: ``` -Notice that the data field of the Spore Cell contains `content-type` and `content`, which allow users to turn any content form into a digital object. All the fields in a Spore Cell are immutable once created. +Notice that the data field of the Spore Cell contains `content-type` and `content`, which allow users to transform any content into a digital object. All fields in a Spore Cell are immutable once created. -In this tutorial, we will build a simple dApp to turn a picture on your computer into a digital object on the blockchain using the Spore SDK. +In this tutorial, you will learn how to build a simple dApp using the Spore SDK that converts a picture on your computer into a digital object on the blockchain. ## Setup Devnet & Run Example diff --git a/website/docs/dapp/create-token.mdx b/website/docs/dapp/create-token.mdx index 6f594cebf..3fedb9881 100644 --- a/website/docs/dapp/create-token.mdx +++ b/website/docs/dapp/create-token.mdx @@ -7,33 +7,26 @@ import Tabs from "@theme/Tabs"; import TabItem from "@theme/TabItem"; import TutorialHeader from "@components/TutorialHeader"; import Tooltip from "@components/Tooltip"; -import { TOKENOVERVIEW } from "./TutorialOverview.tsx"; import SetupProject from "./SetupProject.tsx"; import SwitchToTestnet from "./_SwitchToTestnet.mdx"; # Create a Fungible Token - + -## Custom Token on CKB +## Tutorial Overview -Different from [ERC20(Ethereum)](https://eips.ethereum.org/EIPS/eip-20) and [BRC20(Bitcoin)](https://www.brc-20.io/), CKB uses a unique way to build custom tokens based on the UTXO-like Cell Model. +Unlike [ERC20(Ethereum)](https://eips.ethereum.org/EIPS/eip-20) and [BRC20(Bitcoin)](https://www.brc-20.io/), CKB uses a unique way to build custom tokens based on its UTXO-like Cell Model. -In CKB, custom tokens are called User-Defined-Token, aka UDT. The core team of CKB has proposed a minimal standard for UDT called xUDT(extensible UDT). In this tutorial, we will use the pre-deployed Script `xUDT script` to issue custom tokens. +In CKB, custom tokens are called User-Defined Tokens (UDTs). CKB's core team has proposed a minimal standard for UDT called xUDT(extensible UDT). In this tutorial, you will learn how to issue custom tokens using the pre-deployed `xUDT Script`. -The high-level workflow to issue a custom token with xUDT goes like this: +Steps to Issue a Custom Token with xUDT: -When you issue a token, you create a special Cell that presents some balance of your token, like a piece of printed cash to the dollars. +1. Create a Special Cell: When you issue tokens, you create a special Cell representing a balance of your custom token, similar to how physical cash represents a balance of currency. +2. Configure the Cell's Data: This Cell’s data field will store the token amount, while its Type Script will be the xUDT Script. The script’s args field will contain the Lock Script Hash of the issuer. +3. Establish a Unique Token ID: The issuer’s Lock Script hash serves as the unique identifier for each custom token. Different Lock Script hashes represent different tokens, enabling secure and distinct transactions for each token type. -For this special Cell, its data field contains the amount of the token and its Type Script is xUDT Script where the args of that Script will be the issuer's Lock Script Hash. - -This issuer's Lock Script Hash works like the unique ID for the custom token. Different Lock Script Hash means a different kind of token. It is also used as a checkpoint to tell that a transaction is triggered by the token issuer or a regular token holder to apply different security validation. - -In reality, xUDT is more complicated and powerful with many features but the idea is the same, you can check the [full specs here](https://github.com/XuJiandong/rfcs/blob/xudt/rfcs/0052-extensible-udt/0052-extensible-udt.md). +While xUDT includes more advanced features, this tutorial focuses on its core concept. For more details on xUDT’s capabilities, you can explore the [full xUDT spec](https://github.com/XuJiandong/rfcs/blob/xudt/rfcs/0052-extensible-udt/0052-extensible-udt.md). ## Setup Devnet & Run Example diff --git a/website/docs/dapp/simple-lock.mdx b/website/docs/dapp/simple-lock.mdx index 472f6900c..d158877da 100644 --- a/website/docs/dapp/simple-lock.mdx +++ b/website/docs/dapp/simple-lock.mdx @@ -6,7 +6,6 @@ title: Build a Simple Lock import Tabs from "@theme/Tabs"; import TabItem from "@theme/TabItem"; import TutorialHeader from "@components/TutorialHeader"; -import { LOCKOVERVIEW } from "./TutorialOverview.tsx"; import SwitchToTestnet from "./_SwitchToTestnet.mdx"; import StartDevnet from "./_StartDevnet.mdx"; import useBaseUrl from "@docusaurus/useBaseUrl"; @@ -16,20 +15,18 @@ import CodeTabs from "./_CodeTabs.mdx"; # Build a Simple Lock - + + +## Tutorial Overview -In this tutorial, we'll show you how to create a full-stack dApp, including both the frontend and the Script, to help you better understand CKB blockchain development. +In this tutorial, you will learn how to create a full-stack dApp, including both the frontend and the Script, to deepen your understanding of CKB blockchain development. -Our example dApp will use a simple toy lock. We'll create a Lock Script named `hash_lock` to secure some CKB tokens and build a web interface for users to transfer tokens from this `hash_lock`. +Our example dApp will use a simple toy lock. You will create a Lock Script named `hash_lock` to secure some CKB tokens and build a web interface for users to transfer tokens from this `hash_lock`. -The `hash_lock` project involves specifying a hash in the Script's script_args. To unlock it, users must provide the preimage that matches the hash. +The `hash_lock` project involves specifying a hash in the Script's script_args. To unlock it, users must provide the preimage that matches this hash. :::note -This toy lock example isn't intended for production, You should ONLY use it in Testnet as an starting point for learning the basics. +This toy lock example isn't intended for production. Use it ONLY n Testnet as an starting point for learning the basics. ::: ## Setup Devnet & Run Example diff --git a/website/docs/dapp/transfer-ckb.mdx b/website/docs/dapp/transfer-ckb.mdx index 5811653c8..7547955b6 100644 --- a/website/docs/dapp/transfer-ckb.mdx +++ b/website/docs/dapp/transfer-ckb.mdx @@ -7,23 +7,20 @@ import Tabs from "@theme/Tabs"; import TabItem from "@theme/TabItem"; import TutorialHeader from "@components/TutorialHeader"; import Tooltip from "@components/Tooltip"; -import { TRANSFEROVERVIEW } from "./TutorialOverview.tsx"; import SetupProject from "./SetupProject.tsx"; import SwitchToTestnet from "./_SwitchToTestnet.mdx"; # View and Transfer a CKB Balance - + + +## Tutorial Overview CKB is based on a UTXO-like Cell Model. Every Cell has a capacity limit, which represents both the CKB balance and how much data can be stored in the Cell simultaneously. -Transfering balance in CKB involves consuming some input Cells from the sender's account and producing new output Cells which can be unlocked by the receiver's account. The amount transferred is equal to the total capacities of the coverting Cells. +Transferring balance in CKB involves consuming some input Cells from the sender's account and producing new output Cells which can be unlocked by the receiver's account. The amount transferred is equal to the total capacity of the consumed Cells. -In this tutorial, we will learn how to write a simple dApp to transfer CKB balance from one account to another. +In this tutorial, you will learn how to write a simple dApp to transfer CKB balance from one account to another. ## Setup Devnet & Run Example diff --git a/website/docs/dapp/write-message.mdx b/website/docs/dapp/write-message.mdx index 68b503f59..c51ca1a00 100644 --- a/website/docs/dapp/write-message.mdx +++ b/website/docs/dapp/write-message.mdx @@ -7,21 +7,16 @@ import Tabs from "@theme/Tabs"; import TabItem from "@theme/TabItem"; import TutorialHeader from "@components/TutorialHeader"; import Tooltip from "@components/Tooltip"; -import { WRITEOVERVIEW } from "./TutorialOverview.tsx"; import SetupProject from "./SetupProject.tsx"; import SwitchToTestnet from "./_SwitchToTestnet.mdx"; # Store Data on Cell - + -## Store & Retrieve Cell Data +## Tutorial Overview -In this tutorial, you'll learn how to tuck a nifty message - "**Hello CKB!**" - into a Cell on the CKB blockchain. Imagine it as sending a message in a bottle, but the ocean is digital, and the bottle is a super secure, tamper-proof CKB Cell! +In this tutorial, you will learn how to tuck a nifty message - "**Hello CKB!**" - into a Cell on the CKB blockchain. Imagine it as sending a message in a bottle, but the ocean is digital, and the bottle is a super secure, tamper-proof CKB Cell! As you have learned from the first tutorial [Transfer CKB](/docs/dapp/transfer-ckb), the Cell can store any type of data in the data field of Cell structure. Here we will put a text message encoding in hex string format and store it in the data field. Once your words are encoded and inscribed into the blockchain, we'll then get the hex string from the same Cell back and then decode them to the original text message. the method of encoding and decoding is totally up to your favorite, we use the `TextDecoder` for simplicity through the tutorial. diff --git a/website/docs/getting-started/installation.mdx b/website/docs/getting-started/installation.mdx new file mode 100644 index 000000000..611f1bf54 --- /dev/null +++ b/website/docs/getting-started/installation.mdx @@ -0,0 +1,370 @@ +--- +id: installation-guide +title: Installation Guide +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +# Installation Guide + +This installation guide provides a step-by-step setup of all essential tools needed for completing every tutorial across the documentation. + +## CKB Basic Development + +This section covers the essential tools you need to develop CKB applications, including setting up the local development environment and JavaScript SDK. + +### 1. OffCKB (≥v0.3.0) + +OffCKB sets up a local CKB Devnet, allowing you to test dApps without connecting to the main network. We recommend using **≥v0.3.0**. + +```bash +npm install -g @offckb/cli +``` + +### 2. CCC (≥v0.0.14-alpha.0) + +CCC is the JavaScript SDK used for interacting with CKB, helping you build transactions and interact with the blockchain. +This website's documentation assumes a minimum version of **≥v0.0.14-alpha.0**. + +```mdx-code-block + + +``` + +```bash +npm install @ckb-ccc/core +``` + +```mdx-code-block + + +``` + +```bash +npm install @ckb-ccc/ccc +``` + +```mdx-code-block + + +``` + +```bash +npm install @ckb-ccc/connector +``` + +```mdx-code-block + + +``` + +```bash +npm install @ckb-ccc/connector-react +``` + +```mdx-code-block + + +``` + +## Script Development-Specific Tools + +This section covers additional tools needed for Script development on CKB, focusing on compiling and cross-compiling setups. + +### 1. Make, Sed, Bash, sha256sum + +These tools are often pre-installed on Unix-based systems but can be installed manually if needed. We recommend using Make (≥v4.3), Sed (≥v4.7), Bash (≥v5.0), and sha256sum (≥v9.0) + +```mdx-code-block + + +``` + +First, install Homebrew if you haven't already: + +```bash +/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" +``` + +Then, install: + +```bash +brew install make gnu-sed bash coreutils +``` + +```mdx-code-block + + +``` + +```bash +sudo apt install make sed bash coreutils # Debian/Ubuntu +sudo dnf install make sed bash coreutils # Fedora +sudo pacman -S make sed bash coreutils # ArchLinux +``` + +```mdx-code-block + + +``` + +Install using [WSL (Windows Subsystem for Linux)](https://learn.microsoft.com/en-us/windows/wsl/) + +```mdx-code-block + + +``` + +### 2. Rust (≥v1.71.1) and riscv64 Target + +Ensure Rust is set up with the riscv64imac-unknown-none-elf target: + +```mdx-code-block + + +``` + +First, install Homebrew if you haven't already: + +```bash +/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" +``` + +Then, install Rust: + +```bash +brew install rustup +``` + +We recommend using **≥v1.71.1**. You will need to add the `riscv64` target: + +```bash +rustup target add riscv64imac-unknown-none-elf +``` + +```mdx-code-block + + +``` + +First, install Rust using the Rust installer: + +```bash +curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh +``` + +We recommend using **≥v1.71.1**. You will need to add the `riscv64` target: + +```bash +rustup target add riscv64imac-unknown-none-elf +``` + +```mdx-code-block + + +``` + +First, open your terminal and run the following command to enable script execution and install Scoop: + +```bash +Set-ExecutionPolicy RemoteSigned -Scope CurrentUser +iwr -useb get.scoop.sh | iex +``` + +After installing Scoop, you can install Rust: + +```bash +scoop install rust +``` + +We recommend using **≥v1.71.1**. You will need to add the `riscv64` target: + +```bash +rustup target add riscv64imac-unknown-none-elf +``` + +```mdx-code-block + + +``` + +### 3. Clang (≥v18) + +Clang is a compiler essential for building and running CKB Scripts. You must install **≥v18** to ensure compatibility with the latest tools and libraries. + +```mdx-code-block + + +``` + +First, install Homebrew if you haven't already: + +```bash +/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" +``` + +Then, install Clang (≥v18): + +```bash +brew install llvm@18 +``` + +```mdx-code-block + + +``` + +```bash +wget https://apt.llvm.org/llvm.sh && chmod +x llvm.sh && sudo ./llvm.sh 18 && rm llvm.sh # Debian/Ubuntu +sudo dnf -y install clang # Fedora +sudo pacman --noconfirm -Syu clang # ArchLinux +``` + +```mdx-code-block + + +``` + +First, open your terminal and run the following command to enable script execution and install Scoop + +```bash +Set-ExecutionPolicy RemoteSigned -Scope CurrentUser +iwr -useb get.scoop.sh | iex +``` + +After installing Scoop, you can install Clang (≥v18): + +```bash +scoop install llvm yasm +``` + +```mdx-code-block + + +``` + +### 4. Cargo-generate (≥0.17.0) + +Cargo-generate creates new Rust projects from pre-defined templates, helping set up project structure quickly and consistently. We recommend using **≥0.17.0**. + +```bash +cargo install cargo-generate +``` + +### 5. CKB-Debugger (≥0.113.0) + +CKB-Debugger is a CLI tool that enables off-chain Script development and testing. We recommend using **≥0.113.0**. + +```bash +cargo install --git https://github.com/nervosnetwork/ckb-standalone-debugger ckb-debugger +``` + +### 6. ckb-js-vm + +Built from the lightweight QuickJS engine, `ckb-js-vm` enables you to write and execute Scripts within the CKB-VM environment. + +```bash +git clone https://github.com/nervosnetwork/ckb-js-vm +cd ckb-js-vm +git submodule update --init +make all +``` + +## Other Tools + +This section lists additional tools commonly used in development environments. You may already have these installed, but just in case you still need them, here are installation instructions for each operating system. + +### 1. npm (Node.js v20.18.0 LTS) + +npm is a package manager included with Node.js, which helps to manage dependencies. We recommend using the **v20.18.0 LTS** version. + +```mdx-code-block + + +``` + +First, install Homebrew if you haven't already: + +```bash +/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" +``` + +Then, install Node.js + +```bash +brew install node@20.18.0 +``` + +```mdx-code-block + + +``` + +```bash +curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - +sudo apt install -y nodejs +``` + +```mdx-code-block + + +``` + +[Download Node.js v20.18.0 LTS](https://nodejs.org/en) + +```mdx-code-block + + +``` + +### 2. Yarn (≥1.22.0) + +Yarn is a package manager for JavaScript projects. We recommend using **≥v1.22.0**. +After installing npm, you can run the following command on any operating system to install Yarn: + +```bash +npm install --global yarn +``` + +### 3. Git (≥2.40.0) + +Git is a version control system for managing and tracking code changes. We recommend using **≥v2.40.0**. + +```mdx-code-block + + +``` + +First, install Homebrew if you haven't already: + +```bash +/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" +``` + +Then, install Git: + +```bash +brew install git +``` + +```mdx-code-block + + +``` + +```bash +sudo apt install git +``` + +```mdx-code-block + + +``` + +[Download Git for Windows](https://git-scm.com/downloads/win) + +```mdx-code-block + + +``` diff --git a/website/docs/getting-started/quick-start.mdx b/website/docs/getting-started/quick-start.mdx index 2af1e8540..b9aee3ec4 100644 --- a/website/docs/getting-started/quick-start.mdx +++ b/website/docs/getting-started/quick-start.mdx @@ -21,7 +21,7 @@ npm install -g @offckb/cli ``` :::info -Throughout this documentation, we use offckb/cli version **>=0.3.0-rc2**. You can always run the above command to update to the latest version. +Throughout this documentation, we use offckb/cli version **>=0.3.0**. You can always run the above command to update to the latest version. ::: ## Create a New Project @@ -159,7 +159,7 @@ npm i && npm run dev Once the server is up and running, you can view the dApp by visiting [localhost:3000](http://localhost:3000). You can start editing the page by modifying `app/page.tsx`. As you make changes to the file, the page will automatically update to reflect your edits. For detailed instructions on how to start the dApp and explore additional config options, please see the `README.md` file. -![dapp-screenshot](/img/quick-start/next-js-dapp.jpg) +![dapp-screenshot](/img/quick-start/remix-vite-dapp.png) --- diff --git a/website/docs/history-and-hard-forks/ckb-hard-fork-history.mdx b/website/docs/history-and-hard-forks/ckb-hard-fork-history.mdx new file mode 100644 index 000000000..6f6d6103a --- /dev/null +++ b/website/docs/history-and-hard-forks/ckb-hard-fork-history.mdx @@ -0,0 +1,185 @@ +--- +id: ckb-hard-fork-history +title: "CKB Hard Fork History" +--- + +import HardForkTime from "@components/HardForkTime"; + +# CKB Hard Fork History + +This page contains a timeline of all the hard forks, and updates to the Nervos CKB. + +## 2nd Hard Fork – CKB Edition Meepo (2024) + + + +### Meepo (2024) Summary + +The CKB Edition Meepo (2024) introduces a range of enhancements into CKB Script development, with one major innovation being Spawn. Spawn enables direct cross-script calls, simplifying development process while offering greater control and optimization. This update significantly enhances the flexibility of CKB Script. + +### Important Features + +
+ CKB-VM V2 + + - One notable addition is the inclusion of a new system call called "Spawn," which can be further explored in the [RFC50: CKB-VM Syscalls 3](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0050-vm-syscalls-3/0050-vm-syscalls-3.md). In essence, Spawn serves as an alternative to dynamic library calls and Exec. With Spawn, a Script can create a child Script with an independent memory area, and data can be passed between the parent and child Scripts without restriction. + - Implemented more macro-op fusions to reduce cycle consumption, making Scripts run more efficiently. + - Added a new `data2` value in the Script`hash_type` field to smoothly manage different VM versions, ensuring a seamless upgrade path. + +
+ +### Tools & Upgrade Requirements + +Below is a comprehensive checklist for updating tools, libraries, and SDKs related to the Meepo hardfork. Ensure all components are updated and tested as per the specified versions and notes below. + +#### Core Components + +- [ckb](https://crates.io/crates/ckb-verification) (crate): v0.119.0 (supports data2 and Spawn) + +#### Standard Libraries + +- [ckb-std](https://github.com/nervosnetwork/ckb-std/releases): v0.16.1 +- [ckb-c-stdlib](https://github.com/nervosnetwork/ckb-c-stdlib) + - https://github.com/nervosnetwork/ckb-c-stdlib/pull/63 + - https://github.com/nervosnetwork/ckb-c-stdlib/pull/59 + +#### SDKs + +- [ckb-rust-sdk](https://github.com/nervosnetwork/ckb-sdk-rust/releases): v3.4.1 (supports data2 and CKB preview) +- [ckb-go-sdk](https://github.com/nervosnetwork/ckb-sdk-go/releases): v2.3.0 +- [ckb-sdk-java](https://github.com/nervosnetwork/ckb-sdk-java/releases): https://github.com/nervosnetwork/ckb-sdk-java/pull/683 + +#### Development Tools + +- [ckb-cli](https://github.com/nervosnetwork/ckb-cli/releases): v1.6.0 (supports data2 and CKB preview) +- [ccc](https://github.com/ckb-devrel/ccc/deployments) (common chain connector): v0.0.2 +- [ckb-testtool](https://github.com/nervosnetwork/ckb-testtool): v0.14.0 +- [ckb-standalone-debugger](https://github.com/nervosnetwork/ckb-standalone-debugger/releases): v0.119.0 +- ckb-script-template: https://github.com/cryptape/ckb-script-templates/pull/14 + +#### Virtual Machines + +- [ckb-lua-vm](https://github.com/nervosnetwork/ckb-lua-vm): https://github.com/nervosnetwork/ckb-lua-vm/pull/15 +- [ckb-js-vm](https://github.com/nervosnetwork/ckb-js-vm): https://github.com/nervosnetwork/ckb-js-vm/pull/14 + +### Resources + +- [CKB2023](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0051-ckb2023/0051-ckb2023.md) +- [RFC48](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0048-remove-block-header-version-reservation-rule/0048-remove-block-header-version-reservation-rule.md): Remove Block Header Version Reservation Rule +- [RFC49](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0049-ckb-vm-version-2/0049-ckb-vm-version-2.md): CKB VM version2 +- [RFC50](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0050-vm-syscalls-3/0050-vm-syscalls-3.md): CKB VM Syscalls 3 + +--- + +## 1st Hard Fork – CKB Edition Mirana (2021) + + + +### Mirana (2021) Summary + +The CKB Edition Mirana (2021) introduces both new features and bug fixes. A major upgrade to the virtual machine, CKB-VM v1, was implemented, with Scripts now executing on this version by default unless specified otherwise. Additionally, a new extension field was added to block headers, reserved for future upgrades like Flyclient. Multiple consensus patches were also applied, fixing bugs and improving the network's robustness. + +### Important Features + +
+ CKB-VM V1 + + A key feature of CKB-VM v1 is the support for the RISC-V B extension, which enables direct mapping of RISC-V instructions to native x86-64 CPU instructions. This enhancement significantly improves the efficiency of cryptographic algorithms, such as reducing the cycle consumption of BLS signature verification locks. + + Additionally, CKB-VM v1 utilizes Macro-Operation Fusion (MOP) to merge adjacent instructions into single operations, further optimizing performance by exploiting modern CPU micro-architectures. + + To manage multiple VM versions, CKB-VM v1 introduces a version selection mechanism utilizing the `hash_type` field in the Script structure. This mechanism allows developers to specify the desired VM version for script execution, facilitating a smooth transition to the updated virtual machine environment. + + Different VM versions may result in varying cycle consumption and verification outcomes for the same transaction. To accommodate these differences, separate transaction relay protocols are proposed for each VM version, ensuring a seamless activation of CKB2021. + +
+
+ Extension Field + + The hardfork introduces an optional variable-length field, termed the "extension field," into the block structure. Previously, the fixed-length block header lacked sufficient reserved bits to accommodate such extensions, and this addition addresses the need for incorporating new data into blocks. + + The extension field is integrated into the block body, allowing nodes to synchronize the block header and this field concurrently without additional overhead. Post-activation of CKB2021, this field remains unparsed and unverified, serving as a placeholder for future soft forks to define its specific use cases. For instance, Flyclient can utilize the extension field to store its required hash data. + +
+
+ Consensus Patches + + Several consensus patches were implemented to enhance the robustness and flexibility of the CKB: + + - Simplified the `since` field by using block timestamps as the start time. + - Allowed multiple matches on dependency Cells via Type Script hash when Cells have identical data. + - Ensured the index is less than the length in the `since` field using epoch. + - Removed the header dependencies' immature rule, granting developers more flexibility. + +
+ +### Tools & Upgrade Requirements + +To ensure your project is fully compatible with the new network rules, the following tools and libraries need to be updated: + +#### 1. Update your CKB Node & CKB Indexer Node + +| Tools | Minimum version required | +| ---------------- | --------------------------------------------------------------- | +| CKB Node | [v0.103.0](https://github.com/nervosnetwork/ckb/releases) | +| CKB Indexer Node | [v0.3.2](https://github.com/nervosnetwork/ckb-indexer/releases) | + +Follow these steps to update your node: + +1. Download and decompress the latest stable binaries +2. Shut down your node if it is running +3. Replace the old binaries with the new binaries +4. Start the node manually on the command line to complete the migration process, if necessary. +5. Shut down and restart the node using your normal startup Script. + +:::note +If the CKB node you are updating is running a version below **v0.100.0**, some code changes may be necessary to ensure compatibility. Breaking changes were introduced to the RPC, which are listed on the [release page](https://github.com/nervosnetwork/ckb/releases/tag/v0.100.0). +::: + +#### 2. Update your supporting libraries + +| Tools | Minimum version recommended | +| -------------- | ----------------------------------------------------------------------------- | +| PW-SDK | [v0.4.1-alpha.1](https://www.npmjs.com/package/@jm9k/pw-core/v/0.4.1-alpha.1) | +| Lumos | [v0.18.0-rc6](https://github.com/ckb-js/lumos/releases) | +| ckb-sdk-js | [v0.102.3](https://github.com/nervosnetwork/ckb-sdk-js/releases) | +| ckb-sdk-java | [v1.0.0](https://github.com/nervosnetwork/ckb-sdk-java/releases) | +| ckb-sdk-go | [v1.0.0](https://github.com/nervosnetwork/ckb-sdk-go/releases) | +| ckb-sdk-ruby | [v0.101.0](https://github.com/nervosnetwork/ckb-sdk-ruby/releases) | +| CKIT | [v0.2.0](https://github.com/nervosnetwork/ckit/releases) | +| ckb-js-toolkit | [v0.100.0-rc1](https://github.com/nervosnetwork/ckb-js-toolkit/releases) | + +#### 3. Update to support CKB2021 Addresses + +The CKB2021 address format replaces both short and long addresses from the past, offering improved flexibility and reduced maintenance. While old addresses will still work, it’s recommended to use **CKB2021** for new features introduced in the CKB Edition Mirana (2021) hard fork. + +- [PW-SDK](https://github.com/jordanmack/nervos-ckb2021-hard-fork-migration-guide/blob/master/pw-sdk.md) and [Lumos](https://github.com/jordanmack/nervos-ckb2021-hard-fork-migration-guide/blob/master/lumos.md): Follow their respective guides to support new addresses. +- Other libraries: refer to the [Lumos guide](https://github.com/jordanmack/nervos-ckb2021-hard-fork-migration-guide/blob/master/lumos.md) and their official documentation. + +#### 4. Omnilock Migration + +After adding Omnilock support, users must migrate assets from their PW-Lock address to the new Omnilock address. While private keys remain unchanged, the addresses will be different. + +Developers should guide their users through the migration process and provide tools and instructions for asset migration. The [**PW-UP Asset Migration Tool**](https://pw-up.vercel.app/) (available on [GitHub](https://github.com/homura/pw-up)) can be used for migrating sUDT assets. + +- [PW-SDK](https://github.com/jordanmack/nervos-ckb2021-hard-fork-migration-guide/blob/master/pw-sdk.md) and [Lumos](https://github.com/jordanmack/nervos-ckb2021-hard-fork-migration-guide/blob/master/lumos.md): Follow their respective guides for Omnilock support. +- Other libraries: refer to the [Lumos guide](https://github.com/jordanmack/nervos-ckb2021-hard-fork-migration-guide/blob/master/lumos.md) and their official documentation. + +### Resources + +- [Migration Guide](https://github.com/jordanmack/nervos-ckb2021-hard-fork-migration-guide) +- [CKB2021](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0037-ckb2021/0037-ckb2021.md): Overview +- [RFC28](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0028-change-since-relative-timestamp/0028-change-since-relative-timestamp.md): Use Block Timestamp as Start Timestamp in Since. +- [RFC29](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0029-allow-script-multiple-matches-on-identical-code/0029-allow-script-multiple-matches-on-identical-code.md): Allow multiple matches on dep cells via type script hash when these cells have the same data. +- [RFC30](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0030-ensure-index-less-than-length-in-since/0030-ensure-index-less-than-length-in-since.md): Ensure that index is less than length in input since field using epoch. +- [RFC31](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0031-variable-length-header-field/0031-variable-length-header-field.md): Add a variable length field in the block header. +- [RFC32](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0032-ckb-vm-version-selection/0032-ckb-vm-version-selection.md): CKB VM version selection. +- [RFC33](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0033-ckb-vm-version-1/0033-ckb-vm-version-1.md): CKB VM version1 changes. +- [RFC34](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0034-vm-syscalls-2/0034-vm-syscalls-2.md): CKB VM syscalls bundle 2. +- [RFC35](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0035-ckb2021-p2p-protocol-upgrade/0035-ckb2021-p2p-protocol-upgrade.md): P2P protocol upgrade. +- [RFC36](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0036-remove-header-deps-immature-rule/0036-remove-header-deps-immature-rule.md): Remove header deps immature rule. diff --git a/website/docs/history-and-hard-forks/history-vm-version.mdx b/website/docs/history-and-hard-forks/history-vm-version.mdx new file mode 100644 index 000000000..88fde8639 --- /dev/null +++ b/website/docs/history-and-hard-forks/history-vm-version.mdx @@ -0,0 +1,212 @@ +--- +id: history-vm-version +title: "VM Version History" +--- + +The CKB network has introduced various CKB-VM versions over time to enhance security, performance, resolve bugs, and support new RISC-V extensions. This article lists all versions of the CKB-VM from previous hard fork events. + +It is important to note that, even though a hard fork upgrades the network, it is crucial to prevent the hard fork from breaking the old Script codes. CKB makes best effort to ensure users have the opt-in option to specify the VM version for their Script. For the specific mechanism that determines how the CKB node chooses the CKB-VM version for a transaction's Script group, please refer to [vm-selection](/docs/script/vm-selection). + +## VM 0 + +Since the genesis of CKB network. + +Full description: [RFC](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0003-ckb-vm/0003-ckb-vm.md) + +### Instruction Set + +`rv64imc` architecture: based on core [RV64I](https://riscv.org/specifications/) ISA with M standard extension for integer multiplication and division, and C standard extension for RCV(RISC-V Compressed Instructions) + +### Syscalls + +Full description: [RFC](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0009-vm-syscalls/0009-vm-syscalls.md) + +- [Exit](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0009-vm-syscalls/0009-vm-syscalls.md#exit) +- [Load Transaction Hash](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0009-vm-syscalls/0009-vm-syscalls.md#load-transaction-hash) +- [Load Transaction](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0009-vm-syscalls/0009-vm-syscalls.md#load-transaction) +- [Load Script Hash](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0009-vm-syscalls/0009-vm-syscalls.md#load-script-hash) +- [Load Script](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0009-vm-syscalls/0009-vm-syscalls.md#load-script) +- [Load Cell](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0009-vm-syscalls/0009-vm-syscalls.md#load-cell) +- [Load Cell By Field](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0009-vm-syscalls/0009-vm-syscalls.md#load-cell-by-field) +- [Load Cell Data](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0009-vm-syscalls/0009-vm-syscalls.md#load-cell-data) +- [Load Cell Data As Code](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0009-vm-syscalls/0009-vm-syscalls.md#load-cell-data-as_code) +- [Load Input](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0009-vm-syscalls/0009-vm-syscalls.md#load-input) +- [Load Input By Field](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0009-vm-syscalls/0009-vm-syscalls.md#load-input-by-field) +- [Load Header](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0009-vm-syscalls/0009-vm-syscalls.md#load-header) +- [Load Header By Field](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0009-vm-syscalls/0009-vm-syscalls.md#load-header-by-field) +- [Load Witness](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0009-vm-syscalls/0009-vm-syscalls.md#load-witness) +- [Debug](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0009-vm-syscalls/0009-vm-syscalls.md#debug) + +### Cost Model + +Full description: [RFC](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0014-vm-cycle-limits/0014-vm-cycle-limits.md) + +Specify the cycles needed by each CKB-VM instructions or syscalls. + +1. Cycles for RISC-V instructions are determined based on real hardware that implement RISC-V ISA. +2. Cycles for syscalls are measured based on real runtime performance metrics obtained while benchmarking current CKB implementation. + +**Initial Loading Cycles** + +For each byte loaded into CKB-VM in the initial ELF loading phase, 0.25 cycles will be charged. This is to encourage dApp developers to ship smaller Scripts as well as preventing DDoS attacks using large binaries. Notice fractions will be rounded up here, so 30.25 cycles will become 31 cycles. + +**instructions Cycles** + +All instructions consume 1 cycle except the following ones: + +| Instruction | Cycles | +| ----------- | -------------------- | +| JALR | 3 | +| JAL | 3 | +| J | 3 | +| JR | 3 | +| BEQ | 3 | +| BNE | 3 | +| BLT | 3 | +| BGE | 3 | +| BLTU | 3 | +| BGEU | 3 | +| BEQZ | 3 | +| BNEZ | 3 | +| LD | 2 | +| SD | 2 | +| LDSP | 2 | +| SDSP | 2 | +| LW | 3 | +| LH | 3 | +| LB | 3 | +| LWU | 3 | +| LHU | 3 | +| LBU | 3 | +| SW | 3 | +| SH | 3 | +| SB | 3 | +| LWSP | 3 | +| SWSP | 3 | +| MUL | 5 | +| MULW | 5 | +| MULH | 5 | +| MULHU | 5 | +| MULHSU | 5 | +| DIV | 32 | +| DIVW | 32 | +| DIVU | 32 | +| DIVUW | 32 | +| REM | 32 | +| REMW | 32 | +| REMU | 32 | +| REMUW | 32 | +| ECALL | 500 (see note below) | +| EBREAK | 500 (see note below) | + +**Syscall Cycles** + +As shown in the above chart, each syscall will have 500 initial cycle consumptions. This is based on real performance metrics gathered benchmarking CKB implementation, certain bookkeeping logics are required for each syscall here. + +In addition, for each byte loaded into CKB-VM in the syscalls, 0.25 cycles will be charged. Notice fractions will also be rounded up here, so 30.25 cycles will become 31 cycles. + +## VM 1 + +Introduced since [1st Hard Fork – CKB Edition Mirana (2021)](/docs/history-and-hard-forks/ckb-hard-fork-history#1st-hard-fork--ckb-edition-mirana-2021) + +Full description: [RFC](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0033-ckb-vm-version-1/0033-ckb-vm-version-1.md#1-fixed-several-bugs) + +### Instruction Set + +1. Added the RISC-V B extension (v1.0.0) [1](https://github.com/riscv/riscv-bitmanip). This extension aims at covering the four major categories of bit manipulation: counting, extracting, inserting and swapping. +2. 10 [MOPs](https://en.wikichip.org/wiki/macro-operation_fusion) added: + +| Opcode | Origin | +| ----------------------------------------------------------- | ---------------------------- | +| ADC [2](https://github.com/nervosnetwork/ckb-vm/issues/169) | add + sltu + add + sltu + or | +| SBB | sub + sltu + sub + sltu + or | +| WIDE_MUL | mulh + mul | +| WIDE_MULU | mulhu + mul | +| WIDE_MULSU | mulhsu + mul | +| WIDE_DIV | div + rem | +| WIDE_DIVU | divu + remu | +| FAR_JUMP_REL | auipc + jalr | +| FAR_JUMP_ABS | lui + jalr | +| LD_SIGN_EXTENDED_32_CONSTANT | lui + addiw | + +### Syscalls + +No new added syscalls. + +### Cost Model + +- For all B instructions, 1 cycle will be consumed. +- 10 [MOPs](https://en.wikichip.org/wiki/macro-operation_fusion) cycle cost: + +| Opcode | Origin | Cycles | +| ----------------------------------------------------------- | ---------------------------- | ----------------- | +| ADC [2](https://github.com/nervosnetwork/ckb-vm/issues/169) | add + sltu + add + sltu + or | 1 + 0 + 0 + 0 + 0 | +| SBB | sub + sltu + sub + sltu + or | 1 + 0 + 0 + 0 + 0 | +| WIDE_MUL | mulh + mul | 5 + 0 | +| WIDE_MULU | mulhu + mul | 5 + 0 | +| WIDE_MULSU | mulhsu + mul | 5 + 0 | +| WIDE_DIV | div + rem | 32 + 0 | +| WIDE_DIVU | divu + remu | 32 + 0 | +| FAR_JUMP_REL | auipc + jalr | 0 + 3 | +| FAR_JUMP_ABS | lui + jalr | 0 + 3 | +| LD_SIGN_EXTENDED_32_CONSTANT | lui + addiw | 1 + 0 | + +## VM 2 + +Introduced since [2nd Hard Fork – CKB Edition Meepo (2024)](/docs/history-and-hard-forks/ckb-hard-fork-history#2nd-hard-fork--ckb-edition-meepo-2024) + +Full description: [RFC](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0049-ckb-vm-version-2/0049-ckb-vm-version-2.md) + +### Instruction Set + +5 [MOPs](https://en.wikichip.org/wiki/macro-operation_fusion) added: + +| Opcode | Origin | Description | +| ------ | ---------------- | ------------------------------------------------------------------ | +| ADCS | add + sltu | Overflowing addition | +| SBBS | sub + sltu | Borrowing subtraction | +| ADD3A | add + sltu + add | Overflowing addition and add the overflow flag to the third number | +| ADD3B | add + sltu + add | Similar to ADD3A but the registers order is different | +| ADD3C | add + sltu + add | Similar to ADD3A but the registers order is different | + +### Syscalls + +Added 8 spawn-related syscalls and one block-related syscall: + +- [Spawn](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0050-vm-syscalls-3/0050-vm-syscalls-3.md#spawn) +- [Pipe](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0050-vm-syscalls-3/0050-vm-syscalls-3.md#pipe) +- [Inherited File Descriptors](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0050-vm-syscalls-3/0050-vm-syscalls-3.md#inherited-file-descriptors) +- [Read](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0050-vm-syscalls-3/0050-vm-syscalls-3.md#read) +- [Write](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0050-vm-syscalls-3/0050-vm-syscalls-3.md#write) +- [Close](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0050-vm-syscalls-3/0050-vm-syscalls-3.md#close) +- [Wait](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0050-vm-syscalls-3/0050-vm-syscalls-3.md#wait) +- [Process ID](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0050-vm-syscalls-3/0050-vm-syscalls-3.md#process-id) +- [Load Block Extension](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0050-vm-syscalls-3/0050-vm-syscalls-3.md#load-block-extension) + +Full description: [RFC](https://github.com/nervosnetwork/rfcs/tree/master/rfcs/0050-vm-syscalls-3) + +### Cost Model + +- 5 [MOPs](https://en.wikichip.org/wiki/macro-operation_fusion) cycle cost: + +| Opcode | Origin | Cycles | +| ------ | ---------------- | --------- | +| ADCS | add + sltu | 1 + 0 | +| SBBS | sub + sltu | 1 + 0 | +| ADD3A | add + sltu + add | 1 + 0 + 0 | +| ADD3B | add + sltu + add | 1 + 0 + 0 | +| ADD3C | add + sltu + add | 1 + 0 + 0 | + +- Spawn syscall cycles: + +| Syscall Name | Cycles Charge | +| -------------------- | ---------------------------------------------------------------------------------- | +| spawn | 500 + SPAWN_YIELD_CYCLES_BASE + BYTES_TRANSFERRED_CYCLES + SPAWN_EXTRA_CYCLES_BASE | +| pipe | 500 + SPAWN_YIELD_CYCLES_BASE | +| inherited_fd | 500 + SPAWN_YIELD_CYCLES_BASE | +| read | 500 + SPAWN_YIELD_CYCLES_BASE + BYTES_TRANSFERRED_CYCLES | +| write | 500 + SPAWN_YIELD_CYCLES_BASE + BYTES_TRANSFERRED_CYCLES | +| close | 500 + SPAWN_YIELD_CYCLES_BASE | +| wait | 500 + SPAWN_YIELD_CYCLES_BASE | +| process_id | 500 | +| load block extension | 500 + BYTES_TRANSFERRED_CYCLES | diff --git a/website/docs/history-and-hard-forks/intro-to-hard-fork.mdx b/website/docs/history-and-hard-forks/intro-to-hard-fork.mdx new file mode 100644 index 000000000..abe263847 --- /dev/null +++ b/website/docs/history-and-hard-forks/intro-to-hard-fork.mdx @@ -0,0 +1,37 @@ +--- +id: intro-to-hard-fork +title: "Intro to Hard Fork" +--- + +## What is a Hard Fork? + +A hard fork is a substantial update to the blockchain’s protocol that results in a permanent divergence from the previous version. It includes major changes that are not backward-compatible, requiring all nodes in the network to upgrade to maintain consensus. + +If most nodes upgrade smoothly by the specified epoch number, the hard fork is considered successfully deployed. After the upgrade, nodes running the old version will no longer connect to the network, as they follow the outdated rules. + +## Purpose of a Hard Fork + +Nervos CKB implements hard forks to drive essential improvements that support the network’s growth and security. Hardforks are introduced for: + +- **New functionalities**: Enabling new capabilities and features that enhance the utility of the Nervos CKB platform for developers and users by modifying data structures, introducing new RISC-V extensions, new syscalls, and more. +- **Security upgrades**: Resolving critical issues, addressing critical bugs, and overcoming limitations in the current protocol that cannot be fixed through backward-compatible updates. + +## CKB Hard Fork Process + +The hard fork process for Nervos CKB involves 3 phases to ensure smooth deployment and network stability: + +| Phases | Steps | Duration | +| -------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- | +| Phase 1: Proposal and Discussion | - Create proposal and gather feedback
- Finalize as RFC
- Start initial implementation and testing
- Release hardfork-ready version for local preview | ~9 months (3 months for discussion, 6 months for development and testing) | +| Phase 2: Public Preview & Testnet Deployment | - Deploy public preview network
- Conduct stability testing
- Release node binary & epoch number for Testnet
- Activate at specified epoch number | Variable, based on network stability | +| Phase 3: Mainnet Deployment | - Release node binary & epoch number for Mainnet
- Provide a 3-month preparation period
- Activate at specified epoch number | At least 3 months preparation time after announcement | + +## CKB Hard Fork Naming Tradition + +Nervos CKB’s naming tradition for hard forks gives each major update a distinct identity while maintaining consistency across the network. Each hard fork is called an “edition” and is named after a Dota hero, with the year also marked in the format: **CKB Edition \[Name\](Year).** + +Initially, Nervos CKB used different names for Mainnet (Lina) and Testnet (Aggron). However, starting with the 2nd hard fork, both networks adopted the same edition name, such as “**CKB Edition Meepo (2024**),” with suffixes like “Mainnet” or “Testnet” only added when necessary for distinction. This unified naming format has also been applied retroactively to past editions, creating a consistent naming tradition across all hard fork events. + +## Additional Resources + +- [CKB Hardfork RFC](https://github.com/nervosnetwork/rfcs/blob/3a6ae4fa5d59b6e33fa7bd563d336706d135c0d8/rfcs/0053-ckb-hardfork/0053-ckb-hardfork.md) diff --git a/website/docs/history-and-hard-forks/rethinking-fork.mdx b/website/docs/history-and-hard-forks/rethinking-fork.mdx new file mode 100644 index 000000000..3bc2f1cf4 --- /dev/null +++ b/website/docs/history-and-hard-forks/rethinking-fork.mdx @@ -0,0 +1,59 @@ +--- +id: rethinking-forks +title: "Rethinking Forks" +--- + +# Rethinking Forks: The Philosophy Behind CKB's Network Upgrade Design + +> Originally written by Jan Xie + +## Soft Fork, Hard Fork, and Rice-Noodle Fork + +The discussions in the Bitcoin/Ethereum community about hard forks/soft forks have had a significant impact on CKB's design. +Here're two pieces I can find immediately [[1]](https://vitalik.eth.limo/general/2017/03/14/forks_and_markets.html) [[2]](https://github.com/editor-Ajian/Personal-Work/blob/main/%EF%BC%882024.11%EF%BC%89%E5%86%B0%E5%B1%B1%E4%B9%8B%E4%B8%8B.pdf). + +At some point, I realized that the definitions of hard fork/soft fork themselves are very rough and primitive, unable to accurately depict the differences between various network upgrades. + +For example, "changing Bitcoin opcodes to work with 64-bit values" and "modifying the 21m hard cap" both require hard forks, but their nature is entirely different: the former is akin to expanding a government office building (which may require more budget leading to other side effects), while the latter is like amending a constitution. + +The reason we use these two terms to describe blockchain network upgrades everywhere is probably simply because there was only Bitcoin at the beginning, and distinguishing between hard fork/soft fork happened to address key questions about network upgrades: + +- How does an upgrade occur in a distributed network? +- What are the difficulties of different upgrade methods? + +Clearly, soft forks are more convenient because they only need to convince part of the nodes to upgrade. + +However, this also imposes limitations on what can be done within an upgrade. In contrast is the hard fork. + +With these two concepts came further analysis such as whether soft forks can achieve what hard forks do, how upgrades affect existing users, if they coerce or not, how to signal/form consensus around upgrades etc., which has continued until today. + +But these are all completely different dimensions of considerations - whether network upgrades require partial or full node participation; which parts of protocol can be modified by an upgrade; through what governance process should it pass; whether it ensures current asset owner rights, etc. + +The simple binary division into hard/soft forks mixes considerations across different dimensions, resulting in conflict between upgrading versus coercion, limiting us within black-and-white options: + +- Opt for soft-fork, ensuring asset owner rights, while adding constraints onto networking evolution. +- Choose hard-fork, facilitating forward evolution, while sacrificing guarantees towards existing asset owners, forcing users constantly choosing between upgrade and exit. (Theoretically leaving-users could form new networks, but its costs usually outweigh expected returns, making it practically infeasible.) + +Once realizing these distinct dimensions exist within network upgrades, one could separate & conquer, potentially find better alternatives. CKB does exactly this. + +To CKB, a store of assets, ensuring asset owner rights is a crucial design goal just as to Bitcoin, a Store-of-value. At the same time, UTXO model serve the goal well, because UTXOs are discrete state storage units. Each user holds independent state storage means that everyone can independently specifies his/her own asset store strategy, which make the network-evolution-vs-asset-preservation conflict disappear. + +Individuals can make independent decisions regarding adopting newer protocols or sticking to older ones, and stay in the same network. Forced network splits avoided. This is why CKB introduces data/data1/data2/... hash_type alongside VM version (more details here [[3]](https://talk.nervos.org/t/ckb-version-control-and-blockchain-evolution/4819)[[4]](https://talk.nervos.org/t/first-class-asset/405)[[5]](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0032-ckb-vm-version-selection/0032-ckb-vm-version-selection.md)). + +That leads to intrinsic differences between CKB Hard-forks and Ethereum hard-forks. Although CKB hard-forks could add instructions to CKB-VM, they don't affect existing asset owners' rights provided lock/type scripts used accordingly. Sometimes I feel like "Rice-noodle-fork" might suit better for CKB hard-forks - it's apparently different from "hard-fork", plus rice noodles taste great! + +As CKB ecosystem develops, I believe specifying scripts using `data` hash_type will see increasing use especially in high-security store-of-assets scenarios. To make better use of it also requires better tools and more explorations, like: + +- How to provide easy-to-use UX for data/type hash_type selection? +- How to integrate data hash_type into script upgrade plan? +- How to deploy script code in multiple cells without affecting developer usability? + +In any case, do not let hard-fork/soft-fork categorization limit your imagination. + +## Ref + +- [1] [https://vitalik.eth.limo/general/2017/03/14/forks_and_markets.html…](https://t.co/Pnrh7IV1j5) +- [2] [https://github.com/editor-Ajian/Personal-Work/blob/main/%EF%BC%882024.11%EF%BC%89%E5%86%B0%E5%B1%B1%E4%B9%8B%E4%B8%8B.pdf…](https://t.co/rrlAOTpFvy) +- [3] [https://talk.nervos.org/t/ckb-version-control-and-blockchain-evolution/4819…](https://t.co/GIABUpA7Wl) +- [4] [https://talk.nervos.org/t/first-class-asset/405…](https://t.co/y59RuEUtXy) +- [5] [https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0032-ckb-vm-version-selection/0032-ckb-vm-version-selection.md…](https://t.co/ckzcHIV4Vb) diff --git a/website/docs/node/turn-on-fee-estimator.mdx b/website/docs/node/turn-on-fee-estimator.mdx new file mode 100644 index 000000000..49992bffe --- /dev/null +++ b/website/docs/node/turn-on-fee-estimator.mdx @@ -0,0 +1,44 @@ +--- +id: turn-on-fee-estimator +title: Turn On Fee Estimator +--- + +CKB `v0.120.0` introduces a new experimental feature, **Fee Estimator**, to help developers and users determine optimal transaction fee rates. + +To enable the Fee Estimator, the CKB node operator needs to specify the backend algorithms and activate the "Experiment" JSON-RPC API module in the CKB Node Configuration (`ckb.toml`). As shown below: + +Specify the algorithm in `ckb.toml`: + +```toml +[fee_estimator] +# Specifies the fee estimate algorithm. Current options: ConfirmationFraction, WeightUnitsFlow. +algorithm = "WeightUnitsFlow" +``` + +Enable the JSON-RPC API module `Experiment`: + +```bash +[rpc] +# List of API modules: ["Net", "Pool", "Miner", "Chain", "Stats", "Subscription", "Experiment", "Debug", "Indexer"] +modules = ["Net", "Pool", "Miner", "Chain", "Stats", "Subscription", "Experiment", "Debug", "Indexer"] +``` + +Once the CKB node is started, users can estimate the fee rate by making an RPC request: + +```bash +echo '{ "id": 1, "jsonrpc": "2.0", "method": "estimate_fee_rate", "params": [] }' \ + | curl -s -H "Content-Type: application/json" -d @- "http://localhost:8114" \ + | jq +``` + +Example response: + +```json +{ + "jsonrpc": "2.0", + "result": "0x3e8", + "id": 1 +} +``` + +More About [CKB Transaction Fee Estimator](/docs/tech-explanation/fee-estimator) diff --git a/website/docs/script/ScriptHeaders.tsx b/website/docs/script/ScriptHeaders.tsx deleted file mode 100644 index 22812832c..000000000 --- a/website/docs/script/ScriptHeaders.tsx +++ /dev/null @@ -1,324 +0,0 @@ -import { TutorialHeaderProps } from "@site/src/components/TutorialHeader"; - -export interface ScriptHeadersType { - [key: string]: TutorialHeaderProps; -} - -export const ScriptHeaders: ScriptHeadersType = { - basic: { - time: "5 - 7 min", - topics: [ - { label: "Script", link: "/docs/tech-explanation/script" }, - { - label: "CKB-VM", - link: "/docs/tech-explanation/ckb-vm", - }, - { label: "Cell Model", link: "/docs/tech-explanation/cell-model" }, - { - label: "Transaction", - link: "/docs/tech-explanation/glossary#transaction", - }, - ], - tools: [ -
- - git - - , - - make - - , - - sed - - , - - bash - - , - - sha256sum - - {" and others Unix utilities."} -
, -
- Rust - {" and riscv64 target: "}{" "} - rustup target add riscv64imac-unknown-none-elf -
, -
- - Clang 16+ - - -
    -
  • - Debian / Ubuntu:{" "} - - wget https://apt.llvm.org/llvm.sh && chmod +x llvm.sh && sudo - ./llvm.sh 16 && rm llvm.sh - -
  • -
  • - Fedora 39+: sudo dnf -y install clang -
  • -
  • - Archlinux: sudo pacman --noconfirm -Syu clang -
  • -
  • - MacOS (with Homebrew):{" "} - brew install llvm@16 -
  • -
  • - Windows (with Scoop):{" "} - scoop install llvm yasm -
  • -
-
, - , - ], - }, - typeid: { - time: "5 - 7 min", - topics: [ - { - label: "Type-ID", - link: "https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0022-transaction-structure/0022-transaction-structure.md#type-id", - }, - { label: "Script", link: "/docs/tech-explanation/script" }, - { - label: "Transaction", - link: "/docs/tech-explanation/transaction", - }, - ], - tools: [ -
- - git - - , - - make - - , - - sed - - , - - bash - - , - - sha256sum - - {" and others Unix utilities."} -
, -
- Rust - {" and riscv64 target: "}{" "} - rustup target add riscv64imac-unknown-none-elf -
, -
- - Clang 16+ - - -
    -
  • - Debian / Ubuntu:{" "} - - wget https://apt.llvm.org/llvm.sh && chmod +x llvm.sh && sudo - ./llvm.sh 16 && rm llvm.sh - -
  • -
  • - Fedora 39+: sudo dnf -y install clang -
  • -
  • - Archlinux: sudo pacman --noconfirm -Syu clang -
  • -
  • - MacOS (with Homebrew):{" "} - brew install llvm@16 -
  • -
  • - Windows (with Scoop):{" "} - scoop install llvm yasm -
  • -
-
, - , - ], - }, - sudt: { - time: "5 - 7 min", - topics: [ - { - label: "UDT", - link: "https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0025-simple-udt/0025-simple-udt.md", - }, - { label: "Script", link: "/docs/tech-explanation/script" }, - { - label: "Transaction", - link: "/docs/tech-explanation/transaction", - }, - ], - tools: [ -
- - {"offckb"} - - {", version >= v0.3.0-rc2"} -
, -
- - git - - , - - make - - , - - sed - - , - - bash - - , - - sha256sum - - {" and others Unix utilities."} -
, -
- Rust - {" and riscv64 target: "}{" "} - rustup target add riscv64imac-unknown-none-elf -
, -
- - Clang 16+ - - -
    -
  • - Debian / Ubuntu:{" "} - - wget https://apt.llvm.org/llvm.sh && chmod +x llvm.sh && sudo - ./llvm.sh 16 && rm llvm.sh - -
  • -
  • - Fedora 39+: sudo dnf -y install clang -
  • -
  • - Archlinux: sudo pacman --noconfirm -Syu clang -
  • -
  • - MacOS (with Homebrew):{" "} - brew install llvm@16 -
  • -
  • - Windows (with Scoop):{" "} - scoop install llvm yasm -
  • -
-
, - , - ], - }, -}; - -export default ScriptHeaders; diff --git a/website/docs/script/_ScriptTools.mdx b/website/docs/script/_ScriptTools.mdx index ed8871ac3..9e7cf75ad 100644 --- a/website/docs/script/_ScriptTools.mdx +++ b/website/docs/script/_ScriptTools.mdx @@ -1,16 +1,9 @@ :::info Tools You Need -- [git](https://git-scm.com/), [make](https://www.tutorialspoint.com/unix_commands/make.htm), [sed](https://www.gnu.org/software/sed/), [bash](https://www.gnu.org/software/bash/), [sha256sum](https://linux.die.net/man/1/sha256sum) and others Unix utilities. -- [Rust](https://www.rust-lang.org/) with `riscv64 target`: `rustup target add riscv64imac-unknown-none-elf` -- [Clang 16+](https://releases.llvm.org/16.0.0/tools/clang/docs/ReleaseNotes.html) +- [Make (≥v4.3), Sed (≥v4.7), Bash (≥v5.0), sha256sum (≥v9.0)](/docs/getting-started/installation-guide#1-make-sed-bash-sha256sum) +- [Rust (≥v.1.71.1) and `riscv64` target](/docs/getting-started/installation-guide#2-rust-v1711-and-riscv64-target) +- [Clang (≥v18)](/docs/getting-started/installation-guide#3-clang-18) +- [cargo-generate (≥0.17.0)](/docs/getting-started/installation-guide#4-cargo-generate-0170) - - Debian / Ubuntu: ` wget https://apt.llvm.org/llvm.sh && chmod +x llvm.sh && sudo./llvm.sh 16 && rm llvm.sh` - - Fedora 39+: `sudo dnf -y install clang` - - Archlinux: `sudo pacman --noconfirm -Syu clang` - - MacOS (with [Homebrew](https://brew.sh/)): `brew install llvm@16` - - Windows (with [Scoop](https://scoop.sh/)): `scoop install llvm yasm` - -- [Cargo-generate](https://github.com/cargo-generate/cargo-generate) - -Check out the `ckb-script-templates` for more [details](https://github.com/cryptape/ckb-script-templates/blob/main/README.md#dependencies). +For detailed installation steps, refer to our [Installation Guide](/docs/getting-started/installation-guide) ::: diff --git a/website/docs/script/_dynamic-linking.mdx b/website/docs/script/_dynamic-linking.mdx deleted file mode 100644 index 7ae42953d..000000000 --- a/website/docs/script/_dynamic-linking.mdx +++ /dev/null @@ -1,6 +0,0 @@ ---- -id: dynamic-linking-script -title: Use Dynamic Linking in Script (Coming soon...) ---- - -# Coming soon... diff --git a/website/docs/script/_script-in-js.mdx b/website/docs/script/_script-in-js.mdx deleted file mode 100644 index 42cd17f8e..000000000 --- a/website/docs/script/_script-in-js.mdx +++ /dev/null @@ -1,6 +0,0 @@ ---- -id: script-in-js -title: Run Script on Top of JS runtime (Coming soon...) ---- - -# Coming soon... diff --git a/website/docs/script/a-minimal-script.mdx b/website/docs/script/a-minimal-script.mdx index 03a411f29..2c0a4dc40 100644 --- a/website/docs/script/a-minimal-script.mdx +++ b/website/docs/script/a-minimal-script.mdx @@ -5,17 +5,12 @@ title: "Tutorial: A Minimal Script" import Tabs from "@theme/Tabs"; import TabItem from "@theme/TabItem"; -import ScriptHeaders from "./ScriptHeaders.tsx"; import TutorialHeader from "@components/TutorialHeader"; import ScriptTools from "./_ScriptTools.mdx"; # Tutorial: A Minimal Script - + ## A Minimal Script @@ -43,7 +38,7 @@ Below is a step-by-step guide, and you can also clone the full code example from ### Carrot-Forbidden Script -The first step is to create a new Script project. We use [ckb-script-templates](https://github.com/cryptape/ckb-script-templates) for this purpose. You will need the following dependencies: +The first step is to create a new Script project. We use [ckb-script-templates](https://github.com/cryptape/ckb-script-templates) for this purpose. Make sure you have the following dependencies installed: diff --git a/website/docs/script/debug-script.mdx b/website/docs/script/debug-script.mdx index 61b8ad574..02e3189fc 100644 --- a/website/docs/script/debug-script.mdx +++ b/website/docs/script/debug-script.mdx @@ -5,19 +5,34 @@ title: "Debug Script" import Tabs from "@theme/Tabs"; import TabItem from "@theme/TabItem"; -import ScriptHeaders from "./ScriptHeaders.tsx"; +import Link from "@docusaurus/Link"; import TutorialHeader from "@components/TutorialHeader"; import ScriptTools from "./_ScriptTools.mdx"; # Debug Script -## CKB-Debugger + + + CKB-Debugger (≥0.117.0) + + , + ]} +/> + +## Debug With CKB-Debugger Debugging Scripts on the Nervos CKB can be challenging without the right tools. We recommend using the [CKB-Debugger](https://github.com/nervosnetwork/ckb-standalone-debugger), a powerful standalone command-line tool designed for off-chain Script development. With CKB-Debugger, you can efficiently identify and resolve issues in your Scripts, ensuring smooth execution and optimal performance. -## Install +### Install -Install CKB-Debugger using [cargo](https://doc.rust-lang.org/cargo): +Install CKB-Debugger using [cargo](https://doc.rust-lang.org/cargo). We recommend using **≥v0.113.0**. ```bash cargo install --git https://github.com/nervosnetwork/ckb-standalone-debugger ckb-debugger @@ -29,7 +44,7 @@ On **MacOS**, the `protoc` binary must be available to compile `ckb-vm-pprof-con brew install protobuf ``` -## Usage +### Usage ```bash ckb-debugger 0.113.0 @@ -70,7 +85,7 @@ ARGS: ... ``` -## Examples +### Examples ### 1. Execute Transactions Locally @@ -166,7 +181,95 @@ $ (gdb) c At the Breakpoint 1, we see that `fib (n=5)` at `fib.c:2`. -#### 4. Profiling Data with Flamegraph Visualization Tool +### 4. Debug Script with GDB in VSCode + +Script debugging can be done in an IDE using `ckb-debugger`, which supports a `gdbserver` mode enabled with `--mode=gdb`. VSCode allows debugging via debugger extensions. Below, we explain how to use [NativeDebug](https://marketplace.visualstudio.com/items?itemName=webfreak.debug) and [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb) for CKB Script debugging. + +For testing, refer to [this project](https://github.com/joii2020/ckb-llvm-examples). + +This guide uses Rust for demonstration. Similar principles apply to other languages as well. + +#### Preparation + +- `ckb-debugger` supports older versions of GDB. For LLDB, version 18 or higher is required (older versions lack robust RISC-V support). +- For CodeLLDB, ensure the version is at least `v1.11`. +- For LLDB, use `ckb-debugger` version `0.118` or above. + +:::note + +Compilation may involve some LLVM commands. Just ensure the LLVM version is not too old. + +::: + +#### Compilation + +:::note +If your project was created using `ckb-script-templates`, the following steps are likely already done. You can skip this section. +::: + +Due to CKB's memory constraints, by default, Scripts are compiled in Release mode without debug information. To enable debugging, update your `Cargo.toml` file with these settings for the release build: + +```toml +[profile.release] +overflow-checks = true +strip = false +codegen-units = 1 +debug = true +``` + +After compilation, use the following commands to prepare the Scripts for deployment and debugging: + +```shell +cp .debug +llvm-objcopy --strip-debug --strip-all +``` + +This produces two files: + +- ``: The actual Script for testing and release. +- `.debug`: A debug version with symbols. It is for debugging only due to the large size impossible to be executed as a Script. + +#### VSCode Configuration + +VSCode tasks are configured in `tasks.json`. Here you have two tasks: one to start `ckb-debugger`, the other to stop it. + +```json +{ + "label": "StartDbg-Rust", + "isBackground": true, + "type": "process", + "command": "ckb-debugger", + "args": [ + "--bin=rust/build/release/ckb-c1.debug", + "--mode=gdb", + "--gdb-listen=127.0.0.1:8000" + ], + "options": { + "cwd": "${workspaceRoot}" + }, +}, +{ + "label": "StopCkbDebugger", + "type": "shell", + "command": "killall ckb-debugger || true" +} +``` + +Explanation of the fields: + +- `label` : Customizable task name +- `StartDbg-Rust`: Background-enabled task (`isBackground` set to true) +- `--bin` : Path to the Script file +- `—gdb-listen` : Listening address and port (e.g., `8000` in this example, but it can be different). +- `StopCkbDebugger`: Stops the `ckb-debugger` after a debug session. This is needed because `ckb-debugger` doesn’t exit automatically after debugging, but waits for the next execution instead. + +:::note + +If multiple Scripts are debugged simultaneously, stopping one session may terminate others. + +::: + +### 5. Profiling Data with Flamegraph Visualization Tool Use `ckb-debugger` to profile data for flamegraph visualization: @@ -190,6 +293,164 @@ Open the resulting SVG file to view the flamegraph: ![img](/img/debug-script/ckb-debugger-flamegraph.jpg) +## Debug With Native Simulator + +CKB Scripts follow the RISC-V specification and include APIs related to [VM syscalls](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0009-vm-syscalls/0009-vm-syscalls.md), making them incompatible to execute on common devices. Previously, many projects addressed this limitation by isolating the code unrelated to VM syscalls into separate libraries for development and testing. Some even implemented a rudimentary version of VM syscalls. + +Native Simulator addresses this issue, allowing for compilation and debugging on the native platform, as well as contract-related APIs simulation. For the code unrelated to VM syscalls and thus not executable on RISC-V, it can be compiled into a native executable for the host platform and debugged, while the VM syscalls part is managed by the [ckb-x64-simulator](https://github.com/nervosnetwork/ckb-x64-simulator), which simulates the required APIs. With both parts are covered, you can proceed with project management and testing. These functionalities have been integrated into `ckb-script-templates` and `ckb-testtool`. + +Below, we explain how to incorporate the Native Simulator into existing projects via `ckb-script-templates` or manually. + +### Preparation + +- The `ckb-std` version must be at least 0.16.3 (While the support was introduced since v0.16.1, but the features were not fully developed.). +- Testing with `ckb-testtool` is recommended to save effort. For new projects, consider using `ckb-script-templates` for project management. For project already under development, evaluate the situation and decide on a case-by-case basis. + +### Create with ckb-script-templates + +For projects created with the latest version of `ckb-script-templates`, initialize Native Simulator with the following command: + +```shell +make generate-native-simulator CRATE= +``` + +where `CRATE` must be an existing Script. + +Once created, run `make build` to compile. If custom code causes errors, use `#[cfg(feature = "native-simulator")]` to handle them. + +### Create Manually + +If `ckb-script-templates` is unavailable, manually integrate the Native Simulator as follows: + +#### Step 1. Set Up the Project + +a. Add a [`lib.rs`](http://lib.rs) file in the Scrip's `src` directory with the following content: + +```rust +#![cfg_attr(not(feature = "native-simulator"), no_std)] +#![allow(special_module_name)] +#![allow(unused_attributes)] +#[cfg(feature = "native-simulator")] +mod main; +#[cfg(feature = "native-simulator")] +pub use main::program_entry; +``` + +b. Add a `native-simulator` feature in the `Cargo.toml`: + +```toml +native-simulator = ["ckb-std/native-simulator"] +``` + +c. Update [`main.rs`](http://main.rs) to conditionally enable `no_std`, `no_main`, `ckb_std::entry!`, `(program_entry)`, and `ckb_std::default_alloc!()` for `native-simulator`: + +```rust +#![cfg_attr(not(any(feature = "native-simulator", test)), no_std)] +#![cfg_attr(not(test), no_main)] + +#[cfg(any(feature = "native-simulator", test))] +extern crate alloc; + +#[cfg(not(any(feature = "native-simulator", test)))] +ckb_std::entry!(program_entry); +#[cfg(not(any(feature = "native-simulator", test)))] +ckb_std::default_alloc!(); + +pub fn program_entry() -> i8 { + ... + 0 +} +``` + +#### Step 2. Create and Configure a Library + +Create a Rust lib `-sim` under `./native-simulator/`. There is no naming convention required here, it's just a recommended format. Add this lib to `Cargo.toml`. + +a. Include `ckb-std` and the Script in Step 1 as dependencies in `Cargo.toml`, with the `native-simulator` feature enabled, and ensure the lib type is `cdylib`: + +```toml +[dependencies] +contract = { path = "../../contracts/contract", features = ["native-simulator"] } +ckb-std = { version = "0.16.3", features = ["native-simulator"] } +[lib] +crate-type = ["cdylib"] +``` + +b. Add the following code into lib.rs: + +```rust +ckb_std::entry_simulator!(::program_entry); +``` + +#### Step 3. Compile For Native Platform + +Compile the code for the native platform. Address compatibility issues using `#[cfg(not(any(feature = "native-simulator", test)))]`. + +#### Step 4. Debug and Develop + +Once the project is setup, use `ckb-testtool` (version 0.13.1 or higher) for testing. Refer to [this example](https://github.com/nervosnetwork/ckb-x64-simulator/blob/main/tests/tests/src/tests.rs#L19). + +The newly added `Context::add_contract_dir()` function allows you to set up the Script and the Native Simulator directory. + +To facilitate usage, add a `native-simulator` feature into the `tests`: + +```toml +native-simulator = [ "ckb-testtool/native-simulator" ] +``` + +#### Step 5. Compile Script and Simulator Before Use + +When the `native-simulator` feature is enabled, the Script will use the Native Simulator. At this point, you can use IDE debugging tools to set breakpoints within the Script for debugging. + +### How It Works + +For the Script, `ckb-std` uses [ckb-x64-simulator](https://github.com/nervosnetwork/ckb-x64-simulator/tree/main) to simulate on-chain data. This simulator receives the file paths of the transaction data required via two environment variables: `CKB_TX_FILE` and `CKB_RUNNING_SETUP`, where: + +- `CKB_TX_FILE` contains transaction information +- `CKB_RUNNING_SETUP` contains miscellaneous data related to the transaction + +One key item in `CKB_RUNNING_SETUP` is `native_binaries`. It maps the Script to its corresponding Native Simulator, primarily used in [exec](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0034-vm-syscalls-2/0034-vm-syscalls-2.md#exec) and [Spawn](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0050-vm-syscalls-3/0050-vm-syscalls-3.md#spawn). + +In the `native-simulator`, `ckb-std` provides a macro: [`entry_simulator`](https://github.com/nervosnetwork/ckb-std/blob/master/src/entry.rs#L64) (similar to `entry`). This macro exports two C functions: `__ckb_std_main` and `__set_script_info`, as shown below: + +```toml +unsafe extern "C" fn __ckb_std_main( + argc: core::ffi::c_int, + // Arg is the same as *const c_char ABI wise. + argv: *const $crate::env::Arg, + ) -> i8 { ... } +unsafe extern "C" fn __set_script_info( + ptr: *mut core::ffi::c_void, + tx_ctx_id: u64, + proc_ctx_id: u64, + ) { ... } +``` + +where: + +- `__ckb_std_main`: the entry function. When executed, it dynamically loads the lib and runs this function. The transaction information of the Script is passed through the two above-mentioned environment variables. +- `__set_script_info`: responsible for passing the global state necessary for `exec` and `spawn`. + +:::Attention + +- The separate crate `$crate::env::Arg` is used to prevent project complexity, as combining these two functions would complicate maintenance. +- For developers wishing to use this feature, we recommend to use `ckb-testtool` for development and testing to simplify work. +- Script and Native Simulator are bound one-to-one. If `ckb-testtool` cannot locate the corresponding Native Simulator, it will automatically execute the Script's results. +- Native Simulator is exclusively for debugging and cannot execute in CKB-VM. Be mindful when deploying Script on-chain. +- Native Simulator simulates Script execution, but cannot guarantee identical result to a real environment. Therefore, it should be used only for development. + ::: + +## Which Method to Choose + +These two debugging methods have their pros and cons. We recommend choosing based on the stage of your project (new or in maintenance) and your priority (compatibility or efficiency). + +| Feature | **CKB-debugger + VSCode** | **Native Simulator** | +| ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Pros** | -High compatibility, ready for earlier projects.
- No discrepancies after deployment because CKB-VM and on-chain data retrieval are shared with CKB. | - High execution efficiency.
- Advanced debugging tools (e.g., memory inspection). | +| **Cons** | | - Subtle differences from actual script execution.
- Requires a recent version `ckb-std` and some additional code. | +| **Ideal for** | Projects in maintenance mode where minimal disruption is desired. | New projects or projects undergoing major modification that require extensive debugging. | +| **Tips** | | - Use with `ckb-script-templates` and `ckb-testtool`.
- Avoid enabling Native Simulator in CI ([Continuous Integration](https://docs.github.com/en/actions/about-github-actions/about-continuous-integration-with-github-actions)) testing. | + --- ## Additional Resources diff --git a/website/docs/script/js-script.mdx b/website/docs/script/js-script.mdx index 0cefc328a..8389bd2c9 100644 --- a/website/docs/script/js-script.mdx +++ b/website/docs/script/js-script.mdx @@ -5,7 +5,7 @@ title: "Tutorial: Run JS on CKB" import Tabs from "@theme/Tabs"; import TabItem from "@theme/TabItem"; -import ScriptHeaders from "./ScriptHeaders.tsx"; +import Link from "@docusaurus/Link"; import TutorialHeader from "@components/TutorialHeader"; import Tooltip from "@components/Tooltip"; import ScriptTools from "./_ScriptTools.mdx"; @@ -13,26 +13,44 @@ import ScriptTools from "./_ScriptTools.mdx"; # Tutorial: Run JavaScript Code on CKB + + ckb-js-vm + + , +
+ + offckb {">= 0.3.2"} + +
, + ]} /> -## The High-Level Idea +## Tutorial Overview -As we have learned before, you can use any programming language to write a Script (Smart contract) for CKB. -But does it really work in reality? This tutorial will show a full example of using JavaScript to -write Scripts and execute them in the CKB-VM. +As you have learned before, it's possible to use any programming language to write a Script (Smart contract) for CKB. +But how practical is it in reality? In this tutorial, you will see a full example of using JavaScript to write and execute Scripts within the CKB-VM. -The process is as follows: first we port a JavaScript engine as a base Script to CKB. Then, we write -the business logic in JavaScript and execute this JS-powered Script within the base Script on top of CKB-VM. +The process is as follows: -It sounds like a of work. But thanks to the CKB VM team, we already have a fully runnable JavaScript -engine called [ckb-js-vm](https://github.com/nervosnetwork/ckb-js-vm). It is ported from -[quick.js](https://quick.js.org) so that it is compatible with running on CKB-VM. We just need to take -the ckb-js-vm and deploy it on-chain before we can run our JS Script. +1. Port a JavaScript Engine: You will learn how to port a JavaScript engine as a base Script to run on CKB. +2. Write Business Logic in JavaScript: You will learn how to build and execute JavaScript business logic within this base Script on the CKB-VM. -Below is a step-by-step guide, and you can also clone the full code example from the [Github repo](https://github.com/nervosnetwork/docs.nervos.org/tree/develop/examples/ckb-js-script). +This might sound complex, but thanks to the CKB-VM team, we already have a fully runnable JavaScript +engine called [ckb-js-vm](https://github.com/nervosnetwork/ckb-js-vm), which was ported from +[quick.js](https://quick.js.org) and optimized for CKB-VM. We will deploy the engine on a CKB devnet and use it to run JavaScript-based Scripts on CKB. + +Follow the step-by-step guide below, or check out the [full code example on Github](https://github.com/nervosnetwork/docs.nervos.org/tree/develop/examples/ckb-js-script). ## Get ckb-js-vm Binary @@ -40,7 +58,7 @@ The `ckb-js-vm` is a binary that can be used both in the CLI and in the on-chain binary and give it a try to see if it works as expected. :::info -You will need `clang 16+` to build the `ckb-js-vm` binary: +You will need `Clang ≥v18` to build the `ckb-js-vm` binary: ::: ```sh @@ -57,15 +75,18 @@ quick test. ### Install CKB-Debugger -:::info -To install, you need [Rust](https://www.rust-lang.org) and -[cargo](https://doc.rust-lang.org/cargo) -::: +Install CKB-Debugger using [cargo](https://doc.rust-lang.org/cargo). We recommend using **≥v0.113.0**. -```sh +```bash cargo install --git https://github.com/nervosnetwork/ckb-standalone-debugger ckb-debugger ``` +On **MacOS**, the `protoc` binary must be available to compile `ckb-vm-pprof-converter`. This can be installed via [Homebrew](https://brew.sh/): + +```bash +brew install protobuf +``` + ### Quick Test with CKB-Debugger Now let's run the `ckb-js-vm` with some JS test codes. @@ -87,11 +108,10 @@ ckb-debugger --read-file tests/examples/hello.js --bin build/ckb-js-vm -- -r ``` ```bash -Run from file, local access enabled. For testing only. -hello, world +Script log: Run from file, local access enabled. For Testing only. +Script log: hello, world Run result: 0 -Total cycles consumed: 30081070(2.9m) -Transfer cycles: 125121(122.2k), running cycles: 2955949(2.8m) +All cycles: 3016765(2.9M) ``` ```mdx-code-block @@ -102,7 +122,7 @@ Transfer cycles: 125121(122.2k), running cycles: 2955949(2.8m) With the `-r` option, `ckb-js-vm` will read a local JS file via CKB-Debugger. This function is intended for testing purposes and does not function in a production environment. However, we can see the running output, which includes a `hello, world` message. The run result is 0, indicating that the `hello.js` Script executes successfully. -Also, you can see how many `cycles`(the overhead required to execute a Script) are needed to run the JS Script in the output as well. +Also, you can see how many [cycles](/docs/script/vm-cycle-limits)(the overhead required to execute a Script) are needed to run the JS Script in the output as well. ## Integrate ckb-js-vm @@ -110,103 +130,34 @@ Also, you can see how many `cycles`(the overhead required to execute a Script) a up a project and writing codes to integrate `ckb-js-vm` with JavaScript code to gain a deeper understanding. -The first step is to create a new Script project. We use [ckb-script-templates](https://github.com/cryptape/ckb-script-templates) for this purpose. You will need the following dependencies: - - - -### Init a Script Project - -Now let's run the command to generate a new Script project called `my-first-script-workspace`: - -```mdx-code-block - - -``` - -```bash -alias create-ckb-scripts="cargo generate gh:cryptape/ckb-script-templates workspace" -create-ckb-scripts -``` - -```mdx-code-block - - -``` - -```bash -⚠️ Favorite `gh:cryptape/ckb-script-templates` not found in config, using it as a git repository: https://github.com/cryptape/ckb-script-templates.git -🤷 Project Name: my-first-script-workspace -🔧 Destination: /tmp/my-first-script-workspace ... -🔧 project-name: my-first-script-workspace ... -🔧 Generating template ... -🔧 Moving generated files into: `/tmp/my-first-script-workspace`... -🔧 Initializing a fresh Git repository -✨ Done! New project created /tmp/my-first-script-workspace -``` - -```mdx-code-block - - -``` - -### Create a New Script - -Let’s create a new Script called `run-js`. - -```mdx-code-block - - -``` - -```bash -cd my-first-script-workspace -make generate -``` - -```mdx-code-block - - -``` - -```bash -🤷 Project Name: run-js -🔧 Destination: /tmp/my-first-script-workspace/contracts/run-js ... -🔧 project-name: carrot ... -🔧 Generating template ... -🔧 Moving generated files into: `/tmp/my-first-script-workspace/contracts/run-js`... -🔧 Initializing a fresh Git repository -✨ Done! New project created /tmp/my-first-script-workspace/contracts/run-js -``` +The first step is to create a new Script project. Init a folder named `ckb-js-script`. -```mdx-code-block - - +```sh +mkdir ckb-js-script ``` Our project relies on `ckb-js-vm`, so we need to include it in the project. Create a new folder named -`deps` in the root of our Script workspace: +`deps` in the root of our workspace: ```sh -cd my-first-script-workspace +cd ckb-js-script mkdir deps ``` -Copy the `ckb-js-vm` binary we built before into the `deps` folder. When you're done, it should look like this: +Copy `ckb-js-vm/tools/compile.awk` and the `ckb-js-vm` binary we built before into the `deps` folder. When you're done, it should look like this: ```sh ---build ---contracts --deps + --compile.awk --ckb-js-vm ... ``` Everything looks good now! -### Integrate via Script +The simplest way to run JavaScript code using `ckb-js-vm` is via a Script. -The simplest way to run JavaScript code using `ckb-js-vm` is via a Script. A `ckb-js-vm` Script has the -following structure: +Let's take a look at `ckb-js-vm` Script structure: ```sh code_hash: @@ -219,218 +170,95 @@ javascript code cell, 1 byte> 2 bytes ckb-js-vm args are reserved for further use ::: -Now let's get our hands dirty to integrate `ckb-js-vm` in this way. +We can pass the JavaScript code as `script_args` to the `ckb-js-vm` base Script. In this way, we can execute our own js code and integrate the `ckb-js-vm` in our project. -#### Write a simple `hello.js` Script +### Write a simple `hello.js` Script ```bash -cd my-first-script-workspace +cd ckb-js-script mkdir js/build touch js/hello.js ``` Fill the `hello.js` with the following code: -```js title='my-first-script-workspace/js/hello.js' +```js title='ckb-js-script/js/hello.js' console.log("hello, ckb-js-script!"); ``` -#### Compile the `hello.js` into binary with CKB-Debugger +### Compile the `hello.js` into binary with CKB-Debugger ```sh -ckb-debugger --read-file js/hello.js --bin deps/ckb-js-vm -- -c | awk '/Run result: 0/{exit} {print}' | xxd -r -p > js/build/hello.bc -``` - -#### Write tests for the `hello.js` Script - -Now let's assemble all the Scripts and run them in a single CKB transaction. We will use the built-in test module -from `ckb-script-templates`, which allows us to test without actually running a blockchain. - -```rust title="my-first-script-workspace/tests/src/tests.rs" -use super::*; -use ckb_testtool::{ - builtin::ALWAYS_SUCCESS, - ckb_types::{bytes::Bytes, core::TransactionBuilder, packed::*, prelude::*}, - context::Context, -}; - -const MAX_CYCLES: u64 = 10_000_000; - -#[test] -fn hello_script() { - // deploy contract - let mut context = Context::default(); - let loader = Loader::default(); - let js_vm_bin = loader.load_binary("../../deps/ckb-js-vm"); - let js_vm_out_point = context.deploy_cell(js_vm_bin); - let js_vm_cell_dep = CellDep::new_builder() - .out_point(js_vm_out_point.clone()) - .build(); - - let js_script_bin = loader.load_binary("../../js/build/hello.bc"); - let js_script_out_point = context.deploy_cell(js_script_bin.clone()); - let js_script_cell_dep = CellDep::new_builder() - .out_point(js_script_out_point.clone()) - .build(); - - // prepare scripts - let always_success_out_point = context.deploy_cell(ALWAYS_SUCCESS.clone()); - let lock_script = context - .build_script(&always_success_out_point.clone(), Default::default()) - .expect("script"); - let lock_script_dep = CellDep::new_builder() - .out_point(always_success_out_point) - .build(); - - // prepare cell deps - let cell_deps: Vec = vec![lock_script_dep, js_vm_cell_dep, js_script_cell_dep]; - - // prepare cells - let input_out_point = context.create_cell( - CellOutput::new_builder() - .capacity(1000u64.pack()) - .lock(lock_script.clone()) - .build(), - Bytes::new(), - ); - let input = CellInput::new_builder() - .previous_output(input_out_point.clone()) - .build(); - - // args: - let mut type_script_args: [u8; 35] = [0u8; 35]; - let reserved = [0u8; 2]; - let (js_cell, _) = context.get_cell(&js_script_out_point.clone()).unwrap(); - let js_type_script = js_cell.type_().to_opt().unwrap(); - let code_hash = js_type_script.calc_script_hash(); - let hash_type = js_type_script.hash_type(); - type_script_args[..2].copy_from_slice(&reserved); - type_script_args[2..34].copy_from_slice(code_hash.as_slice()); - type_script_args[34..35].copy_from_slice(&hash_type.as_slice()); - - let type_script = context - .build_script(&js_vm_out_point, type_script_args.to_vec().into()) - .expect("script"); - - let outputs = vec![ - CellOutput::new_builder() - .capacity(500u64.pack()) - .lock(lock_script.clone()) - .type_(Some(type_script.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(500u64.pack()) - .lock(lock_script) - .build(), - ]; - - // prepare output cell data - let outputs_data = vec![Bytes::new(), Bytes::new()]; - - // build transaction - let tx = TransactionBuilder::default() - .cell_deps(cell_deps) - .input(input) - .outputs(outputs) - .outputs_data(outputs_data.pack()) - .build(); - - let tx = tx.as_advanced_builder().build(); - - // run - let cycles = context - .verify_tx(&tx, MAX_CYCLES) - .expect("pass verification"); - println!("consume cycles: {}", cycles); -} - +ckb-debugger --read-file js/hello.js --bin deps/ckb-js-vm -- -c | awk -f deps/compile.awk | xxd -r -p > js/build/hello.bc ``` -Let's break down the code provided: - -First, We deploy the `ckb-js-vm`, `hello.bc` and `ALWAYS_SUCCESS` binaries to the blockchain, resulting in -3 Scripts in Live Cells. The `ALWAYS_SUCCESS` is used solely to simplify the -Lock Script in our test flow. - -Then, we build an output Cell that carries a special Type Script to execute the `hello.js` codes. -The `code_hash` and `hash_type` in the Type Script reference the `ckb-js-vm` Script Cell. It -is automatically done by this line of code: +If you are using Mac, change `awk` to `gawk` which can be installed by `brew install gawk`: -```rust - let type_script = context - .build_script(&js_vm_out_point, type_script_args.to_vec().into()) - .expect("script"); +```sh +ckb-debugger --read-file js/hello.js --bin deps/ckb-js-vm -- -c | gawk -f deps/compile.awk | xxd -r -p > js/build/hello.bc ``` -The key here is the args of the Type Script. We locate the Cell that carries our `hello.js` codes and -insert the reference information—which includes `code_hash` and `hash_type`–of that Cell into the args, -following the args structure of `ckb-js-vm`. +### Test `hello.js` Script on Devnet -```rust - // args: - let mut type_script_args: [u8; 35] = [0u8; 35]; - let reserved = [0u8; 2]; - let (js_cell, _) = context.get_cell(&js_script_out_point.clone()).unwrap(); - let js_type_script = js_cell.type_().to_opt().unwrap(); - let code_hash = js_type_script.calc_script_hash(); - let hash_type = js_type_script.hash_type(); - type_script_args[..2].copy_from_slice(&reserved); - type_script_args[2..34].copy_from_slice(code_hash.as_slice()); - type_script_args[34..35].copy_from_slice(&hash_type.as_slice()); -``` +Now let's assemble all the Scripts and run them in a single CKB transaction. +We will use [`offckb`](/docs/sdk-and-devtool/offckb) and [`CCC`](/docs/sdk-and-devtool/ccc) SDK, which allows us to test it locally. -Finally, don't forget to add all the Live Cells containing the related Scripts in the `cellDeps` in the transaction: +First, start a local blockchain: -```rust - // prepare cell deps - let cell_deps: Vec = vec![lock_script_dep, js_vm_cell_dep, js_script_cell_dep]; +```sh +offckb node +``` - // build transaction - let tx = TransactionBuilder::default() - .cell_deps(cell_deps) - .input(input) - .outputs(outputs) - .outputs_data(outputs_data.pack()) - .build(); +Open a new terminal, deploy the `ckb-js-vm` and `hello.bc` binaries to the blockchain, resulting in +2 Scripts in Live Cells. - let tx = tx.as_advanced_builder().build(); +```mdx-code-block + + +``` - // run - let cycles = context - .verify_tx(&tx, MAX_CYCLES) - .expect("pass verification"); - println!("consume cycles: {}", cycles); +```sh +offckb deploy --target ./deps/ckb-js-vm --type-id ``` -#### Run the Test to See If It Passes +```mdx-code-block + + +``` ```sh -make build -make test +wait for tx confirmed on-chain... +tx committed. +ckb-js-vm deployment.toml file /Library/Application Support/offckb-nodejs/devnet/contracts/ckb-js-vm/deployment.toml generated successfully. +ckb-js-vm migration json file /Library/Application Support/offckb-nodejs/devnet/contracts/ckb-js-vm/migrations/2024-11-18-195031.json generated successfully. +done. ``` -By default, the test output does not display the executing logs of the Scripts. To view them, you can use the following -alternative command: +```mdx-code-block + + +``` ```mdx-code-block - + ``` ```sh -cargo test -- --nocapture +offckb deploy --target ./js/build/hello.bc --type-id ``` ```mdx-code-block - + ``` ```sh -running 1 test -[contract debug] hello, ckb-js-script! -consume cycles: 3070458 -test tests::hello_script ... ok +wait for tx confirmed on-chain... +tx committed. +hello.bc deployment.toml file /Library/Application Support/offckb-nodejs/devnet/contracts/hello.bc/deployment.toml generated successfully. +hello.bc migration json file /Library/Application Support/offckb-nodejs/devnet/contracts/hello.bc/migrations/2024-11-18-195031.json generated successfully. +done. ``` ```mdx-code-block @@ -438,551 +266,251 @@ test tests::hello_script ... ok ``` -The logs show `hello, ckb-js-script!`, indicating our JavaScript code executed successfully. - -#### Write a `fib.js` Script +Open another terminal and start a offckb Nodejs Repl to build the transaction: -We can try a different JavaScript example. Let's write a `fib.js` in the `js` folder: - -```js title='my-first-script-workspace/js/fib.js' -console.log("testing fib"); -function fib(n) { - if (n <= 0) return 0; - else if (n == 1) return 1; - else return fib(n - 1) + fib(n - 2); -} -var value = fib(10); -console.assert(value == 55, "fib(10) = 55"); +```sh +offckb repl -r ``` -#### Compile the `fib.js` into Binary with CKB-Debugger - ```sh -ckb-debugger --read-file js/fib.js --bin deps/ckb-js-vm -- -c | awk '/Run result: 0/{exit} {print}' | xxd -r -p > js/build/fib.bc +Welcome to OffCKB REPL! +[[ Default Network: devnet, enableProxyRPC: true, CCC SDK: 0.0.16-alpha.3 ]] +Type 'help()' to learn how to use. +OffCKB > ``` -#### Add a New Test for The `fib.js` Script - -```rust title='my-first-script-workspace/tests/src/tests.rs' -#[test] -fn fib_script() { - // deploy contract - let mut context = Context::default(); - let loader = Loader::default(); - let js_vm_bin = loader.load_binary("../../deps/ckb-js-vm"); - let js_vm_out_point = context.deploy_cell(js_vm_bin); - let js_vm_cell_dep = CellDep::new_builder() - .out_point(js_vm_out_point.clone()) - .build(); - - let js_script_bin = loader.load_binary("../../js/build/fib.bc"); - let js_script_out_point = context.deploy_cell(js_script_bin.clone()); - let js_script_cell_dep = CellDep::new_builder() - .out_point(js_script_out_point.clone()) - .build(); - - // prepare scripts - let always_success_out_point = context.deploy_cell(ALWAYS_SUCCESS.clone()); - let lock_script = context - .build_script(&always_success_out_point.clone(), Default::default()) - .expect("script"); - let lock_script_dep = CellDep::new_builder() - .out_point(always_success_out_point) - .build(); - - // prepare cell deps - let cell_deps: Vec = vec![lock_script_dep, js_vm_cell_dep, js_script_cell_dep]; - - // prepare cells - let input_out_point = context.create_cell( - CellOutput::new_builder() - .capacity(1000u64.pack()) - .lock(lock_script.clone()) - .build(), - Bytes::new(), - ); - let input = CellInput::new_builder() - .previous_output(input_out_point.clone()) - .build(); - - // args: - let mut type_script_args: [u8; 35] = [0u8; 35]; - let reserved = [0u8; 2]; - let (js_cell, _) = context.get_cell(&js_script_out_point.clone()).unwrap(); - let js_type_script = js_cell.type_().to_opt().unwrap(); - let code_hash = js_type_script.calc_script_hash(); - let hash_type = js_type_script.hash_type(); - type_script_args[..2].copy_from_slice(&reserved); - type_script_args[2..34].copy_from_slice(code_hash.as_slice()); - type_script_args[34..35].copy_from_slice(&hash_type.as_slice()); - - let type_script = context - .build_script(&js_vm_out_point, type_script_args.to_vec().into()) - .expect("script"); - - let outputs = vec![ - CellOutput::new_builder() - .capacity(500u64.pack()) - .lock(lock_script.clone()) - .type_(Some(type_script.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(500u64.pack()) - .lock(lock_script) - .build(), - ]; - - // prepare output cell data - let outputs_data = vec![Bytes::new(), Bytes::new()]; - - // build transaction - let tx = TransactionBuilder::default() - .cell_deps(cell_deps) - .input(input) - .outputs(outputs) - .outputs_data(outputs_data.pack()) - .build(); - - let tx = tx.as_advanced_builder().build(); - - // run - let cycles = context - .verify_tx(&tx, MAX_CYCLES) - .expect("pass verification"); - println!("consume cycles: {}", cycles); -} -``` +Build the transaction to test our hello Script. -#### Run the test for `fib.js` smart contract +First, we will construct an output Cell that carries a special Type Script to execute the `hello.js` codes. +The `code_hash` and `hash_type` in the Type Script reference the `ckb-js-vm` Script Cell. The information can directly access from the REPL with `myScripts` variable: ```sh -make build -make test +OffCKB > let baseScriptArgs = `0x0000${myScripts['hello.bc'].codeHash.slice(2)}0${ccc.hashTypeToBytes(myScripts['hello.bc'].hashType).toString()}`; +OffCKB > let baseScript = ccc.Script.from({ +... codeHash: myScripts["ckb-js-vm"].codeHash, +... hashType: myScripts["ckb-js-vm"].hashType, +... args: baseScriptArgs, +... }) ``` -### Integrate via Spawn Syscall +The key here is the args of the Type Script. We locate the Cell that carries our `hello.js` codes and +insert the reference information—which includes `code_hash` and `hash_type`–of that Cell into the args, +following the args structure of `ckb-js-vm`. -Another way to integrate `ckb-js-vm` is by calling it from your own Scripts. This approach is useful when you have -more complex custom logic to handle and still want to execute some JavaScript code. In this example, we -use `ckb_spawn` syscall to call Script from another Script. `ckb_spawn` is the recommended way to -call `ckb-js-vm`, here is -[why](https://github.com/nervosnetwork/ckb-js-vm/blob/main/docs/intro.md#integration). +```sh +OffCKB > let tx = ccc.Transaction.from({ +... outputs: [ +... { +... lock: accounts[0].lockScript, +... type: baseScript +... }, +... ], +... cellDeps: [ +... ...myScripts["ckb-js-vm"].cellDeps.map(c => c.cellDep), +... ...myScripts['hello.bc'].cellDeps.map(c => c.cellDep) +... ], +... }); +``` -We will use Rust to write a new Script called `run-js`. In this Script, you can add custom logics and -validations before calling the `ckb-js-vm` Script to execute JS codes. +Also, don't forget to add all the Live Cells containing the related Scripts in the `cellDeps` in the transaction. -#### Write `run-js` Script +Finally, we sign and send the transaction: -```rust title='my-first-script-workspace/contracts/run-js/src/main.rs' -#![no_std] -#![cfg_attr(not(test), no_main)] +```sh +OffCKB > let signer = new ccc.SignerCkbPrivateKey(client, accounts[0].privkey); +OffCKB > await tx.completeInputsByCapacity(signer); +2 +OffCKB > await tx.completeFeeBy(signer, 1000); +[ 0, true ] +OffCKB > await signer.sendTransaction(tx); +'0x1464fec71bd95c4caa2a2640f1573850b25ba9c696c1bfdbe0dc7459717c734b' +OffCKB > +``` -#[cfg(test)] -extern crate alloc; +### Debug the transaction to See If It works expected -#[cfg(not(test))] -use ckb_std::default_alloc; -use ckb_std::syscalls; -#[cfg(not(test))] -ckb_std::entry!(program_entry); -#[cfg(not(test))] -default_alloc!(); +```mdx-code-block + + +``` -pub fn program_entry() -> i8 { - ckb_std::debug!("This is a sample run JS code contract!"); +```sh +offckb debug --tx-hash 0x1464fec71bd95c4caa2a2640f1573850b25ba9c696c1bfdbe0dc7459717c734b +``` - let mut spgs_exit_code: i8 = -1; +```mdx-code-block + + +``` - let mut spgs_content = [0u8; 80]; - let mut spgs_content_length: u64 = 80; - let spgs = syscalls::SpawnArgs { - memory_limit: 8, - exit_code: &mut spgs_exit_code as *mut i8, - content: &mut spgs_content as *mut u8, - content_length: &mut spgs_content_length as *mut u64, - }; +```sh +Dump transaction successfully - // we supposed the first cell in cellDeps is the ckb-js-vm cell - // we then call ckb-js-vm script using spawn syscall to execute the js code in the script args - let result = - ckb_std::syscalls::spawn(0, ckb_std::ckb_constants::Source::CellDep, 0, &[], &spgs); - ckb_std::debug!("spawn result: {:?}", result); +****************************** +****** Input[0].Lock ****** - if result != 0 { - return 1; - } +Run result: 0 +All cycles: 1640617(1.6M) - if spgs_exit_code != 0 { - return 1; - } +****************************** +****** Input[1].Lock ****** - 0 -} -``` +Run result: 0 +All cycles: 1640617(1.6M) -The most important code in the Script is the usage of `ckb_std` library to perform the `spawn` syscall -to call the `ckb-js-vm`: +****************************** +****** Output[0].Type ****** -```rust - // we supposed the first cell in cellDeps is the ckb-js-vm cell - // we then call ckb-js-vm script using spawn syscall to execute the js code in the script args - let result = - ckb_std::syscalls::spawn(0, ckb_std::ckb_constants::Source::CellDep, 0, &[], &spgs); +Script log: hello, ckb-js-script! +Run result: 0 +All cycles: 2993892(2.9M) +✨ Done in 1.50s. ``` -In order to use `ckb_std::syscalls::spawn`, you need to enable the `ckb2023` feature in the `ckb-std` deps: - -```toml title="my-first-script-workspace/contracts/run-js/Cargo.toml" -[dependencies] -ckb-std = {version = "0.15.1", features = ["ckb2023"]} +```mdx-code-block + + ``` -For simplicity, we supposed the `ckb-js-vm` Script is in the first position of the cell deps in the -transaction. - -We can check the return result from the `spawn` syscall to see if the code executes successfully. - -#### Write Test for Run-JS Script - -We have our custom Script `run-js` that can execute JS codes and customize validations. Now let's -write some tests for our Script. - -This time, let's use a more realistic JS Script to test. We will utilize the [ckb-syscall JS binding](https://github.com/nervosnetwork/ckb-js-vm/blob/main/docs/syscalls.md) to write a +The logs show `hello, ckb-js-script!`, indicating our JavaScript code executed successfully. -sUDT example in JavaScript and verify that it executes successfully -in our `run-js` Scripts. +### Write a `fib.js` Script -```js title='my-first-script-workspace/js/sudt.js' -const CKB_INDEX_OUT_OF_BOUND = 1; -const ERROR_AMOUNT = -52; +We can try a different JavaScript example. Let's write a `fib.js` in the `js` folder: -function assert(cond, obj1) { - if (!cond) { - throw Error(obj1); - } +```js title='ckb-js-script/js/fib.js' +console.log("testing fib"); +function fib(n) { + if (n <= 0) return 0; + else if (n == 1) return 1; + else return fib(n - 1) + fib(n - 2); } +var value = fib(10); +console.assert(value == 55, "fib(10) = 55"); +``` -function compare_array(a, b) { - if (a.byteLength != b.byteLength) { - return false; - } - for (let i = 0; i < a.byteLength; i++) { - if (a[i] != b[i]) { - return false; - } - } - return true; -} +### Compile the `fib.js` into Binary with CKB-Debugger -function unpack_script(buf) { - let script = new Uint32Array(buf); - let raw_data = new Uint8Array(buf); - - let full_size = script[0]; - assert(full_size == buf.byteLength, "full_size == buf.byteLength"); - let code_hash_offset = script[1]; - let code_hash = buf.slice(code_hash_offset, code_hash_offset + 32); - let hash_type_offset = script[2]; - let hash_type = raw_data[hash_type_offset]; - let args_offset = script[3]; - let args = buf.slice(args_offset + 4); - return { code_hash: code_hash, hash_type: hash_type, args: args }; -} +```sh +ckb-debugger --read-file js/fib.js --bin deps/ckb-js-vm -- -c | awk '/Run result: 0/{exit} {print}' | xxd -r -p > js/build/fib.bc +``` -function* iterate_field(source, field) { - let index = 0; - while (true) { - try { - let ret = ckb.load_cell_by_field(index, source, field); - yield ret; - index++; - } catch (e) { - if (e.error_code == CKB_INDEX_OUT_OF_BOUND) { - break; - } else { - throw e; - } - } - } -} +### Build a New Transaction to Test `fib.js` Script -function* iterate_cell_data(source) { - let index = 0; - while (true) { - try { - let ret = ckb.load_cell_data(index, source); - yield ret; - index++; - } catch (e) { - if (e.error_code == CKB_INDEX_OUT_OF_BOUND) { - break; - } else { - throw e; - } - } - } -} +We repeat the same process as above: -function main() { - console.log("simple UDT ..."); - let buf = ckb.load_script(); - let script = unpack_script(buf); - let owner_mode = false; - // ckb-js-vm has leading 35 bytes args - let real_args = script.args.slice(35); - for (let lock_hash of iterate_field( - ckb.SOURCE_INPUT, - ckb.CELL_FIELD_LOCK_HASH - )) { - if (compare_array(lock_hash, real_args)) { - owner_mode = true; - } - } - if (owner_mode) { - return 0; - } - let input_amount = 0n; - - for (let data of iterate_cell_data(ckb.SOURCE_GROUP_INPUT)) { - if (data.byteLength != 16) { - throw `Invalid data length: ${data.byteLength}`; - } - let n = new BigUint64Array(data); - let current_amount = n[0] | (n[1] << 64n); - input_amount += current_amount; - } - let output_amount = 0n; - for (let data of iterate_cell_data(ckb.SOURCE_GROUP_OUTPUT)) { - if (data.byteLength != 16) { - throw `Invalid data length: ${data.byteLength}`; - } - let n = new BigUint64Array(data); - let current_amount = n[0] | (n[1] << 64n); - output_amount += current_amount; - } - console.log(`verifying amount: ${input_amount} and ${output_amount}`); - if (input_amount < output_amount) { - return ERROR_AMOUNT; - } - console.log("Simple UDT quit successfully"); - return 0; -} +Deploy the fib Script: -let exit_code = main(); -if (exit_code != 0) { - ckb.exit(exit_code); -} +```mdx-code-block + + ``` -Compile this `sudt.js` into binaries with CKB-Debugger: - ```sh -ckb-debugger --read-file js/sudt.js --bin deps/ckb-js-vm -- -c | awk '/Run result: 0/{exit} {print}' | xxd -r -p > js/build/sudt.bc -``` - -Add a new test to the `tests` file: - -```rust title='my-first-script-workspace/tests/src/tests.rs' -#[test] -fn sudt_script() { - // deploy contract - let mut context = Context::default(); - let loader = Loader::default(); - let js_vm_bin = loader.load_binary("../../deps/ckb-js-vm"); - let js_vm_out_point = context.deploy_cell(js_vm_bin); - let js_vm_cell_dep = CellDep::new_builder() - .out_point(js_vm_out_point.clone()) - .build(); - - let run_js_bin = loader.load_binary("run-js"); - let run_js_out_point = context.deploy_cell(run_js_bin); - let run_js_cell_dep = CellDep::new_builder() - .out_point(run_js_out_point.clone()) - .build(); - - let js_script_bin = loader.load_binary("../../js/build/sudt.bc"); - let js_script_out_point = context.deploy_cell(js_script_bin.clone()); - let js_script_cell_dep = CellDep::new_builder() - .out_point(js_script_out_point.clone()) - .build(); - - // prepare scripts - let always_success_out_point = context.deploy_cell(ALWAYS_SUCCESS.clone()); - let lock_script = context - .build_script(&always_success_out_point.clone(), Default::default()) - .expect("script"); - let lock_script_dep = CellDep::new_builder() - .out_point(always_success_out_point) - .build(); - - // prepare cell deps - let cell_deps: Vec = vec![ - js_vm_cell_dep, - run_js_cell_dep, - lock_script_dep, - js_script_cell_dep, - ]; - - // prepare cells - let input_out_point = context.create_cell( - CellOutput::new_builder() - .capacity(1000u64.pack()) - .lock(lock_script.clone()) - .build(), - Bytes::new(), - ); - let input = CellInput::new_builder() - .previous_output(input_out_point.clone()) - .build(); - - // args: - let mut type_script_args: [u8; 67] = [0u8; 67]; - let reserved = [0u8; 2]; - let (js_cell, _) = context.get_cell(&js_script_out_point.clone()).unwrap(); - let js_type_script = js_cell.type_().to_opt().unwrap(); - let code_hash = js_type_script.calc_script_hash(); - let hash_type = js_type_script.hash_type(); - let owner_lock_script_hash = lock_script.clone().calc_script_hash(); - - type_script_args[..2].copy_from_slice(&reserved); - type_script_args[2..34].copy_from_slice(code_hash.as_slice()); - type_script_args[34..35].copy_from_slice(&hash_type.as_slice()); - type_script_args[35..].copy_from_slice(owner_lock_script_hash.as_slice()); - - let type_script = context - .build_script(&run_js_out_point, type_script_args.to_vec().into()) - .expect("script"); - - let outputs = vec![ - CellOutput::new_builder() - .capacity(500u64.pack()) - .lock(lock_script.clone()) - .type_(Some(type_script.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(500u64.pack()) - .lock(lock_script) - .build(), - ]; - - // prepare output cell data - let sudt_amount: u128 = 10; // issue 10 tokens - let outputs_data = vec![ - Bytes::from(sudt_amount.to_le_bytes().to_vec()), - Bytes::new(), - ]; - - // build transaction - let tx = TransactionBuilder::default() - .cell_deps(cell_deps) - .input(input) - .outputs(outputs) - .outputs_data(outputs_data.pack()) - .build(); - - let tx = tx.as_advanced_builder().build(); - - // run - let cycles = context - .verify_tx(&tx, MAX_CYCLES) - .expect("pass verification"); - println!("consume cycles: {}", cycles); -} +offckb deploy --target ./js/build/fib.bc --type-id ``` -Some explanation for this test: - -Just like the previous tests, we deploy all the Scripts we need, including `ckb-js-vm`, `run-js`, -`sudt.js` and so on. We then assemble a transaction that produce an output Cell that carries our -`run-js` Script as its Type Script. In the args of this Type Script, we follow the `ckb-js-vm` args -data structure. The difference this time is that we also include the arguments for the `sudt.js` within -the Type Script args. This allows our `sudt.js` code can read its own arguments and get executed as -expected. The arguments for `sudt.js` include a Lock Script hash, which is used to determine if it is under -`owner_mode` to perform different validations. - -```rust - // args: - let mut type_script_args: [u8; 67] = [0u8; 67]; - let reserved = [0u8; 2]; - let (js_cell, _) = context.get_cell(&js_script_out_point.clone()).unwrap(); - let js_type_script = js_cell.type_().to_opt().unwrap(); - let code_hash = js_type_script.calc_script_hash(); - let hash_type = js_type_script.hash_type(); - let owner_lock_script_hash = lock_script.clone().calc_script_hash(); - - type_script_args[..2].copy_from_slice(&reserved); - type_script_args[2..34].copy_from_slice(code_hash.as_slice()); - type_script_args[34..35].copy_from_slice(&hash_type.as_slice()); - type_script_args[35..].copy_from_slice(owner_lock_script_hash.as_slice()); +```mdx-code-block + + ``` -Lastly, we put the token amount in the data field of the output Cell containing our `run-js` Script and then -assemble the transaction for submission on-chain: +```sh +wait for tx confirmed on-chain... +tx committed. +fib.bc deployment.toml file /Library/Application Support/offckb-nodejs/devnet/contracts/fib.bc/deployment.toml generated successfully. +fib.bc migration json file /Library/Application Support/offckb-nodejs/devnet/contracts/fib.bc/migrations/2024-11-18-195031.json generated successfully. +done. +``` -```rust - // prepare output cell data - let sudt_amount: u128 = 10; // issue 10 tokens - let outputs_data = vec![ - Bytes::from(sudt_amount.to_le_bytes().to_vec()), - Bytes::new(), - ]; +```mdx-code-block + + +``` - // build transaction - let tx = TransactionBuilder::default() - .cell_deps(cell_deps) - .input(input) - .outputs(outputs) - .outputs_data(outputs_data.pack()) - .build(); +Build and send the transaction: - let tx = tx.as_advanced_builder().build(); +```sh +OffCKB > let baseScriptArgs = `0x0000${myScripts['fib.bc'].codeHash.slice(2)}0${ccc.hashTypeToBytes(myScripts['fib.bc'].hashType).toString()}`; +OffCKB > let baseScript = ccc.Script.from({ +... codeHash: myScripts["ckb-js-vm"].codeHash, +... hashType: myScripts["ckb-js-vm"].hashType, +... args: baseScriptArgs, +... }) +OffCKB > let tx = ccc.Transaction.from({ +... outputs: [ +... { +... lock: accounts[0].lockScript, +... type: baseScript +... }, +... ], +... cellDeps: [ +... ...myScripts["ckb-js-vm"].cellDeps.map(c => c.cellDep), +... ...myScripts['fib.bc'].cellDeps.map(c => c.cellDep) +... ], +... }); +OffCKB > let signer = new ccc.SignerCkbPrivateKey(client, accounts[0].privkey); +OffCKB > await tx.completeInputsByCapacity(signer); +2 +OffCKB > await tx.completeFeeBy(signer, 1000); +[ 0, true ] +OffCKB > await signer.sendTransaction(tx); +'0x3f8d8f0e4ef3be052ecb2784d058a5e88d700831783524f7295b23df047897d0' +OffCKB > +``` + +### Debug the transaction to See If It works expected - // run - let cycles = context - .verify_tx(&tx, MAX_CYCLES) - .expect("pass verification"); - println!("consume cycles: {}", cycles); +```mdx-code-block + + ``` -#### Run test for `sudt.js` - ```sh -make build -cargo test -- --nocapture sudt_script +offckb debug --tx-hash 0x1464fec71bd95c4caa2a2640f1573850b25ba9c696c1bfdbe0dc7459717c734b ``` -You can see the output contains the spawn result and other information: +```mdx-code-block + + +``` ```sh -running 1 test -[contract debug] This is a sample run js code contract! -[contract debug] simple UDT ... -[contract debug] checking failed on quickjs/ckb_module.c:123, code = 1 -[contract debug] spawn result: 0 -consume cycles: 3775332 -test tests::sudt_script ... ok +Dump transaction successfully + +****************************** +****** Input[0].Lock ****** + +Run result: 0 +All cycles: 1652553(1.6M) + +****************************** +****** Output[0].Type ****** -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 2 filtered out; finished in 0.04s +Script log: testing fib +Run result: 0 +All cycles: 3190302(3.0M) +✨ Done in 1.71s. ``` ---- +```mdx-code-block + + +``` ## Congratulations! By following this tutorial so far, you have mastered how to write Scripts that integrates `ckb-js-vm` to execute JavaScript codes on CKB. Here's a quick recap: -- Use `ckb-script-templates` to init a Script project -- Use `ckb_std` to leverage CKB syscalls for performing `ckb_spawn` syscall to call `ckb-js-vm`. -- Build args for the Script to carry the reference info to the JavaScript code Cell and its - arguments. +- Use `offckb` REPL to quickly prototype with JavaScript code and CKB bundles +- Use Script `code_hash` and `hash_type` to build the base layer layer of `ckb-js-vm`. +- Build args for the Script to carry the reference info of the JavaScript code Cell ## Additional Resources - Full source code of this tutorial: [ckb-js-script](https://github.com/nervosnetwork/docs.nervos.org/tree/develop/examples/ckb-js-script) - More about `ckb-js-vm`: [ckb-js-vm docs](https://nervosnetwork/ckb-js-vm/blob/main/docs) -- CKB syscalls specs: [RFC-0009](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0009-vm-syscalls/0009-vm-syscalls.md) -- Script templates: [ckb-script-templates](https://github.com/cryptape/ckb-script-templates) - CKB transaction structure: [RFC-0022-transaction-structure](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0022-transaction-structure/0022-transaction-structure.md) - CKB data structure basics: [RFC-0019-data-structure](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0019-data-structures/0019-data-structures.md) diff --git a/website/docs/script/script-upgrade-workflow.mdx b/website/docs/script/script-upgrade-workflow.mdx new file mode 100644 index 000000000..f0a665d8a --- /dev/null +++ b/website/docs/script/script-upgrade-workflow.mdx @@ -0,0 +1,71 @@ +--- +id: script-upgrade-workflow +title: "Script Upgrades Workflow" +--- + +# Recommended Workflow for Script Upgrades + +> This article is based on ideas presented in [this talk](https://blog.cryptape.com/reaching-design-consensus-on-ckb-script-execution-model) by Xuejie Xiao + +We have introduced the [`Type ID` upgradable code mechanism](/docs/script/type-id) that enables us to build a Cell with a unique Type Script across all CKB Live Cells while maintaining the ability to modify this Cell. + +This article outlines the recommended process for using Type ID Cells, adhering to the original principles of on-chain Script upgrades. + +## Workflow: Type ID + Lock Script + +![/img/script-upgrade-workflow/typeid-with-different-lock.jpeg](/img/script-upgrade-workflow/typeid-with-different-lock.jpeg) + +The key observation is that Lock Scripts can be changed in a Type ID Cell. This flexibility means that you don’t always have to use the same Lock Script. When upgrading a Type ID Cell, you can change the lock to leverage its flexibility. + +The recommended workflow aligns well with the typical upgrade process, as outlined below: + +1. **Initial Deployment** + +When a piece of code is deployed for the first time, it’s unclear if it is free of bugs or if additional features will be requested after further interaction with the Script. At this stage, deploying the code with Type ID is preferable, as it allows for future upgrades. A multi-sig lock can be used at this point. + +2. **Iterative** **Upgrade** + +As development goes, the deployed code may undergo several upgrades using the “Type ID” design, addressing bug fixes and incorporating new features. + +3. **Final Code Freezing** + +Eventually we might reach a state where freezing the code is desirable, due to reasons like: + +- Quirks in the deployed code have been sufficiently understood with enough confidence gained in the code stability +- A significant amount of assets are controlled by the code, bringing high risk if the code is changeable. + +At this stage, one can perform a final upgrade on the Cell by simply altering the Lock Script to “unlockable”—to freeze the code. This way, even though the Type ID setup is still present, the Cell can no longer be modified. In other words, **Type ID alone does not imply that the stored code is mutable—the Lock Script also plays a critical role in this process**. + +This recommended workflow addresses two distinct roles: + +- **For Script developer**: A Script developer can choose to deploy a piece of code in an upgradable Cell using the "Type ID" Script. +- **For dApp developer**: It is entirely up to the actual dApp developer to decide whether to reference the deployed code using the "Type ID" approach. + +These two roles are completely independent, offering flexibility in how upgrades and references are managed within the system. + +## An Example + +Assume someone deployed UDT (User-Defined Token) code with a Type ID setup on-chain. Suppose two tokens are issued using this UDT code, where: + +- **UDT A** uses a Type Script with `type` as its `hash_type`. +- **UDT B** uses a Type Script with `data2` (a data variant) as its `hash_type`. + +If the UDT developer upgrades the UDT code from Version 1 to Version 2, then: + +- **UDT A** will immediately adopt Version 2 +- **UDT B** will continue using Version 1, ignoring the new version of the code. + +![/img/script-upgrade-workflow/typeid-can-be-ignored.jpeg](/img/script-upgrade-workflow/typeid-can-be-ignored.jpeg) + +One might say that Version 1 is no longer present in a Live Cell, but that does not mean Version 1 is unusable. There are several options for retaining access to Version 1: + +- By tracking the CKB chain history, one can locate the original Version 1 of the UDT code, redeploy it in a new Cell, and use it for subsequent operations. + +![/img/script-upgrade-workflow/redeploy-lost-cells.jpeg](/img/script-upgrade-workflow/redeploy-lost-cells.jpeg) + +- A fully developed ecosystem might also have a lending system aiding these requirements. + Additionally, there is an interesting possibility to consider: While a Script currently locates code within a dep Cell, there has been historical discussion around allowing a CKB transaction to temporarily store code within the `witness` structures. If there is enough interest in this idea, CKB could potentially reintroduce this feature in the future. + +## Conclusion + +This article introduced the original design workflow for implementing an upgradable Script using Type ID. By leveraging Lock Scripts strategically, developers can establish a structured and iterative approach to build decentralized Scripts on CKB, ensuring both flexibility and security. diff --git a/website/docs/script/spawn-direct-cross-script-calling.mdx b/website/docs/script/spawn-direct-cross-script-calling.mdx new file mode 100644 index 000000000..3f0afa48f --- /dev/null +++ b/website/docs/script/spawn-direct-cross-script-calling.mdx @@ -0,0 +1,322 @@ +--- +id: spawn-cross-script-calling +title: "Spawn: Direct Cross-Script Calling" +--- + +import Tooltip from "@components/Tooltip"; + +# Spawn: Direct Cross-Script Calling + +The Meepo hard fork in 2024 has introduced a range of enhancements into CKB Script development, with one major innovation being Spawn. + +In [CKB Script](/docs/script/intro-to-script), Spawn refers to a concept and a set of syscalls for creating new processes. Unlike the [exec syscall](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0034-vm-syscalls-2/0034-vm-syscalls-2.md#exec) introduced during [CKB’s first hard fork in 2021](/docs/history-and-hard-forks/ckb-hard-fork-history#1st-hard-fork--ckb-edition-mirana-2021), Spawn enables **direct cross-script calls**, simplifying development process while offering greater control and optimization. + +## Why Spawn + +The exec syscall, introduced into CKB-VM during [CKB’s first hard fork](/docs/history-and-hard-forks/ckb-hard-fork-history#1st-hard-fork--ckb-edition-mirana-2021), was designed to enable the loading and executing of a new Script within the current execution space. While powerful, exec can be inefficient, especially when preserving the current execution space is necessary. With exec, all state information of the current Script is discarded. When Script A calls Script B using exec, Script A's context is lost, as illustrated below: + +``` + +----------+ Exec +----------+ +----->+ Script A +--------->+ Script B +----> + +----------+ +----------+ +``` + +We aim to preserve the context of Script A. Ideally, when Script B executes, Script A should be able to retrieve B's execution result and then continue its own execution. This process is illustrated below: + +``` + +----------+ +----->+ Script A +--------------+-----------> + +-----+----+ ^ + | | + | Spawn | Exit + v | + +----------+ | + | Script B +--------------+ + +----------+ +``` + +This is where Spawn comes in, fulfilling exactly this purpose. + +## Development of Spawn in CKB Virtual Machine + +The Spawn syscalls in the CKB-VM draw inspiration from Linux standards, offering an efficient method for process creation and using familiar terms like "process," "pipe," and "file descriptor." We've dedicated considerable effort to make this new technology user-friendly, enabling developers to build multi-process applications with the same ease as on a local system. + +:::note + +The term "process" in CKB-VM differs from its meaning in an operating system: in CKB-VM, each running Script is considered a process, essentially an entity with its own independent execution space. However, at the OS level, CKB-VM remains a single-process, single-threaded program. + +::: + +``` + +--------------------+ .--. + | Hi, CKB, This is | .- \ + | 0. Process | /_ \ + +-----+ | 1. Pipe | (o ) +-------+ + | CKB | | 2. File Descriptor | _/ | | Linux | + +-----+ +--------------------+ (c .-. | +-------+ + ___ ;; / .' \ + .'' ``. ;; O) | \ + _/ .-. .-. \_ () () / _ `.__ \ \ + (o|( O O )|o) ()(O)() |/ ) / \ \ + .' `. ()\ _|_ / \ \ + / (c c) \ \(_ \ / \ \ + | | (__) `.______ ( ._/ \ ) + \ (o) / (___)`._ .' ) / + `. .' (__) ______ / / / + `-.___.-' /|\ | / / + ___)(___ / \ \ / / + .-' `-. `. .' / + / .-. .-. \ `- /.' / + / / ( . . ) \ \ / \)| | | | + / / \ / \ \ / \_\_\_) + \ \ ) ( / / ( / + \ \ ( __ ) / / \ \ \ \ + / ) // \\ ( \ \ \ \ \ +(\ / / /\) \\ // (/\ \ \ /) ) \ \ \ + -'-'-' .' )( `. `-`-`- .' |.' | + .'_ .' `. _`. _.--' ( ( + oOO(_) (_)OOo (__.--._____)_____) +``` + +## Spawn Functions Overview + +In the CKB-VM, Spawn is primarily implemented through the `spawn()` and `spawn_cell()` functions, offering nearly the same functionality with the one key distinction: `spawn_cell()` locates the Script using the `code_hash` and `hash_type`, while `spawn()` requires the developer to provide an absolute index and source. + +The function signatures are as follows: + +```rust +pub fn spawn( + index: usize, + source: Source, + place: usize, + bounds: usize, + spgs: &mut SpawnArgs, +) -> Result; +``` + +```rust +pub fn spawn_cell( + code_hash: &[u8], + hash_type: ScriptHashType, + argv: &[&CStr], + inherited_fds: &[u64], +) -> Result; +``` + +### `spawn()` + +From a low-level perspective, `spawn_cell()` is simply a wrapper around `spawn()`. Therefore, I will primarily focus on `spawn()` function, the parameters for which are explained as follows: + +- **index**: an index value denoting the index of entries to read. +- **source**: a flag denoting the source of Cells or witnesses to locate, possible values include: + - 1: input Cells + - 0x0100000000000001: input Cells with the same running Script as current Script + - 2: output Cells + - 0x0100000000000002: output Cells with the same running Script as current Script + - 3: dep Cells +- **place**: A value of 0 or 1: + - 0: read from Cell data + - 1: read from witness +- **bounds**: high 32 bits means offset; low 32 bits means length. If length equals to zero, it reads to end instead of reading 0 byte. +- **spawn_args**: pass data during process creation or save return data. It is a structure with four members: + - **argc**: contains the number of arguments passed to the program + - **argv**: a one-dimensional array of strings + - **process_id**: a pointer used to save the process_id of the child process + - **inherited_fds**: an array representing the file descriptors passed to the child process. It must end with zero. For example, if you want to pass fd1 and fd2, you need to construct an array [fd1, fd2, 0]. + +The arguments used here—index, source, bounds, place, argc, and argv—are identical to those used in `exec()`. + +### `pipe()` + +Like Linux, CKB-VM uses pipes and file descriptors to pass data between processes. Here's how it works: + +```rust +pub fn pipe() -> Result<(u64, u64), SysError>; +``` + +The `pipe()` function creates a pipe—a unidirectional data channel used for interprocess communication. It returns a tuple of two file descriptors representing the pipe's ends. The first descriptor refers to the read end, while the second refers to the write end. Data written to the write end is buffered by CKB-VM until it is read from the read end. + +``` + __------__ + /~ ~\ +--------------------------------------------+ + | //^\\//^\| | Pipes create a unidirectional data channel | + /~~\ || o| |o|:~\ | Data can be written to or read from a pipe | + | |6 ||___|_|_||:| +--------------------------------------------+ + \__. / o \/' + | ( O ) + /~~~~\ `\ \ / + | |~~\ | ) ~------~`\ + /' | | | / ____ /~~~)\ +(_/' | | | /' | ( | + | | | \ / __)/ \ + \ \ \ \/ /' \ `\ + \ \|\ / | |\___| + \ | \____/ | | + /^~> \ _/ < + | | \ \ + | | \ \ \ + -^-\ \ | ) + `\_______/^\______/ +``` + +### `read()` + +The `read()` function attempts to read up to the number of bytes specified by length from the file descriptor `fd` into the buffer, returning the actual number of bytes read. + +```rust +pub fn read(fd: u64, buffer: &mut [u8]) -> Result; +``` + +### `write()` + +The counterpart to the `read()` function is `write()`. This syscall writes data to a pipe through a file descriptor. It writes up to the number of bytes specified by length from the buffer, returning the actual number of bytes written. + +```rust +pub fn write(fd: u64, buffer: &[u8]) -> Result; +``` + +### `inherited_fds()` + +The child Script uses this function to verify its available file descriptors. A file descriptor must— and can only—belong to one process. The file descriptor can be passed when using the `spawn()` function, as I demonstrated when introducing the `spawn()`. + +```rust +pub fn inherited_fds() -> Vec; +``` + +### `close` + +This syscall manually closes a file descriptor. After calling it, any attempts to read from or write to the file descriptor at the other end will fail. + +``` +pub fn close(fd: u64) -> Result<(), SysError>; +``` + +### `wait()` + +The last function is `wait()`. The syscall pauses execution until the process specified by `pid` has completed. + +```rust +pub fn wait(pid: u64) -> Result; +``` + +## Errors + +The Spawn family of syscalls can return five distinct errors. Most of them are self-explanatory and typically occur when you pass incorrect arguments or attempt to double-close a file descriptor. + +```rust +pub enum SysError { + /// Failed to wait. Its value is 5. + WaitFailure, + /// Invalid file descriptor. Its value is 6. + InvalidFd, + /// Reading from or writing to file descriptor failed due to other end closed. Its value is 7. + OtherEndClosed, + /// Max vms has been spawned. Its value is 8. + MaxVmsSpawned, + /// Max fds has been created. Its value is 9. + MaxFdsCreated, +} +``` + +Among these errors, a notable one is `OtherEndClosed`. This error allows us to implement a function like `read_all(fd) -> Vec` to read all the data from the pipe at once. Many programming languages provide similar functions in their standard libraries, and you can easily implement this functionality yourself in the CKB-VM. + +```rust +pub fn read_all(fd: u64) -> Result, SysError> { + let mut ret = Vec::new(); + let mut buf = [0; 256]; + loop { + match syscalls::read(fd, &mut buf) { + Ok(data) => ret.extend_from_slice(&buf[..data]), + Err(SysError::OtherEndClosed) => break, + Err(err) => return Err(err), + } + } + Ok(ret) +} +``` + +## Example + +Let's walk through a basic example of using spawn. Imagine we want to deploy a public library on the chain, which is quite simple: it receives input parameters, concatenates them, and returns the result to the caller. Let’s see how to implement it. + +The main code only consists of the following four lines, where: + +- The first line obtains the file descriptor. +- The second line gathers and concatenates all the arguments. +- The third line writes the result to the file descriptor. +- The last line closes the file descriptor. + +```rust +#[no_mangle] +pub unsafe extern "C" fn main() -> u64 { + let fds = inherited_fds(); + let out = ARGS.join(""); + write(fds[0], out.as_bytes()); + close(fds[0]); + return 0; +} +``` + +So, how to use this library? Follow the following code: + +- The first line defines the arguments to be passed to the child Script. +- The second line creates a pipe. +- The third line calls the `spawn()` function, passing in the arguments and the writable file descriptor. +- The fourth line reads all the data from the readable file descriptor. +- The last line uses the `wait()` function to wait until the child Script exits. + +```rust +#[no_mangle] +pub unsafe extern "C" fn main() -> u64 { + let argv = ["Hello", "World!"]; + let fds = pipe(); + let pid = spawn_cell(code_hash, hash_type, &argv, &[fds[1]]); + let data = read_all(fds[0]); + assert_eq!(&data, b"Hello World!"); + wait(pid); + return 0; +} +``` + +## Enhanced Efficiency With Spawn’s Pipes + +Since `spawn()` operates within its own memory space, independent of the parent process, it can mitigate certain security risks, particularly in scenarios involving sensitive data. + +While some other blockchain virtual machines, such as the EVM, also offer cross-contract call functions, these calls tend to be quite expensive, especially when invoking child contracts repeatedly. This is primarily because each call requires continuously creating and destroying a virtual machine, as illustrated below: + +```rust + +----------+ +----->+ Script A +---+------+------------+------+-------+------+---------------> + +----------+ | ^ | ^ | ^ + | | | | | | + Create | | Destroy | | | | + v | v | v | + +-+------+-+ +-+------+-+ +-+------+-+ + | Script B | | Script B | | Script B | + +----------+ +----------+ +----------+ +``` + +In contrast, CKB-VM implements pipes, allowing multiple calls to a child Script while only creating and destroying its execution space once. This approach significantly enhances efficiency as shown below: + +``` + +----------+ +----->+ Script A +----+------------------+------+-------+------+-------+-------> + +----------+ | | ^ | ^ ^ + | | Pipe | | Pipe | | + Create | | IO | | IO | | Destroy + v | | | | | + +--+-------+ v | v | | + | Script B |----------+------+-------+------+-------+ + +----------+ +``` + +## Typical Use Cases + +Spawn has several potential applications, and we believe it's particularly advantageous in the following scenarios: + +- **Public Library**: Spawn enables the development of common libraries, allowing different Scripts to reuse shared code. This approach simplifies Script development and substantially reduces deployment costs. For instance, we could publish diverse cryptographic algorithms on CKB as public libraries. +- **Large Script Management**: When your Script's binary size exceeds 500K, it surpasses CKB's maximum transaction size limit for Script deployment. In such cases, you can leverage Spawn to divide and deploy your Script logic separately, effectively circumventing this limitation. + +## Conclusion + +The Spawn family of functions in the CKB-VM offers an efficient, flexible, and secure method for process creation, particularly in scenarios involving complex Scripts. Using Spawn can boost system performance and security. By mastering the use of `spawn()`, developers can more effectively manage Scripts while building decentralized applications, unlocking new possibilities in blockchain development. diff --git a/website/docs/script/spawn-script.mdx b/website/docs/script/spawn-script.mdx new file mode 100644 index 000000000..c34f4d9fa --- /dev/null +++ b/website/docs/script/spawn-script.mdx @@ -0,0 +1,604 @@ +--- +id: spawn-script +title: "Tutorial: Spawn Script" +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; +import TutorialHeader from "@components/TutorialHeader"; +import Tooltip from "@components/Tooltip"; +import ScriptTools from "./_ScriptTools.mdx"; +import Link from "@docusaurus/Link"; + +# Tutorial: Spawn Script + + + + offckb {">= 0.3.2"} + + , + ]} +/> + +The design of the syscall spawn function draws inspiration from Unix and Linux, hence they share the same terminologies: process, pipe, and file descriptor. +The spawn mechanism is used in CKB-VM to create new processes, which can then execute a different program or command independently of the parent process. + +In the context of CKB-VM, a process represents the active execution of a RISC-V binary, which can be located within a Cell. +Additionally, a RISC-V binary can also be found within the witness during a Spawn syscall. +A pipe is established by associating two file descriptors, each linked to one of its ends. +These file descriptors can't be duplicated and are exclusively owned by the process. +Furthermore, the file descriptors can only be either read from or written to; they can't be both read from and written to simultaneously. + +In this tutorial, you will learn how to write a complete Rust example using Spawn syscall to call a Script from another on CKB. +The full code of this tutorial can be found at [Github](https://github.com/nervosnetwork/docs.nervos.org/tree/develop/examples/spawn-script). + +## Initialize a Script Project + +```mdx-code-block + + +``` + +```bash +offckb create --script spawn-script +``` + +```mdx-code-block + + +``` + +```bash +⚠️ Favorite `gh:cryptape/ckb-script-templates` not found in config, using it as a git repository: https://github.com/cryptape/ckb-script-templates.git +🤷 Project Name: spawn-script +🔧 Destination: /tmp/spawn-script ... +🔧 project-name: spawn-script ... +🔧 Generating template ... +🔧 Moving generated files into: `/tmp/spawn-script`... +🔧 Initializing a fresh Git repository +✨ Done! New project created /tmp/spawn-script +``` + +```mdx-code-block + + +``` + +## Create Two New Scripts + +Let’s create a new Script called `caller` inside the project. + +```mdx-code-block + + +``` + +```bash +cd caller-script +make generate +``` + +```mdx-code-block + + +``` + +```bash +🤷 Project Name: caller +🔧 Destination: /tmp/spawn-script/contracts/caller ... +🔧 project-name: caller ... +🔧 Generating template ... +🔧 Moving generated files into: `/tmp/caller-script/contracts/caller`... +🔧 Initializing a fresh Git repository +✨ Done! New project created /tmp/caller-script/contracts/caller +``` + +```mdx-code-block + + +``` + +And create another new Script called `callee` inside the project. + +```mdx-code-block + + +``` + +```bash +make generate +``` + +```mdx-code-block + + +``` + +```bash +🤷 Project Name: callee +🔧 Destination: /tmp/spawn-script/contracts/callee ... +🔧 project-name: callee ... +🔧 Generating template ... +🔧 Moving generated files into: `/tmp/spawn-script/contracts/callee`... +🔧 Initializing a fresh Git repository +✨ Done! New project created /tmp/spawn-script/contracts/callee +``` + +```mdx-code-block + + +``` + +Our project is successfully setup now. + +## Implement Caller + +First, add an error handler module called `Error` in `error.rs`: + +```rust name="spawn-script/contracts/caller/src/error.rs" +use ckb_std::error::SysError; + +#[cfg(test)] +extern crate alloc; + +#[repr(i8)] +pub enum Error { + IndexOutOfBound = 1, + ItemMissing, + LengthNotEnough, + Encoding, + WaitFailure, + InvalidFD, + OtherEndClose, + MaxVmSpawned, + MaxFdCreated, + // Add customized errors here... +} + +impl From for Error { + fn from(err: SysError) -> Self { + match err { + SysError::IndexOutOfBound => Self::IndexOutOfBound, + SysError::ItemMissing => Self::ItemMissing, + SysError::LengthNotEnough(_) => Self::LengthNotEnough, + SysError::Encoding => Self::Encoding, + SysError::WaitFailure => Self::WaitFailure, + SysError::InvalidFd => Self::InvalidFD, + SysError::OtherEndClosed => Self::OtherEndClose, + SysError::MaxVmsSpawned => Self::MaxVmSpawned, + SysError::MaxFdsCreated => Self::MaxFdCreated, + SysError::Unknown(err_code) => panic!("unexpected sys error {}", err_code), + } + } +} +``` + +Let's include the error module and necessary libs in the `main.rs` file: + +```rust name="spawn-script/contracts/caller/src/main.rs" +mod error; +use ckb_std::syscalls::SpawnArgs; +use core::ffi::CStr; +``` + +Next, we will wrap the logic in a `caller` function and use it in the `program_entry`: + +```rust name="spawn-script/contracts/caller/src/main.rs" +pub fn program_entry() -> i8 { + ckb_std::debug!("Enter caller contract!"); + + match caller() { + Ok(_) => 0, + Err(err) => err as i8, + } +} + +fn caller() -> Result<(), error::Error> {} +``` + +Now, let's implement the `caller` function, which creates pipes and uses Spawn syscall to call another Script in a standalone process. + +The pipe is used as a one-direction data flow that carries data from one Script to another Script. +We will pass two strings as arguments to the callee Script, expecting it to return their concatenated result. +We also assume that the callee Script is located in the first Cell of the transaction's Cell Deps. + +```rust name="spawn-script/contracts/caller/src/main.rs" +fn caller() -> Result<(), error::Error> { + let (r1, w1) = ckb_std::syscalls::pipe()?; + let (r2, w2) = ckb_std::syscalls::pipe()?; + let to_parent_fds: [u64; 2] = [r1, w2]; + let to_child_fds: [u64; 3] = [r2, w1, 0]; // must ends with 0 + + let mut pid: u64 = 0; + let place = 0; // 0 means read from cell data + let bounds = 0; // 0 means read to end + let argc: u64 = 2; + let argv = [ + CStr::from_bytes_with_nul(b"hello\0").unwrap().as_ptr(), + CStr::from_bytes_with_nul(b"world\0").unwrap().as_ptr(), + ]; + let mut spgs: SpawnArgs = SpawnArgs { + argc, + argv: argv.as_ptr(), + process_id: &mut pid as *mut u64, + inherited_fds: to_child_fds.as_ptr(), + }; + ckb_std::syscalls::spawn( + 0, + ckb_std::ckb_constants::Source::CellDep, + place, + bounds, + &mut spgs, + )?; + + let mut buf = [0; 256]; + let len = ckb_std::syscalls::read(to_parent_fds[0], &mut buf)?; + assert_eq!(len, 10); + buf[len] = 0; + assert_eq!( + CStr::from_bytes_until_nul(&buf).unwrap().to_str().unwrap(), + "helloworld" + ); + Ok(()) +} +``` + +Note that each pipe can only be used for either reading or writing. To facilitate communication, we create two pipes: one for the child process to write and the parent process to read; the other does the reverse. + +```rust +let (r1, w1) = ckb_std::syscalls::pipe()?; +let (r2, w2) = ckb_std::syscalls::pipe()?; +let to_parent_fds: [u64; 2] = [r1, w2]; +let to_child_fds: [u64; 3] = [r2, w1, 0]; // must ends with 0 + + +// ... + +let len = ckb_std::syscalls::read(to_parent_fds[0], &mut buf)?; +``` + +## Implement Callee + +We need to create the same components here: an `error.rs` file and a `callee` function in the `main.rs`: + +```rust name="spawn-script/contracts/callee/src/error.rs" +use ckb_std::error::SysError; + +#[cfg(test)] +extern crate alloc; + +#[repr(i8)] +pub enum Error { + IndexOutOfBound = 1, + ItemMissing, + LengthNotEnough, + Encoding, + WaitFailure, + InvalidFD, + OtherEndClose, + MaxVmSpawned, + MaxFdCreated, + // Add customized errors here... +} + +impl From for Error { + fn from(err: SysError) -> Self { + match err { + SysError::IndexOutOfBound => Self::IndexOutOfBound, + SysError::ItemMissing => Self::ItemMissing, + SysError::LengthNotEnough(_) => Self::LengthNotEnough, + SysError::Encoding => Self::Encoding, + SysError::WaitFailure => Self::WaitFailure, + SysError::InvalidFd => Self::InvalidFD, + SysError::OtherEndClosed => Self::OtherEndClose, + SysError::MaxVmsSpawned => Self::MaxVmSpawned, + SysError::MaxFdsCreated => Self::MaxFdCreated, + SysError::Unknown(err_code) => panic!("unexpected sys error {}", err_code), + } + } +} +``` + +```rust name="spawn-script/contracts/callee/src/error.rs" +mod error; +use alloc::vec; + +pub fn program_entry() -> i8 { + ckb_std::debug!("Enter callee contract!"); + + match callee() { + Ok(_) => 0, + Err(err) => err as i8, + } +} + +pub fn callee() -> Result<(), error::Error> { + let argv = ckb_std::env::argv(); + let mut to_parent_fds: [u64; 2] = [0; 2]; + ckb_std::syscalls::inherited_fds(&mut to_parent_fds); + let mut out = vec![]; + for arg in argv { + out.extend_from_slice(arg.to_bytes()); + } + let len = ckb_std::syscalls::write(to_parent_fds[1], &out)?; + assert_eq!(len, 10); + Ok(()) +} +``` + +The `callee` function has a simpler logic. +It receives arguments using `ckb_std::env::argv()` and inherits the pipe using `inherited_fds`. + +Then it uses the `write` syscall to write the concatenated result to the pipe: + +```rust +let len = ckb_std::syscalls::write(to_parent_fds[1], &out)?; +``` + +## Write Unit Tests + +The Unit Test files are located in the `spawn-script/tests/src/tests.rs`. +We'll create one test for our Scripts that uses `caller` as the input Lock Script and verifies it in the transaction. The `callee` Script Cell will also be pushed into the Cell Deps of the transaction. + +```rust name="spawn-script/tests/src/tests.rs" +use crate::Loader; +use ckb_testtool::ckb_types::{ + bytes::Bytes, + core::TransactionBuilder, + packed::*, + prelude::*, +}; +use ckb_testtool::context::Context; + +// Include your tests here +// See https://github.com/xxuejie/ckb-native-build-sample/blob/main/tests/src/tests.rs for more examples + +// generated unit test for contract caller +#[test] +fn test_spawn() { + // deploy contract + let mut context = Context::default(); + let caller_contract_bin: Bytes = Loader::default().load_binary("caller"); + let caller_out_point = context.deploy_cell(caller_contract_bin); + let callee_contract_bin: Bytes = Loader::default().load_binary("callee"); + let callee_out_point = context.deploy_cell(callee_contract_bin); + + // prepare scripts + let lock_script = context + .build_script(&caller_out_point, Bytes::from(vec![42])) + .expect("script"); + + // prepare cells + let input_out_point = context.create_cell( + CellOutput::new_builder() + .capacity(1000u64.pack()) + .lock(lock_script.clone()) + .build(), + Bytes::new(), + ); + let input = CellInput::new_builder() + .previous_output(input_out_point) + .build(); + let outputs = vec![ + CellOutput::new_builder() + .capacity(500u64.pack()) + .lock(lock_script.clone()) + .build(), + CellOutput::new_builder() + .capacity(500u64.pack()) + .lock(lock_script) + .build(), + ]; + + let outputs_data = vec![Bytes::new(); 2]; + + // prepare cell deps + let callee_dep = CellDep::new_builder() + .out_point(callee_out_point) + .build(); + let caller_dep = CellDep::new_builder() + .out_point(caller_out_point) + .build(); + let cell_deps: Vec = vec![callee_dep, caller_dep]; + + // build transaction + let tx = TransactionBuilder::default() + .input(input) + .outputs(outputs) + .outputs_data(outputs_data.pack()) + .cell_deps(cell_deps) + .build(); + let tx = context.complete_tx(tx); + + // run + let cycles = context + .verify_tx(&tx, 10_000_000) + .expect("pass verification"); + println!("consume cycles: {}", cycles); +} +``` + +First, build the Scripts: + +```sh +make build +``` + +Then, run the tests: + +```sh +make test +``` + +## Test on Devnet + +After testing our Scripts, we can be more confident to test them in a more realistic environment. + +We will use `offckb` to start a Devnet and deploy the Scripts, then test the Scripts by sending a transaction to the Devnet using `offckb` REPL. + +1. Start the Devnet + +```sh +offckb node +``` + +2. Deploy the Scripts + +Open a new terminal, navigate to the root of the `spawn-script` project, then run: + +```mdx-code-block + + +``` + +```sh +offckb deploy --target build/release/caller +``` + +```mdx-code-block + + +``` + +```sh +contract caller deployed, tx hash: 0x74bed00091f062e46225662fc90e460a4cc975478117eaa8570d454bf8dc58e9 +wait for tx confirmed on-chain... +tx committed. +caller deployment.toml file /Users/retric/Library/Application Support/offckb-nodejs/devnet/contracts/caller/deployment.toml generated successfully. +caller migration json file /Users/retric/Library/Application Support/offckb-nodejs/devnet/contracts/caller/migrations/2024-11-23-133222.json generated successfully. +done. +``` + +```mdx-code-block + + +``` + +```mdx-code-block + + +``` + +```sh +offckb deploy --target build/release/callee +``` + +```mdx-code-block + + +``` + +```sh +contract callee deployed, tx hash: 0xdb91398beafb3c41b3e6f4c4a078a08aa1f4245b0d964b9d51913e8514f20b72 +wait for tx confirmed on-chain... +tx committed. +callee deployment.toml file /Users/retric/Library/Application Support/offckb-nodejs/devnet/contracts/callee/deployment.toml generated successfully. +callee migration json file /Users/retric/Library/Application Support/offckb-nodejs/devnet/contracts/callee/migrations/2024-11-23-133257.json generated successfully. +done. +``` + +```mdx-code-block + + +``` + +3. Send a Test Transaction + +Open a new terminal and start an offckb REPL: + +```mdx-code-block + + +``` + +```sh +offckb repl -r +``` + +```mdx-code-block + + +``` + +```sh +Welcome to OffCKB REPL! +[[ Default Network: devnet, enableProxyRPC: true, CCC SDK: 0.0.16-alpha.3 ]] +Type 'help()' to learn how to use. +OffCKB > +``` + +```mdx-code-block + + +``` + +Next, we'll construct a transaction in the offckb REPL: + +```sh +OffCKB > let amountInCKB = ccc.fixedPointFrom(63); +OffCKB > let caller = myScripts['caller']; +OffCKB > let lockScript = new ccc.Script(caller.codeHash, caller.hashType, "0x00"); +OffCKB > let tx = ccc.Transaction.from({ +... outputs: [ +... { +... capacity: ccc.fixedPointFrom(amountInCKB), +... lock: lockScript, +... }, +... ], +... cellDeps: [ +... ...myScripts["callee"].cellDeps.map(c => c.cellDep), +... ...myScripts['caller'].cellDeps.map(c => c.cellDep), +... ]} +... ); +OffCKB > let signer = new ccc.SignerCkbPrivateKey(client, accounts[0].privkey); +OffCKB > await tx.completeInputsByCapacity(signer); +1 +OffCKB > await tx.completeFeeBy(signer, 1000); +[ 0, true ] +OffCKB > await signer.sendTransaction(tx) +'0x252305141e6b7db81f7da94b098493a36b756fe9d5d4436c9d7c966882bc0b38' +``` + +We can re-run the transaction with `offckb debug` to test our Scripts: + +```sh +offckb debug --tx-hash 0x252305141e6b7db81f7da94b098493a36b756fe9d5d4436c9d7c966882bc0b38 +Dump transaction successfully + +****************************** +****** Input[0].Lock ****** + +Run result: 0 +All cycles: 1646754(1.6M) +``` + +:::note +The deployed Scripts use `cargo build --release` mode that removes all the logs from the Script binary to reduce the size. +::: + +## Congratulations! + +By following this tutorial so far, you have mastered how to write simple Spawn Scripts that pass data between them. +Here's a quick recap: + +- Use `offckb` and `ckb-script-templates` to init a Script project +- Use `ckb_std` to leverage CKB syscalls to create pipes and call Spawn Script. +- Write unit tests to make sure the Spawn Scripts work as expected. +- Use `offckb` REPL to send a testing transaction that verifies Spawn Scripts. + +## Additional Resources + +- Full source code of this tutorial: + [spawn-script](https://github.com/nervosnetwork/docs.nervos.org/tree/develop/examples/spawn-script) +- CKB syscalls specs: [RFC-0009](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0009-vm-syscalls/0009-vm-syscalls.md) +- Script templates: [ckb-script-templates](https://github.com/cryptape/ckb-script-templates) +- CKB transaction structure: [RFC-0022-transaction-structure](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0022-transaction-structure/0022-transaction-structure.md) +- CKB data structure basics: [RFC-0019-data-structure](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0019-data-structures/0019-data-structures.md) diff --git a/website/docs/script/sudt-script.mdx b/website/docs/script/sudt-script.mdx index 63b7164f1..b8ae18d2e 100644 --- a/website/docs/script/sudt-script.mdx +++ b/website/docs/script/sudt-script.mdx @@ -5,17 +5,27 @@ title: "Tutorial: Simple UDT" import Tabs from "@theme/Tabs"; import TabItem from "@theme/TabItem"; -import ScriptHeaders from "./ScriptHeaders.tsx"; import TutorialHeader from "@components/TutorialHeader"; import Tooltip from "@components/Tooltip"; import ScriptTools from "./_ScriptTools.mdx"; +import Link from "@docusaurus/Link"; # Tutorial: Simple UDT Script + + offckb {">= 0.3.2"} + + , + ]} /> User-Defined Token (UDT) is a fungible token standard on CKB blockchain. diff --git a/website/docs/script/syscalls_for_script.mdx b/website/docs/script/syscalls-for-script.mdx similarity index 100% rename from website/docs/script/syscalls_for_script.mdx rename to website/docs/script/syscalls-for-script.mdx diff --git a/website/docs/script/type-id.mdx b/website/docs/script/type-id.mdx index e567ae2d6..c5b576d94 100644 --- a/website/docs/script/type-id.mdx +++ b/website/docs/script/type-id.mdx @@ -1,22 +1,14 @@ --- id: type-id -title: "Tutorial: Upgradable Scripts with Type ID" +title: "Type ID: Upgradable Scripts" --- import Tabs from "@theme/Tabs"; import TabItem from "@theme/TabItem"; -import ScriptHeaders from "./ScriptHeaders.tsx"; -import TutorialHeader from "@components/TutorialHeader"; import ScriptTools from "./_ScriptTools.mdx"; import Tooltip from "@components/Tooltip"; -# Tutorial: Type ID (Upgradable Script) - - +# Type ID: Upgradable Scripts Scripts are codes that execute on-chain and cannot be stopped. However, sometimes you might want to ensure your Script is upgradable in case there are bugs in the source code. diff --git a/website/docs/script/vm-selection.mdx b/website/docs/script/vm-selection.mdx new file mode 100644 index 000000000..791bda344 --- /dev/null +++ b/website/docs/script/vm-selection.mdx @@ -0,0 +1,46 @@ +--- +id: vm-selection +title: "VM Version Selection" +--- + +When writing a Script, it is important to understand how the Script will be executed under a specific CKB-VM version. The CKB network has introduced various CKB-VM versions over time to enhance security, performance, bug fixes and support for new RISC-V extensions. However, the upgrade should not break the old code, and users must have the opt-in option to specify the VM version. + +This article explains the general mechanism that determines how a CKB node chooses the appropriate CKB-VM version for a transaction Script group, based on [RPC-32](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0032-ckb-vm-version-selection/0032-ckb-vm-version-selection.md). + +## How It Works + +In CKB, each VM version has its bundled instruction set, syscalls and cost model. + +During a CKB hard fork, a specific activation epoch is determined through community consensus. Typically, transactions in blocks before the activation epoch are verified using the previous CKB-VM version. + +Once the fork is activated, CKB nodes determine the CKB-VM version for each Script group based on the `hash_type` field in the Script Structure. The allowed values for `hash_type` are 0, 1, 2 and 4. Cells with different `hash_type` are grouped separately. + +According to the value of `hash_type`: + +- When the `hash_type` is 0, the Script group matches code via `data hash` and will run the code using the CKB-VM version 0. +- When the `hash_type` is 1, the Script group matches code via `type Script hash` and will run the code using the CKB-VM version 2. +- When the `hash_type` is 2, the Script group matches code via `data hash` and will run the code using the CKB-VM version 1. +- When the `hash_type` is 4, the Script group matches code via `data hash` and will run the code using the CKB-VM version 2. + +| `hash_type` | JSON Representation | Matched by | VM Version | +| ----------- | ------------------- | ------------------- | ---------- | +| 0 | “data” | Data hash (blake2b) | 0 | +| 1 | “type” | Type Script hash | 2 | +| 2 | “data1” | Data hash (blake2b) | 1 | +| 4 | “data2” | Data hash (blake2b) | 2 | + +The `hash_type` encoding pattern ensures that if a Script matches code via `type hash`, CKB always uses the latest available version of VM depending when the Script is executed. But if the Script matches code via `data hash`, the VM version to execute is determined when the Cell is created. + +Cell owners can trade off between the determination and VM performance boost when creating the Cell. They should use `data hash` for determination, and `type hash` for the latest VM techniques. + +## Rationale + +Several solutions were discussed for VM version selection, but the current approach balances flexibility and determinism. Here are some of the alternatives and their drawbacks: + +- **Always use the latest VM version**: While straightforward, this approach would remove user control over version selections, making transaction executions non-deterministic as it will depend on the chain state. +- **Depend on the Script code Cell epoch**: This approach would use the old VM version for code Cells deployed before the fork and the new one for later deployments. However, anyone could redeploy the Cell and force transactions to use a different VM version using a new code Cell, which reduces determinism. + +## Backward compatibility + +For Scripts referencing code via `data hash`, the VM version remains consistent before and after a hard fork. In contrast, Scripts referencing code via `type hash` will use different VM versions. +DApps developers must ensure the compatibility of their Scripts and upgrade them if necessary. By carefully selecting the appropriate `hash_type` and understanding its implications, developers can build robust dApps on CKB while leveraging the flexibility of VM version management. diff --git a/website/docs/sdk-and-devtool/ckb-cli.mdx b/website/docs/sdk-and-devtool/ckb-cli.mdx new file mode 100644 index 000000000..09baee8bd --- /dev/null +++ b/website/docs/sdk-and-devtool/ckb-cli.mdx @@ -0,0 +1,83 @@ +--- +id: ckb-cli +title: CKB-CLI +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; +import Tooltip from "@components/Tooltip"; + +# CKB-CLI + +[ckb-cli](https://github.com/nervosnetwork/ckb-cli) is a CKB command-line tool developed in Rust. + +If you need to interact with Mainnet blockchain from the command line, `ckb-cli` is an ideal choice to manage accounts, deploy Scripts and send Transactions. + +### Features + +``` + rpc Invoke RPC call to node + account Manage accounts + mock-tx Handle mock transactions (verify/send) + tx Handle common sighash/multisig transaction + util Utilities + molecule Molecule encode/decode utilities + wallet Transfer / query balance (with local index) / key utils + dao Deposit / prepare / withdraw / query NervosDAO balance (with local index) / key utils +``` + +All second-level sub-commands are listed on the [wiki page](https://github.com/nervosnetwork/ckb-cli/wiki/Sub-Commands). + +### Install + +``` +git clone https://github.com/nervosnetwork/ckb-cli.git +cd ckb-cli +cargo install --path . -f --locked +``` + +### Usage + +Better export an env first (or give in argument) + +``` +export API_URL=http://127.0.0.1:8114 +``` + +Directly go to **gorgeous** interactive mode: + +``` +ckb-cli +``` + +Show available commands + +```shell +# Top level help doc +ckb-cli --help +# RPC help doc +ckb-cli rpc --help +``` + +#### Example: Get Live Cell (JSON Output Format) + +``` +ckb-cli rpc get_live_cell --tx-hash 0x4ec75b5a8de8d180853d5046760a99285c73283a5dc528f81d6ee056f5335172 --index 0 +``` + +**Response:** + +```json +{ + "cell": { + "capacity": "125000000000", + "lock": { + "args": ["0x64257f00b6b63e987609fa9be2d0c86d351020fb"], + "code_hash": "0x1892ea40d82b53c678ff88312450bbb17e164d7a3e0a90941aa58839f56f8df2", + "hash_type": "type" + }, + "type": null + }, + "status": "live" +} +``` diff --git a/website/docs/sdk-and-devtool/cli-tool.mdx b/website/docs/sdk-and-devtool/cli-tool.mdx deleted file mode 100644 index 37d1bb891..000000000 --- a/website/docs/sdk-and-devtool/cli-tool.mdx +++ /dev/null @@ -1,269 +0,0 @@ ---- -id: cli-tools -title: CLI Tools ---- - -import Tabs from "@theme/Tabs"; -import TabItem from "@theme/TabItem"; -import Tooltip from "@components/Tooltip"; - -# CLI Tools - -Command-line tools are often used by developers to perform specific blockchain tasks in a faster and more efficient way. - -## CKB-CLI - -[ckb-cli](https://github.com/nervosnetwork/ckb-cli) is a CKB command-line tool developed in Rust. - -If you need to interact with Mainnet blockchain from the command line, `ckb-cli` is an ideal choice to manage accounts, deploy Scripts and send Transactions. - -### Features - -``` - rpc Invoke RPC call to node - account Manage accounts - mock-tx Handle mock transactions (verify/send) - tx Handle common sighash/multisig transaction - util Utilities - molecule Molecule encode/decode utilities - wallet Transfer / query balance (with local index) / key utils - dao Deposit / prepare / withdraw / query NervosDAO balance (with local index) / key utils -``` - -All second-level sub-commands are listed on the [wiki page](https://github.com/nervosnetwork/ckb-cli/wiki/Sub-Commands). - -### Install - -``` -git clone https://github.com/nervosnetwork/ckb-cli.git -cd ckb-cli -cargo install --path . -f --locked -``` - -### Usage - -Better export an env first (or give in argument) - -``` -export API_URL=http://127.0.0.1:8114 -``` - -Directly go to **gorgeous** interactive mode: - -``` -ckb-cli -``` - -Show available commands - -```shell -# Top level help doc -ckb-cli --help -# RPC help doc -ckb-cli rpc --help -``` - -#### Example: Get Live Cell (JSON Output Format) - -``` -ckb-cli rpc get_live_cell --tx-hash 0x4ec75b5a8de8d180853d5046760a99285c73283a5dc528f81d6ee056f5335172 --index 0 -``` - -**Response:** - -```json -{ - "cell": { - "capacity": "125000000000", - "lock": { - "args": ["0x64257f00b6b63e987609fa9be2d0c86d351020fb"], - "code_hash": "0x1892ea40d82b53c678ff88312450bbb17e164d7a3e0a90941aa58839f56f8df2", - "hash_type": "type" - }, - "type": null - }, - "status": "live" -} -``` - -## OffCKB - -[offckb](https://github.com/ckb-devrel/offckb) is a CLI tool developed in Node.js to help you quickly set up a predefined CKB Devnet and create dApp boilerplates. - -If you need a local development environment for the very first try on your dApp, `offckb` is the ideal choice. - -### Install - -```sh -npm install -g @offckb/cli -``` - -### Usage - -```sh -Usage: offckb [options] [command] - -ckb development network for your first try - -Options: - -V, --version output the version number - -h, --help display help for command - -Commands: - create [your-project-name] Create a new dApp from bare templates - node Use the CKB to start devnet - clean Clean the devnet data, need to stop running the chain first - accounts Print account list info - list-hashes Use the CKB to list blockchain scripts hashes - inject-config Add offckb.config.ts to your workspace - sync-config sync offckb.config.ts in your workspace - deposit [options] [toAddress] [amountInShannon] Deposit CKB tokens to address, only devnet and testnet - transfer [options] [toAddress] [amountInShannon] Transfer CKB tokens to address, only devnet and testnet - balance [options] [toAddress] Check account balance, only devnet and testnet - deploy [options] Deploy contracts to different networks, only supports devnet and testnet - deployed-scripts [options] Show deployed contracts info on networks, only supports devnet and testnet - help [command] display help for command -``` - -#### Create a Full-Stack Project - -Create a new project from predefined boilerplates. - -```sh -offckb create -``` - -The boilerplate can target on different CKB networks. Check the [README.md](https://github.com/nervosnetwork/docs.nervos.org/blob/develop/examples/remix-vite-template/readme.md) in the project to get started. - -#### Access Testing Accounts - -`offckb` provides 20 pre-funded accounts for use on Devnet. Each account is funded with 42,000,000,000,000,000 capacity in the Devnet's genesis block. You can access these accounts and copy the private keys and addresses for use when developing your dApps. - -```mdx-code-block - - -``` - -```bash -offckb accounts -``` - -```mdx-code-block - - -``` - -```bash -#### ALL ACCOUNTS ARE FOR TEST AND DEVELOP ONLY #### -#### DON'T USE THESE ACCOUNTS ON MAINNET #### -#### OTHERWISE YOU WILL LOOSE YOUR MONEY #### - -Print account list, each account is funded with 42_000_000_00000000 capacity in the devnet genesis block. - -- "#": 0 -address: ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqvwg2cen8extgq8s5puft8vf40px3f599cytcyd8 -privkey: 0x6109170b275a09ad54877b82f7d9930f88cab5717d484fb4741ae9d1dd078cd6 -pubkey: 0x02025fa7b61b2365aa459807b84df065f1949d58c0ae590ff22dd2595157bffefa -lock_arg: 0x8e42b1999f265a0078503c4acec4d5e134534297 -lockScript: - codeHash: 0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8 - hashType: type - args: 0x8e42b1999f265a0078503c4acec4d5e134534297 - -- "#": 1 -address: ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqt435c3epyrupszm7khk6weq5lrlyt52lg48ucew -privkey: 0x9f315d5a9618a39fdc487c7a67a8581d40b045bd7a42d83648ca80ef3b2cb4a1 -pubkey: 0x026efa0579f09cc7c1129b78544f70098c90b2ab155c10746316f945829c034a2d -lock_arg: 0x758d311c8483e0602dfad7b69d9053e3f917457d -lockScript: - codeHash: 0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8 - hashType: type - args: 0x758d311c8483e0602dfad7b69d9053e3f917457d - -- "#": 2 -address: ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqvarm0tahu0qfkq6ktuf3wd8azaas0h24c9myfz6 -privkey: 0x59ddda57ba06d6e9c5fa9040bdb98b4b098c2fce6520d39f51bc5e825364697a -pubkey: 0x02f1ec8d18e8ff13ecf7b3ab8f683d0c3a6d63478a7f7d14ca0fdfe8fea331e863 -lock_arg: 0x9d1edebedf8f026c0d597c4c5cd3f45dec1f7557 -lockScript: - codeHash: 0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8 - hashType: type - args: 0x9d1edebedf8f026c0d597c4c5cd3f45dec1f7557 - -- "#": 3 -address: ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsq0xt7prh3dy3gu9z45svp89q0d6f6c46cg9dp9mn -privkey: 0xf4a1fc19468b51ba9d1f0f5441fa3f4d91e625b2af105e1e37cc54bf9b19c0a1 -pubkey: 0x02e72cbdff20422a3886ec667a138a59478d93da072173be4344c55582acdce67c -lock_arg: 0xe65f823bc5a48a38515690604e503dba4eb15d61 -lockScript: - codeHash: 0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8 - hashType: type - args: 0xe65f823bc5a48a38515690604e503dba4eb15d61 -# More accounts... -``` - -```mdx-code-block - - -``` - -:::note -To deposit or check balances on Devnet, ensure that you have started the `offckb node`. This step is not required for Testnet operations. -::: - -#### Deposit Funds - -Occasionally, you may prefer to use your personal CKB account rather than the pre-funded accounts provided by `offckb`. To deposit CKB into your own account using `offckb`, use the command below. Replace `` with your personal CKB address and `` with the specific amount you wish to deposit, expressed in shannons: -:::tip CKB vs. Shannons -1 CKByte = 100,000,000 Shannons -::: - -```mdx-code-block - - -``` - -```bash -offckb deposit --network devnet -``` - -```mdx-code-block - - -``` - -```bash -tx hash: 0xe895970e9c75a5c4703c38a4e37b000895e7690552ba67ef82ae92109d7322fd -``` - -```mdx-code-block - - -``` - -#### Check Balance - -To check the balance of a specific account, use the following command. Replace `` with the address of the account you want to check, and `` with the appropriate network depending on which one you are using: - -```mdx-code-block - - -``` - -```bash -offckb balance --network -``` - -```mdx-code-block - - -``` - -```bash -Balance: 42000000 CKB -``` - -```mdx-code-block - - -``` diff --git a/website/docs/sdk-and-devtool/offckb.mdx b/website/docs/sdk-and-devtool/offckb.mdx new file mode 100644 index 000000000..bcf5bea6b --- /dev/null +++ b/website/docs/sdk-and-devtool/offckb.mdx @@ -0,0 +1,505 @@ +--- +id: offckb +title: OffCKB +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; +import Tooltip from "@components/Tooltip"; + +# OffCKB + +[offckb](https://github.com/ckb-devrel/offckb) is a an all-in-one CLI tool that provides a local CKB development environment. + +- Simplifies development with one-line command to start the devnet and create projects from boilerplate +- Comes with 20 pre-funded accounts and multiple minimal dApp templates for quick project setup +- Embeds common Scripts in the genesis block, such as Omnilock, xUDT, and Spore +- Provides a complete workflow from Script building and deployment to frontend integration for devnet +- Includes tools like ckb-debugger, molecule, and ckb-cli +- Features a REPL mode for quick Script testing +- Offers configurable settings via a JSON file +- Is built on and leverages CKB's JavaScript SDK, CCC, in the development framework + +This guide will walk you through leveraging OffCKB to kickstart your first CKB project. The version used here is [`v0.3.0`](https://github.com/ckb-devrel/offckb/releases/tag/v0.3.0) or later. + +## Install + +```bash +npm install -g @offckb/cli +``` + +:::tip + +We recommend using [LTS](https://nodejs.org/en/download/package-manager) version of Node to run `offckb`. + +::: + +Once installed, you can view available commands by running `offckb --help`: + +``` +Usage: offckb [options] [command] + +ckb development network for your first try + +Options: + -V, --version output the version number + -h, --help display help for command + +Commands: + create [options] [your-project-name] Create a new dApp from bare templates + node [options] [CKB-Version] Use the CKB to start devnet + proxy-rpc [options] Start the rpc proxy server + clean Clean the devnet data, need to stop running the chain first + accounts Print account list info + list-hashes [CKB-Version] Use the CKB to list blockchain scripts hashes + inject-config Add offckb.config.ts to your frontend workspace + sync-scripts Sync scripts json files in your frontend workspace + deposit [options] [toAddress] [amountInCKB] Deposit CKB tokens to address, only devnet and testnet + transfer [options] [toAddress] [amountInCKB] Transfer CKB tokens to address, only devnet and testnet + transfer-all [options] [toAddress] Transfer All CKB tokens to address, only devnet and testnet + balance [options] [toAddress] Check account balance, only devnet and testnet + deploy [options] Deploy contracts to different networks, only supports devnet and testnet + my-scripts [options] Show deployed contracts info on different networks, only supports devnet and testnet + config [item] [value] do a configuration action + debug [options] CKB Debugger for development + system-scripts [options] Output system scripts of the local devnet + mol [options] Generate CKB Moleculec binding code for development + repl [options] A custom Nodejs REPL environment bundle for CKB. + help [command] display help for command + +``` + +:::tip + +Use `offckb [command] -h` to see detailed help for a specific sub command and its options. + +::: + +## Get started + +### Run CKB + +Start a local blockchain with the default CKB version: + +``` +offckb node +``` + +Or, specify a CKB version: + +``` +offckb node 0.117.0 +``` + +Or, set a default CKB version: + +``` +offckb config set ckb-version 0.117.0 +offckb node +``` + +Once the Devnet is running, a RPC server will be available at `http://localhost:8114`. + +An optional RPC proxy server runs at `http://localhost:9000`, forwarding requests to the RPC server. A proxy RPC server is for recording requests and automatically dumping failed transactions for later debugging. + +The proxy server is optional. You can skip it by running: + +``` +offckb node --no-proxy +``` + +Alternatively, start the proxy server in a standalone terminal to better monitor the logs: + +``` +offckb proxy-rpc --ckb-rpc --port 9000 --network devnet +``` + +### Tweak Devnet Config + +OffCKB provides a default configuration for the Devnet, which you can tweak as follows: + +First, start your default CKB Devnet and locate the folder. + +```bash +offckb node +# Once started, press Ctrl+C to stop the node +# Get the config +offckb config list +``` + +Result: + +```json +{ + "devnet": { + "rpcUrl": "", + "configPath": "~/Library/Application Support/offckb-nodejs/devnet", + "dataPath": "~/Library/Application Support/offckb-nodejs/devnet/data" + } +} +``` + +Pay attention to the `devnet.configPath` and `devnet.dataPath`. They are the directories for configuration and chain data storage. + +1. Navigate to `devnet.configPath`, which contains the configuration files for the local blockchain. + +```bash +cd +``` + +Modify the config files as needed to customize your Devnet. For guidance, see [Custom Devnet Setup](https://docs.nervos.org/docs/node/run-devnet-node#custom-devnet-setup) and [Configure CKB](https://github.com/nervosnetwork/ckb/blob/develop/docs/configure.md) for a detailed explanation. + +1. Once modified, clear the existing chain data in `devnet.dataPath`. + +``` +rm -rf +``` + +1. Restart the chain with new configurations by running `offckb node`. + +Now your customized Devnet is ready to go. + +### Create a Full-Stack Project + +You can create a new project from predefined boilerplates with the following command: + +``` +offckb create +``` + +The fullstack boilerplate project is a monorepo that contains a script and a frontend project. + +### Start the Frontend + +To start the frontend, navigate to the frontend folder and run: + +``` +cd frontend && npm i & npm run dev +``` + +![image](https://hackmd.io/_uploads/Hkavbybzkg.png) + +The boilerplate supports different CKB networks. Check the [README.md](https://github.com/nervosnetwork/docs.nervos.org/blob/develop/examples/remix-vite-template/readme.md) in the project for details. + +### Create a Script-Only Project + +You can create a new Script project without a frontend, which is useful when you only want to develop smart contracts for CKB. + +``` +offckb create --script +``` + +:::Note + +Make sure Rust/Cargo/Cargo-generate/Clang 16+ is installed in your environment, since OffCKB relies on [ckb-script-template](https://github.com/cryptape/ckb-script-templates) to handle the core process. + +::: + +### Build and Deploy a Script + +To build the Script, navigate to the root of the project and run: + +``` +make build +``` + +To deploy, go to the frontend folder where the default `offckb.config.ts` is located and run: + +``` +cd frontend && offckb deploy --network +``` + +Or specific the path to `offckb.config.ts` for deploy command to locate: + +``` +offckb deploy --network --config +``` + +Pass `--type-id` to make Scripts upgradable. This is optional: + +``` +cd frontend && offckb deploy --type-id --network +``` + +Once deployed, check the Scripts with following command: + +``` +offckb my-scripts --network +``` + +The deployed Scripts will also be listed in the `frontend/offckb/my-scripts` folder in your frontend project. Also, `offckb.config.ts` will contain the integration details to import and utilize your Scripts in the frontend dApp. + +### Use Deployed Scripts + +Once deployed, use the Scripts as follows in your frontend: + +``` +import offckb from "offckb.config"; + +const myScriptDeps: CellDep[] = offCKB.myScripts["YOUR_SCRIPT_NAME"]!.cellDeps; +const myScript: Script = { + codeHash: offCKB.myScripts["hash-lock"]!.codeHash, + hashType: offCKB.myScripts["hash-lock"]!.hashType, + args: lockArgs, +}; + +``` + +### Debug a Transaction + +Failed transactions will be dumped and recorded by the proxy RPC server for later debugging. + +To debug a transaction by its transaction hash, run the following command: + +``` +offckb debug +``` + +It will verify all the Scripts in the transaction and print the details in the terminal: + +``` +offckb debug --tx-hash 0x64c936ee78107450d49e57b7453dce9031ce68b056b2f1cdad5c2218ab7232ad +Dump transaction successfully + +****************************** +****** Input[0].Lock ****** + +hello, this is new add! +Hashed 1148 bytes in sighash_all +sighash_all = 5d9b2340738ee28729fc74eba35e6ef969878354fe556bd89d5b6f62642f6e50 +event = {"pubkey":"45c41f21e1cf715fa6d9ca20b8e002a574db7bb49e96ee89834c66dac5446b7a","tags":[["ckb_sighash_all","5d9b2340738ee28729fc74eba35e6ef969878354fe556bd89d5b6f62642f6e50"]],"created_at":1725339769,"kind":23334,"content":"Signing a CKB transaction\\n\\nIMPORTANT: Please verify the integrity and authenticity of connected Nostr client before signing this message\\n","id":"90af298075ac878901282e23ce35b24e584b7727bc545e149fc259875a23a7aa","sig":"b505e7d5b643d2e6b1f0e5581221bbfe3c37f17534715e51eecf5ff97a2e1b828a3d767eb712555c78a8736e9085b4960458014fa171d5d169a1b267b186d2f3"} +verify_signature costs 3654 k cycles +Run result: 0 +Total cycles consumed: 4013717(3.8M) +Transfer cycles: 44947(43.9K), running cycles: 3968770(3.8M) + +****************************** +****** Output[0].Type ****** + +verify_signature costs 3654 k cycles +Run result: 0 +Total cycles consumed: 3916670(3.7M) +Transfer cycles: 43162(42.2K), running cycles: 3873508(3.7M) + +``` + +To debug a single Cell Script in a transaction, use the following command: + +``` +offckb debug --single-script +``` + +The `single-cell-script-option` format is `[].`, eg: `"input[0].lock"` + +- `cell-type` can be `input` or `output`, referring to the Cell type +- `cell-index` is the index of the Cell in the transaction +- `script-type` can be `lock` or `type` referring to the Script type + +Or, you can replace the Script with a binary file in a single Cell Script debug session: + +``` +offckb debug --single-script --bin +``` + +All the debug utils are provided by [ckb-debugger](https://github.com/nervosnetwork/ckb-standalone-debugger/tree/develop/ckb-debugger). + +### Generate Molecule Bindings + +[Molecule](https://github.com/nervosnetwork/molecule) is the official [Serialization/Deserialization](https://docs.nervos.org/docs/serialization/serialization-molecule-in-ckb) system for CKB Scripts. + +Define your data structure in `.mol` file (schema), and generate the bindings for different programming languages used in your project. + +``` +offckb mol --schema --output --lang +``` + +Supported languages (`lang`): `ts`, `js`, `c`, `rs`, and `go`. + +For multiple `.mol` files, use a folder as the input and specify an output folder: + +``` +offckb mol --schema --output-folder --lang +``` + +## REPL Mode + +OffCKB packs a custom Node.js REPL with built-in variables and functions to help you develop CKB in the terminal with minimized effort. This is most suitable for simple Script testing tasks when long code is not desirable. + +### Start the OffCKB REPL + +``` +offckb repl --network + +Welcome to OffCKB REPL! +[[ Default Network: devnet, enableProxyRPC: false ]] +Type 'help()' to learn how to use. +OffCKB > + +``` + +Type `help()` to learn about the built-in variables and functions: + +``` +OffCKB > help() + +OffCKB Repl, a Nodejs REPL with CKB bundles. + +Global Variables to use: + - ccc, cccA, imported from CKB Javascript SDK CCC + - client, a CCC client instance bundle with current network + - Client, a Wrap of CCC client class, you can build new client with + const myClient = Client.new('devnet' | 'testnet' | 'mainnet'); + // or + const myClient = Client.fromUrl('', 'devnet' | 'testnet' | 'mainnet'); + - accounts, test accounts array from OffCKB + - networks, network information configs + - help, print this help message + +``` + +### Build a CKB Transaction in REPL + +``` +OffCKB > let amountInCKB = ccc.fixedPointFrom(63); +OffCKB > let tx = ccc.Transaction.from({ +... outputs: [ +... { +... capacity: ccc.fixedPointFrom(amountInCKB), +... lock: accounts[0].lockScript, +... }, +... ], +... }); +OffCKB > let signer = new ccc.SignerCkbPrivateKey(client, accounts[0].privkey); +OffCKB > await tx.completeInputsByCapacity(signer); +2 +OffCKB > await tx.completeFeeBy(signer, 1000); +[ 0, true ] +OffCKB > await mySigner.sendTransaction(tx) +'0x50fbfa8c47907d6842a325e85e48d5da6917e16ca7e2253ec3bd5bcdf8da99ce' + +``` + +### Check Balance in REPL + +``` +OffCKB > let myClient = Client.fromUrl(networks.testnet.rpc_url, 'testnet'); +OffCKB > await myClient.getBalanceSingle(accounts[0].lockScript); +60838485293944n +OffCKB > +``` + +## Configure Settings + +OffCKB settings are saved in a JSON file, which you can edit to update your preferences. + +### List All Settings + +To view all available options and the JSON file path, run: + +``` +offckb config list +``` + +### Set CKB Version + +``` +offckb config get ckb-version +> 0.113.0 +offckb config set ckb-version 0.117.0 +offckb config get ckb-version +> 0.117.0 +``` + +### Set Network Proxy + +``` +offckb config set proxy +> save new settings +offckb config get proxy +> +offckb config rm proxy +> save new settings +offckb config get proxy +> No Proxy. +``` + +## Pre-Funded Accounts + +OffCKB comes with 20 pre-funded accounts, where each one has `42_000_000_00000000` capacity in the genesis block. + +:::note + +These accounts are for development only, do **NOT** send real assets into any of them. + +::: + +Run `offckb accounts` to print the details of these accounts: + +```bash +Print account list, each account is funded with 42_000_000_00000000 capacity in the devnet genesis block. + +- "#": 0 +address: ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqvwg2cen8extgq8s5puft8vf40px3f599cytcyd8 +privkey: 0x6109170b275a09ad54877b82f7d9930f88cab5717d484fb4741ae9d1dd078cd6 +pubkey: 0x02025fa7b61b2365aa459807b84df065f1949d58c0ae590ff22dd2595157bffefa +lock_arg: 0x8e42b1999f265a0078503c4acec4d5e134534297 +lockScript: + codeHash: 0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8 + hashType: type + args: 0x8e42b1999f265a0078503c4acec4d5e134534297 + +- "#": 1 +address: ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqt435c3epyrupszm7khk6weq5lrlyt52lg48ucew +privkey: 0x9f315d5a9618a39fdc487c7a67a8581d40b045bd7a42d83648ca80ef3b2cb4a1 +pubkey: 0x026efa0579f09cc7c1129b78544f70098c90b2ab155c10746316f945829c034a2d +lock_arg: 0x758d311c8483e0602dfad7b69d9053e3f917457d +lockScript: + codeHash: 0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8 + hashType: type + args: 0x758d311c8483e0602dfad7b69d9053e3f917457d +.... +``` + +## Built-In Scripts + +OffCKB embeds common Scripts in the genesis block of the local chain. You can use it without manual deployment. + +Here we list the built-in Scripts source information: + +- [xUDT](<[https://github.com/nervosnetwork/rfcs/pull/428](https://github.com/nervosnetwork/rfcs/pull/428)>) + - commit id: 410b16c +- [Omnilock](<[https://github.com/cryptape/omnilock](https://github.com/cryptape/omnilock)>) + - commit id: cd764d7 +- [AnyoneCanPay](<[https://github.com/cryptape/anyone-can-pay](https://github.com/cryptape/anyone-can-pay)>) + - commit id: b845b3b +- [AlwaysSuccess](<[https://github.com/nervosnetwork/ckb-production-scripts/blob/master/c/always_success.c](https://github.com/nervosnetwork/ckb-production-scripts/blob/master/c/always_success.c)>) + - commit id: 410b16c +- [Spore](<[https://github.com/sporeprotocol/spore-contract](https://github.com/sporeprotocol/spore-contract)>) + - version: 0.2.2-beta.1 + +For all the genesis built-in Scripts information, use `offckb system-scripts` command: + +``` +offckb system-scripts --network devnet +``` + +Or export the Scripts info to a Lumos JSON file: + +``` +offckb system-scripts --export-style lumos +``` + +Or print the Scripts info in the CCC format: + +``` +offckb system-scripts --export-style ccc +``` + +## About CCC + +OffCKB uses [CCC](https://github.com/ckb-devrel/ccc) (CKB Javascript SDK) as the development framework for CKB dApp template projects and is itself built on CCC. For documentation, visit: + +- CCC on Nervos Docs: [docs.nervos.org/docs/sdk-and-devtool/ccc](https://docs.nervos.org/docs/sdk-and-devtool/ccc) +- CCC Documentation: [docs.ckbccc.com](https://docs.ckbccc.com/) + +We hope this guide can help you get started with your CKB development journey! If you encounter any problems, please don't hesitate to reach out via [@CKBDev](https://x.com/CKBdev) on X/Twitter. diff --git a/website/docs/tech-explanation/ckb-vm.md b/website/docs/tech-explanation/ckb-vm.md index b1c6e1919..f2273ceb5 100644 --- a/website/docs/tech-explanation/ckb-vm.md +++ b/website/docs/tech-explanation/ckb-vm.md @@ -17,6 +17,10 @@ Any programming language that can target RISC-V can be used natively for develop Nervos CKB offers native SDKs in several mainstream programming languages, such as JavaScript, Rust, Go, Java, and Ruby. +## CKB-VM Version + +The CKB network has introduced various CKB-VM versions over time to enhance security, performance, resolve bugs, and support new RISC-V extensions. To check out all versions of the CKB-VM from previous hard fork events, please visit [VM Version History](/docs/history-and-hard-forks/history-vm-version) + --- For more information on CKB-VM, please refer to the [RFC CKB-VM](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0003-ckb-vm/0003-ckb-vm.md). diff --git a/website/docs/tech-explanation/fee-estimator.md b/website/docs/tech-explanation/fee-estimator.md new file mode 100644 index 000000000..f7cc24656 --- /dev/null +++ b/website/docs/tech-explanation/fee-estimator.md @@ -0,0 +1,113 @@ +--- +id: fee-estimator +title: "Fee Estimator" +--- + +As the number of transactions on CKB continues to grow, accurate fee rate estimation becomes increasingly essential. CKB `v0.120.0` introduces a new experimental feature, **Fee Estimator**, to help developers and users determine optimal transaction fee rates. + +## Key Features + +- **Switchable Algorithms:** Fee Estimator supports multiple backend algorithms, with a built-in fallback mechanism to ensure greater reliability. +- **Priority Modes:** Rather than relying on specific block numbers or time units, the estimator operates with four priority modes: + - No Priority + - Low Priority + - Medium Priority + - High Priority + +## How It Works + +The Fee Estimator works through a well-designed system that: + +- Analyzes transaction pool data and historical information to provide fee rate estimates. +- Uses a fallback algorithm for newly started nodes that lack sufficient historical data. +- Automatically switches to the fallback algorithm if the primary algorithm encounters errors. + +Fee Estimator currently supports two backend algorithms: + +- **Confirmation Fraction:** Adapted from Bitcoin’s [estimatesmartfee RPC](https://bitcoincore.org/en/doc/0.16.0/rpc/util/estimatesmartfee/) +- **Weight-Units Flow:** A variant of the [Weight-Units Flow Fee Estimator for Bitcoin](https://bitcoiner.live/?tab=info). + +To enable the Fee Estimator, the CKB node operator needs to specify the backend algorithms and activate the "Experiment" JSON-RPC API module in the CKB Node Configuration (`ckb.toml`). As shown below: + +Specify the algorithm in `ckb.toml`: + +```toml +[fee_estimator] +# Specifies the fee estimate algorithm. Current options: ConfirmationFraction, WeightUnitsFlow. +algorithm = "WeightUnitsFlow" +``` + +Enable the JSON-RPC API module `Experiment`: + +```bash +[rpc] +# List of API modules: ["Net", "Pool", "Miner", "Chain", "Stats", "Subscription", "Experiment", "Debug", "Indexer"] +modules = ["Net", "Pool", "Miner", "Chain", "Stats", "Subscription", "Experiment", "Debug", "Indexer"] +``` + +Once the CKB node is started, users can estimate the fee rate by making an RPC request: + +```bash +echo '{ "id": 1, "jsonrpc": "2.0", "method": "estimate_fee_rate", "params": [] }' \ + | curl -s -H "Content-Type: application/json" -d @- "http://localhost:8114" \ + | jq +``` + +Example response: + +```json +{ + "jsonrpc": "2.0", + "result": "0x3e8", + "id": 1 +} +``` + +## Technical Implementation + +### 1. **Confirmation Fraction** + +Inspired by Bitcoin’s `estimatesmartfee` RPC, the **Confirmation Fraction** algorithm estimates transaction fees based on the probability of transaction confirmation within a specified time frame. + +The algorithm works by categorizing transactions into fee-rate buckets. For each bucket, the ‘committed rate’ is calculated. The algorithm then traverse these buckets in ascending order of fee rate. The goal is to identify the best buckets by considering the cumulative committed rate of all transactions in the buckets with a fee rate less than or equal to the current traversing bucket meets or exceeds a target value. When the accumulated transaction backlog in the selected best buckets exceeds half of the total backlog in those buckets, the fee rate is selected. + +This estimator requires a substantial amount of transaction history and tracks the rate of transactions moving through the pool, while accounting for transaction backlog to ensure the chosen fee rate is appropriate. + +### 2. **Weight-Units Flow** + +Based on a non-official Bitcoin algorithm, **Weight-Units Flow** focuses on the overall flow of transactions in and out of the transaction pool, rather than individual transaction commit status. + +The algorithm categorizes transactions into fee-rate buckets, calculating the current weight and flow rate of transactions in each bucket. It then predicts how much weight will be added or removed over a specific time period, estimating the final weight of all transactions in the buckets with a fee rate greater than or equal to the current bucket as all buckets are traversed in descending order. If the final weight is less than or equal to zero, it indicates that transactions with that fee rate are flowing out of the pool faster than they are flowing in. + +This method heavily relies on historical data, particularly to predict transaction congestion and how it will evolve over time. By analyzing transaction flow and adjusting based on future conditions, the algorithm provides a estimate of the likelihood that a transaction will be included in the next block. + +### 3. **Fallback Estimator** + +The **Fallback Estimator** provides a basic fee estimate when the primary backend algorithm fails. It operates under two key assumptions: + +- All current transactions in the transaction pool will eventually be proposed. +- No new transactions will be added to the transaction pool. + +The estimator uses the current state of the transaction pool to quickly generate a fee estimate. Although less precise than the backend algorithms, it ensures that a fee estimate is always returned, even in failure scenarios. + +## Current Limitations + +Developers should be aware of the following limitations: + +- Chain-style transactions, where the previous transaction’s output serves as the input of the next, may affect estimation accuracy. +- Results rely on network conditions and available historical data, so short-term on-chain fee rate fluctuations have minimal impact on estimates. + +## Best Practices for Developers + +- Always implement error handling for cases where fee estimation might fail. +- Consider using the fallback mechanism to ensure more reliable results. +- Monitor network conditions when integrating fee rate estimation into your applications. +- In the future, we plan to integrate the fee estimator feature into CKB SDKs like [CCC](https://github.com/ckb-ecofund/ccc) + +This Fee Estimator marks a significant step forward in improving transaction fee prediction on CKB, helping developers create more efficient and user-friendly applications. + +## Resources + +For more information on the Fee Estimator, visit the PR: + +- [https://github.com/nervosnetwork/ckb/pull/4477](https://github.com/nervosnetwork/ckb/pull/4477) diff --git a/website/docs/tech-explanation/hash-type.md b/website/docs/tech-explanation/hash-type.md index 451018e91..3910a806d 100644 --- a/website/docs/tech-explanation/hash-type.md +++ b/website/docs/tech-explanation/hash-type.md @@ -3,7 +3,13 @@ id: hash-type title: hash_type --- -`hash_type` defines the interpretation of the `code_hash` when looking for matching dep Cells. +`hash_type` defines the interpretation of the `code_hash` when looking for matching dep Cells. Each hash_type value in this fields corresponds to a specific JSON representation, hash matching method, and the compatible VM version, specified as follows: -- If it is 0, i.e., data, `code_hash` should match the blake2b hash of data in a dep Cell; -- if it is 1, i.e., type, `code_hash` should match the Type Script hash of a dep Cell. +| `hash_type` | JSON Representation | Matched by | VM Version | +| ----------- | ------------------- | ------------------- | ---------- | +| 0 | "data" | Data hash (blake2b) | 0 | +| 1 | "type" | Type Script hash | 2 | +| 2 | "data1" | Data hash (blake2b) | 1 | +| 4 | "data2" | Data hash (blake2b) | 2 | + +Learn more about VM versions and how to choose, visit [RFC0032: CKB VM Version Selection](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0032-ckb-vm-version-selection/0032-ckb-vm-version-selection.md) diff --git a/website/docs/tech-explanation/script.md b/website/docs/tech-explanation/script.md index b9ba3a0e5..4a589541c 100644 --- a/website/docs/tech-explanation/script.md +++ b/website/docs/tech-explanation/script.md @@ -13,7 +13,7 @@ In addition to the rules defined by the CKB protocol, verification based on the Script: { code_hash: HexString args: HexString - hash_type: Uint8, there are 4 allowed values: {0: "data", 1: "type", 2: "data1", 3: "data2"} + hash_type: Uint8, there are 4 allowed values: {0: "data", 1: "type", 2: "data1", 4: "data2"} } ``` diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js index 4bc88415a..b178e15bd 100644 --- a/website/docusaurus.config.js +++ b/website/docusaurus.config.js @@ -187,6 +187,10 @@ const config = { ], to: "https://docs-old.nervos.org/docs/basics/guides/crypto wallets/neuron", }, + { + from: "/docs/basics/tools", + to: "https://docs-old.nervos.org/docs/basics/tools", + }, ], createRedirects(existingPath) { if ( diff --git a/website/package.json b/website/package.json index 068b95dfc..6a1b96549 100644 --- a/website/package.json +++ b/website/package.json @@ -1,6 +1,6 @@ { "name": "docs.nervos.org", - "version": "2.13.0", + "version": "2.14.0", "description": "Official docs website for Nervos CKB", "license": "MIT", "scripts": { diff --git a/website/sidebars.js b/website/sidebars.js index fda850fe4..7ec4a602b 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -8,6 +8,7 @@ export default { items: [ "getting-started/how-ckb-works", "getting-started/quick-start", + "getting-started/installation-guide", "getting-started/blockchain-networks", "getting-started/ckb-vs-btc", ], @@ -23,7 +24,8 @@ export default { "sdk-and-devtool/java", "sdk-and-devtool/ccc", "sdk-and-devtool/lumos", - "sdk-and-devtool/cli-tools", + "sdk-and-devtool/ckb-cli", + "sdk-and-devtool/offckb", "sdk-and-devtool/devtool", ], }, @@ -50,12 +52,16 @@ export default { "script/program-language-for-script", "script/syscalls-for-script", "script/vm-cycle-limits", - "script/minimal-script", - "script/sudt-script", + "script/vm-selection", "script/type-id", - "script/js-script", + "script/spawn-cross-script-calling", "script/debug-script", + "script/script-upgrade-workflow", "script/common-script-error-code", + "script/minimal-script", + "script/sudt-script", + "script/spawn-script", + "script/js-script", ], }, { @@ -92,6 +98,7 @@ export default { "node/run-testnet-node", "node/run-devnet-node", "node/run-public-rpc-node", + "node/turn-on-fee-estimator", ], }, { @@ -122,12 +129,25 @@ export default { "how-tos/how-to-calculate-code-hash", ], }, + { + type: "category", + label: "History & Hard Forks", + className: "category-history", + collapsible: false, + items: [ + "history-and-hard-forks/intro-to-hard-fork", + "history-and-hard-forks/ckb-hard-fork-history", + "history-and-hard-forks/history-vm-version", + "history-and-hard-forks/rethinking-forks", + ], + }, { type: "category", label: "Tech Explanation", className: "category-tech-explanation", collapsible: false, items: [ + "tech-explanation/fee-estimator", "tech-explanation/nervos-blockchain", "tech-explanation/cell", "tech-explanation/cell-model", diff --git a/website/src/components/HardForkTime/index.tsx b/website/src/components/HardForkTime/index.tsx new file mode 100644 index 000000000..8ee728403 --- /dev/null +++ b/website/src/components/HardForkTime/index.tsx @@ -0,0 +1,42 @@ +import styles from "./styles.module.css"; + +export interface HardForkTimeProps { + mainnetDate?: string; + mainnetEpoch?: string | number; + testnetDate?: string; + testnetEpoch?: string | number; +} + +export default function HardForkTime({ + mainnetDate = "TBD", + mainnetEpoch = "TBD", + testnetDate = "TBD", + testnetEpoch = "TBD", +}: HardForkTimeProps): JSX.Element { + return ( +
+
+

Mainnet Launch

+
+ {"📅 Date: "} + {mainnetDate} +
+
+ {"⏳ Epoch number: "} + {mainnetEpoch} +
+
+
+

Testnet Launch

+
+ {"📅 Date: "} + {testnetDate} +
+
+ {"⏳ Epoch number: "} + {testnetEpoch} +
+
+
+ ); +} diff --git a/website/src/components/HardForkTime/styles.module.css b/website/src/components/HardForkTime/styles.module.css new file mode 100644 index 000000000..38e86936c --- /dev/null +++ b/website/src/components/HardForkTime/styles.module.css @@ -0,0 +1,32 @@ +@import "@css/customVariables.css"; + +.box { + border-radius: 20px; + padding: 2rem 1.5rem; + background-color: var(--surface-accent); + display: flex; + gap: 1.25rem; + justify-content: space-between; +} +.mainnet, +.testnet { + color: var(--text-primary); + font-weight: 600; + display: flex; + flex-direction: column; + flex: 1; +} +.subtitle { + margin-bottom: 0.5rem; +} +.value { + font-weight: 400; + color: var(--text-secondary); + margin-top: 0.5rem; +} + +@media (max-width: 768px) { + .box { + flex-direction: column; + } +} diff --git a/website/src/components/Home/index.tsx b/website/src/components/Home/index.tsx index a30245802..eb598ea23 100644 --- a/website/src/components/Home/index.tsx +++ b/website/src/components/Home/index.tsx @@ -431,6 +431,36 @@ function DevLogSection(): JSX.Element { ); } +function HistorySection(): JSX.Element { + return ( +
+
+ +
+
+

Explore CKB History & Hard Forks

+
+ Delve into the milestones and pivotal updates that have shaped CKB's + development. Gain detailed insights into each hard fork and understand + their impact on the evolution of the network. +
+ +
+
+ {"history +
+
+ ); +} + function CTASection(): JSX.Element { const [copied, setCopied] = useState(false); @@ -535,6 +565,7 @@ export { ToolDisplay, ProjectDisplay, DevLogSection, + HistorySection, CTASection, FooterSection, }; diff --git a/website/src/components/TutorialHeader/index.tsx b/website/src/components/TutorialHeader/index.tsx index 82189c835..f522f49e2 100644 --- a/website/src/components/TutorialHeader/index.tsx +++ b/website/src/components/TutorialHeader/index.tsx @@ -1,61 +1,140 @@ import React from "react"; import styles from "./styles.module.css"; import Link from "@docusaurus/Link"; -import { CardLinks } from "@site/src/pages/homeContents"; -import ScriptHeaders from "@site/docs/script/ScriptHeaders"; export interface TutorialHeaderProps { time: string; - topics?: CardLinks[]; - tools: JSX.Element[]; + tools: "dapp" | "script" | "debug"; + customTools?: JSX.Element[]; } +const DAPP_HEADER: JSX.Element[] = [ +
+ + Git (≥2.40.0) + +
, +
+ + Yarn (≥1.22.0) + +
, +
+ CKB dev environment:{" "} + + OffCKB (≥v0.3.0) + +
, +
+ JavaScript SDK:{" "} + + CCC (≥v0.0.14-alpha.0) + +
, +]; + +const SCRIPT_HEADER: JSX.Element[] = [ +
+ + Make (≥v4.3), Sed (≥v4.7), Bash (≥v5.0), sha256sum (≥v9.0) + +
, +
+ + Rust (≥v.1.71.1) and riscv64 target + +
, +
+ + Clang (≥v18) + +
, +
+ + cargo-generate (≥0.17.0) + +
, +]; + +const DEBUG_HEADER: JSX.Element[] = [ + ...SCRIPT_HEADER, +
+ + CKB-Debugger (≥0.117.0) + +
, +]; + export default function TutorialHeader({ time, - topics, tools, + customTools, }: TutorialHeaderProps): JSX.Element { + const baseTools = + tools === "dapp" + ? DAPP_HEADER + : tools === "script" + ? SCRIPT_HEADER + : tools === "debug" + ? DEBUG_HEADER + : []; + + const selectedTools = customTools + ? [...baseTools, ...customTools] + : baseTools; + return (
-

Tutorial Overview

⏰ Estimated Time: {time}
- {topics && ( -
- 💡 Topics: - {topics.map((topic, index) => ( - - {index > 0 && ", "} - {topic.label} - - ))} -
- )}
- 🔧 Tools You Need: + 🔧 What You Will Need:
    - {tools.map((tool, index) => { - if (tool.props.children === "Script develop tools") { - return ( -
    - - Script develop tools - -
    - {ScriptHeaders.basic.tools.map((scriptTool, scriptIndex) => { - return
  • {scriptTool}
  • ; - })} -
    -
    - ); - } else { - return
  • {tool}
  • ; - } - })} + {selectedTools.map((tool, index) => ( +
  • {tool}
  • + ))}
+
+ For detailed installation steps, refer to our{" "} + + Installation Guide + +
); } diff --git a/website/src/components/TutorialHeader/styles.module.css b/website/src/components/TutorialHeader/styles.module.css index 36c5662f5..36a81bce3 100644 --- a/website/src/components/TutorialHeader/styles.module.css +++ b/website/src/components/TutorialHeader/styles.module.css @@ -17,6 +17,10 @@ margin: 0; padding-left: 2.5rem; } +.details { + padding-left: 1rem; + padding-top: 0.5rem; +} .collapsibleHeader { margin-left: -1.125rem; } diff --git a/website/src/css/customTheme.css b/website/src/css/customTheme.css index d968185d2..ede09c9d4 100644 --- a/website/src/css/customTheme.css +++ b/website/src/css/customTheme.css @@ -290,6 +290,12 @@ width: 1.125rem; height: 1.125rem; } +.category-history-hardfork > div > a:before { + content: url("/svg/icon-sidebar-history.svg"); + margin-right: 0.5rem; + width: 1.125rem; + height: 1.125rem; +} .category-tech-explanation > div > a:before { content: url("/svg/icon-sidebar-concept.svg"); margin-right: 0.5rem; diff --git a/website/src/pages/index.tsx b/website/src/pages/index.tsx index 70af69a27..9708c4e24 100644 --- a/website/src/pages/index.tsx +++ b/website/src/pages/index.tsx @@ -9,6 +9,7 @@ import { WalletDisplay, ToolDisplay, DevLogSection, + HistorySection, ProjectDisplay, FooterSection, CTASection, @@ -72,9 +73,12 @@ export default function Home() { )} >
- Unveil Latest Update + Unveil{" "} + Updates and Evolution
+
+
Ready to Dive In?
diff --git a/website/static/img/quick-start/next-js-dapp.jpg b/website/static/img/quick-start/next-js-dapp.jpg deleted file mode 100644 index 66e0c2b5d..000000000 Binary files a/website/static/img/quick-start/next-js-dapp.jpg and /dev/null differ diff --git a/website/static/img/quick-start/remix-vite-dapp.jpg b/website/static/img/quick-start/remix-vite-dapp.jpg deleted file mode 100644 index f628f3db0..000000000 Binary files a/website/static/img/quick-start/remix-vite-dapp.jpg and /dev/null differ diff --git a/website/static/img/quick-start/remix-vite-dapp.png b/website/static/img/quick-start/remix-vite-dapp.png new file mode 100644 index 000000000..ee206b59e Binary files /dev/null and b/website/static/img/quick-start/remix-vite-dapp.png differ diff --git a/website/static/img/script-upgrade-workflow/redeploy-lost-cells.jpeg b/website/static/img/script-upgrade-workflow/redeploy-lost-cells.jpeg new file mode 100644 index 000000000..eec7dd3af Binary files /dev/null and b/website/static/img/script-upgrade-workflow/redeploy-lost-cells.jpeg differ diff --git a/website/static/img/script-upgrade-workflow/typeid-can-be-ignored.jpeg b/website/static/img/script-upgrade-workflow/typeid-can-be-ignored.jpeg new file mode 100644 index 000000000..d40bf2dc2 Binary files /dev/null and b/website/static/img/script-upgrade-workflow/typeid-can-be-ignored.jpeg differ diff --git a/website/static/img/script-upgrade-workflow/typeid-with-different-lock.jpeg b/website/static/img/script-upgrade-workflow/typeid-with-different-lock.jpeg new file mode 100644 index 000000000..04c10a9fe Binary files /dev/null and b/website/static/img/script-upgrade-workflow/typeid-with-different-lock.jpeg differ diff --git a/website/static/svg/icon-sidebar-history.svg b/website/static/svg/icon-sidebar-history.svg new file mode 100644 index 000000000..d890bceae --- /dev/null +++ b/website/static/svg/icon-sidebar-history.svg @@ -0,0 +1,3 @@ + + + diff --git a/website/static/svg/illus-history.svg b/website/static/svg/illus-history.svg new file mode 100644 index 000000000..62de60450 --- /dev/null +++ b/website/static/svg/illus-history.svg @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +