# Holochain Fluidity DSL hdk_extern - represnting public/zome_functions Get rid of the rust macros - annotations, remove anuthing not directly related to programmer intention ## Major Pain Points Validation functions:: Pulling info out of Op requires a huge matching arm... - OpType helps flatten it (crate/hdi readme) to_type Same code in front-end: be able to get info shapes into front-end Unit entry type: to refer to the data without knowing about the data structure itself specify entry type along with the entry - coupling to entry type with schema, enforced at entry level. could've had entry_type enum, but you have to use the right entry type with the data astructure - this could be limited in the dsl: limit the possible types that can associate with an entry type - overloaded functions in rust would allow us to not use a EntryType enum. - Why would you be able to name your EntryTypes UnitEntryTypes enum? never need multiple, it's just a single thing that has all possible - DSL needs Constructor Overloading - can't create an instance of EntryTypes::Nonce without creating a Nonce.. - We have this so we can refer to the type without having already built an object with all needed data.. ## Host/Guest Boundary WASM stuff to take into account: host/guest, how wasm calls into the host, what is assumed to exist. How to call out of WASM context , how it's serialized, how to communicate across host/guest boundary. How to make those calls? Look into FFI for accessing types/libraries in other languages. Can we use HDK functions directly? ### HOW: Language design: Compiling, Interpreting - Transpile to Rust, then compile to Wasm - Compile directly to Wasm, call Rust functions - Interpret scripting language - Existing language like assemblyscript - Clang (actually [LLVM](https://www.llvm.org/docs/tutorial/MyFirstLanguageFrontend/index.html) -JB), AST - Possibility: Parse, build up an AST, spit it out into a Rust Template - Racket: Language for generating DSLs ### What is not done well? - apps reason about what it's hard to reason about - Rust has trouble listening and responding to events(?) - Callback: run this arbitrary closure when this thing happens - re-entrancy hard, since wasm instance is killed when it stops running - Better error handling! - Conversions into inner macros, etc # Why A Holochain DSL? The kinds of things that we want to be able to talk about that are pretty native to Holochain sensemaking: - **DHT Saturation:** Has this op or record successfully saturated the DHT (based on validation receipt count of ops?) - **Synced-ness:** Progress indicator for each chunk of DHT we hold in terms of total number of ops contained vs. number we've validated. - **Valid-ness:** success of each op as validated by the network - **DHT Health:** - **Online-ness:** - **Neighborhood Health:** - **Peer Reliability:** - **Connection Health:** - **Micro-Consensus:** reasoning tools for m of n signing of rivalrous data - **Chain State:** Is a chain healthy, or forked, spammed, key revoked, or maybe dead/inactive/idle - ** #### Validation Notes Authority Types Op Types Helpers for pulling up the Capability context Could validation be related to the definition itself? Then split out into HDI later? As peer - dev thinks about what role they're in, not reason about Holochain primitives. # Sample code ### Fancy: ``` struct MailingAddress { street: String, number: u16, } entry Attestation { content: String, about: AgentKey, mailing_address: MailingAddress, } entry Nonce { id: u32, note: String, with: AgentKey, } link_types { Of, By, Who } zome fn create_some_links(a: SomeInput, b: SomeInput) -> SomeOutput { // CREATE LINK TYPE Who AT a TO b TAGGED "frenemy"; let hash = create_link(Who) a -> b "frenemy"; let hash = create_link<Who> a -> b "frenemy"; let hash = a -Who("frenemy")-> b; let hash = link:Who a -> b #tag; (create-link Who a b #"tag") RETURN hash } zome fn attest(about: AgentKey) -> () { create Attestation { content: "they are awesome" about, mailing_address: MailingAddress { street: "Main St", number: 314, } } } validate(op: Op) { as entry_authority match on { Attestation: Nonce: } as link_base_authority match on Linktype as record_authority match on Sys / Entry / Link, then match on subtype as author_neighbor match on Sys / Entry / Link, then match on subtype as previous_entry_authority as previous_record_authority } ``` ### Current: ``` rust /// Attestation entry definition #[hdk_entry_helper] #[serde(rename_all = "camelCase")] #[derive(Clone)] pub struct Attestation { pub content: String, pub about: AgentPubKeyB64, } /// Nonce entry definition #[hdk_entry_helper] #[derive(Clone)] pub struct Nonce { pub id: u32, pub note: String, pub with: AgentPubKeyB64, } #[hdk_entry_defs] #[unit_enum(UnitEntryTypes)] pub enum EntryTypes { #[entry_def(required_validations = 5)] Attestation(Attestation), #[entry_def(required_validations = 5, visibility= "private")] Nonce(Nonce), } #[hdk_link_types] pub enum LinkTypes { Of, By, Who, } #[hdk_extern] pub fn validate(op: Op) -> ExternResult<ValidateCallbackResult> { match op { Op::StoreRecord ( _ ) => Ok(ValidateCallbackResult::Valid), Op::StoreEntry { .. } => Ok(ValidateCallbackResult::Valid), Op::RegisterCreateLink (create_link) => { //let hashed = create_link.hashed; let (create, _action) = create_link.create_link.into_inner(); let link_type = LinkTypes::try_from(ScopedLinkType { zome_id: create.zome_id, zome_type: create.link_type, })?; if link_type == LinkTypes::By { Ok(ValidateCallbackResult::Valid) } else if link_type == LinkTypes::Of { Ok(ValidateCallbackResult::Valid) } else if link_type == LinkTypes::Who { let attestation: Attestation = must_get_entry(create.target_address.clone().into())?.try_into()?; let agent = AgentPubKey::try_from(SerializedBytes::try_from(create.tag.clone()).map_err(|e| wasm_error!(e.into()))?).map_err(|e| wasm_error!(e.into()))?; if AgentPubKey::from(attestation.about) == agent { Ok(ValidateCallbackResult::Valid) } else { Ok(ValidateCallbackResult::Invalid( "tag doesn't point to about".to_string(), )) } } else { Ok(ValidateCallbackResult::Invalid( "unknown link type".to_string(), )) } } Op::RegisterDeleteLink (_)=> Ok(ValidateCallbackResult::Invalid( "deleting links isn't valid".to_string(), )), Op::RegisterUpdate { .. } => Ok(ValidateCallbackResult::Invalid( "updating entries isn't valid".to_string(), )), Op::RegisterDelete { .. } => Ok(ValidateCallbackResult::Invalid( "deleting entries isn't valid".to_string(), )), Op::RegisterAgentActivity { .. } => Ok(ValidateCallbackResult::Valid), } } ``` ``` ```