use hdk::prelude::*;
#[hdk_extern] // - Comes from hdk::prelude::*
// - Exposes a function to be callable from the outside
fn zome_function_hello(name: String) -> ExternResult<String> { // - Zome function name
// must be unique in this zome
// - Zome functions can only
// accept one parameter
Ok(format!("hello {}!", name)) // Must return an "ExternResult" of a typing that implements
// "Serialize", "Deserialize" and "Debug"
}
#[hdk_extern]
fn zome_function_hello_world(_: ()) -> ExternResult<String> { // To indicate disregard
// for input parameter, we use
// the unit typing "()"
Ok(format!("hello world!"))
}
use hdk::prelude::*;
// We can define custom input parameter structs
#[derive(Serialize, Deserialize, Debug)] // Input parameters must derive
// "Serialize", "Deserialize" and "Debug"
struct CustomInputStruct {
name: String
}
#[hdk_extern]
fn zome_function_with_custom_input(input: CustomInputStruct) -> ExternResult<String> { // Ok
Ok(format!("hello {}!", input.name))
}
struct BrokenInputStruct { // This input struct won't work,
// because it doesn't derive the right traits
name: String
}
#[hdk_extern]
fn zome_function_with_broken_custom_input(
input: BrokenInputStruct // Error: Input parameters must derive
// "Serialize", "Deserialize" and "Debug"
) -> ExternResult<String> {
Ok(format!("hello {}!", input.name))
}
use hdk::prelude::*;
#[hdk_extern]
fn returning_errors(_: ()) -> ExternResult<()> {
Err(wasm_error!( // "wasm_error!" Captures debugging information (eg. line numbers)
WasmErrorInner::Guest(String::from("This function returns an error"))
))
}
#[hdk_extern]
fn debugging(_: ()) -> ExternResult<()> {
error!("This is an error log that functions just like println");
warn!("This is a warn log that functions just like println");
Ok(())
}
use hdk::prelude::*;
#[hdk_extern]
fn get_my_pub_key(_: ()) -> ExternResult<AgentPubKey> { // "AgentPubKey" acts as the "agent ID"
let my_agent_info = agent_info()?; // Will return a different value depending on
// which cell is executing the function
let my_pub_key: AgentPubKey = my_agent_info.agent_initial_pubkey; // In the future the
// public key of a cell
// may change
Ok(my_pub_key)
}
#[hdk_extern]
fn get_zome_name(_: ()) -> ExternResult<ZomeName> { // "ZomeName" is a simple Tuple(Struct)
// wrapping a String
let my_zome_info = zome_info()?; // Will return a different value depending on
// which zome this function is defined within,
// but will return the same for all agents
let zome_name: ZomeName = my_zome_info.name; // Human readable name,
// defined in the DNA manifest
let zome_id: ZomeId = my_zome_info.id; // Zome index (integer) in the DNA that Holochain
// uses to identify the zome
Ok(zome_name)
}
use hdk::prelude::*;
#[hdk_extern]
fn get_dna_hash(_: ()) -> ExternResult<DnaHash> {
let my_dna_info = dna_info()?; // Will return the same value for all agents
// and zomes in the same DNA
let dna_name: String = my_dna_info.name; // Human readable name, defined in the DNA manifest
let dna_hash: DnaHash = my_dna_info.hash; // Hash of source code, network seed and properties
let dna_properties = my_dna_info.properties; // Properties: configuration that the
// DNA can read to modify it's behaviour
let pubkey = AgentPubKey::try_from(dna_properties)?; // 'dna_properties' is of type
// 'SerializedBytes', so it can
// serialize to any rust typing
// that derives 'Serialize' and
// 'Deserialize'
Ok(dna_hash)
}
// zomes/integrity/lib.rs
use hdi::prelude::*;
#[hdk_entry_helper] // Adds necessary trait implementations
struct Comment {
comment: String
}
#[hdk_entry_helper]
struct Post {
title: String,
content: String
}
#[hdk_entry_defs] // - Defines all the entries for this zome
// - Must be the only "#[hdk_entry_defs]" in the zome
// - Can only be defined in integrity zomes
#[unit_enum(UnitEntryTypes)] // Defines a "UnitEntryTypes" enum that's a copy of "EntryTypes"
// but with the converted variants to unit variants (no payload)
enum EntryTypes { // Enum with each entry type as a variant
#[entry_def( // Configures entry behaviour
name = "comment", // Must be unique across entry types
visibility = "private" // Entry not published to the DHT, only stored in the source chain
)]
Comment(Comment),
// Can be omitted, defaults to the struct name in snake_case and "public"
Post(Post),
}
// zomes/coordinator/lib.rs
use hdk::prelude::*;
use integrity_zome::{EntryTypes, Comment}; // Import the types defined in our integrity zome
#[hdk_extern]
fn create_comment(comment: Comment) -> ExternResult<()> {
create_entry(EntryTypes::Comment(comment))?; // - "create_entry" comes from hdk::prelude::*;
// - Input must be an instance of the
// entry types enumerable
Ok(())
}
#[hdk_extern]
fn create_comment_and_return_action_hash(comment: Comment) -> ExternResult<ActionHash> {
let action_hash = create_entry(EntryTypes::Comment(comment))?; // create_entry() returns
// the hash of the action
// that has just been inserted
// into the agent's
// source chain
Ok(action_hash)
}
// zomes/coordinator/lib.rs
use hdk::prelude::*;
use integrity_zome::{EntryTypes, Comment}; // Import the types defined in our integrity zome
#[derive(Serialize, Deserialize, Debug)]
struct UpdateCommentInput {
original_action_hash: ActionHash,
new_comment: Comment
}
#[hdk_extern]
fn update_comment(input: UpdateCommentInput) -> ExternResult<ActionHash> {
let action_hash = update_entry(
input.original_action_hash, // The original action must be a create or an update action
EntryTypes::Comment(input.new_comment) // New entry must be of the same entrytype
)?;
Ok(action_hash)
}
// zomes/coordinator/lib.rs
use hdk::prelude::*;
use integrity_zome::{EntryTypes, Comment}; // Import the types defined in our integrity zome
#[hdk_extern]
fn delete_comment(comment_action_hash: ActionHash) -> ExternResult<()> {
let action_hash = delete_entry(comment_action_hash)?; // - Deleting an entry is also its
// own action
// - Deleted action hash must be
// a create or an update action
Ok(())
}
// zomes/coordinator/lib.rs
use hdk::prelude::*;
use integrity_zome::{EntryTypes, Comment}; // Import the types defined in our integrity zome
#[hdk_extern]
fn get_comment(comment_action_hash: ActionHash) -> ExternResult<Option<Record>> {
let comment_record: Option<Record> = get(
comment_action_hash, // Accepts an "ActionHash" or an "EntryHash"
GetOptions::default() // Cache control, by default returns cached records
)?;
/* In case you need to extract the entry struct from the record */
let maybe_entry: Option<Entry> = record
.entry
.into_option();
let entry: Entry = maybe_entry.ok_or(wasm_error!(
WasmErrorInner::Guest(String::from("This record doesn't include any entry"))
))?;
let _comment = Comment::try_from(entry)?;
Ok(comment_record)
}
// zomes/coordinator/lib.rs
use hdk::prelude::*;
use integrity_zome::{EntryTypes, Comment}; // Import the types defined in our integrity zome
#[hdk_extern]
fn get_comment_action_details(comment_action_hash: ActionHash) -> ExternResult<Record> {
let record_details: Option<Details> = get_details(
comment_action_hash, // Accepts an "ActionHash" or an "EntryHash"
GetOptions::default() // Same options as "get()"
)?;
match record_details {
Some(Details::Record(RecordDetails { record, deletes, updates, .. })) => Ok(record),
_ => Err(wasm_error!(
WasmErrorInner::Guest(String::from("Error trying to get the details of this action"))
))
}
}
// zomes/coordinator/lib.rs
use hdk::prelude::*;
use integrity_zome::{EntryTypes, Comment}; // Import the types defined in our integrity zome
#[hdk_extern]
fn get_comment_entry_details(comment_entry_hash: EntryHash) -> ExternResult<Entry> {
let entry_details: Option<Details> = get_details(
comment_entry_hash, // Entry Hash
GetOptions::default()
)?;
match entry_details {
Some(Details::Entry(EntryDetails { entry, actions, deletes, updates, .. })) => Ok(entry),
_ => Err(wasm_error!(
WasmErrorInner::Guest(String::from("Error trying to get the details of this action"))
))
}
}
// zomes/integrity/lib.rs
use hdi::prelude::*;
// Defining link types
#[hdk_link_types] // - Defines all the link types for this zome
// - Must be the only "#[hdk_link_types]" in the zome
// - Can only be defined in integrity zomes
enum LinkTypes { // Enum with each entry type as a variant
AuthorToComment, // Must be a Unit variant (without any payload)
}
// zomes/coordinator/lib.rs
use hdk::prelude::*;
use integrity_zome::{LinkTypes, EntryTypes, Comment}; // Import the types defined
// in our integrity zome
#[hdk_extern]
fn create_comment(comment: Comment) -> ExternResult<ActionHash> {
let comment_action_hash = create_entry(EntryTypes::Comment(comment))?; // Create comment
let my_pub_key: AgentPubKey = agent_info()?.agent_initial_pubkey; // The author of the
// comment is the agent
// executing this
// function call
let create_link_action_hash: ActionHash = create_link( // Creating a link is
// an action in itself
my_pub_key, // Base hash: my agent pub key
comment_action_hash, // Target hash: the action hash that has just been created
LinkTypes::AuthorToComment, // LinkType: one of the variants defined in the integrity zome
() // Link tag, can be any struct that derives 'Serialized' and 'Deserialized'
)?;
Ok(comment_action_hash)
}
// zomes/coordinator/lib.rs
use hdk::prelude::*;
use integrity_zome::*; // Import the types defined in our integrity zome
#[hdk_extern]
fn get_all_comments_by_agent(author: AgentPubKey) -> ExternResult<Vec<Record>> {
let links: Vec<Link> = get_links(
author, // Base hash: the given agent pub key
LinkTypes::AuthorToComment, // LinkType: one of the variants defined in the integrity zome
None, // "Option<LinkTag>": filter result set down to only those links
// with a matching prefix on their link tag
)?;
let mut comments: Vec<Record> = vec![];
for link in links {
if let Some(record) = get(
ActionHash::from(link.target), // - Conversion is important to specify the
// type of hash we are retrieving for
// - Will be the action hash for each of the
// comments that the agent has created
GetOptions::default()
)? {
comments.push(record);
}
}
Ok(comments)
}