Rust Holochain开发工具包hdk_derive的使用,简化HDK宏派生与WASM智能合约开发

hdk_derive

Holochain HDK的派生宏。

安装

在项目目录中运行以下Cargo命令:

cargo add hdk_derive

或者在Cargo.toml中添加以下行:

hdk_derive = "0.5.4"

使用示例

下面是一个完整的示例,展示如何使用hdk_derive简化HDK宏派生和WASM智能合约开发:

// 导入必要的宏和类型
use hdk::prelude::*;
use hdk_derive::*;

// 定义一个将被序列化/反序列化的Entry
#[hdk_entry(id = "my_entry")]
pub struct MyEntry {
    content: String,
}

// 定义一个将被注册为Zome函数的函数
#[hdk_extern]
pub fn create_entry(input: MyEntry) -> ExternResult<HeaderHash> {
    create_entry(&input)
}

// 定义一个将被注册为Zome函数的查询函数
#[hdk_extern]
pub fn get_entry(header_hash: HeaderHash) -> ExternResult<Option<MyEntry>> {
    get_entry(&header_hash)
}

// 使用hdk_derive的入口注册宏
entry_defs![
    MyEntry::entry_def()
];

这个示例展示了如何:

  1. 使用#[hdk_entry]宏定义一个Entry类型
  2. 使用#[hdk_extern]宏定义Zome函数
  3. 使用entry_defs!宏注册Entry类型

完整示例demo

基于上述示例,下面是一个更完整的Holochain WASM智能合约开发示例:

// 导入必要的宏和类型
use hdk::prelude::*;
use hdk_derive::*;

// 定义Person Entry类型
#[hdk_entry(id = "person")]
pub struct Person {
    name: String,
    age: u32,
    email: String,
}

// 创建Person Entry的Zome函数
#[hdk_extern]
pub fn create_person(input: Person) -> ExternResult<HeaderHash> {
    // 验证输入数据
    if input.age > 150 {
        return Err(WasmError::Guest("Age must be less than 150".into()));
    }
    
    // 创建Entry并返回其HeaderHash
    create_entry(&input)
}

// 查询Person Entry的Zome函数
#[hdk_extern]
pub fn get_person(header_hash: HeaderHash) -> ExternResult<Option<Person>> {
    get_entry(&header_hash)
}

// 更新Person Entry的Zome函数
#[hdk_extern]
pub fn update_person(input: (HeaderHash, Person)) -> ExternResult<HeaderHash> {
    let (original_header_hash, updated_person) = input;
    
    // 删除旧Entry
    delete_entry(original_header_hash)?;
    
    // 创建更新后的Entry
    create_entry(&updated_person)
}

// 删除Person Entry的Zome函数
#[hdk_extern]
pub fn delete_person(header_hash: HeaderHash) -> ExternResult<HeaderHash> {
    delete_entry(header_hash)
}

// 注册所有Entry定义
entry_defs![
    Person::entry_def()
];

这个完整示例展示了:

  1. 定义更复杂的Entry类型Person
  2. 添加了数据验证逻辑
  3. 实现了完整的CRUD操作
  4. 展示了错误处理

主要功能

hdk_derive提供的主要派生宏包括:

  • #[hdk_entry] - 用于定义Holochain Entry类型
  • #[hdk_extern] - 用于定义Zome外部函数
  • 其他简化HDK开发的派生宏

许可证

Apache-2.0

所有者

  • holochain/Core Dev团队
  • Stefan Junker
  • Eric Harris-Braun
  • Holochain Release Automation

分类

密码学(Cryptography)


1 回复

Rust Holochain开发工具包hdk_derive的使用

介绍

hdk_derive是Holochain开发工具包(HDK)中的一个派生宏工具,它简化了Holochain WASM智能合约的开发过程。通过提供一系列过程宏,它可以帮助开发者更轻松地定义和使用Holochain中的各种数据类型和函数。

hdk_derive主要解决了HDK中重复性代码编写的问题,通过宏派生自动生成必要的样板代码,让开发者能更专注于业务逻辑的实现。

主要功能

  1. 简化入口函数的定义
  2. 自动派生Holochain数据类型的序列化/反序列化
  3. 提供便捷的宏来定义zome函数
  4. 自动生成必要的WASM导出

使用方法

基本设置

首先在Cargo.toml中添加依赖:

[dependencies]
hdk = "0.2"
hdk_derive = "0.2"
serde = { version = "1.0", features = ["derive"] }

定义入口函数

use hdk_derive::zome;

#[zome]
mod my_zome {
    #[init]
    fn init() {
        Ok(())
    }

    #[validate_agent]
    fn validate_agent(validation_data: EntryValidationData<AgentId>) {
        Ok(())
    }
}

定义入口类型

use hdk_derive::entry_defs;

#[entry_defs]
#[unit_enum(UnitEntryTypes)]
enum EntryTypes {
    #[entry_def(required_validations = 5)]
    BlogPost(BlogPost),
    
    #[entry_def]
    Comment(Comment),
}

#[hdk_entry(id = "blog_post")]
pub struct BlogPost {
    title: String,
    content: String,
    author: AgentPubKey,
}

#[hdk_entry(id = "comment")]
pub struct Comment {
    post_hash: HeaderHash,
    content: String,
    author: AgentPubKey,
}

定义zome函数

use hdk_derive::zome_fn;

#[zome_fn("hc_public")]
fn create_blog_post(blog_post: BlogPost) -> ExternResult<HeaderHash> {
    let header_hash = hdk::create_entry(&blog_post)?;
    Ok(header_hash)
}

#[zome_fn("hc_public")]
fn get_blog_post(header_hash: HeaderHash) -> ExternResult<Option<BlogPost>> {
    let element = hdk::get(header_hash, GetOptions::default())?;
    match element {
        Some(element) => {
            let blog_post: BlogPost = element.entry()
                .to_app_option()?
                .ok_or(WasmError::Guest("Could not deserialize element to BlogPost".into()))?;
            Ok(Some(blog_post))
        }
        None => Ok(None),
    }
}

完整示例

use hdk::prelude::*;
use hdk_derive::{zome, entry_defs};

#[entry_defs]
#[unit_enum(UnitEntryTypes)]
enum EntryTypes {
    #[entry_def]
    Post(Post),
}

#[hdk_entry(id = "post")]
pub struct Post {
    title: String,
    content: String,
}

#[zome]
mod blog_zome {
    use super::*;
    
    #[init]
    fn init() {
        Ok(())
    }
    
    #[zome_fn("hc_public")]
    fn create_post(post: Post) -> ExternResult<HeaderHash> {
        hdk::create_entry(&post)
    }
    
    #[zome_fn("hc_public")]
    fn get_post(header_hash: HeaderHash) -> ExternResult<Option<Post>> {
        let element = hdk::get(header_hash, GetOptions::default())?;
        match element {
            Some(element) => {
                let post: Post = element.entry()
                    .to_app_option()?
                    .ok_or(WasmError::Guest("Could not deserialize element to Post".into()))?;
                Ok(Some(post))
            }
            None => Ok(None),
        }
    }
}

完整示例demo

下面是一个更完整的博客系统示例,展示了如何使用hdk_derive构建一个简单的Holochain应用:

use hdk::prelude::*;
use hdk_derive::{zome, entry_defs};

// 定义入口类型
#[entry_defs]
#[unit_enum(UnitEntryTypes)]
enum EntryTypes {
    #[entry_def(required_validations = 3)]
    BlogPost(BlogPost),
    
    #[entry_def]
    Comment(Comment),
}

// 博客文章结构体
#[hdk_entry(id = "blog_post")]
pub struct BlogPost {
    title: String,
    content: String,
    author: AgentPubKey,
    timestamp: u64,
}

// 评论结构体
#[hdk_entry(id = "comment")]
pub struct Comment {
    post_hash: HeaderHash,
    content: String,
    author: AgentPubKey,
    timestamp: u64,
}

// 定义zome模块
#[zome]
mod blog_zome {
    use super::*;
    
    // 初始化函数
    #[init]
    fn init() {
        Ok(())
    }
    
    // 验证代理函数
    #[validate_agent]
    fn validate_agent(validation_data: EntryValidationData<AgentId>) {
        Ok(())
    }
    
    // 创建博客文章
    #[zome_fn("hc_public")]
    fn create_blog_post(title: String, content: String) -> ExternResult<HeaderHash> {
        let author = hdk::agent_info()?.agent_latest_pubkey;
        let timestamp = sys_time()?.as_seconds();
        
        let blog_post = BlogPost {
            title,
            content,
            author,
            timestamp,
        };
        
        hdk::create_entry(&blog_post)
    }
    
    // 获取博客文章
    #[zome_fn("hc_public")]
    fn get_blog_post(header_hash: HeaderHash) -> ExternResult<Option<BlogPost>> {
        let element = hdk::get(header_hash, GetOptions::default())?;
        match element {
            Some(element) => {
                let blog_post: BlogPost = element.entry()
                    .to_app_option()?
                    .ok_or(WasmError::Guest("Could not deserialize element to BlogPost".into()))?;
                Ok(Some(blog_post))
            }
            None => Ok(None),
        }
    }
    
    // 添加评论
    #[zome_fn("hc_public")]
    fn add_comment(post_hash: HeaderHash, content: String) -> ExternResult<HeaderHash> {
        let author = hdk::agent_info()?.agent_latest_pubkey;
        let timestamp = sys_time()?.as_seconds();
        
        let comment = Comment {
            post_hash,
            content,
            author,
            timestamp,
        };
        
        hdk::create_entry(&comment)
    }
    
    // 获取文章的所有评论
    #[zome_fn("hc_public")]
    fn get_comments_for_post(post_hash: HeaderHash) -> ExternResult<Vec<Comment>> {
        let query = QueryFilter::new()
            .entry_type(EntryTypes::Comment(Comment::entry_def_id()?))
            .include_entries(true);
            
        let elements = hdk::query(query)?;
        
        let mut comments = Vec::new();
        for element in elements {
            if let Some(entry) = element.entry().to_app_option::<Comment>()? {
                if entry.post_hash == post_hash {
                    comments.push(entry);
                }
            }
        }
        
        Ok(comments)
    }
    
    // 辅助函数:获取系统时间
    fn sys_time() -> ExternResult<Timestamp> {
        Ok(hdk::sys_time()?)
    }
}

注意事项

  1. 使用hdk_derive时,确保你的项目是针对WASM目标编译的
  2. 派生宏生成的代码会处理大部分Holochain特定的样板代码,但开发者仍需理解基本的Holochain概念
  3. 在定义入口类型时,required_validations参数可以控制该条目需要多少验证才能被网络接受
  4. hc_public属性标记的函数可以被其他zome或前端调用

hdk_derive极大地简化了Holochain应用开发流程,让开发者能够更专注于业务逻辑而非底层细节。

回到顶部