EntryHash vs EntryHashB64 in hashes exercise

Hello,

I’m working through the gym, thank you for the work that has been put into this. On exercise 2 there is a small mismatch between the code listing at https://holochain-gym.github.io/developers/basic/hashes/#exercise and the code in the repo at https://github.com/holochain-gym/developer-exercises/blob/master/basic/1.hashes/zomes/exercise/src/lib.rs

The web version has EntryHash, the code has EntryHashB64. Is this intentional? It looks like the code can be made to work either way. If the target audience is people new to Rust and new to Holochain, there is a little bit less Rust syntax for the first one, so that might be preferable.

Thanks again for all the resources. I’m still learning to navigate these forums so let me know if this is in the wrong place.

2 Likes

I was literally typing up a new thread draft on this topic last night but didn’t finish. I also ran into this exact issue, but once I solved it I was more curious about the following:

What are all the different hash types? (and) What is the purpose of each?

For example, I see HoloHash, EntryHash, HeaderHash, some are base 64… the documentation says a lot, but it can be hard to follow at times. I’d be curious to see a simple overview of all the different hash types that exist, what they do, how they are related, how they are different, and when to use each one.

1 Like

Those are good questions, did you get anywhere with them? From what I can tell, it’s complicated. I did some looking and came up with this.

HoloHash is the library used to create the various types of hashes. An EntryHash is the hash of the data itself. A HeaderHash points to a particular piece of metadata. The metadata contains information related to a particular entry.

I think the use case might be related to what you’re doing. If you have a hash for a book title and you just want the actual title, you can look up the book title by the hash. If you are in the context of an application, and you want to know if a user has a book in their book list, you’d use the header hash to construct which actions a user has performed on various books.

I was guessing the various encodings might be for different consumer applications, or that a more efficient encoding was discovered and the docs had the old method but the code had the newer method. That’s a total guess, though.

I have no idea if you’ve read the docs; I’ll drop the link in case you haven’t… They’re so informative that after reading them, there will remain not a pinch of doubt in your mind regarding the purpose that those hashes serve…

https://docs.rs/hdk/0.0.100/hdk/entry/index.html

Moreover, hashes can be embedded within an entry too; makes for a great design pattern, especially for some special use-cases. Kinda like an alternative to entry-linking…

https://docs.rs/hdk/0.0.100/hdk/link/index.html

https://docs.rs/hdk/0.0.100/hdk/link/fn.create_link.html


1 Like

So this isn’t quite clear to me, and is hopefully what I could get clarification on.

let data = Book()

EntryHash: hash(data)? now if i have data i can derive EntryHash? what can I do with EntryHash? is this the address on the DHT?

HeaderHash: create(data)? I can use this to get CRUD operations? where does this header hash get stored? do I get this HeaderHash back as part of a get(entryHash) call?

And then yeah, again, not totally sure when and why you’d used the B64 versions. And yeah I’ve read through the docs, not fully drawing the picture for me.

On the way to trying to answer this question of EntryHash vs HeaderHash I took some notes. Looking at the source code definitions for Element, Entry, Header and their helpers and cross referencing with the docs was more helpful than either alone. I was hoping to be able to get to the bottom of this in a way that would he helpful for others in the future but it is starting to feel like you have to “understand everything” as a prerequisite to understanding everything. Still, I’ll share my notes in case they are useful.

For each type below, “Definition” is copy/pasted from the Glossary. “Code” is copy/pasted from the hdk doc’s links to the source code, then trimmed according to my whims.

If I hadn’t read https://doc.rust-lang.org/book/ch06-01-defining-an-enum.html the struct definitions would not have been helpful to me.

Types Relevant to EntryHash/HeaderHash

Element

Definition

The data structure that holds an action in an agent’s source chain. Some elements are a combination of header and entry, such as new-entry actions while others contain all their data inside the header.

Sources
pub struct Element {
    signed_header: SignedHeaderHashed,
    entry: ElementEntry,
}

pub struct SignedHeaderHashed {
    header: HeaderHashed,
    signature: Signature,
}

pub struct SignedHeader(pub Header, pub Signature);

pub enum ElementEntry {
    Present(Entry),
    /// The Header has an entry_address reference, but we are in a public
    /// context and the entry is private.
    Hidden,
    /// The Header does not contain an entry_address reference.
    NotApplicable,
    /// The Header has an entry but was stored without it.
    /// This can happen when you receive gossip of just a header
    /// when the header type is a [NewEntryHeader]
    NotStored,
}

Header

Definition

A piece of data that represents an element on an agent‘s source chain. Headers link to the hash of their previous header, which creates a tamper-evident journal or ledger of all their actions in an application.

Code

pub enum Header {
    Dna(Dna),
    AgentValidationPkg(AgentValidationPkg),
    InitZomesComplete(InitZomesComplete),
    CreateLink(CreateLink),
    DeleteLink(DeleteLink),
    OpenChain(OpenChain),
    CloseChain(CloseChain),
    Create(Create),
    Update(Update),
    Delete(Delete),
}

Relevant Header Types

Create or “Create-entry action”
Definition

A new-entry action that, when published to the DHT, causes an entry to be available to other DHT members (unless the entry is private), in which case only a record of its creation is published).

Code
pub struct Create {
    pub author: AgentPubKey,
    pub timestamp: Timestamp,
    pub header_seq: u32,
    pub prev_header: HeaderHash,

    pub entry_type: EntryType,
    pub entry_hash: EntryHash,
}

pub enum EntryType {
    AgentPubKey,
    App(AppEntryType),
    CapClaim,
    CapGrant,
}

pub type EntryHash = HoloHash<hash_type::Entry>;

Entry

Definition

A basic unit of user data in a Holochain app. Each entry has its own defined entry type. When an agent commits an entry, it is combined with a header into an element that expresses a new-entry action. Then it is written to their source chain as a record of the action having taken place. An entry can be public or private; if it’s public, it’s also published to the DHT. There are app entries whose purpose and structure are defined by the DNA developer, and there are special system entries such as an agent ID entry.

Code

pub enum Entry {
    Agent(AgentPubKey),
    App(AppEntryBytes),
    CapClaim(CapClaimEntry),
    CapGrant(CapGrantEntry),
}

Functions Relevant to HeaderHash/EntryHash

hdk::entry::create_entry

create_entry takes your application defined data, inserts it into the log, then returns a HeaderHash. The HeaderHash points to your specific Create Element, whose EntryHash points to the hash of your application data.

hdk::entry::get

entry::get takes a HeaderHash or EntryHash and returns an Element.
entry::get<HeaderHash>() returns the Element for the Header.
entry::get<EntryHash>() returns the oldest live Header+Entry

Oldest live

I’m still working to understand this part.

“oldest live” only relates to disambiguating many creates and updates
from many authors pointing to a single entry, it is not the “current value”
of an entry in a CRUD sense.

If “foo” is created then updated to “bar”, a get on the Entry hash of
“foo” will return “foo” as part of an element with the “oldest live” header.

To discover “bar” the agent needs to call get_details and decide how
it wants to collapse many potential creates, updates and deletes
down into a single or filtered set of updates, to “walk the tree”.

hdk::entry::get_details

I have a notion based on other technologies that somewhere in your app there is going to be a state machine processing a series of elements to produce the current state of your application data, and that this call is related. I could also imagine that some applications would not have not need to do this. Is this notion accurate, should I keep digging for this answer or just move through the exercises until it becomes clear? Maybe it should be clear from “walking the tree”.

Update to my previous answer

An EntryHash is the hash of an Entry. A HeaderHash is the hash of Header. An Entry, among other things, is the actual serialized application data. Metadata in Holochain lingo has a definition that is different from what I meant, but I think I see why The-A-Man added the documentation for create_link.

Summary

“It’s down there somewhere, let me take another look.” - The Dude

1 Like

Hi @nhardt and @jakintosh, thanks so much for this feedback, this is really valuable. We are in the middle of major upgrades in the gym, so bear a bit with it this week :slight_smile:

So, to answer the question about normal hashes vs B64 ones: they are basically the same, expect that when they return they value to the UI, the normal ones are a binary array, and the B64 ones are returned with a string that contains the hash encoded as base64. I use the B64 in all my code to have an easier time on the UI side, but in the gym that’s not necessary. It is in our todo list to remove those, and make a note for it somewhere.

About the different uses of hashes, I would encourage you very much to go to the second exercise that’s now available: Getting elements. There you can see what you can do with hashes and the difference of usage between HeaderHash and EntryHash.

@jakintosh in general yes, if you have any piece of data you can hash it, but not the reverse. I would encourage you to go throught the hashes exercise, and report back the things that should be there and are not :slight_smile:

Thanks a lot for trying out the gym, it’s always great to have feedback. If in the future you want to contribute some exercise, that would be awesome as well :slight_smile:

3 Likes