Basic test hApp (Holochain application) in Rust (using the Holochain Development Kit)

Basic test hApp (Holochain application) in Rust (using the Holochain Development Kit)

By rhyzom | rhyzom | 28 Apr 2020


We've covered much of the background previously, now for an example of how hApps are written.

Holochain apps (hApps) consist of DNA where the logic, validation rules and behavior are defined. DNAs build from zomes which are the functional building blocks. As hApp DNA needs to be written in something that compiles to WebAssembly, Rust has been decided upon as the underlying language in which things are to be written.

Holochain's vision is one of many small, composable and interconnected apps (e.g., zomes and/or bridges). Your hApps tells you what components of your other used hApps they need to access and you grant or deny them (access control) permissions. This is just how for example some web services and apps ask you for access permissions to your Twitter, Facebook or Google accounts. And also how Solid data pods works as well.

The main components of the Rust HDK are the holochain-specific macros, structs (which are more complex data types additionally defined) and the APIs.

Once you create your hApp layout (the basic structure of directories and files) with the scaffolding tool (the "hc-happ-create" command) — which should look something like this:

5b322b0f7900287ffdbd0d3b8d11a39f1ed98fb7f4efa7cd03e4fb61f2c0503a.png

Open your zome's lib.rs. First at the top there are the crate imports — the libraries needed for you to be able to use the HDK and avoid writing a lot of boilerplate code by using the holochain-specific macros:

#![feature(proc_macro_hygiene)]
-#[macro_use]
extern crate hdk;
extern crate hdk_proc_macros;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
-#[macro_use]
extern crate holochain_json_derive;

Then after that are the use statements which specify exactly what is needed from the each crate for our purposes at hand:

use hdk::{
-    entry_definition::ValidatingEntryType,
    error::ZomeApiResult,
};
-use hdk::holochain_core_types::{-    entry::Entry,-    dna::entry_types::Sharing,-};--use hdk::holochain_json_api::{-    json::JsonString,-    error::JsonError-};--use hdk::holochain_persistence_api::{-    cas::content::Address-};

use hdk_proc_macros::zome;

The my_zome module (declared with mod) is where all your zome code is contained. #[zome] is a procedural macro that says that the module in question defines all the things that holochain should know about this zome (saving you writing a lot of code). Change it (my_zome) to test_zome:

#[zome]
- mod my_zome {
+ mod test_zome {

The init function is triggered when a user/agent initializes/calls the app for the first time — every zome defines this function for the purpose of running some basic setup and framing some initial ground parameters (though in the example of our zome right now it doesn’t really do anything):

#[init]    
fn init() {
       Ok(())
}

Return success ("Ok")the empty value () (which in Rust is called the unit type and is similar — though not identical — to a void type in other languages). Besides init, this function is also executed on startup — checking that the user/agent is allowed to join the network of that given application (in this instance as written below, it gives everyone a free pass):

#[validate_agent] 
pub fn validate_agent(validation_data: EntryValidationData) { 
    Ok(()) 
}

The new function that we're defining goes below (next to) the one above (validate_agent). The hc_public procedural macro will turn the function directly below it into a public function that GUIs and other zomes and DNAs can call.

#[zome_fn("hc_public")]

And now our test function, taking no arguments and returning a holochain result type (in this case, if ok, a string). Write the function like that:

pub fn test_function() -> ZomeApiResult
    Ok("Testing".into())
}

The pub prefix makes the function public and callable. It returns an Ok result and .into() in Rust turns it into a string.

Now compile the zome (using hc package). 

To interact with the hApp you can run it in HTTP mode and use curl (a command-line tool for making HTTP requests that's included in the holochain environment) to send a POST message:

$ curl -X POST -H "Content-Type: application/json" -d '{"id": "0", "jsonrpc": "2.0", "method": "call", "params": {"instance_id": "test-instance", "zome": "test", "function": "test_function", "args": {} }}' http://127.0.0.1:8888

To which you should receive back a response from the test function in the form of a JSON-RPC string that looks like this:

{"jsonrpc":"2.0","result":"{\"Ok\":\"Testing\"}","id":"0"}

This is as rudimentary as it gets, of course. And one does need some basic Rust to code anything more complex. (This blog post, "A half hour to learn Rust", is pretty handy — it goes through many Rust code snippets, explaining what the keywords and symbols they contain mean.) 

Holochain also makes use of links extensively which is basically a relationship between two entries (e.g., a post and the user/agent ID associated with it, or anything else imaginable) — and is in principle also similar to Solid's linked data

How do you rate this article?


38

1

rhyzom
rhyzom

Verum ipsum factum. Chaotic neutral.


rhyzom
rhyzom

Ad hoc heuristics for approaching complex systems and the "unknown unknowns". Techne & episteme. Verum ipsum factum. In the words of Archimedes: "Give me a lever and a place to rest it... or I shall kill a hostage every hour." Rants, share-worthy pieces and occasional insights and revelations.

Send a $0.01 microtip in crypto to the author, and earn yourself as you read!

20% to author / 80% to me.
We pay the tips from our rewards pool.