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生态系统中用于确保数据完整性的核心库,专为分布式应用设计。它提供了一套工具和模式,使开发者能够在完全去中心化的环境中实现数据验证、存储和检索,同时保证数据的确定性和一致性。
主要功能
- 数据验证:确保所有写入的数据符合预定义规则
- 确定性操作:保证所有节点对相同输入产生相同输出
- 分布式存储:支持数据在P2P网络中的分布式存储
- 模式定义:提供结构化数据定义方式
完整示例代码
下面是一个完整的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)
}
最佳实践
- 保持验证逻辑确定性:所有验证规则必须产生确定性的结果
- 最小化存储数据:只存储必要数据,因为每个节点都会存储完整副本
- 合理使用链接:利用链接关系组织数据,而非集中式索引
- 考虑数据隐私:敏感数据应在应用层加密
这个完整示例展示了如何使用HDI构建一个功能完整的去中心化博客系统,包括创建、读取、更新和删除文章,以及通过作者和分类组织文章。