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