Rust智能合约脚本库ckb-script的使用,ckb-script为Nervos CKB区块链提供灵活的脚本编程与自定义验证功能
ckb-script
这是一个 CKB 的组件,用于运行类型/锁定脚本。
最低支持的 Rust 版本政策 (MSRV)
该 crate 的最低支持 rustc 版本是 1.85.0
安装
在项目目录中运行以下 Cargo 命令:
cargo add ckb-script
或者在你的 Cargo.toml 中添加以下行:
ckb-script = "0.202.0"
使用示例
下面是一个使用 ckb-script 创建简单智能合约的完整示例:
use ckb_script::{ScriptGroup, ScriptGroupType, ScriptVerifier};
use ckb_types::{bytes::Bytes, core::ScriptHashType, packed::Script, prelude::*};
// 创建一个简单的脚本验证器
fn main() {
    // 创建脚本
    let script = Script::new_builder()
        .code_hash([0u8; 32].pack()) // 替换为实际的代码哈希
        .hash_type(ScriptHashType::Type.into())
        .args(Bytes::from("some_args").pack())
        .build();
    // 创建脚本组
    let script_group = ScriptGroup {
        script,
        group_type: ScriptGroupType::Lock,
        input_indices: vec![0], // 输入索引
        output_indices: vec![], // 输出索引
    };
    // 创建脚本验证器
    let verifier = ScriptVerifier::new(script_group);
    // 验证脚本
    let result = verifier.verify(&Default::default());
    println!("验证结果: {:?}", result);
}
完整示例代码
下面是一个更完整的 ckb-script 使用示例,包含实际交易验证场景:
use ckb_script::{ScriptGroup, ScriptGroupType, ScriptVerifier};
use ckb_types::{
    bytes::Bytes,
    core::{ScriptHashType, TransactionView},
    packed::{Byte32, Script},
    prelude::*,
};
// 示例:验证包含多个输入输出的交易脚本
fn verify_transaction_scripts() {
    // 1. 准备交易数据 (这里简化处理)
    let transaction = TransactionView::new_advanced_builder().build();
    
    // 2. 创建锁定脚本
    let lock_script = Script::new_builder()
        .code_hash(
            // 使用真实的代码哈希
            Byte32::from_slice(&[1u8; 32]).unwrap()
        )
        .hash_type(ScriptHashType::Type.into())
        .args(Bytes::from("lock_args").pack())
        .build();
    // 3. 创建类型脚本
    let type_script = Script::new_builder()
        .code_hash(
            // 使用真实的代码哈希
            Byte32::from_slice(&[2u8; 32]).unwrap()
        )
        .hash_type(ScriptHashType::Data.into())
        .args(Bytes::from("type_args").pack())
        .build();
    // 4. 创建脚本组
    let lock_group = ScriptGroup {
        script: lock_script.clone(),
        group_type: ScriptGroupType::Lock,
        input_indices: vec![0, 1], // 两个输入使用相同的锁定脚本
        output_indices: vec![],
    };
    let type_group = ScriptGroup {
        script: type_script.clone(),
        group_type: ScriptGroupType::Type,
        input_indices: vec![],
        output_indices: vec![0], // 输出0使用该类型脚本
    };
    // 5. 创建验证器并验证
    let verifier = ScriptVerifier::new(lock_group);
    let result = verifier.verify(&transaction);
    println!("锁定脚本验证结果: {:?}", result);
    let verifier = ScriptVerifier::new(type_group);
    let result = verifier.verify(&transaction);
    println!("类型脚本验证结果: {:?}", result);
}
fn main() {
    verify_transaction_scripts();
}
代码说明
- 首先我们创建了交易数据和两种脚本(锁定脚本和类型脚本)
 - 然后为每种脚本创建了脚本组,指定了:
- 脚本类型 (Lock 或 Type)
 - 输入/输出索引
 
 - 最后使用 ScriptVerifier 分别验证两种脚本
 
文档
更多详细用法请参考官方文档。
        
          1 回复
        
      
      
        Rust智能合约脚本库ckb-script使用指南
介绍
ckb-script是Nervos CKB(Common Knowledge Base)区块链上的一个Rust库,专门用于编写和执行智能合约脚本。它为开发者提供了在CKB上创建自定义验证逻辑的能力,是构建去中心化应用(DApp)和扩展CKB功能的核心工具。
CKB采用独特的Cell模型而非账户模型,ckb-script允许开发者定义如何验证Cell的消费和创建,从而实现各种复杂的业务逻辑。
主要特性
- 提供在CKB上执行自定义脚本的基础设施
 - 支持多种编程语言编写的脚本(通过RISC-V VM)
 - 灵活的验证逻辑定义能力
 - 与CKB-VM深度集成
 - 高性能的脚本执行环境
 
安装方法
在Cargo.toml中添加依赖:
[dependencies]
ckb-script = "0.5.0"
基本使用方法
1. 编写简单脚本
use ckb_script::Script;
use ckb_types::{packed, prelude::*};
fn main() {
    // 创建一个简单的锁定脚本
    let args: Vec<u8> = vec![1, 2, 3, 4];
    let script = Script::new_builder()
        .code_hash(Default::default())
        .hash_type(Default::default())
        .args(args.pack())
        .build();
    
    println!("Script created: {:?}", script);
}
2. 脚本验证示例
use ckb_script::{ScriptError, ScriptGroup, ScriptVerifier};
use ckb_types::core::TransactionView;
fn verify_transaction(tx: TransactionView) ->
Result<(), ScriptError> {
    let script_group = ScriptGroup::from_transaction(&tx)?;
    let verifier = ScriptVerifier::new(tx);
    
    for group in script_group.groups() {
        verifier.verify(&group)?;
    }
    
    Ok(())
}
3. 自定义脚本实现
use ckb_script::{ScriptFn, ScriptResult};
use ckb_types::{bytes::Bytes, core::ScriptHashType};
#[derive(Debug, Clone)]
pub struct MyCustomScript;
impl ScriptFn for MyCustomScript {
    fn verify(&self, data: &[u8], args: &[u8]) -> ScriptResult {
        // 自定义验证逻辑
        if args.len() < 4 {
            return Err("Args too short".into());
        }
        
        if data.len() > 1024 {
            return Err("Data too large".into());
        }
        
        Ok(())
    }
    
    fn script_hash_type(&self) -> ScriptHashType {
        ScriptHashType::Data
    }
}
高级用法
1. 与CKB-VM集成
use ckb_script::{ScriptConfig, ScriptVersion};
use ckb_vm::machine::asm::AsmCoreMachine;
let config = ScriptConfig::new_builder()
    .version(ScriptVersion::V1)
    .build();
let machine = AsmCoreMachine::new(
    config.max_cycles(),
    config.vm_version(),
    config.isa(),
);
2. 处理脚本组
use ckb_script::{ScriptGroup, ScriptGroupType};
let tx = get_transaction(); // 获取交易
let script_groups = ScriptGroup::from_transaction(&tx)?;
for group in script_groups.groups() {
    match group.group_type() {
        ScriptGroupType::Lock => println!("Lock script group"),
        ScriptGroupType::Type => println!("Type script group"),
    }
    
    println!("Input indices: {:?}", group.input_indices());
    println!("Output indices: {:?}", group.output_indices());
}
实际应用示例
实现一个多签脚本
use ckb_script::{ScriptFn, ScriptResult};
use ckb_types::{bytes::Bytes, core::ScriptHashType};
use secp256k1::{PublicKey, Signature, Message};
pub struct MultiSigScript {
    pub public_keys: Vec<PublicKey>,
    pub threshold: usize,
}
impl ScriptFn for MultiSigScript {
    fn verify(&self, witness: &[u8], args: &[u8]) -> ScriptResult {
        let signatures: Vec<Signature> = deserialize_signatures(witness)?;
        
        if signatures.len() < self.threshold {
            return Err("Not enough signatures".into());
        }
        
        let message = Message::from_slice(args).map_err(|_| "Invalid message")?;
        
        let mut valid_sigs = 0;
        for sig in signatures {
            for pubkey in &self.public_keys {
                if sig.verify(&message, pubkey).is_ok() {
                    valid_sigs += 1;
                    break;
                }
            }
        }
        
        if valid_sigs >= self.threshold {
            Ok(())
        } else {
            Err("Not enough valid signatures".into())
        }
    }
    
    fn script_hash_type(&self) -> ScriptHashType {
        ScriptHashType::Type
    }
}
完整示例Demo
下面是一个完整的ckb-script使用示例,展示了如何创建一个简单的资产转移合约:
use ckb_script::{Script, ScriptFn, ScriptResult, ScriptVerifier};
use ckb_types::{
    bytes::Bytes,
    core::{ScriptHashType, TransactionView},
    packed,
    prelude::*,
};
// 自定义资产转移脚本
#[derive(Debug, Clone)]
pub struct AssetTransferScript {
    pub min_balance: u64,
}
impl ScriptFn for AssetTransferScript {
    fn verify(&self, data: &[u8], args: &[u8]) -> ScriptResult {
        // 验证输入参数长度
        if args.len() != 32 {
            return Err("Invalid args length, expected 32-byte asset ID".into());
        }
        
        // 解析数据中的余额
        if data.len() != 8 {
            return Err("Invalid data length, expected 8-byte balance".into());
        }
        
        let balance = u64::from_le_bytes(data.try_into().unwrap());
        if balance < self.min_balance {
            return Err(format!(
                "Balance {} is below minimum required {}", 
                balance, 
                self.min_balance
            ).into());
        }
        
        Ok(())
    }
    
    fn script_hash_type(&self) -> ScriptHashType {
        ScriptHashType::Data
    }
}
fn main() {
    // 1. 创建脚本
    let script_args = vec![1; 32]; // 32字节的资产ID
    let script = Script::new_builder()
        .code_hash([0u8; 32].pack()) // 实际使用中替换为真实的code hash
        .hash_type(ScriptHashType::Data.into())
        .args(script_args.pack())
        .build();
    
    println!("Created script: {:?}", script);
    
    // 2. 准备模拟交易数据
    let tx = TransactionView::new_advanced_builder()
        .build();
    
    // 3. 创建脚本验证器
    let verifier = ScriptVerifier::new(tx.clone());
    
    // 4. 创建脚本组
    if let Ok(script_group) = ScriptGroup::from_transaction(&tx) {
        for group in script_group.groups() {
            println!("Processing script group: {:?}", group);
            
            // 5. 验证脚本
            if let Err(e) = verifier.verify(&group) {
                println!("Script verification failed: {}", e);
            } else {
                println!("Script verified successfully!");
            }
        }
    }
    
    // 6. 使用自定义脚本
    let asset_script = AssetTransferScript { min_balance: 100 };
    let test_data = 150u64.to_le_bytes();
    let test_args = vec![1; 32];
    
    match asset_script.verify(&test_data, &test_args) {
        Ok(_) => println!("Asset transfer validation passed"),
        Err(e) => println!("Validation failed: {}", e),
    }
}
最佳实践
- 脚本优化:保持脚本尽可能精简,减少执行周期(cycles)消耗
 - 错误处理:提供清晰的错误信息,方便调试
 - 测试:使用ckb-test工具对脚本进行充分测试
 - 安全考虑:特别注意边界条件和异常输入的处理
 
调试技巧
use ckb_script::syscalls::Debugger;
struct MyDebugger;
impl Debugger for MyDebugger {
    fn debug(&self, message: &str) {
        println!("[SCRIPT DEBUG] {}", message);
    }
}
let debugger = MyDebugger;
let verifier = ScriptVerifier::new(tx).with_debugger(&debugger);
ckb-script为Nervos CKB提供了强大的脚本编程能力,通过灵活运用可以构建各种复杂的区块链业务逻辑。
        
      
                    
                  
                    
