---
# System prepended metadata

title: Holochain Fluidity DSL

---

# 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),
    }
}
```

```

```