Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Call #453

Merged
merged 18 commits into from
Nov 6, 2020
1 change: 1 addition & 0 deletions CHANGELOG-UNRELEASED.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
- BREAKING: ZomeInfo now returns the ZomeId [390](https://github.com/holochain/holochain/pull/390)
- Implemented the `emit_signals` host function [#371](https://github.com/holochain/holochain/pull/371), which broadcasts a signal across all app interfaces (fine-grained pub/sub to be done in future work)
- get_details on a HeaderHash now returns the updates if it's an entry header
- call host fn (This is an actual function not a macro). Allows you to call a zome that is installed on the same conductor. [#453](https://github.com/holochain/holochain/pull/453)

### Changed

Expand Down
27 changes: 26 additions & 1 deletion crates/hdk/src/host_fn/call.rs
Original file line number Diff line number Diff line change
@@ -1 +1,26 @@
//! @todo
use crate::prelude::*;
use holo_hash::AgentPubKey;
use holochain_wasmer_guest::SerializedBytesError;
use holochain_zome_types::{
call::Call,
zome::{FunctionName, ZomeName},
};

use crate::host_fn;

pub fn call(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I notice this is a function rather than a macro. Don't get me wrong -- the fewer exclamation points the better, esp for people who are using RLS for code intel -- but in order to be consistent with the other host functions, should it stay a macro for now?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are planning to make them all function calls very soon

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather just change them all to functions then add in macros to then change back. It's not a big job to change them

Copy link
Contributor

@pdaoust pdaoust Nov 4, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That'd be lovely. Another thing that I've discovered in my "audit of RSM documentation" is that macros thwart rustdoc's ability to do auto-linking of argument and return types, which is painful for dev ergonomics. Means they have to do a lot of legwork themselves via the search box.

to_agent: AgentPubKey,
zome_name: ZomeName,
fn_name: FunctionName,
cap_secret: Option<CapSecret>,
request: SerializedBytes,
) -> Result<ZomeCallResponse, SerializedBytesError> {
freesig marked this conversation as resolved.
Show resolved Hide resolved
let provenance = agent_info!()?.agent_latest_pubkey;
host_fn!(
__call,
CallInput::new(Call::new(
to_agent, zome_name, fn_name, cap_secret, request, provenance
)),
CallOutput
)
}
1 change: 1 addition & 0 deletions crates/hdk/src/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ pub use crate::hash_path::anchor::list_anchor_tags;
pub use crate::hash_path::anchor::list_anchor_type_addresses;
pub use crate::hash_path::anchor::Anchor;
pub use crate::hash_path::path::Path;
pub use crate::host_fn::call::call;
pub use crate::map_extern;
pub use crate::map_extern::ExternResult;
pub use crate::query;
Expand Down
51 changes: 48 additions & 3 deletions crates/holochain/src/conductor/api/api_cell.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
//! The CellConductorApi allows Cells to talk to their Conductor

use std::sync::Arc;

use super::error::{ConductorApiError, ConductorApiResult};
use crate::conductor::{
entry_def_store::EntryDefBufferKey, interface::SignalBroadcaster, ConductorHandle,
};
use crate::core::ribosome::ZomeCallInvocation;
use crate::core::workflow::ZomeCallInvocationResult;
use crate::{
conductor::{
entry_def_store::EntryDefBufferKey, interface::SignalBroadcaster, ConductorHandle,
},
core::workflow::CallZomeWorkspaceLock,
};
use async_trait::async_trait;
use holo_hash::DnaHash;
use holochain_keystore::KeystoreSender;
Expand All @@ -21,6 +26,10 @@ pub struct CellConductorApi {
cell_id: CellId,
}

/// A handle that cn only call zome functions to avoid
/// making write lock calls
pub type CellConductorReadHandle = Arc<dyn CellConductorReadHandleT>;

impl CellConductorApi {
/// Instantiate from a Conductor reference and a CellId to identify which Cell
/// this API instance is associated with
Expand Down Expand Up @@ -86,6 +95,10 @@ impl CellConductorApiT for CellConductorApi {
async fn get_entry_def(&self, key: &EntryDefBufferKey) -> Option<EntryDef> {
self.conductor_handle.get_entry_def(key).await
}

fn into_call_zome_handle(self) -> CellConductorReadHandle {
Arc::new(self)
}
}

/// The "internal" Conductor API interface, for a Cell to talk to its calling Conductor.
Expand Down Expand Up @@ -125,4 +138,36 @@ pub trait CellConductorApiT: Clone + Send + Sync + Sized {

/// Get a [EntryDef] from the [EntryDefBuf]
async fn get_entry_def(&self, key: &EntryDefBufferKey) -> Option<EntryDef>;

/// Turn this into a call zome handle
fn into_call_zome_handle(self) -> CellConductorReadHandle;
}

#[async_trait]
/// A handle that cn only call zome functions to avoid
/// making write lock calls
pub trait CellConductorReadHandleT: Send + Sync {
/// Invoke a zome function on a Cell
async fn call_zome(
&self,
invocation: ZomeCallInvocation,
workspace_lock: &CallZomeWorkspaceLock,
) -> ConductorApiResult<ZomeCallInvocationResult>;
}

#[async_trait]
impl CellConductorReadHandleT for CellConductorApi {
async fn call_zome(
&self,
invocation: ZomeCallInvocation,
workspace_lock: &CallZomeWorkspaceLock,
) -> ConductorApiResult<ZomeCallInvocationResult> {
if self.cell_id == invocation.cell_id {
self.conductor_handle
.call_zome_with_workspace(invocation, workspace_lock.clone())
.await
} else {
self.conductor_handle.call_zome(invocation).await
}
}
}
4 changes: 4 additions & 0 deletions crates/holochain/src/conductor/api/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ mock! {
fn sync_get_dna(&self, dna_hash: &DnaHash) -> Option<DnaFile>;
fn sync_get_this_dna(&self) -> Option<DnaFile>;
fn sync_get_entry_def(&self, key: &EntryDefBufferKey) -> Option<EntryDef>;
fn into_call_zome_handle(self) -> super::CellConductorReadHandle;
}

trait Clone {
Expand Down Expand Up @@ -86,4 +87,7 @@ impl CellConductorApiT for MockCellConductorApi {
async fn get_entry_def(&self, key: &EntryDefBufferKey) -> Option<EntryDef> {
self.sync_get_entry_def(key)
}
fn into_call_zome_handle(self) -> super::CellConductorReadHandle {
self.into_call_zome_handle()
}
}
13 changes: 9 additions & 4 deletions crates/holochain/src/conductor/cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@
//! SourceChain which has already undergone Genesis.

use super::{interface::SignalBroadcaster, manager::ManagedTaskAdd};
use crate::conductor::handle::ConductorHandle;
use crate::conductor::{api::error::ConductorApiError, entry_def_store::get_entry_def_from_ids};
use crate::core::queue_consumer::{spawn_queue_consumer_tasks, InitialQueueTriggers};
use crate::core::ribosome::ZomeCallInvocation;
use crate::{
conductor::api::CellConductorApiT,
core::workflow::produce_dht_ops_workflow::dht_op_light::light_to_op,
};
use crate::{conductor::handle::ConductorHandle, core::workflow::CallZomeWorkspaceType};
use call_zome_workflow::call_zome_workspace_lock::CallZomeWorkspaceLock;
use holochain_zome_types::validate::ValidationPackage;
use holochain_zome_types::zome::FunctionName;
use holochain_zome_types::{header::EntryType, query::AgentActivity};
Expand Down Expand Up @@ -752,21 +753,25 @@ impl Cell {
// double ? because
// - ConductorApiResult
// - ZomeCallInvocationResult
Ok(self.call_zome(invocation).await??.try_into()?)
Ok(self.call_zome(invocation, None).await??.try_into()?)
}

/// Function called by the Conductor
#[instrument(skip(self, invocation))]
#[instrument(skip(self, invocation, workspace_lock))]
pub async fn call_zome(
&self,
invocation: ZomeCallInvocation,
workspace_lock: Option<CallZomeWorkspaceLock>,
) -> CellResult<ZomeCallInvocationResult> {
// Check if init has run if not run it
self.check_or_run_zome_init().await?;

let arc = self.env();
let keystore = arc.keystore().clone();
let workspace = CallZomeWorkspace::new(arc.clone().into())?;
let workspace = match workspace_lock {
Some(l) => CallZomeWorkspaceType::Used(l),
None => CallZomeWorkspaceType::Fresh(CallZomeWorkspace::new(arc.clone().into())?),
};
let conductor_api = self.conductor_api.clone();
let signal_tx = self.signal_broadcaster().await;
let ribosome = self.get_ribosome().await?;
Expand Down
25 changes: 23 additions & 2 deletions crates/holochain/src/conductor/handle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ use super::{
manager::TaskManagerRunHandle,
Cell, Conductor,
};
use crate::core::ribosome::ZomeCallInvocation;
use crate::core::workflow::ZomeCallInvocationResult;
use crate::core::{ribosome::ZomeCallInvocation, workflow::CallZomeWorkspaceLock};
use derive_more::From;
use holochain_types::{
app::{AppId, InstalledApp, InstalledCell, MembraneProof},
Expand Down Expand Up @@ -139,6 +139,13 @@ pub trait ConductorHandleT: Send + Sync {
invocation: ZomeCallInvocation,
) -> ConductorApiResult<ZomeCallInvocationResult>;

/// Invoke a zome function on a Cell with a workspace
async fn call_zome_with_workspace(
&self,
invocation: ZomeCallInvocation,
workspace_lock: CallZomeWorkspaceLock,
) -> ConductorApiResult<ZomeCallInvocationResult>;

/// Cue the autonomic system to perform some action early (experimental)
async fn autonomic_cue(&self, cue: AutonomicCue, cell_id: &CellId) -> ConductorApiResult<()>;

Expand Down Expand Up @@ -329,7 +336,21 @@ impl<DS: DnaStore + 'static> ConductorHandleT for ConductorHandleImpl<DS> {
let lock = self.conductor.read().await;
debug!(cell_id = ?invocation.cell_id);
let cell: &Cell = lock.cell_by_id(&invocation.cell_id)?;
Ok(cell.call_zome(invocation).await?)
Ok(cell.call_zome(invocation, None).await?)
}

async fn call_zome_with_workspace(
&self,
invocation: ZomeCallInvocation,
workspace_lock: CallZomeWorkspaceLock,
) -> ConductorApiResult<ZomeCallInvocationResult> {
// FIXME: D-01058: We are holding this read lock for
// the entire call to call_zome and blocking
// any writes to the conductor
let lock = self.conductor.read().await;
debug!(cell_id = ?invocation.cell_id);
let cell: &Cell = lock.cell_by_id(&invocation.cell_id)?;
Ok(cell.call_zome(invocation, Some(workspace_lock)).await?)
}

async fn autonomic_cue(&self, cue: AutonomicCue, cell_id: &CellId) -> ConductorApiResult<()> {
Expand Down
16 changes: 15 additions & 1 deletion crates/holochain/src/core/ribosome.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ pub mod guest_callback;
pub mod host_fn;
pub mod wasm_ribosome;

use crate::core::ribosome::guest_callback::entry_defs::EntryDefsInvocation;
use crate::core::ribosome::guest_callback::entry_defs::EntryDefsResult;
use crate::core::ribosome::guest_callback::init::InitInvocation;
use crate::core::ribosome::guest_callback::init::InitResult;
Expand All @@ -32,6 +31,10 @@ use crate::core::workflow::CallZomeWorkspaceLock;
use crate::fixt::ExternInputFixturator;
use crate::fixt::FunctionNameFixturator;
use crate::fixt::ZomeNameFixturator;
use crate::{
conductor::api::CellConductorReadHandle,
core::ribosome::guest_callback::entry_defs::EntryDefsInvocation,
};
use crate::{conductor::interface::SignalBroadcaster, core::ribosome::error::RibosomeError};
use ::fixt::prelude::*;
use derive_more::Constructor;
Expand Down Expand Up @@ -175,6 +178,16 @@ impl HostAccess {
_ => panic!("Gave access to a host function that references a CellId"),
}
}

/// Get the call zome handle, panics if none was provided
pub fn call_zome_handle(&self) -> &CellConductorReadHandle {
match self {
Self::ZomeCall(ZomeCallHostAccess{call_zome_handle, .. }) => {
call_zome_handle
}
_ => panic!("Gave access to a host function that uses the call zome handle without providing a call zome handle"),
}
}
}

#[derive(Clone, Debug)]
Expand Down Expand Up @@ -390,6 +403,7 @@ pub struct ZomeCallHostAccess {
pub keystore: KeystoreSender,
pub network: HolochainP2pCell,
pub signal_tx: SignalBroadcaster,
pub call_zome_handle: CellConductorReadHandle,
// NB: this is kind of an odd place for this, since CellId is not really a special
// "resource" to give access to, but rather it's a bit of data that makes sense in
// the context of zome calls, but not every CallContext
Expand Down
6 changes: 5 additions & 1 deletion crates/holochain/src/core/ribosome/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//! Errors occurring during a [Ribosome] call

use crate::{
conductor::interface::error::InterfaceError,
conductor::{api::error::ConductorApiError, interface::error::InterfaceError},
core::state::{cascade::error::CascadeError, source_chain::SourceChainError},
};
use holo_hash::AnyDhtHash;
Expand Down Expand Up @@ -65,6 +65,10 @@ pub enum RibosomeError {
#[error(transparent)]
CascadeError(#[from] CascadeError),

/// ident
#[error(transparent)]
ConductorApiError(#[from] Box<ConductorApiError>),

/// ident
#[error(transparent)]
SourceChainError(#[from] SourceChainError),
Expand Down