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

Trait feature: introspection/trait/get_zomes_by_trait #2181

Open
wants to merge 20 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG-UNRELEASED.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
{{ version-heading }}

### Added
* Trait handle / introspection: admin interfaces can now query the conductor to get all instances/zomes that implement a given zome trait. [#2181](https://github.com/holochain/holochain-rust/pull/2181)

### Changed

Expand Down
27 changes: 27 additions & 0 deletions app_spec/test/files/traits.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
const { one } = require('../config')

module.exports = scenario => {
scenario('get zomes by trait', async (s, t) => {
const {conductor} = await s.players({conductor: one}, true)

const crypto_trait = {
name: 'crypto',
functions: [
{
name: 'encrypt',
inputs: [{ name: 'payload', type: 'String' }],
outputs: [{ name: 'result', type: 'ZomeApiResult<String>' }],
},
{
name: 'decrypt',
inputs: [{ name: 'payload', type: 'String' }],
outputs: [{ name: 'result', type: 'ZomeApiResult<String>' }],
}
]
};

const zomes = await conductor.admin('introspection/traits/get_zomes_by_trait', {trait: crypto_trait})

t.deepEqual(zomes, [ { instance_id: 'app', zome_name: 'simple' } ] )
})
}
1 change: 1 addition & 0 deletions app_spec/test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ require('./files/links')(orchestrator.registerScenario)
require('./files/memo')(orchestrator.registerScenario)
require('./files/crypto')(orchestrator.registerScenario)
require('./files/offline-validation')(orchestrator.registerScenario)
require('./files/traits')(orchestrator.registerScenario)
require('./multi-dna')(orchestrator.registerScenario)
require('./offline')(orchestrator.registerScenario)
// require('./validate-agent-test')(orchestrator.registerScenario)
Expand Down
1 change: 1 addition & 0 deletions app_spec/zomes/simple/code/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -315,5 +315,6 @@ define_zome! {

traits: {
hc_public [create_anchor, get_entry, create_link, delete_link, get_my_links, test_emit_signal,get_my_links_count,create_link_with_tag,get_my_links_count_by_tag,delete_link_with_tag,get_my_links_with_tag,encrypt,decrypt,get_my_links_with_pagination,get_my_links_with_time_pagination]
crypto [encrypt, decrypt]
}
}
6 changes: 6 additions & 0 deletions app_spec/zomes/summer/code/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ define_zome! {

traits: {
hc_public [sum]

// This is to make sure the test for introspection/trait/get_zome_by_trait
// not only checks the trait name but also the function signatures in the trait.
// The according test expects to NOT get this zome as result for the crypto trait
// that is appropriately implemented only in the simple zome.
crypto [sum]
}

}
Expand Down
1 change: 0 additions & 1 deletion app_spec_proc_macro/build_and_test.sh

This file was deleted.

35 changes: 35 additions & 0 deletions app_spec_proc_macro/build_and_test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#!/usr/bin/env bash
set -euxo pipefail
mkdir -p dist

echo "===================================================================================="
echo "RUNNING cargo test for zomes"
echo "Using conductor binary: `command -v holochain`"
echo "Using cli binary: `command -v hc`"
echo "------------------------------------------------------------------------------------"

cargo test --manifest-path zomes/blog/code/Cargo.toml
cargo test --manifest-path zomes/summer/code/Cargo.toml

echo "===================================================================================="
echo "BUILDING genome with 'hc package --output dist/app_spec.dna.json':"
echo "------------------------------------------------------------------------------------"

rm -rf dist
mkdir dist
hc package --output dist/app_spec.dna.json
cp dist/app_spec.dna.json ../app_spec/dist/app_spec.dna.json

echo "DONE."
echo "===================================================================================="
echo "Running test.js in node"
echo "------------------------------------------------------------------------------------"

cd test
# --no-bin-links is required for windows vagrant support
# more precisely symlinks are not supported without additional work on the host
# e.g. https://superuser.com/questions/1115329/vagrant-shared-folder-and-symbolic-links-under-windows-10
npm install --no-bin-links
if [[ -z ${HC_APP_SPEC_BUILD_RUN:-} ]]
then APP_SPEC_NETWORK_TYPE=sim2h npm run test-ci
fi
1 change: 1 addition & 0 deletions app_spec_proc_macro/test
2 changes: 1 addition & 1 deletion app_spec_proc_macro/zomes/blog/code/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ edition = "2018"
serde = "=1.0.104"
serde_json = { version = "=1.0.47", features = ["preserve_order"] }
hdk = { path = "../../../../crates/hdk" }
hdk-proc-macros = { path = "../../../../crates/hdk_v2" }
hdk_proc_macros = { path = "../../../../crates/hdk_v2" }

holochain_json_derive = "=0.0.23"
serde_derive = "=1.0.104"
Expand Down
2 changes: 1 addition & 1 deletion app_spec_proc_macro/zomes/blog/code/src/blog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ pub fn handle_posts_by_agent(agent: Address) -> ZomeApiResult<GetLinksResult> {


pub fn handle_my_posts(tag: Option<String>) -> ZomeApiResult<GetLinksResult> {
let tag = match tag {Some(ref s) => LinkMatch::Regex(s.as_ref()), None => LinkMatch::Any};
let tag = match tag {Some(ref s) => LinkMatch::Exactly(s.as_ref()), None => LinkMatch::Any};
hdk::get_links(&AGENT_ADDRESS, LinkMatch::Exactly("authored_posts"), tag)
}

Expand Down
2 changes: 1 addition & 1 deletion app_spec_proc_macro/zomes/converse/code/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ serde = "=1.0.104"
serde_json = "=1.0.47"
serde_derive = "=1.0.104"
hdk = { path = "../../../../crates/hdk" }
hdk-proc-macros = { path = "../../../../crates/hdk_v2" }
hdk_proc_macros = { path = "../../../../crates/hdk_v2" }

[lib]
path = "src/lib.rs"
Expand Down
2 changes: 1 addition & 1 deletion app_spec_proc_macro/zomes/simple/code/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ edition = "2018"

[dependencies]
hdk = { path = "../../../../crates/hdk" }
hdk-proc-macros = { path = "../../../../crates/hdk_v2" }
hdk_proc_macros = { path = "../../../../crates/hdk_v2" }
serde = "=1.0.104"
serde_json = { version = "=1.0.47", features = ["preserve_order"] }
serde_derive = "=1.0.104"
Expand Down
4 changes: 2 additions & 2 deletions app_spec_proc_macro/zomes/simple/code/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,13 +143,13 @@ pub mod simple {
hdk::emit_signal("test-signal", SignalPayload{message})
}

#[zome_fn("hc_public")]
#[zome_fn("hc_public", "crypto")]
pub fn encrypt(payload : String) -> ZomeApiResult<String>
{
hdk::encrypt(payload)
}

#[zome_fn("hc_public")]
#[zome_fn("hc_public", "crypto")]
pub fn decrypt(payload : String) -> ZomeApiResult<String>
{
hdk::decrypt(payload)
Expand Down
3 changes: 2 additions & 1 deletion app_spec_proc_macro/zomes/summer/code/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
name = "summer"
version = "0.0.47-alpha1"
authors = ["Holochain Core Dev Team <[email protected]>"]
edition = "2018"

[dependencies]
serde = "=1.0.104"
serde_json = { version = "=1.0.47", features = ["preserve_order"] }
hdk = { path = "../../../../crates/hdk" }
hdk-proc-macros = { path = "../../../../crates/hdk_v2" }
hdk_proc_macros = { path = "../../../../crates/hdk_v2" }

serde_derive = "=1.0.104"
boolinator = "=2.4.0"
Expand Down
2 changes: 1 addition & 1 deletion app_spec_proc_macro/zomes/summer/code/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub mod summer {
Ok(())
}

#[zome_fn("hc_public")]
#[zome_fn("hc_public", "crypto")]
fn sum(num1: u32, num2: u32) -> ZomeApiResult<u32> {
Ok(num1 + num2)
}
Expand Down
3 changes: 2 additions & 1 deletion crates/conductor_lib/src/conductor/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1332,7 +1332,8 @@ impl Conductor {
.with_admin_dna_functions()
.with_admin_ui_functions()
.with_test_admin_functions()
.with_debug_functions();
.with_debug_functions()
.with_introspection_functions();
}

conductor_api_builder.spawn()
Expand Down
67 changes: 67 additions & 0 deletions crates/conductor_lib/src/conductor/introspection.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
use crate::conductor::Conductor;
use holochain_core_types::{
dna::fn_declarations::{FnDeclaration, TraitFns},
error::HolochainError,
};

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub struct ZomePath {
pub instance_id: String,
pub zome_name: String,
}

pub trait ConductorIntrospection {
fn get_zomes_by_trait(
&mut self,
trait_name: String,
trait_functions: Vec<FnDeclaration>,
) -> Result<Vec<ZomePath>, HolochainError>;
}

impl ConductorIntrospection for Conductor {
fn get_zomes_by_trait(
&mut self,
trait_name: String,
trait_functions: Vec<FnDeclaration>,
) -> Result<Vec<ZomePath>, HolochainError> {
let mut result = Vec::new();
for (instance_id, instance_lock) in self.instances.iter() {
if let Ok(dna) = instance_lock.read()?.dna() {
// Instance is initialized and has DNA
for (zome_name, zome) in dna.zomes.iter() {
if let Some(TraitFns { functions }) = zome.traits.get(&trait_name) {
// DNA implements a trait with same name.
// Still need to check all functions signatures...
let mut is_good = true;
for trait_fn_decl in trait_functions.iter() {
// Is the function name declared (by the zome) as part of that trait
// and does the whole declaration (complete signature) of the function
// as found in the some match the declaration in the given trait?
if !functions.contains(&trait_fn_decl.name)
|| !zome.fn_declarations.contains(&trait_fn_decl)
{
// If not we can exit this loop since it takes only one missing
// function to not have the trait implemented.
is_good = false;
break;
}
}

// If we didn't break out of above loop, we could fine all functions
// and we're good - this zome implements the trait.
if is_good {
let instance_id = instance_id.clone();
let zome_name = zome_name.clone();
result.push(ZomePath {
instance_id,
zome_name,
})
}
}
}
}
}

Ok(result)
}
}
2 changes: 2 additions & 0 deletions crates/conductor_lib/src/conductor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ pub mod admin;
pub mod base;
pub mod broadcaster;
pub mod debug;
pub mod introspection;
pub mod passphrase_manager;
pub mod test_admin;
pub mod ui_admin;
Expand All @@ -10,6 +11,7 @@ pub use self::{
admin::ConductorAdmin,
base::{mount_conductor_from_config, Conductor, CONDUCTOR},
debug::ConductorDebug,
introspection::ConductorIntrospection,
test_admin::ConductorTestAdmin,
ui_admin::ConductorUiAdmin,
};
Expand Down
14 changes: 14 additions & 0 deletions crates/conductor_lib/src/holochain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,20 @@ impl Holochain {
.expect("Context must be Some since we've checked it with check_instance()? above"),
)?)
}

pub fn dna(&self) -> Result<Dna, HolochainInstanceError> {
self.check_instance()?;
let state = self
.context
.as_ref()
.unwrap()
.state()
.ok_or(HolochainInstanceError::InstanceNotInitialized)?;
state
.nucleus()
.dna()
.ok_or(HolochainInstanceError::InstanceNotInitialized)
}
}

#[cfg(test)]
Expand Down
Loading