Rust Holochain数据完整性库HDI的使用,实现分布式应用数据验证与存储

下面是关于Rust Holochain数据完整性库HDI的使用以及实现分布式应用数据验证与存储的完整内容:

Rust Holochain数据完整性库HDI的使用

Holochain Deterministic Integrity (HDI) 是Holochain用于编写zomes的数据模型和完整性工具集。一个Holochain DNA的逻辑可以分为两部分:完整性和协调性。

数据定义

完整性部分定义了数据类型并验证数据操作。DNA的数据模型在完整性zomes中定义,包含:

  • 条目类型定义
  • 链接类型定义
  • 验证回调函数

示例代码展示了如何使用FlatOp进行数据验证:

match op.flattened()? {
    FlatOp::StoreEntry(OpEntry::CreateEntry { app_entry, .. }) => match app_entry {
        EntryTypes::A(_) => Ok(ValidateCallbackResult::Valid),
        EntryTypes::B(_) => Ok(ValidateCallbackResult::Invalid(
            "No Bs allowed in this app".to_string(),
        )),
    },
    FlatOp::RegisterCreateLink {
        base_address: _,
        target_address: _,
        tag: _,
        link_type,
        action: _,
    } => match link_type {
        LinkTypes::A => Ok(ValidateCallbackResult::Valid),
        LinkTypes::B => Ok(ValidateCallbackResult::Invalid(
            "No Bs allowed in this app".to_string(),
        )),
    },
    _ => Ok(ValidateCallbackResult::Valid),
};

完整示例Demo

下面是一个完整的HDI使用示例,展示如何定义条目类型和实现数据验证:

// 导入必要的HDI模块
use hdi::prelude::*;

// 定义条目类型
#[hdk_entry_types]
#[unit_enum(UnitEntryTypes)]
pub enum EntryTypes {
    #[entry_type(required_validations = 5)]
    Post(Post),
    #[entry_type(required_validations = 5)]
    Comment(Comment),
}

// 定义链接类型
#[hdk_link_types]
pub enum LinkTypes {
    PostToComments,
    AuthorToPosts,
}

// 定义Post结构体
#[derive(Serialize, Deserialize, SerializedBytes, Debug)]
pub struct Post {
    pub title: String,
    pub content: String,
    pub author: AgentPubKey,
}

// 定义Comment结构体
#[derive(Serialize, Deserialize, SerializedBytes, Debug)]
pub struct Comment {
    pub content: String,
    pub author: AgentPubKey,
    pub post_hash: HeaderHash,
}

// 实现验证回调
#[hdk_extern]
pub fn validate(op: Op) -> ExternResult<ValidateCallbackResult> {
    match op.flattened()? {
        FlatOp::StoreEntry(OpEntry::CreateEntry { app_entry, .. }) => match app_entry {
            EntryTypes::Post(post) => validate_post(post),
            EntryTypes::Comment(comment) => validate_comment(comment),
        },
        FlatOp::RegisterCreateLink {
            base_address,
            target_address,
            tag,
            link_type,
            action: _,
        } => match link_type {
            LinkTypes::PostToComments => validate_post_to_comments_link(base_address, target_address, tag),
            LinkTypes::AuthorToPosts => validate_author_to_posts_link(base_address, target_address, tag),
        },
        _ => Ok(ValidateCallbackResult::Valid),
    }
}

// 验证Post条目
fn validate_post(post: Post) -> ExternResult<ValidateCallbackResult> {
    if post.title.is_empty() {
        return Ok(ValidateCallbackResult::Invalid("Post title cannot be empty".to_string()));
    }
    if post.content.is_empty() {
        return Ok(ValidateCallbackResult::Invalid("Post content cannot be empty".to_string()));
    }
    Ok(ValidateCallbackResult::Valid)
}

// 验证Comment条目
fn validate_comment(comment: Comment) -> ExternResult<ValidateCallbackResult> {
    if comment.content.is_empty() {
        return Ok(ValidateCallbackResult::Invalid("Comment content cannot be empty".to_string()));
    }
    Ok(ValidateCallbackResult::Valid)
}

// 验证Post到Comments的链接
fn validate_post_to_comments_link(
    base_address: AnyLinkableHash,
    target_address: AnyLinkableHash,
    _tag: LinkTag,
) -> ExternResult<ValidateCallbackResult> {
    // 在这里可以添加验证逻辑,确保只有有效的Post和Comment之间才能创建链接
    Ok(ValidateCallbackResult::Valid)
}

// 验证Author到Posts的链接
fn validate_author_to_posts_link(
    base_address: AnyLinkableHash,
    target_address: AnyLinkableHash,
    _tag: LinkTag,
) -> ExternResult<ValidateCallbackResult> {
    // 在这里可以添加验证逻辑,确保只有作者才能创建到自己帖子的链接
    Ok(ValidateCallbackResult::Valid)
}

数据验证

HDI的第二个核心部分是数据验证。为每个操作都可以指定验证规则,包括数据类型和值的验证。这些验证规则都在validate回调中声明,当有新操作时,每个验证权威都会执行这个回调。

HDI提供了FlatOp辅助类型,可以更轻松地访问所有链接和条目变体进行验证操作。


1 回复

Rust Holochain数据完整性库HDI的使用指南

HDI简介

HDI (Holochain Deterministic Integrity) 是Holochain生态系统中用于确保数据完整性的核心库,专为分布式应用设计。它提供了一套工具和模式,使开发者能够在完全去中心化的环境中实现数据验证、存储和检索,同时保证数据的确定性和一致性。

主要功能

  1. 数据验证:确保所有写入的数据符合预定义规则
  2. 确定性操作:保证所有节点对相同输入产生相同输出
  3. 分布式存储:支持数据在P2P网络中的分布式存储
  4. 模式定义:提供结构化数据定义方式

完整示例代码

下面是一个完整的HDI应用示例,展示了如何创建博客系统:

use hdi::prelude::*;

// 1. 定义博客文章结构
#[hdk_entry_helper]
struct BlogPost {
    title: String,
    content: String,
    author: AgentPubKey,
    timestamp: u64,
    category: Option<String>,
}

// 2. 定义链接类型
#[hdk_link_types]
enum LinkTypes {
    BlogPostToAuthor,
    AuthorToBlogPosts,
    BlogPostsInCategory,
}

// 3. 实现数据验证
#[hdk_extern]
fn validate(op: Op) -> ExternResult<ValidateCallbackResult> {
    match op {
        Op::StoreEntry { entry } => {
            if let Entry::App(app_entry) = entry {
                // 验证博客文章
                if let Ok(blog_post) = BlogPost::try_from(app_entry) {
                    if blog_post.content.is_empty() {
                        return Ok(ValidateCallbackResult::Invalid(
                            "内容不能为空".to_string(),
                        ));
                    }
                    if blog_post.title.is_empty() {
                        return Ok(ValidateCallbackResult::Invalid(
                            "标题不能为空".to_string(),
                        ));
                    }
                }
            }
            Ok(ValidateCallbackResult::Valid)
        }
        Op::UpdateEntry {
            original_action,
            app_entry,
            ..
        } => {
            if let Entry::App(app_entry) = app_entry {
                if let Ok(blog_post) = BlogPost::try_from(app_entry) {
                    // 获取原始记录
                    let original_record = get(original_action, GetOptions::default())?;
                    if let Some(original_record) = original_record {
                        let original_blog_post = BlogPost::try_from(original_record.entry())?;
                        // 只允许原作者更新
                        if blog_post.author != original_blog_post.author {
                            return Ok(ValidateCallbackResult::Invalid(
                                "只有原作者可以更新文章".to_string(),
                            ));
                        }
                    }
                }
            }
            Ok(ValidateCallbackResult::Valid)
        }
        _ => Ok(ValidateCallbackResult::Valid),
    }
}

// 4. 创建博客文章
#[hdk_extern]
fn create_post(input: BlogPost) -> ExternResult<ActionHash> {
    // 创建文章
    let action_hash = create_entry(&input)?;
    
    // 链接到作者
    create_link(
        input.author.clone(),
        action_hash.clone(),
        LinkTypes::AuthorToBlogPosts,
        (),
    )?;
    
    create_link(
        action_hash.clone(),
        input.author,
        LinkTypes::BlogPostToAuthor,
        (),
    )?;
    
    // 如果有分类,链接到分类
    if let Some(category) = input.category {
        let path = Path::from(format!("category.{}", category));
        path.ensure()?;
        create_link(
            path.path_entry_hash()?,
            action_hash.clone(),
            LinkTypes::BlogPostsInCategory,
            (),
        )?;
    }
    
    Ok(action_hash)
}

// 5. 获取文章
#[hdk_extern]
fn get_post(action_hash: ActionHash) -> ExternResult<Option<BlogPost>> {
    let record = get(action_hash, GetOptions::default())?;
    match record {
        Some(record) => BlogPost::try_from(record.entry()),
        None => Ok(None),
    }
}

// 6. 获取作者的所有文章
#[hdk_extern]
fn get_posts_by_author(author: AgentPubKey) -> ExternResult<Vec<BlogPost>> {
    let links = get_links(author, LinkTypes::AuthorToBlogPosts, None)?;
    let mut posts = Vec::new();
    
    for link in links {
        if let Some(record) = get(link.target, GetOptions::default())? {
            if let Ok(post) = BlogPost::try_from(record.entry()) {
                posts.push(post);
            }
        }
    }
    
    Ok(posts)
}

// 7. 获取分类下的所有文章
#[hdk_extern]
fn get_posts_by_category(category: String) -> ExternResult<Vec<BlogPost>> {
    let path = Path::from(format!("category.{}", category));
    let links = get_links(path.path_entry_hash()?, LinkTypes::BlogPostsInCategory, None)?;
    let mut posts = Vec::new();
    
    for link in links {
        if let Some(record) = get(link.target, GetOptions::default())? {
            if let Ok(post) = BlogPost::try_from(record.entry()) {
                posts.push(post);
            }
        }
    }
    
    Ok(posts)
}

// 8. 更新文章
#[hdk_extern]
fn update_post(input: (ActionHash, BlogPost)) -> ExternResult<ActionHash> {
    let (original_hash, new_post) = input;
    update_entry(original_hash, &new_post)
}

// 9. 删除文章
#[hdk_extern]
fn delete_post(action_hash: ActionHash) -> ExternResult<()> {
    delete_entry(action_hash)
}

最佳实践

  1. 保持验证逻辑确定性:所有验证规则必须产生确定性的结果
  2. 最小化存储数据:只存储必要数据,因为每个节点都会存储完整副本
  3. 合理使用链接:利用链接关系组织数据,而非集中式索引
  4. 考虑数据隐私:敏感数据应在应用层加密

这个完整示例展示了如何使用HDI构建一个功能完整的去中心化博客系统,包括创建、读取、更新和删除文章,以及通过作者和分类组织文章。

回到顶部