Skip to content
This repository has been archived by the owner on Feb 3, 2023. It is now read-only.

Commit

Permalink
Merge pull request #752 from holochain/bridges-dna-definition
Browse files Browse the repository at this point in the history
Bridges DNA definition
  • Loading branch information
Nicolas Luck authored Dec 19, 2018
2 parents 72021eb + 33f972b commit 256f874
Show file tree
Hide file tree
Showing 6 changed files with 237 additions and 5 deletions.
1 change: 1 addition & 0 deletions core_types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ regex = "^1.1"
[dev-dependencies]
test_utils = { path = "../test_utils"}
holochain_core = { path = "../core"}
maplit = "1.0.1"
66 changes: 66 additions & 0 deletions core_types/src/dna/bridges.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
use crate::{cas::content::Address, dna::capabilities::Capability};
use std::collections::BTreeMap;

/// A bridge is the definition of a connection to another DNA that runs under the same agency,
/// i.e. in the same container.
///
/// Defining a bridge means that the code in this DNA can call zome functions of that other
/// DNA.
///
/// The other DNA can either be referenced statically by exact DNA address/hash or dynamically
/// by defining the capabilities that other DNA has to provide in order to be usable as bridge.
///
/// Bridges can be required or optional. If a required bridge DNA is not installed this DNA
/// can't run, so required bridges are hard dependencies that have to be enforced by the container.
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash)]
pub struct Bridge {
/// Required or optional
pub presence: BridgePresence,

/// An arbitrary name of this bridge that is used as handle to reference this
/// bridge in according zome API functions
pub handle: String,

/// Define what other DNA(s) to bridge to
pub reference: BridgeReference,
}

/// This enum represents the two different ways of referring to another DNA instance.
/// If we know a priori what exact version of another DNA we want to bridge to we can
/// specify the DNA address (i.e. hash) and lock it in.
/// Often, we need more flexibility when
/// * the other DNA gets replaced by a newer version
/// * the other DNA gets created from a template and thus we don't know the exact hash
/// during build-time
/// * we want to build a complex system of components that should be pluggable.
/// Bridges can therefore also be specified by capabilities (read traits or interfaces).
/// That means we specify a list of functions with their signatures and allow the container
/// (through the container bridge config) to resolve this bridge by any DNA instance that
/// implements all specified functions, just like a dynamic binding of function calls.
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash)]
#[serde(untagged)]
pub enum BridgeReference {
/// A bridge reference that defines another DNA statically by its address (i.e. hash).
/// If this variant is used the other DNA gets locked in as per DNA hash
Address { dna_address: Address },

/// A bridge reference that defines another DNA loosely by expecting a DNA that implements
/// a given set of capabilities, i.e. that has specific sets of zome functions with
/// matching signatures.
Capability {
capabilities: BTreeMap<String, Capability>,
},
}

/// Required or optional
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash)]
#[serde(rename_all = "lowercase")]
pub enum BridgePresence {
/// A required bridge is a dependency to another DNA.
/// This DNA won't load without it.
Required,

/// An optional bridge may be missing.
/// This DNA's code can check via API functions if the other DNA is installed and connected.
Optional,
}
10 changes: 9 additions & 1 deletion core_types/src/dna/dna.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{
dna::{capabilities::Capability, entry_types::EntryTypeDef, wasm, zome},
dna::{bridges::Bridge, capabilities::Capability, entry_types::EntryTypeDef, wasm, zome},
entry::entry_type::EntryType,
error::{DnaError, HolochainError},
json::JsonString,
Expand Down Expand Up @@ -192,6 +192,14 @@ impl Dna {
multihash::encode(multihash::Hash::SHA2256, &s.into_bytes())
.map_err(|error| HolochainError::ErrorGeneric(error.to_string()))
}

pub fn get_required_bridges(&self) -> Vec<Bridge> {
self.zomes
.values()
.map(|zome| zome.get_required_bridges())
.flatten()
.collect()
}
}

impl Hash for Dna {
Expand Down
138 changes: 136 additions & 2 deletions core_types/src/dna/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
//! assert_eq!(name, dna2.name);
//! ```

pub mod bridges;
pub mod capabilities;
pub mod dna;
pub mod entry_types;
Expand All @@ -36,7 +37,13 @@ pub mod tests {
use super::*;
extern crate base64;
use crate::{
dna::{entry_types::EntryTypeDef, zome::tests::test_zome},
cas::content::Address,
dna::{
bridges::{Bridge, BridgePresence, BridgeReference},
capabilities::{Capability, CapabilityType, FnDeclaration, FnParameter, Membrane},
entry_types::EntryTypeDef,
zome::tests::test_zome,
},
entry::entry_type::{AppEntryType, EntryType},
json::JsonString,
};
Expand Down Expand Up @@ -132,7 +139,8 @@ pub mod tests {
},
"code": {
"code": "AAECAw=="
}
},
"bridges": []
}
}
}"#,
Expand Down Expand Up @@ -457,4 +465,130 @@ pub mod tests {
.get_zome_name_for_app_entry_type(&AppEntryType::from("non existant entry type"))
.is_none());
}

#[test]
fn test_get_required_bridges() {
let dna = Dna::try_from(JsonString::from(
r#"{
"name": "test",
"description": "test",
"version": "test",
"uuid": "00000000-0000-0000-0000-000000000000",
"dna_spec_version": "2.0",
"properties": {
"test": "test"
},
"zomes": {
"test zome": {
"name": "test zome",
"description": "test",
"config": {},
"capabilities": {
"test capability": {
"capability": {
"membrane": "public"
},
"fn_declarations": []
}
},
"entry_types": {
"test type": {
"description": "",
"sharing": "public"
}
},
"code": {
"code": ""
},
"bridges": [
{
"presence": "required",
"handle": "DPKI",
"reference": {
"dna_address": "Qmabcdef1234567890"
}
},
{
"presence": "optional",
"handle": "Vault",
"reference": {
"capabilities": {
"persona_management": {
"capability": {
"membrane": "public"
},
"functions": [
{
"name": "get_persona",
"inputs": [{"name": "domain", "type": "string"}],
"outputs": [{"name": "persona", "type": "json"}]
}
]
}
}
}
},
{
"presence": "required",
"handle": "HCHC",
"reference": {
"capabilities": {
"happ_directory": {
"capability": {
"membrane": "public"
},
"functions": [
{
"name": "get_happs",
"inputs": [],
"outputs": [{"name": "happs", "type": "json"}]
}
]
}
}
}
}
]
}
}
}"#,
))
.unwrap();

assert_eq!(
dna.get_required_bridges(),
vec![
Bridge {
presence: BridgePresence::Required,
handle: String::from("DPKI"),
reference: BridgeReference::Address {
dna_address: Address::from("Qmabcdef1234567890"),
}
},
Bridge {
presence: BridgePresence::Required,
handle: String::from("HCHC"),
reference: BridgeReference::Capability {
capabilities: btreemap! {
String::from("happ_directory") => Capability{
cap_type: CapabilityType {
membrane: Membrane::Public
},
functions: vec![
FnDeclaration {
name: String::from("get_happs"),
inputs: vec![],
outputs: vec![FnParameter{
name: String::from("happs"),
parameter_type: String::from("json"),
}],
}
]
}
}
},
},
]
);
}
}
24 changes: 22 additions & 2 deletions core_types/src/dna/zome.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
//! holochain_core_types::dna::zome is a set of structs for working with holochain dna.

use crate::{
dna::wasm::DnaWasm, entry::entry_type::EntryType, error::HolochainError, json::JsonString,
dna::{
bridges::{Bridge, BridgePresence},
wasm::DnaWasm,
},
entry::entry_type::EntryType,
error::HolochainError,
json::JsonString,
};
use dna::{
capabilities,
Expand Down Expand Up @@ -76,6 +82,10 @@ pub struct Zome {
/// Validation code for this entry_type.
#[serde(default)]
pub code: DnaWasm,

/// A list of bridges to other DNAs that this DNA can use or depends on.
#[serde(default)]
pub bridges: Vec<Bridge>,
}

impl Eq for Zome {}
Expand All @@ -89,6 +99,7 @@ impl Default for Zome {
entry_types: BTreeMap::new(),
capabilities: BTreeMap::new(),
code: DnaWasm::new(),
bridges: Vec::new(),
}
}
}
Expand All @@ -108,8 +119,17 @@ impl Zome {
entry_types: entry_types.to_owned(),
capabilities: capabilities.to_owned(),
code: code.clone(),
bridges: Vec::new(),
}
}

pub fn get_required_bridges(&self) -> Vec<Bridge> {
self.bridges
.iter()
.filter(|bridge| bridge.presence == BridgePresence::Required)
.cloned()
.collect()
}
}

#[cfg(test)]
Expand Down Expand Up @@ -153,7 +173,7 @@ pub mod tests {
..Default::default()
};

let expected = "{\"description\":\"\",\"config\":{\"error_handling\":\"throw-errors\"},\"entry_types\":{\"foo\":{\"description\":\"\",\"sharing\":\"public\",\"links_to\":[],\"linked_from\":[]}},\"capabilities\":{},\"code\":{\"code\":\"\"}}";
let expected = "{\"description\":\"\",\"config\":{\"error_handling\":\"throw-errors\"},\"entry_types\":{\"foo\":{\"description\":\"\",\"sharing\":\"public\",\"links_to\":[],\"linked_from\":[]}},\"capabilities\":{},\"code\":{\"code\":\"\"},\"bridges\":[]}";

assert_eq!(
JsonString::from(expected.clone()),
Expand Down
3 changes: 3 additions & 0 deletions core_types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ extern crate snowflake;
#[macro_use]
extern crate holochain_core_types_derive;
extern crate regex;
#[cfg(test)]
#[macro_use]
extern crate maplit;

extern crate uuid;

Expand Down

0 comments on commit 256f874

Please sign in to comment.